diff options
author | Luke Alonso <lalonso@gmail.com> | 2020-12-29 17:25:46 -0800 |
---|---|---|
committer | Luke Alonso <lalonso@gmail.com> | 2020-12-30 13:54:59 -0800 |
commit | 358fe468439fa36c0944ee758e9aff8f042f2fab (patch) | |
tree | 924f15993c80d1eaacc9c39a8e1053315392c1bf | |
parent | c02530fa4165f483d85f129f3da1217f2a66715f (diff) |
Fix 'is:submittable' query on multiple submit records
When a project has multiple submit rules, which produce
multiple submit records, the 'is:submittable' query stops
working as the documentation indicates it should. Rather
than returning changes that are ready to be submitted,
it returns any change where at least one submit record
is OK, despite the overall change not being submittable.
For example, with the code-owners plugin, which uses
a java-based submit rule, 'is:submittable' will return
changes that are passing owners checks, but might
have CodeReview:-2 or Verified:-1.
For projects with a single submit rule, the behavior
is exactly the same as before, since we simply check
that *any* of the submit records is OK, exactly as before,
AND that *none* of them are NOT_READY or RULE_ERROR.
Bug: Issue 13884
Change-Id: I4878ce13c6673852916d6891253d5e62b46f3db5
-rw-r--r-- | java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java | 10 | ||||
-rw-r--r-- | javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java | 104 |
2 files changed, 108 insertions, 6 deletions
diff --git a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java index 886d0eea09..d7627462fe 100644 --- a/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java +++ b/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java @@ -621,7 +621,15 @@ public class ChangeQueryBuilder extends QueryBuilder<ChangeData, ChangeQueryBuil } if ("submittable".equalsIgnoreCase(value)) { - return new SubmittablePredicate(SubmitRecord.Status.OK); + // SubmittablePredicate will match if *any* of the submit records are OK, + // but we need to check that they're *all* OK, so check that none of the + // submit records match any of the negative cases. To avoid checking yet + // more negative cases for CLOSED and FORCED, instead make sure at least + // one submit record is OK. + return Predicate.and( + new SubmittablePredicate(SubmitRecord.Status.OK), + Predicate.not(new SubmittablePredicate(SubmitRecord.Status.NOT_READY)), + Predicate.not(new SubmittablePredicate(SubmitRecord.Status.RULE_ERROR))); } if ("ignored".equalsIgnoreCase(value)) { diff --git a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java index 40dd70ed7f..5523f9ca50 100644 --- a/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java +++ b/javatests/com/google/gerrit/acceptance/api/change/ChangeSubmitRequirementIT.java @@ -22,6 +22,8 @@ import com.google.gerrit.acceptance.PushOneCommit; import com.google.gerrit.common.data.SubmitRecord; import com.google.gerrit.common.data.SubmitRequirement; import com.google.gerrit.extensions.annotations.Exports; +import com.google.gerrit.extensions.api.changes.ChangeApi; +import com.google.gerrit.extensions.api.changes.ReviewInput; import com.google.gerrit.extensions.common.ChangeInfo; import com.google.gerrit.extensions.common.SubmitRequirementInfo; import com.google.gerrit.extensions.config.FactoryModule; @@ -33,7 +35,6 @@ import com.google.inject.Singleton; import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Test; public class ChangeSubmitRequirementIT extends AbstractDaemonTest { @@ -93,20 +94,113 @@ public class ChangeSubmitRequirementIT extends AbstractDaemonTest { assertThat(result.get(0).requirements).containsExactly(reqInfo); } + @Test + public void submittableQueryRuleNotReady() throws Exception { + ChangeApi change = newChangeApi(); + + // Satisfy the default rule. + approveChange(change); + + // The custom rule is NOT_READY. + rule.block(true); + change.index(); + + assertThat(queryIsSubmittable()).isEmpty(); + } + + @Test + public void submittableQueryRuleError() throws Exception { + ChangeApi change = newChangeApi(); + + // Satisfy the default rule. + approveChange(change); + + rule.status(Optional.of(SubmitRecord.Status.RULE_ERROR)); + change.index(); + + assertThat(queryIsSubmittable()).isEmpty(); + } + + @Test + public void submittableQueryDefaultRejected() throws Exception { + ChangeApi change = newChangeApi(); + + // CodeReview:-2 the change, causing the default rule to fail. + rejectChange(change); + + rule.status(Optional.of(SubmitRecord.Status.OK)); + change.index(); + + assertThat(queryIsSubmittable()).isEmpty(); + } + + @Test + public void submittableQueryRuleOk() throws Exception { + ChangeApi change = newChangeApi(); + + // Satisfy the default rule. + approveChange(change); + + rule.status(Optional.of(SubmitRecord.Status.OK)); + change.index(); + + List<ChangeInfo> result = queryIsSubmittable(); + assertThat(result).hasSize(1); + assertThat(result.get(0).changeId).isEqualTo(change.info().changeId); + } + + @Test + public void submittableQueryRuleNoRecord() throws Exception { + ChangeApi change = newChangeApi(); + + // Satisfy the default rule. + approveChange(change); + + // Our custom rule isn't providing any submit records. + rule.status(Optional.empty()); + change.index(); + + // is:submittable should return the change, since it was approved and the custom rule is not + // blocking it. + List<ChangeInfo> result = queryIsSubmittable(); + assertThat(result).hasSize(1); + assertThat(result.get(0).changeId).isEqualTo(change.info().changeId); + } + + private List<ChangeInfo> queryIsSubmittable() throws Exception { + return gApi.changes().query("is:submittable project:" + project.get()).get(); + } + + private ChangeApi newChangeApi() throws Exception { + return gApi.changes().id(createChange().getChangeId()); + } + + private void approveChange(ChangeApi changeApi) throws Exception { + changeApi.current().review(ReviewInput.approve()); + } + + private void rejectChange(ChangeApi changeApi) throws Exception { + changeApi.current().review(ReviewInput.reject()); + } + @Singleton private static class CustomSubmitRule implements SubmitRule { - private final AtomicBoolean block = new AtomicBoolean(true); + private Optional<SubmitRecord.Status> recordStatus = Optional.empty(); public void block(boolean block) { - this.block.set(block); + this.status(block ? Optional.of(SubmitRecord.Status.NOT_READY) : Optional.empty()); + } + + public void status(Optional<SubmitRecord.Status> status) { + this.recordStatus = status; } @Override public Optional<SubmitRecord> evaluate(ChangeData changeData) { - if (block.get()) { + if (this.recordStatus.isPresent()) { SubmitRecord record = new SubmitRecord(); record.labels = new ArrayList<>(); - record.status = SubmitRecord.Status.NOT_READY; + record.status = this.recordStatus.get(); record.requirements = ImmutableList.of(req); return Optional.of(record); } |