rules.pl: add Trust+2 check and disallow self-code-review
For golang/go#40699.
Change-Id: I681f08cb84aa9bf4b227188594ea02c2727b3697
Reviewed-on: https://go-review.googlesource.com/c/All-Projects/+/254799
Reviewed-by: Andrew Bonventre <andybons@google.com>
diff --git a/rules.pl b/rules.pl
index 88efe81..4247e63 100644
--- a/rules.pl
+++ b/rules.pl
@@ -1,22 +1,93 @@
-% We don't send email if the commit message says DO NOT REVIEW, so don't allow submit either.
-% Case insensitive because the mail filter rules are.
+% submit_rule in the actual project (go, scratch, etc.)
+% generates a list of labels and whether they are ok, needed, or can be ignored.
+% Most repos don't define a specific submit_rule; the server uses gerrit:default_submit.
+%
+% submit_filter, defined below, is applied to the output of submit_rule to adjust it.
+% The adjustments are:
+%
+% * do_not_review_filter: add a “rejected by Do-Not-Review label”
+% if the commit message says DO NOT REVIEW.
+%
+% * do_not_submit_filter: add a “rejected by Do-Not-Submit label”
+% if the commit message says DO NOT SUBMIT.
+%
+% * trust_filter: make sure that two different people have set
+% either Code-Review+2 or Trust+1 on the commit.
+%
+% * self_review_filter: make sure that Code-Review+2
+% is from someone other than the author of the commit.
+%
+% Note that if you make any mistake in this file that causes
+% a Prolog execution exception or makes submit_filter not succeed,
+% the usual signal you get in Gerrit is that labels disappear from the UI for all CLs.
+% Sometimes you get an internal error popup instead (syntax errors do this, for example).
+
submit_filter(In, Out) :-
- In =.. [submit | I],
+ Gobot = user(5976),
+ In =.. [submit | A],
+ do_not_review_filter(Gobot, A, B),
+ do_not_submit_filter(Gobot, B, C),
+ trust_filter(Gobot, C, D),
+ self_review_filter(Gobot, D, E),
+ Out =.. [submit | E].
+
+% We don't send email if the commit message says DO NOT REVIEW,
+% so don't allow submit either.
+% Case insensitive because the mail filter rules are.
+do_not_review_filter(Gobot, In, Out) :-
gerrit:commit_message_matches('[Dd][Oo][ \t\r\n]+[Nn][Oo][Tt][ \t\r\n]+[Rr][Ee][Vv][Ii][Ee][Ww]'),
!,
gerrit:commit_author(Id),
Error = label('Do-Not-Review', reject(Id)),
- Out =.. [submit, Error | I].
+ Out = [Error | In].
+
+do_not_review_filter(Gobot, In, Out) :-
+ Out = In.
% Don't allow submit of DO NOT SUBMIT commit message either.
% Case insensitive because DO NOT REVIEW is.
-submit_filter(In, Out) :-
- In =.. [submit | I],
+do_not_submit_filter(Gobot, In, Out) :-
gerrit:commit_message_matches('[Dd][Oo][ \t\r\n]+[Nn][Oo][Tt][ \t\r\n]+[Ss][Uu][Bb][Mm][Ii][Tt]'),
!,
gerrit:commit_author(Id),
Error = label('Do-Not-Submit', reject(Id)),
- Out =.. [submit, Error | I].
+ Out = [Error | In].
-% Otherwise, pass submit rule through.
-submit_filter(In, Out) :- In = Out.
+do_not_submit_filter(Gobot, In, Out) :-
+ Out = In.
+
+% Check for two trusted author/reviewers, unless Self-Review-OK label set by project.
+trust_filter(Gobot, In, Out) :- has_label('Self-Review-OK', In), !, Out = In.
+trust_filter(Gobot, In, Out) :- trust2, !, Out = [label('Trust-2', ok(Gobot)) | In].
+trust_filter(Gobot, In, Out) :- Out = [label('Trust-2', reject(Gobot)) | In].
+
+trust2 :- trust(U1), trust(U2), U1 \= U2.
+
+trust(U) :- gerrit:commit_label(label('Code-Review', 2), U).
+trust(U) :- gerrit:commit_label(label('Trust', 1), U).
+
+% Reject self-code-review, unless Self-Review-OK label set by project.
+%
+% NOTE: Projects (= repos) that allow self-code-review and that do not require Trust+2
+% (for example, the blog and proposal projects), can use this in rules.pl to set Self-Review-OK:
+%
+% submit_rule(S) :-
+% Gobot = user(5976),
+% gerrit:default_submit(R),
+% R =.. [submit | A],
+% self_review_ok(Gobot, A, B),
+% S =.. [submit | B].
+%
+% self_review_ok(Gobot, In, Out) :- Out = [label('Self-Review-OK', ok(Gobot)) | In].
+%
+self_review_filter(Gobot, In, Out) :- has_label('Self-Review-OK', In), !, Out = In.
+self_review_filter(Gobot, In, Out) :- self_review, !, Out = [label('Self-Review', reject(Gobot)) | In].
+self_review_filter(Gobot, In, Out) :- Out = In.
+
+self_review :-
+ gerrit:change_owner(Owner),
+ gerrit:commit_label(label('Code-Review', 2), Owner).
+
+% has_label checks whether the list contains the label L.
+has_label(L, [label(L, _) | T]).
+has_label(L, [_ | T]) :- has_label(L, T).