blob: 105929a40edab9709d20909644104e04093ce49e [file] [log] [blame]
Sasa Zivkovae50f712012-07-24 14:51:44 +02001Gerrit Code Review - Prolog Submit Rules Cookbook
2=================================================
3
4Submit Rule
5-----------
6A 'Submit Rule' in Gerrit is logic that defines when a change is submittable.
7By default, a change is submittable when it gets at least one
8highest vote in each voting category and has no lowest vote (aka veto vote) in
9any category. Typically, this means that a change needs 'Code-Review+2',
10'Verified+1' and has neither 'Code-Review-2' nor 'Verified-1' to become
11submittable.
12
13While this rule is a good default, there are projects which need more
14flexibility for defining when a change is submittable. In Gerrit, it is
15possible to use Prolog based rules to provide project specific submit rules and
16replace the default submit rules. Using Prolog based rules, project owners can
17define a set of criteria which must be fulfilled for a change to become
18submittable. For a change that is not submittable, the set of needed criteria
19is displayed in the Gerrit UI.
20
21NOTE: Loading and executing Prolog submit rules may be disabled by setting
22`rules.enabled=false` in the Gerrit config file (see
23link:config-gerrit.html#_a_id_rules_a_section_rules[rules section])
24
25link:https://groups.google.com/d/topic/repo-discuss/wJxTGhlHZMM/discussion[This
26discussion thread] explains why Prolog was chosen for the purpose of writing
27project specific submit rules.
28link:http://gerrit-documentation.googlecode.com/svn/ReleaseNotes/ReleaseNotes-2.2.2.html[Gerrit
292.2.2 ReleaseNotes] introduces Prolog support in Gerrit.
30
31Prolog Language
32---------------
33This document is not a complete Prolog tutorial.
34link:http://en.wikipedia.org/wiki/Prolog[This Wikipedia page on Prolog] is a
35good starting point for learning the Prolog language. This document will only explain
36some elements of Prolog that are necessary to understand the provided examples.
37
38Prolog in Gerrit
39----------------
40Gerrit uses its own link:https://code.google.com/p/prolog-cafe/[fork] of the
41original link:http://kaminari.istc.kobe-u.ac.jp/PrologCafe/[prolog-cafe]
42project. Gerrit embeds the prolog-cafe library and can interpret Prolog programs at
43runtime.
44
45Interactive Prolog Cafe Shell
46-----------------------------
47For interactive testing and playing with Prolog, Gerrit provides the
48link:pgm-prolog-shell.html[prolog-shell] program which opens an interactive
49Prolog interpreter shell.
50
51NOTE: It is currently *not possible* to test a Prolog program which implements
52Gerrit submit rules using the link:pgm-prolog-shell.html[prolog-shell] program.
53The reason is that the Prolog environment that exposes facts about a change
54requires a lot of Gerrit server environment to be loaded and running.
55
56SWI-Prolog
57----------
58Instead of using the link:pgm-prolog-shell.html[prolog-shell] program one can
59also use the link:http://www.swi-prolog.org/[SWI-Prolog] environment. It
60provides a better shell interface and a graphical source-level debugger.
61
62The rules.pl file
63-----------------
64This section explains how to create and edit project specific submit rules. How
65to actually write the submit rules is explained in the next section.
66
67Project specific submit rules are stored in the `rules.pl` file in the
68`refs/meta/config` branch of that project. Therefore, we need to fetch and
69checkout the `refs/meta/config` branch in order to create or edit the `rules.pl`
70file:
71
72====
73 $ git fetch origin refs/meta/config:config
74 $ git checkout config
75 ... edit or create the rules.pl file
76 $ git add rules.pl
77 $ git commit -m "My submit rules"
78 $ git push origin HEAD:refs/meta/config
79====
80
81How to write submit rules
82-------------------------
83Whenever Gerrit needs to evaluate submit rules for a change `C` from project `P` it
84will first initialize the embedded Prolog interpreter by:
85
86* consulting a set of facts about the change `C`
87* consulting the `rules.pl` from the project `P`
88
89Conceptually we can imagine that Gerrit adds a set of facts about the change
90`C` on top of the `rules.pl` file and then consults it. The set of facts about
91the change `C` will look like:
92
93====
94 :- package gerrit. <1>
95
96 commit_author(user(1000000), 'John Doe', 'john.doe@example.com'). <2>
97 commit_committer(user(1000000), 'John Doe', 'john.doe@example.com'). <3>
98 commit_message('Add plugin support to Gerrit'). <4>
99 ...
100====
101
102<1> Gerrit will provide its facts in a package named `gerrit`. This means we
103have to use qualified names when writing our code and referencing these facts.
104For example: `gerrit:commit_author(ID, N, M)`
105<2> user ID, full name and email address of the commit author
106<3> user ID, full name and email address of the commit committer
107<4> commit message
108
109A complete set of facts which Gerrit provides about the change is listed in the
110link:prolog-change-facts.html[Prolog Facts for Gerrit Change].
111
112By default, Gerrit will search for a `submit_rule/1` predicate in the `rules.pl`
113file, evaluate the `submit_rule(X)` and then inspect the value of `X` in order
114to decide whether the change is submittable or not and also to find the set of
115needed criteria for the change to become submittable. This means that Gerrit has an
116expectation on the format and value of the result of the `submit_rule` predicate
117which is expected to be a `submit` term of the following format:
118
119====
120 submit(label(label-name, status) [, label(label-name, status)]*)
121====
122
123where `label-name` is usually `'Code-Review'` or `'Verified'` but could also
124be any other string (see examples below). The `status` is one of:
125
126* `ok(user(ID))` or just `ok(_)` if user info is not important. This status is
127 used to tell that this label/category has been met.
128* `need(_)` is used to tell that this label/category is needed for change to
129 become submittable
130* `reject(user(ID))` or just `reject(_)`. This status is used to tell that label/category
131 is blocking change submission
132* `impossible(_)` is used when the logic knows that the change cannot be submitted as-is.
133 Administrative intervention is probably required. This is meant for cases
134 where the logic requires members of "FooEng" to score "Code-Review +2" on a
135 change, but nobody is in group "FooEng". It is to hint at permissions
136 misconfigurations.
137* `may(_)` allows expression of approval categories that are optional, i.e.
138 could either be set or unset without ever influencing whether the change
139 could be submitted.
140
141NOTE: For a change to be submittable all `label` terms contained in the returned
142`submit` term must have either `ok` or `may` status.
143
144IMPORTANT: Gerrit will let the Prolog engine continue searching for solutions of
145the `submit_rule(X)` query until it finds the first one where all labels in the
146return result have either status `ok` or `may` or there are no more solutions.
147If a solution where all labels have status `ok` is found then all previously
148found solutions are ignored. Otherwise, all labels names with status `need`
149from all solutions will be displayed in the UI indicating the set of conditions
150needed for the change to become submittable.
151
152Here some examples of possible return values from the `submit_rule` predicate:
153
154====
155 submit(label('Code-Review', ok(_))) <1>
156 submit(label('Code-Review', ok(_)), label('Verified', reject(_))) <2>
157 submit(label('Author-is-John-Doe', need(_)) <3>
158====
159
160<1> label `'Code-Review'` is met. As there are no other labels in the
161 return result, the change is submittable.
162<2> label `'Verified'` is rejected. Change is not submittable.
163<3> label `'Author-is-John-Doe'` is needed for the change to become submittable.
164 Note that this tells nothing about how this criteria will be met. It is up
165 to the implementor of the `submit_rule` to return `label('Author-is-John-Doe',
166 ok(_))` when this criteria is met. Most likely, it will have to match
167 against `gerrit:commit_author` in order to check if this criteria is met.
168 This will become clear through the examples below.
169
170Of course, when implementing the `submit_rule` we will use the facts about the
171change that are already provided by Gerrit.
172
173Another aspect of the return result from the `submit_rule` predicate is that
174Gerrit uses it to decide which set of labels to display on the change review
175screen for voting. If the return result contains label `'ABC'` and if the label
176`'ABC'` is one of the (global) voting categories then voting for the label
177`'ABC'` will be displayed. Otherwise, it is not displayed. Note that we don't
178need a (global) voting category for each label contained in the result of
179`submit_rule` predicate. For example, the decision whether `'Author-is-John-Doe'`
180label is met will probably not be made by explicit voting but, instead, by
181inspecting the facts about the change.
182
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200183Submit Filter
184-------------
185Another mechanism of changing the default submit rules is to implement the
186`submit_filter/2` predicate. While Gerrit will search for the `submit_rule` only
187in the `rules.pl` file of the current project, the `submit_filter` will be
188searched for in the `rules.pl` of all parent projects of the current project,
189but not in the `rules.pl` of the current project. The search will start from the
190immediate parent of the current project, then in the parent project of that
191project and so on until, and including, the 'All-Projects' project.
192
193The purpose of the submit filter is, as its name says, to filter the results
194of the `submit_rule`. Therefore, the `submit_filter` predicate has two
195parameters:
196
197====
198 submit_filter(In, Out) :- ...
199====
200
201Gerrit will invoke `submit_filter` with the `In` parameter containing a `submit`
202structure produced by the `submit_rule` and will take the value of the `Out`
203parameter as the result.
204
205The `Out` value of a `submit_filter` will become the `In` value for the
206next `submit_filter` in the parent line. The value of the `Out` parameter
207of the top-most `submit_filter` is the final result of the submit rule that
208is used to decide whether a change is submittable or not.
209
210IMPORTANT: `submit_filter` is a mechanism for Gerrit administrators to implement
211and enforce submit rules that would apply to all projects while `submit_rule` is
212a mechanism for project owners to implement project specific submit rules.
213However, project owners who own several projects could also make use of
214`submit_filter` by using a common parent project for all their projects and
215implementing the `submit_filter` in this common parent project. This way they
216can avoid implementing the same `submit_rule` in all their projects.
217
218The following "drawing" illustrates the order of the invocation and the chaining
219of the results of the `submit_rule` and `submit_filter` predicates.
220
221====
222 All-Projects
223 ^ submit_filter(B, S) :- ... <4>
224 |
225 Parent-3
226 ^ <no submit filter here>
227 |
228 Parent-2
229 ^ submit_filter(A, B) :- ... <3>
230 |
231 Parent-1
232 ^ submit_filter(X, A) :- ... <2>
233 |
234 MyProject
235 submit_rule(X) :- ... <1>
236====
237
238<1> The `submit_rule` of `MyProject` is invoked first.
239<2> The result `X` is filtered through the `submit_filter` from the `Parent-1`
240project.
241<3> The result of `submit_filter` from `Parent-1` project is filtered by the
242`submit_filter` in the `Parent-2` project. Since `Parent-3` project doesn't have
243a `submit_filter` it is skipped.
244<4> The result of `submit_filter` from `Parent-2` project is filtered by the
245`submit_filter` in the `All-Projects` project. The value in `S` is the final
246value of the submit rule evaluation.
247
248NOTE: If `MyProject` doesn't define its own `submit_rule` Gerrit will invoke the
249default implementation of submit rule that is named `gerrit:default_submit` and
250its result will be filtered as described above.
251
252
Sasa Zivkovae50f712012-07-24 14:51:44 +0200253Prolog vs Gerrit plugin for project specific submit rules
254---------------------------------------------------------
255Since version 2.5 Gerrit supports plugins and extension points. A plugin or an
256extension point could also be used as another means to provide custom submit
257rules. One could ask for a guideline when to use Prolog based submit rules and
258when to go for writing a new plugin. Writing a Prolog program is usually much
259faster than writing a Gerrit plugin. Prolog based submit rules can be pushed
260to a project by project owners while Gerrit plugins could only be installed by
261Gerrit administrators. In addition, Prolog based submit rules can be pushed
262for review by pushing to `refs/for/refs/meta/config` branch.
263
264On the other hand, Prolog based submit rules get a limited amount of facts about
265the change exposed to them. Gerrit plugins get full access to Gerrit internals
266and can potentially check more things than Prolog based rules.
267
268Examples
269--------
270The following examples should serve as a cookbook for developing own submit rules.
271Some of them are too trivial to be used in production and their only purpose is
272to provide step by step introduction and understanding.
273
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200274Some of the examples will implement the `submit_rule` and some will implement
275the `submit_filter` just to show both possibilities. Remember that
276`submit_rule` is only invoked from the current project and `submit_filter` is
277invoked from all parent projects. This is the most important fact in deciding
278whether to implement `submit_rule` or `submit_filter`.
279
Sasa Zivkovae50f712012-07-24 14:51:44 +0200280Example 1: Make every change submittable
281~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
282Let's start with a most trivial example where we would make every change submittable
283regardless of the votes it has:
284
285.rules.pl
286[caption=""]
287====
288 submit_rule(submit(label('Any-Label-Name', ok(_)))).
289====
290
291In this case we make no use of facts about the change. We don't need it as we are simply
292making every change submittable. Note that, in this case, the Gerrit UI will not show
293the UI for voting for the standard `'Code-Review'` and `'Verified'` categories as labels
294with these names are not part of the return result. The `'Any-Label-Name'` could really
295be any string.
296
297Example 2: Every change submittable and voting in the standard categories possible
298~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
299This is continuation of the previous example where, in addition, to making
300every change submittable we want to enable voting in the standard
301`'Code-Review'` and `'Verified'` categories.
302
303.rules.pl
304[caption=""]
305====
306 submit_rule(submit(label('Code-Review', ok(_)), label('Verified', ok(_)))).
307====
308
309Since for every change all label statuses are `'ok'` every change will be submittable.
310Voting in the standard labels will be shown in the UI as the standard label names are
311included in the return result.
312
313Example 3: Nothing is submittable
314~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
315This example shows how to make all changes non-submittable regardless of the
316votes they have.
317
318.rules.pl
319[caption=""]
320====
321 submit_rule(submit(label('Any-Label-Name', reject(_)))).
322====
323
324Since for any change we return only one label with status `reject`, no change
325will be submittable. The UI will, however, not indicate what is needed for a
326change to become submittable as we return no labels with status `need`.
327
328Example 4: Nothing is submittable but UI shows several 'Need ...' criteria
329~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
330In this example no change is submittable but here we show how to present 'Need
331<label>' information to the user in the UI.
332
333.rules.pl
334[caption=""]
335====
336 % In the UI this will show: Need Any-Label-Name
337 submit_rule(submit(label('Any-Label-Name', need(_)))).
338
339 % We could define more "need" labels by adding more rules
340 submit_rule(submit(label('Another-Label-Name', need(_)))).
341
342 % or by providing more than one need label in the same rule
343 submit_rule(submit(label('X-Label-Name', need(_)), label('Y-Label-Name', need(_)))).
344====
345
346In the UI this will show:
347****
348* Need Any-Label-Name
349* Need Another-Label-Name
350* Need X-Label-Name
351* Need Y-Label-Name
352****
353
354From the example above we can see a few more things:
355
356* comment in Prolog starts with the `%` character
357* there could be multiple `submit_rule` predicates. Since Prolog, by default, tries to find
358 all solutions for a query, the result will be union of all solutions.
359 Therefore, we see all 4 `need` labels in the UI.
360
361Example 5: The 'Need ...' labels not shown when change is submittable
362~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
363This example shows that, when there is a solution for `submit_rule(X)` where all labels
364have status `ok` then Gerrit will not show any labels with the `need` status from
365any of the previous `submit_rule(X)` solutions.
366
367.rules.pl
368[caption=""]
369====
370 submit_rule(label('Some-Condition', need(_))).
371 submit_rule(label('Another-Condition', ok(_))).
372====
373
374The 'Need Some-Condition' will not be show in the UI because of the result of
375the second rule.
376
377The same is valid if the two rules are swapped:
378
379.rules.pl
380[caption=""]
381====
382 submit_rule(label('Another-Condition', ok(_))).
383 submit_rule(label('Some-Condition', need(_))).
384====
385
386The result of the first rule will stop search for any further solutions.
387
388Example 6: Make change submittable if commit author is "John Doe"
389~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
390This is the first example where we will use the Prolog facts about a change that
391are automatically exposed by Gerrit. Our goal is to make any change submittable
392when the commit author is named `'John Doe'`. In the very first
393step let's make sure Gerrit UI shows 'Need Author-is-John-Doe' in
394the UI to clearly indicate to the user what is needed for a change to become
395submittable:
396
397.rules.pl
398[caption=""]
399====
400 submit_rule(submit(label('Author-is-John-Doe', need(_)))).
401====
402
403This will show:
404****
405* Need Author-is-John-Doe
406****
407
408in the UI but no change will be submittable yet. Let's add another rule:
409
410.rules.pl
411[caption=""]
412====
413 submit_rule(submit(label('Author-is-John-Doe', need(_)))).
414 submit_rule(submit(label('Author-is-John-Doe', ok(_))))
415 :- gerrit:commit_author(_, 'John Doe', _).
416====
417
418In the second rule we return `ok` status for the `'Author-is-John-Doe'` label
419if there is a `commit_author` fact where the full name is `'John Doe'`. If
420author of a change is `'John Doe'` then the second rule will return a solution
421where all labels have `ok` status and the change will become submittable. If
422author of a change is not `'John Doe'` then only the first rule will produce a
423solution. The UI will show 'Need Author-is-John-Doe' but, as expected, the
424change will not be submittable.
425
426Instead of checking by full name we could also check by the email address:
427
428.rules.pl
429[caption=""]
430====
431 submit_rule(submit(label('Author-is-John-Doe', need(_)))).
432 submit_rule(submit(label('Author-is-John-Doe', ok(_))))
433 :- gerrit:commit_author(_, _, 'john.doe@example.com').
434====
435
436or by user id (assuming it is 1000000):
437
438.rules.pl
439[caption=""]
440====
441 submit_rule(submit(label('Author-is-John-Doe', need(_)))).
442 submit_rule(submit(label('Author-is-John-Doe', ok(_))))
443 :- gerrit:commit_author(user(1000000), _, _).
444====
445
446or by a combination of these 3 attributes:
447
448.rules.pl
449[caption=""]
450====
451 submit_rule(submit(label('Author-is-John-Doe', need(_)))).
452 submit_rule(submit(label('Author-is-John-Doe', ok(_))))
453 :- gerrit:commit_author(_, 'John Doe', 'john.doe@example.com').
454====
455
456Example 7: Make change submittable if commit message starts with "Trivial fix"
457~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
458Besides showing how to make use of the commit message text the purpose of this
459example is also to show how to match only a part of a string symbol. Similarly
460like commit author the commit message is provided as a string symbol which is
461an atom in Prolog terms. When working with an atom we could only match against
462the whole value. To match only part of a string symbol we have, at least, two
463options:
464
465* convert the string symbol into a list of characters and then perform
466 the "classical" list matching
467* use the `regex_matches/2` or, even more convenient, the
468 `gerrit:commit_message_matches/1` predicate
469
470Let's implement both options:
471
472.rules.pl
473[caption=""]
474====
475 submit_rule(submit(label('Commit-Message-starts-with-Trivial-Fix', need(_)))).
476 submit_rule(submit(label('Commit-Message-starts-with-Trivial-Fix', ok(_))))
477 :- gerrit:commit_message(M), name(M, L), starts_with(L, "Trivial Fix").
478
479 starts_with(L, []).
480 starts_with([H|T1], [H|T2]) :- starts_with(T1, T2).
481====
482
483NOTE: The `name/2` embedded predicate is used to convert a string symbol into a
484list of characters. A string `abc` is converted into a list of characters `[97,
48598, 99]`. A double quoted string in Prolog is just a shortcut for creating a
486list of characters. `"abc"` is a shortcut for `[97, 98, 99]`. This is why we use
487double quotes for the `"Trivial Fix"` in the example above.
488
489The `starts_with` predicate is self explaining.
490
491Using the `gerrit:commit_message_matches` predicate is probably more efficient:
492
493.rules.pl
494[caption=""]
495====
496 submit_rule(submit(label('Commit-Message-starts-with-Trivial-Fix', need(_)))).
497 submit_rule(submit(label('Commit-Message-starts-with-Trivial-Fix', ok(_))))
498 :- gerrit:commit_message_matches('^Trivial Fix').
499====
500
501Reusing the default submit policy
502---------------------------------
503All examples until now concentrate on one particular aspect of change data.
504However, in real-life scenarios we would rather want to reuse Gerrit's default
505submit policy and extend/change it for our specific purpose. In other words, we
506would like to keep all the default policies (like the `Verified` category,
507vetoing change, etc...) and only extend/change an aspect of it. For example, we
508may want to disable the ability for change authors to approve their own changes
509but keep all other policies the same.
510
511To get results of Gerrits default submit policy we use the
512`gerrit:default_submit` predicate. This means that if we write a submit rule like:
513
514.rules.pl
515[caption=""]
516====
517 submit_rule(X) :- gerrit:default_submit(X).
518====
519
520then this is equivalent to not using `rules.pl` at all. We just delegate to
521default logic. However, once we invoke the `gerrit:default_submit(X)` we can
522perform further actions on the return result `X` and apply our specific
523logic. The following pattern illustrates this technique:
524
525.rules.pl
526[caption=""]
527====
528 submit_rule(S) :- gerrit:default_submit(R), project_specific_policy(R, S).
529
530 project_specific_policy(R, S) :- ...
531====
532
533The following examples build on top of the default submit policy.
534
535Example 8: Make change submittable only if `Code-Review+2` is given by a non author
536~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
537In this example we introduce a new label `Non-Author-Code-Review` and make it
538satisfied if there is at least one `Code-Review+2` from a non author. All other
539default policies like the `Verified` category and vetoing changes still apply.
540
541First, we invoke `gerrit:default_submit` to compute the result for the default
542submit policy and then add the `Non-Author-Code-Review` label to it. The
543`Non-Author-Code-Review` label is added with status `ok` if such an approval
544exists or with status `need` if it doesn't exist.
545
546.rules.pl
547[caption=""]
548====
549 submit_rule(S) :-
550 gerrit:default_submit(X),
551 X =.. [submit | Ls],
552 add_non_author_approval(Ls, R),
553 S =.. [submit | R].
554
555 add_non_author_approval(S1, S2) :-
556 gerrit:commit_author(A), gerrit:commit_label(label('Code-Review', 2), R),
557 R \= A, !,
558 S2 = [label('Non-Author-Code-Review', ok(R)) | S1].
559 add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]).
560====
561
562This example uses the `univ` operator `=..` to "unpack" the result of the
563default_submit, which is a structure of the form `submit(label('Code-Review',
564ok(_)), label('Verified', need(_)) ...)` into a list like `[submit,
565label('Code-Review', ok(_)), label('Verified', need(_)), ...]`. Then we
566process the tail of the list (the list of labels) as a Prolog list, which is
567much easier than processing a structure. In the end we use the same `univ`
568operator to convert the resulting list of labels back into a `submit` structure
569which is expected as a return result. The `univ` operator works both ways.
570
571In `add_non_author_approval` we use the `cut` operator `!` to prevent Prolog
572from searching for more solutions once the `cut` point is reached. This is
573important because in the second `add_non_author_approval` rule we just add the
574`label('Non-Author-Code-Review', need(_))` without first checking that there
575is no non author `Code-Review+2`. The second rule will only be reached
576if the `cut` in the first rule is not reached and it only happens if a
577predicate before the `cut` fails.
578
579Example 9: Remove the `Verified` category
580~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
581A project has no build and test. It consists of only text files and needs only
582code review. We want to remove the `Verified` category from this project so
583that `Code-Review+2` is the only criteria for a change to become submittable.
584We also want the UI to not show the `Verified` category in the table with
585votes and on the voting screen.
586
587.rules.pl
588[caption=""]
589====
590 submit_rule(S) :-
591 gerrit:default_submit(X),
592 X =.. [submit | Ls],
593 remove_verified_category(Ls, R),
594 S =.. [submit | R].
595
596 remove_verified_category([], []).
597 remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
598 remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
599====
600
601Example 10: Combine examples 8 and 9
602~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
603In this example we want to both remove the verified and have the four eyes
604principle. This means we want a combination of examples 7 and 8.
605
606.rules.pl
607[caption=""]
608====
609 submit_rule(S) :-
610 gerrit:default_submit(X),
611 X =.. [submit | Ls],
612 remove_verified_category(Ls, R1),
613 add_non_author_approval(R1, R),
614 S =.. [submit | R].
615====
616
617The `remove_verified_category` and `add_non_author_approval` predicates are the
618same as defined in the previous two examples.
619
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200620Example 11: Remove the `Verified` category from all projects
621~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
622Example 9, implements `submit_rule` that removes the `Verified` category from
623one project. In this example we do the same but we want to remove the `Verified`
624category from all projects. This means we have to implement `submit_filter` and
625we have to do that in the `rules.pl` of the `All-Projects` project.
626
627.rules.pl
628[caption=""]
629====
630 submit_filter(In, Out) :-
631 In =.. [submit | Ls],
632 remove_verified_category(Ls, R),
633 Out =.. [submit | R].
634
635 remove_verified_category([], []).
636 remove_verified_category([label('Verified', _) | T], R) :-
637 remove_verified_category(T, R), !.
638 remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
639====
640
Johan Björkef028542012-10-24 12:06:33 -0400641Example 12: 1+1=2 Code-Review
642~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
643In this example we introduce accumulative voting to determine if a change is
644submittable or not. We modify the standard Code-Review to be accumulative, and make the
645change submittable if the total score is 2 or higher.
646
647The code in this example is very similar to Example 8, with the addition of findall/3
648and gerrit:remove_label.
649The findall/3 embedded predicate is used to form a list of all objects that satisfy a
650specified Goal. In this example it is used to get a list of all the 'Code-Review' scores.
651gerrit:remove_label is a built-in helper that is implemented similarly to the
652'remove_verified_category' as seen in the previous example.
653
654.rules.pl
655[caption=""]
656====
657 sum_list([], 0).
658 sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp.
659
660 add_category_min_score(In, Category, Min, P) :-
661 findall(X, gerrit:commit_label(label(Category,X),R),Z),
662 sum_list(Z, Sum),
663 Sum >= Min, !,
664 P = [label(Category,ok(R)) | In].
665
666 add_category_min_score(In, Category,Min,P) :-
667 P = [label(Category,need(Min)) | In].
668
669 submit_rule(S) :-
670 gerrit:default_submit(X),
671 X =.. [submit | Ls],
672 gerrit:remove_label(Ls,label('Code-Review',_),NoCR),
673 add_category_min_score(NoCR,'Code-Review', 2, Labels),
674 S =.. [submit | Labels].
675====
676
Sasa Zivkovae50f712012-07-24 14:51:44 +0200677GERRIT
678------
679Part of link:index.html[Gerrit Code Review]