Add an 'unresolved_comments_count' prolog fact for each change
This change introduces a new prolog fact for the number of unresolved comments. This fact can be further used by some prolog rules to block the submission of changes with some unresolved comments. A new example is also added to the prolog cookbook to show how to use this new fact. Change-Id: Iadc48f0758137b0071484265c22ebcb9bc2d2b26
This commit is contained in:
parent
4ed2216797
commit
a5d01788a9
@ -60,6 +60,9 @@ of them we must use a qualified name like `gerrit:change_branch(X)`.
|
||||
|
||||
|`uploader/1` |`uploader(user(1000000)).`
|
||||
|Uploader as `user(ID)` term. ID is the numeric account ID
|
||||
|
||||
|`unresolved_comments_count/1` |`unresolved_comments_count(0).`
|
||||
|The number of unresolved comments as an integer atom
|
||||
|=============================================================================
|
||||
|
||||
In addition Gerrit provides a set of built-in helper predicates that can be used
|
||||
|
@ -998,6 +998,56 @@ only_allow_author_to_submit(S, S) :-
|
||||
only_allow_author_to_submit(S1, [label('Only-Author-Can-Submit', need(_)) | S1]).
|
||||
----
|
||||
|
||||
=== Example 16: Make change submittable if all comments have been resolved
|
||||
In this example we will use the `unresolved_comments_count` fact about a
|
||||
change. Our goal is to block the submission of any change with some
|
||||
unresolved comments. Basically, it can be achieved by the following rules:
|
||||
|
||||
`rules.pl`
|
||||
[source,prolog]
|
||||
----
|
||||
submit_rule(submit(R)) :-
|
||||
gerrit:unresolved_comments_count(0),
|
||||
!,
|
||||
gerrit:commit_author(A),
|
||||
R = label('All-Comments-Resolved', ok(A)).
|
||||
|
||||
submit_rule(submit(R)) :-
|
||||
gerrit:unresolved_comments_count(U),
|
||||
U > 0,
|
||||
R = label('All-Comments-Resolved', need(_)).
|
||||
----
|
||||
|
||||
Suppose currently a change is submittable if it gets `+2` for `Code-Review`
|
||||
and `+1` for `Verified`. It can be extended to support the above rules as
|
||||
follows:
|
||||
|
||||
`rules.pl`
|
||||
[source,prolog]
|
||||
----
|
||||
submit_rule(submit(CR, V, R)) :-
|
||||
base(CR, V),
|
||||
gerrit:unresolved_comments_count(0),
|
||||
!,
|
||||
gerrit:commit_author(A),
|
||||
R = label('All-Comments-Resolved', ok(A)).
|
||||
|
||||
submit_rule(submit(CR, V, R)) :-
|
||||
base(CR, V),
|
||||
gerrit:unresolved_comments_count(U),
|
||||
U > 0,
|
||||
R = label('All-Comments-Resolved', need(_)).
|
||||
|
||||
base(CR, V) :-
|
||||
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
||||
gerrit:max_with_block(-1, 1, 'Verified', V).
|
||||
----
|
||||
|
||||
Note that a new label as `All-Comments-Resolved` should not be configured.
|
||||
It's only used to show `'Needs All-Comments-Resolved'` in the UI to clearly
|
||||
indicate to the user that all the comments have to be resolved for the
|
||||
change to become submittable.
|
||||
|
||||
== Examples - Submit Type
|
||||
The following examples show how to implement own submit type rules.
|
||||
|
||||
|
@ -46,6 +46,7 @@ import com.google.gerrit.acceptance.GerritConfig;
|
||||
import com.google.gerrit.acceptance.GitUtil;
|
||||
import com.google.gerrit.acceptance.NoHttpd;
|
||||
import com.google.gerrit.acceptance.PushOneCommit;
|
||||
import com.google.gerrit.acceptance.Sandboxed;
|
||||
import com.google.gerrit.acceptance.TestAccount;
|
||||
import com.google.gerrit.acceptance.TestProjectInput;
|
||||
import com.google.gerrit.common.FooterConstants;
|
||||
@ -2408,6 +2409,71 @@ public class ChangeIT extends AbstractDaemonTest {
|
||||
assertThat(approval.permittedVotingRange).isNull();
|
||||
}
|
||||
|
||||
@Sandboxed
|
||||
@Test
|
||||
public void unresolvedCommentsBlocked() throws Exception {
|
||||
RevCommit oldHead = getRemoteHead();
|
||||
GitUtil.fetch(testRepo, RefNames.REFS_CONFIG + ":config");
|
||||
testRepo.reset("config");
|
||||
PushOneCommit push =
|
||||
pushFactory.create(
|
||||
db,
|
||||
admin.getIdent(),
|
||||
testRepo,
|
||||
"Configure",
|
||||
"rules.pl",
|
||||
"submit_rule(submit(R)) :- \n"
|
||||
+ "gerrit:unresolved_comments_count(0), \n"
|
||||
+ "!,"
|
||||
+ "gerrit:commit_author(A), \n"
|
||||
+ "R = label('All-Comments-Resolved', ok(A)).\n"
|
||||
+ "submit_rule(submit(R)) :- \n"
|
||||
+ "gerrit:unresolved_comments_count(U), \n"
|
||||
+ "U > 0,"
|
||||
+ "R = label('All-Comments-Resolved', need(_)). \n\n");
|
||||
|
||||
push.to(RefNames.REFS_CONFIG);
|
||||
testRepo.reset(oldHead);
|
||||
|
||||
oldHead = getRemoteHead();
|
||||
PushOneCommit.Result result1 =
|
||||
pushFactory.create(db, user.getIdent(), testRepo).to("refs/for/master");
|
||||
testRepo.reset(oldHead);
|
||||
PushOneCommit.Result result2 =
|
||||
pushFactory.create(db, user.getIdent(), testRepo).to("refs/for/master");
|
||||
|
||||
addComment(result1, "comment 1", true, false, null);
|
||||
addComment(result2, "comment 2", true, true, null);
|
||||
|
||||
gApi.changes().id(result1.getChangeId()).current().submit();
|
||||
|
||||
exception.expect(ResourceConflictException.class);
|
||||
exception.expectMessage(
|
||||
"Failed to submit 1 change due to the following problems:\n"
|
||||
+ "Change 2: needs All-Comments-Resolved");
|
||||
gApi.changes().id(result2.getChangeId()).current().submit();
|
||||
}
|
||||
|
||||
private void addComment(
|
||||
PushOneCommit.Result r,
|
||||
String message,
|
||||
boolean omitDuplicateComments,
|
||||
Boolean unresolved,
|
||||
String inReplyTo)
|
||||
throws Exception {
|
||||
ReviewInput.CommentInput c = new ReviewInput.CommentInput();
|
||||
c.line = 1;
|
||||
c.message = message;
|
||||
c.path = FILE_NAME;
|
||||
c.unresolved = unresolved;
|
||||
c.inReplyTo = inReplyTo;
|
||||
ReviewInput in = new ReviewInput();
|
||||
in.comments = new HashMap<>();
|
||||
in.comments.put(c.path, Lists.newArrayList(c));
|
||||
in.omitDuplicateComments = omitDuplicateComments;
|
||||
gApi.changes().id(r.getChangeId()).revision(r.getCommit().name()).review(in);
|
||||
}
|
||||
|
||||
private static Iterable<Account.Id> getReviewers(Collection<AccountInfo> r) {
|
||||
return Iterables.transform(r, a -> new Account.Id(a._accountId));
|
||||
}
|
||||
|
@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2017 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 gerrit;
|
||||
|
||||
import com.google.gerrit.rules.StoredValues;
|
||||
import com.google.gwtorm.server.OrmException;
|
||||
import com.googlecode.prolog_cafe.exceptions.JavaException;
|
||||
import com.googlecode.prolog_cafe.exceptions.PrologException;
|
||||
import com.googlecode.prolog_cafe.lang.IntegerTerm;
|
||||
import com.googlecode.prolog_cafe.lang.Operation;
|
||||
import com.googlecode.prolog_cafe.lang.Predicate;
|
||||
import com.googlecode.prolog_cafe.lang.Prolog;
|
||||
import com.googlecode.prolog_cafe.lang.Term;
|
||||
|
||||
public class PRED_unresolved_comments_count_1 extends Predicate.P1 {
|
||||
public PRED_unresolved_comments_count_1(Term a1, Operation n) {
|
||||
arg1 = a1;
|
||||
cont = n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Operation exec(Prolog engine) throws PrologException {
|
||||
engine.setB0();
|
||||
Term a1 = arg1.dereference();
|
||||
|
||||
try {
|
||||
Integer count = StoredValues.CHANGE_DATA.get(engine).unresolvedCommentCount();
|
||||
if (!a1.unify(new IntegerTerm(count != null ? count : 0), engine.trail)) {
|
||||
return engine.fail();
|
||||
}
|
||||
} catch (OrmException err) {
|
||||
throw new JavaException(this, 1, err);
|
||||
}
|
||||
return cont;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user