blob: 648c71bf736d5f9b8f2c87be42e0926cb889d996 [file] [log] [blame]
// Copyright (C) 2018 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.googlesource.gerrit.plugins.simplesubmitrules.rules;
import com.google.common.annotations.VisibleForTesting;
import com.google.gerrit.common.data.LabelFunction;
import com.google.gerrit.common.data.LabelType;
import com.google.gerrit.common.data.SubmitRecord;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.PatchSetApproval;
import com.google.gerrit.server.project.ProjectCache;
import com.google.gerrit.server.project.ProjectConfig;
import com.google.gerrit.server.project.ProjectState;
import com.google.gerrit.server.project.SubmitRuleOptions;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.rules.SubmitRule;
import com.google.gwtorm.server.OrmException;
import com.google.inject.Inject;
import com.googlesource.gerrit.plugins.simplesubmitrules.SimpleSubmitRulesConfig;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Simple rule: require a non-author approval or block submission */
public class RequireNonAuthorApprovalRule implements SubmitRule {
private static final Logger log = LoggerFactory.getLogger(RequireNonAuthorApprovalRule.class);
private static final String E_UNABLE_TO_FETCH_CHANGE_OWNER = "Unable to fetch the change owner";
private static final String E_UNABLE_TO_FETCH_LABELS =
"Unable to fetch labels and approvals for the change";
private final ProjectCache projectCache;
@Inject
public RequireNonAuthorApprovalRule(ProjectCache projectCache) {
this.projectCache = projectCache;
}
@Override
public Collection<SubmitRecord> evaluate(ChangeData cd, SubmitRuleOptions options) {
ProjectState projectState = projectCache.get(cd.project());
Config config = projectState.getConfig(ProjectConfig.PROJECT_CONFIG).getWithInheritance();
Account.Id owner;
try {
owner = cd.change().getOwner();
} catch (OrmException e) {
log.error(E_UNABLE_TO_FETCH_CHANGE_OWNER, e);
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.errorMessage = E_UNABLE_TO_FETCH_CHANGE_OWNER;
submitRecord.status = SubmitRecord.Status.RULE_ERROR;
return Collections.singletonList(submitRecord);
}
List<LabelType> labelTypes;
List<PatchSetApproval> approvals;
try {
labelTypes = cd.getLabelTypes().getLabelTypes();
approvals = cd.currentApprovals();
} catch (OrmException e) {
log.error(E_UNABLE_TO_FETCH_LABELS, e);
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.errorMessage = E_UNABLE_TO_FETCH_LABELS;
submitRecord.status = SubmitRecord.Status.RULE_ERROR;
return Collections.singletonList(submitRecord);
}
SubmitRecord submitRecord = new SubmitRecord();
submitRecord.status = SubmitRecord.Status.OK;
submitRecord.labels = new ArrayList<>(labelTypes.size());
for (LabelType t : labelTypes) {
if (!config.getBoolean(
t.getName(), SimpleSubmitRulesConfig.KEY_REQUIRE_NON_AUTHOR_APPROVAL, false)) {
// The default rules are enough in this case.
continue;
}
LabelFunction labelFunction = t.getFunction();
if (labelFunction == null) {
continue;
}
Collection<PatchSetApproval> approvalsForLabel = getApprovalsForLabel(approvals, t, owner);
SubmitRecord.Label label = labelFunction.check(t, approvalsForLabel);
switch (label.status) {
case OK:
case MAY:
break;
case NEED:
case REJECT:
case IMPOSSIBLE:
submitRecord.labels.add(label);
submitRecord.status = SubmitRecord.Status.NOT_READY;
break;
}
}
if (submitRecord.labels.isEmpty()) {
return Collections.emptyList();
}
return Collections.singletonList(submitRecord);
}
/**
* Returns the approvals for a given label, for everyone except from `user`, except if the vote is
* negative.
*/
@VisibleForTesting
static Collection<PatchSetApproval> getApprovalsForLabel(
Collection<PatchSetApproval> approvals, LabelType t, Account.Id user) {
return approvals
.stream()
.filter(input -> input.getValue() < 0 || !input.getAccountId().equals(user))
.filter(input -> input.getLabel().equals(t.getLabelId().get()))
.collect(Collectors.toList());
}
}