blob: 21b8c9f5bede39ad04501ca455ad78081c6728f1 [file] [log] [blame]
Marian Harbachebeb1542019-12-13 10:42:46 +01001:linkattrs:
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -08002= Gerrit Code Review - Prolog Submit Rules Cookbook
Sasa Zivkovae50f712012-07-24 14:51:44 +02003
Edwin Kempin1781adb2014-04-22 10:02:40 +02004[[SubmitRule]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -08005== Submit Rule
David Myllykangasc5f591d2015-01-23 11:39:01 +01006A _Submit Rule_ in Gerrit is logic that defines when a change is submittable.
Sasa Zivkovae50f712012-07-24 14:51:44 +02007By 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
David Myllykangasc5f591d2015-01-23 11:39:01 +01009any 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
Sasa Zivkovae50f712012-07-24 14:51:44 +020011submittable.
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
Michael Ochmann8129ece2016-07-08 11:25:25 +020021[NOTE]
22Loading and executing Prolog submit rules may be disabled by setting
Jonathan Niederf0e6dc02016-02-29 13:57:23 -080023`rules.enable=false` in the Gerrit config file (see
Sasa Zivkovae50f712012-07-24 14:51:44 +020024link:config-gerrit.html#_a_id_rules_a_section_rules[rules section])
25
26link:https://groups.google.com/d/topic/repo-discuss/wJxTGhlHZMM/discussion[This
Marian Harbach34253372019-12-10 18:01:31 +010027discussion thread,role=external,window=_blank] explains why Prolog was chosen for the purpose of writing
Sasa Zivkovae50f712012-07-24 14:51:44 +020028project specific submit rules.
29link:http://gerrit-documentation.googlecode.com/svn/ReleaseNotes/ReleaseNotes-2.2.2.html[Gerrit
Marian Harbach34253372019-12-10 18:01:31 +0100302.2.2 ReleaseNotes,role=external,window=_blank] introduces Prolog support in Gerrit.
Sasa Zivkovae50f712012-07-24 14:51:44 +020031
Edwin Kempin1781adb2014-04-22 10:02:40 +020032[[SubmitType]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080033== Submit Type
David Myllykangasc5f591d2015-01-23 11:39:01 +010034A _Submit Type_ is a strategy that is used on submit to integrate the
Sasa Zivkovb91296d2012-11-08 14:19:12 +010035change into the destination branch. Supported submit types are:
36
37* `Fast Forward Only`
38* `Merge If Necessary`
39* `Merge Always`
40* `Cherry Pick`
41* `Rebase If Necessary`
42
David Myllykangasc5f591d2015-01-23 11:39:01 +010043_Submit Type_ is a project global setting. This means that the same submit type
Sasa Zivkovb91296d2012-11-08 14:19:12 +010044is used for all changes of one project.
45
46Projects which need more flexibility in choosing, or enforcing, a submit type
47can use Prolog based submit type which replaces the project's default submit
48type.
49
50Prolog based submit type computes a submit type for each change. The computed
51submit type is shown on the change screen for each change.
52
Dave Borowitz0761fd52015-12-13 21:59:04 -050053When submitting changes in a batch using "Submit including ancestors" or "Submit
54whole topic", submit type rules may not be used to mix submit types on a single
55branch, and trying to submit such a batch will fail. This avoids potentially
56confusing behavior and spurious submit failures. It is recommended to only use
57submit type rules to change submit types for an entire branch, which avoids this
58situation.
59
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080060== Prolog Language
Sasa Zivkovae50f712012-07-24 14:51:44 +020061This document is not a complete Prolog tutorial.
Marian Harbach34253372019-12-10 18:01:31 +010062link:http://en.wikipedia.org/wiki/Prolog[This Wikipedia page on Prolog,role=external,window=_blank] is a
David Myllykangasc5f591d2015-01-23 11:39:01 +010063good starting point for learning the Prolog language. This document will only
64explain some elements of Prolog that are necessary to understand the provided
65examples.
Sasa Zivkovae50f712012-07-24 14:51:44 +020066
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080067== Prolog in Gerrit
Marian Harbach34253372019-12-10 18:01:31 +010068Gerrit uses its own link:https://gerrit.googlesource.com/prolog-cafe/[fork,role=external,window=_blank] of the
69original link:http://kaminari.istc.kobe-u.ac.jp/PrologCafe/[prolog-cafe,role=external,window=_blank]
David Myllykangasc5f591d2015-01-23 11:39:01 +010070project. Gerrit embeds the prolog-cafe library and can interpret Prolog programs
71at runtime.
Sasa Zivkovae50f712012-07-24 14:51:44 +020072
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080073== Interactive Prolog Cafe Shell
Sasa Zivkovae50f712012-07-24 14:51:44 +020074For interactive testing and playing with Prolog, Gerrit provides the
75link:pgm-prolog-shell.html[prolog-shell] program which opens an interactive
76Prolog interpreter shell.
77
Chih-Hung Hsiehbde955c2019-04-01 20:05:54 -070078For batch or unit tests, see the examples in Gerrit source directory
Marian Harbach34253372019-12-10 18:01:31 +010079link:https://gerrit.googlesource.com/gerrit/+/refs/heads/master/prologtests/examples/[prologtests/examples,role=external,window=_blank].
Chih-Hung Hsiehbde955c2019-04-01 20:05:54 -070080
Michael Ochmann8129ece2016-07-08 11:25:25 +020081[NOTE]
82The interactive shell is just a prolog shell, it does not load
David Myllykangasc5f591d2015-01-23 11:39:01 +010083a gerrit server environment and thus is not intended for
84xref:TestingSubmitRules[testing submit rules].
Sasa Zivkovae50f712012-07-24 14:51:44 +020085
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080086== SWI-Prolog
Sasa Zivkovae50f712012-07-24 14:51:44 +020087Instead of using the link:pgm-prolog-shell.html[prolog-shell] program one can
Marian Harbach34253372019-12-10 18:01:31 +010088also use the link:http://www.swi-prolog.org/[SWI-Prolog,role=external,window=_blank] environment. It
Sasa Zivkovae50f712012-07-24 14:51:44 +020089provides a better shell interface and a graphical source-level debugger.
90
Edwin Kempin1781adb2014-04-22 10:02:40 +020091[[RulesFile]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -080092== The rules.pl file
Sasa Zivkovae50f712012-07-24 14:51:44 +020093This section explains how to create and edit project specific submit rules. How
94to actually write the submit rules is explained in the next section.
95
96Project specific submit rules are stored in the `rules.pl` file in the
97`refs/meta/config` branch of that project. Therefore, we need to fetch and
98checkout the `refs/meta/config` branch in order to create or edit the `rules.pl`
99file:
100
Michael Ochmannb99feab2016-07-06 14:10:22 +0200101----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200102 $ git fetch origin refs/meta/config:config
103 $ git checkout config
104 ... edit or create the rules.pl file
105 $ git add rules.pl
106 $ git commit -m "My submit rules"
107 $ git push origin HEAD:refs/meta/config
Michael Ochmannb99feab2016-07-06 14:10:22 +0200108----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200109
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100110[[HowToWriteSubmitRules]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800111== How to write submit rules
David Myllykangasc5f591d2015-01-23 11:39:01 +0100112Whenever Gerrit needs to evaluate submit rules for a change `C` from project `P`
113it will first initialize the embedded Prolog interpreter by:
Sasa Zivkovae50f712012-07-24 14:51:44 +0200114
115* consulting a set of facts about the change `C`
116* consulting the `rules.pl` from the project `P`
117
118Conceptually we can imagine that Gerrit adds a set of facts about the change
119`C` on top of the `rules.pl` file and then consults it. The set of facts about
120the change `C` will look like:
121
Michael Ochmannb99feab2016-07-06 14:10:22 +0200122----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200123 :- package gerrit. <1>
124
125 commit_author(user(1000000), 'John Doe', 'john.doe@example.com'). <2>
126 commit_committer(user(1000000), 'John Doe', 'john.doe@example.com'). <3>
127 commit_message('Add plugin support to Gerrit'). <4>
128 ...
Michael Ochmannb99feab2016-07-06 14:10:22 +0200129----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200130
131<1> Gerrit will provide its facts in a package named `gerrit`. This means we
132have to use qualified names when writing our code and referencing these facts.
133For example: `gerrit:commit_author(ID, N, M)`
134<2> user ID, full name and email address of the commit author
135<3> user ID, full name and email address of the commit committer
136<4> commit message
137
138A complete set of facts which Gerrit provides about the change is listed in the
139link:prolog-change-facts.html[Prolog Facts for Gerrit Change].
140
141By default, Gerrit will search for a `submit_rule/1` predicate in the `rules.pl`
142file, evaluate the `submit_rule(X)` and then inspect the value of `X` in order
143to decide whether the change is submittable or not and also to find the set of
David Myllykangasc5f591d2015-01-23 11:39:01 +0100144needed criteria for the change to become submittable. This means that Gerrit has
145an expectation on the format and value of the result of the `submit_rule`
146predicate which is expected to be a `submit` term of the following format:
Sasa Zivkovae50f712012-07-24 14:51:44 +0200147
Michael Ochmannb99feab2016-07-06 14:10:22 +0200148----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200149 submit(label(label-name, status) [, label(label-name, status)]*)
Michael Ochmannb99feab2016-07-06 14:10:22 +0200150----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200151
152where `label-name` is usually `'Code-Review'` or `'Verified'` but could also
153be any other string (see examples below). The `status` is one of:
154
Saša Živkovaa870632016-07-15 13:10:11 +0200155* `ok(user(ID))`. This status is used to tell that this label/category has been
156 met.
David Pursehouse3f918902015-05-19 09:41:02 +0900157* `need(_)` is used to tell that this label/category is needed for the change to
Saša Živkovaa870632016-07-15 13:10:11 +0200158 become submittable.
159* `reject(user(ID))`. This status is used to tell that this label/category is
160 blocking submission of the change.
David Pursehouse3f918902015-05-19 09:41:02 +0900161* `impossible(_)` is used when the logic knows that the change cannot be submitted
Saša Živkovaa870632016-07-15 13:10:11 +0200162 as-is. This is meant for cases where the logic requires members of a specific
163 group to apply a specific label on a change, but no users are in that group.
164 This is usually caused by misconfiguration of permissions.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200165* `may(_)` allows expression of approval categories that are optional, i.e.
David Myllykangasc5f591d2015-01-23 11:39:01 +0100166 could either be set or unset without ever influencing whether the change
167 could be submitted.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200168
Michael Ochmann8129ece2016-07-08 11:25:25 +0200169[NOTE]
170For a change to be submittable all `label` terms contained in the returned
Sasa Zivkovae50f712012-07-24 14:51:44 +0200171`submit` term must have either `ok` or `may` status.
172
Michael Ochmann8129ece2016-07-08 11:25:25 +0200173[IMPORTANT]
174Gerrit will let the Prolog engine continue searching for solutions of
Sasa Zivkovae50f712012-07-24 14:51:44 +0200175the `submit_rule(X)` query until it finds the first one where all labels in the
176return result have either status `ok` or `may` or there are no more solutions.
177If a solution where all labels have status `ok` is found then all previously
178found solutions are ignored. Otherwise, all labels names with status `need`
179from all solutions will be displayed in the UI indicating the set of conditions
180needed for the change to become submittable.
181
182Here some examples of possible return values from the `submit_rule` predicate:
183
Michael Ochmannb99feab2016-07-06 14:10:22 +0200184----
Saša Živkovaa870632016-07-15 13:10:11 +0200185 submit(label('Code-Review', ok(user(ID)))) <1>
186 submit(label('Code-Review', ok(user(ID))),
187 label('Verified', reject(user(ID)))) <2>
Sasa Zivkovae50f712012-07-24 14:51:44 +0200188 submit(label('Author-is-John-Doe', need(_)) <3>
Michael Ochmannb99feab2016-07-06 14:10:22 +0200189----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200190
191<1> label `'Code-Review'` is met. As there are no other labels in the
192 return result, the change is submittable.
193<2> label `'Verified'` is rejected. Change is not submittable.
194<3> label `'Author-is-John-Doe'` is needed for the change to become submittable.
195 Note that this tells nothing about how this criteria will be met. It is up
David Myllykangasc5f591d2015-01-23 11:39:01 +0100196 to the implementer of the `submit_rule` to return
Saša Živkovaa870632016-07-15 13:10:11 +0200197 `label('Author-is-John-Doe', ok(user(ID)))` when this criteria is met. Most
David Myllykangasc5f591d2015-01-23 11:39:01 +0100198 likely, it will have to match against `gerrit:commit_author` in order to
199 check if this criteria is met. This will become clear through the examples
200 below.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200201
202Of course, when implementing the `submit_rule` we will use the facts about the
203change that are already provided by Gerrit.
204
205Another aspect of the return result from the `submit_rule` predicate is that
206Gerrit uses it to decide which set of labels to display on the change review
207screen for voting. If the return result contains label `'ABC'` and if the label
Dave Borowitz01c1b1f2013-02-27 13:49:04 -0800208`'ABC'` is link:config-labels.html[defined for the project] then voting for the
209label `'ABC'` will be displayed. Otherwise, it is not displayed. Note that the
210project doesn't need a defined label for each label contained in the result of
David Myllykangasc5f591d2015-01-23 11:39:01 +0100211`submit_rule` predicate. For example, the decision whether
212`'Author-is-John-Doe'` label is met will probably not be made by explicit voting
213but, instead, by inspecting the facts about the change.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200214
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100215[[SubmitFilter]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800216== Submit Filter
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200217Another mechanism of changing the default submit rules is to implement the
218`submit_filter/2` predicate. While Gerrit will search for the `submit_rule` only
219in the `rules.pl` file of the current project, the `submit_filter` will be
220searched for in the `rules.pl` of all parent projects of the current project,
221but not in the `rules.pl` of the current project. The search will start from the
222immediate parent of the current project, then in the parent project of that
David Myllykangasc5f591d2015-01-23 11:39:01 +0100223project and so on until, and including, the `'All-Projects'` project.
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200224
225The purpose of the submit filter is, as its name says, to filter the results
226of the `submit_rule`. Therefore, the `submit_filter` predicate has two
227parameters:
228
Michael Ochmannb99feab2016-07-06 14:10:22 +0200229----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200230 submit_filter(In, Out) :- ...
Michael Ochmannb99feab2016-07-06 14:10:22 +0200231----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200232Gerrit will invoke `submit_filter` with the `In` parameter containing a `submit`
233structure produced by the `submit_rule` and will take the value of the `Out`
234parameter as the result.
235
236The `Out` value of a `submit_filter` will become the `In` value for the
237next `submit_filter` in the parent line. The value of the `Out` parameter
238of the top-most `submit_filter` is the final result of the submit rule that
239is used to decide whether a change is submittable or not.
240
Michael Ochmann8129ece2016-07-08 11:25:25 +0200241[IMPORTANT]
242`submit_filter` is a mechanism for Gerrit administrators to implement
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200243and enforce submit rules that would apply to all projects while `submit_rule` is
244a mechanism for project owners to implement project specific submit rules.
245However, project owners who own several projects could also make use of
246`submit_filter` by using a common parent project for all their projects and
247implementing the `submit_filter` in this common parent project. This way they
248can avoid implementing the same `submit_rule` in all their projects.
249
250The following "drawing" illustrates the order of the invocation and the chaining
251of the results of the `submit_rule` and `submit_filter` predicates.
Michael Ochmannb99feab2016-07-06 14:10:22 +0200252----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200253 All-Projects
254 ^ submit_filter(B, S) :- ... <4>
255 |
256 Parent-3
257 ^ <no submit filter here>
258 |
259 Parent-2
260 ^ submit_filter(A, B) :- ... <3>
261 |
262 Parent-1
263 ^ submit_filter(X, A) :- ... <2>
264 |
265 MyProject
266 submit_rule(X) :- ... <1>
Michael Ochmannb99feab2016-07-06 14:10:22 +0200267----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200268
269<1> The `submit_rule` of `MyProject` is invoked first.
270<2> The result `X` is filtered through the `submit_filter` from the `Parent-1`
271project.
272<3> The result of `submit_filter` from `Parent-1` project is filtered by the
273`submit_filter` in the `Parent-2` project. Since `Parent-3` project doesn't have
274a `submit_filter` it is skipped.
275<4> The result of `submit_filter` from `Parent-2` project is filtered by the
276`submit_filter` in the `All-Projects` project. The value in `S` is the final
277value of the submit rule evaluation.
278
Michael Ochmann8129ece2016-07-08 11:25:25 +0200279[NOTE]
280If `MyProject` doesn't define its own `submit_rule` Gerrit will invoke the
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200281default implementation of submit rule that is named `gerrit:default_submit` and
282its result will be filtered as described above.
283
Edwin Kempinca24f5c2013-03-26 13:23:20 +0100284[[HowToWriteSubmitType]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800285== How to write submit type
Chris Lee849cbd82014-10-20 16:23:21 -0700286Writing custom submit type logic in Prolog is similar to
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100287xref:HowToWriteSubmitRules[writing submit rules]. The only difference is that
288one has to implement a `submit_type` predicate (instead of the `submit_rule`)
289and that the return result of the `submit_type` has to be an atom that
290represents one of the supported submit types:
291
292* `fast_forward_only`
293* `merge_if_necessary`
294* `merge_always`
295* `cherry_pick`
296* `rebase_if_necessary`
297
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800298== Submit Type Filter
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100299Submit type filter works the same way as the xref:SubmitFilter[Submit Filter]
300where the name of the filter predicate is `submit_type_filter`.
301
Michael Ochmannb99feab2016-07-06 14:10:22 +0200302----
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100303 submit_type_filter(In, Out).
Michael Ochmannb99feab2016-07-06 14:10:22 +0200304----
Sasa Zivkovb91296d2012-11-08 14:19:12 +0100305
306Gerrit will invoke `submit_type_filter` with the `In` parameter containing a
307result of the `submit_type` and will take the value of the `Out` parameter as
308the result.
309
Johan Björk2119f052012-10-24 12:10:45 -0400310[[TestingSubmitRules]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800311== Testing submit rules
David Myllykangasc5f591d2015-01-23 11:39:01 +0100312The prolog environment running the `submit_rule` is loaded with state describing
313the change that is being evaluated. The easiest way to load this state is to
314test your `submit_rule` against a real change on a running gerrit instance. The
315command link:cmd-test-submit-rule.html[test-submit rule] loads a specific change
316and executes the `submit_rule`. It optionally reads the rule from from `stdin`
317to facilitate easy testing.
Johan Björk2119f052012-10-24 12:10:45 -0400318
Michael Ochmannb99feab2016-07-06 14:10:22 +0200319----
David Myllykangasc5f591d2015-01-23 11:39:01 +0100320 $ cat rules.pl | ssh gerrit_srv gerrit test-submit rule I45e080b105a50a625cc8e1fb5b357c0bfabe6d68 -s
Michael Ochmannb99feab2016-07-06 14:10:22 +0200321----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200322
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800323== Prolog vs Gerrit plugin for project specific submit rules
Sasa Zivkovae50f712012-07-24 14:51:44 +0200324Since version 2.5 Gerrit supports plugins and extension points. A plugin or an
325extension point could also be used as another means to provide custom submit
326rules. One could ask for a guideline when to use Prolog based submit rules and
327when to go for writing a new plugin. Writing a Prolog program is usually much
328faster than writing a Gerrit plugin. Prolog based submit rules can be pushed
329to a project by project owners while Gerrit plugins could only be installed by
330Gerrit administrators. In addition, Prolog based submit rules can be pushed
331for review by pushing to `refs/for/refs/meta/config` branch.
332
333On the other hand, Prolog based submit rules get a limited amount of facts about
334the change exposed to them. Gerrit plugins get full access to Gerrit internals
335and can potentially check more things than Prolog based rules.
336
Sasa Zivkovd0e55262013-01-16 14:26:06 +0100337From version 2.6 Gerrit plugins can contribute Prolog predicates. This way, we
338can make use of the plugin provided predicates when writing Prolog based rules.
339
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800340== Examples - Submit Rule
David Myllykangasc5f591d2015-01-23 11:39:01 +0100341The following examples should serve as a cookbook for developing own submit
342rules. Some of them are too trivial to be used in production and their only
343purpose is to provide step by step introduction and understanding.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200344
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200345Some of the examples will implement the `submit_rule` and some will implement
346the `submit_filter` just to show both possibilities. Remember that
347`submit_rule` is only invoked from the current project and `submit_filter` is
348invoked from all parent projects. This is the most important fact in deciding
349whether to implement `submit_rule` or `submit_filter`.
350
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800351=== Example 1: Make every change submittable
David Myllykangasc5f591d2015-01-23 11:39:01 +0100352Let's start with a most trivial example where we would make every change
353submittable regardless of the votes it has:
Sasa Zivkovae50f712012-07-24 14:51:44 +0200354
David Myllykangasc5f591d2015-01-23 11:39:01 +0100355`rules.pl`
356[source,prolog]
357----
358submit_rule(submit(W)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200359 W = label('Any-Label-Name', ok(user(1000000))).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100360----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200361
David Myllykangasc5f591d2015-01-23 11:39:01 +0100362In this case we make no use of facts about the change. We don't need it as we
363are simply making every change submittable. Note that, in this case, the Gerrit
364UI will not show the UI for voting for the standard `'Code-Review'` and
365`'Verified'` categories as labels with these names are not part of the return
366result. The `'Any-Label-Name'` could really be any string.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200367
Saša Živkovaa870632016-07-15 13:10:11 +0200368The `user(1000000)` represents the user whose account ID is `1000000`.
369
370[NOTE]
371Instead of the account ID `1000000` we could have used any other account ID.
372The following examples will use `user(ID)` instead of `user(1000000)` because
373it is easier to read and doesn't suggest that there is anything special with
374the account ID `1000000`.
375
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800376=== Example 2: Every change submittable and voting in the standard categories possible
Sasa Zivkovae50f712012-07-24 14:51:44 +0200377This is continuation of the previous example where, in addition, to making
378every change submittable we want to enable voting in the standard
379`'Code-Review'` and `'Verified'` categories.
380
David Myllykangasc5f591d2015-01-23 11:39:01 +0100381`rules.pl`
382[source,prolog]
383----
384submit_rule(submit(CR, V)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200385 CR = label('Code-Review', ok(user(ID))),
386 V = label('Verified', ok(user(ID))).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100387----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200388
David Myllykangasc5f591d2015-01-23 11:39:01 +0100389Since for every change all label statuses are `'ok'` every change will be
390submittable. Voting in the standard labels will be shown in the UI as the
391standard label names are included in the return result.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200392
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800393=== Example 3: Nothing is submittable
Sasa Zivkovae50f712012-07-24 14:51:44 +0200394This example shows how to make all changes non-submittable regardless of the
395votes they have.
396
David Myllykangasc5f591d2015-01-23 11:39:01 +0100397`rules.pl`
398[source,prolog]
399----
400submit_rule(submit(R)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200401 R = label('Any-Label-Name', reject(user(ID))).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100402----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200403
404Since for any change we return only one label with status `reject`, no change
405will be submittable. The UI will, however, not indicate what is needed for a
406change to become submittable as we return no labels with status `need`.
407
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800408=== Example 4: Nothing is submittable but UI shows several 'Need ...' criteria
Sasa Zivkovae50f712012-07-24 14:51:44 +0200409In this example no change is submittable but here we show how to present 'Need
410<label>' information to the user in the UI.
411
David Myllykangasc5f591d2015-01-23 11:39:01 +0100412`rules.pl`
413[source,prolog]
414----
415% In the UI this will show: Need Any-Label-Name
416submit_rule(submit(N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100417 N = label('Any-Label-Name', need(_)).
Sasa Zivkovae50f712012-07-24 14:51:44 +0200418
David Myllykangasc5f591d2015-01-23 11:39:01 +0100419% We could define more "need" labels by adding more rules
420submit_rule(submit(N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100421 N = label('Another-Label-Name', need(_)).
Sasa Zivkovae50f712012-07-24 14:51:44 +0200422
David Myllykangasc5f591d2015-01-23 11:39:01 +0100423% or by providing more than one need label in the same rule
424submit_rule(submit(NX, NY)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100425 NX = label('X-Label-Name', need(_)),
426 NY = label('Y-Label-Name', need(_)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100427----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200428
429In the UI this will show:
David Myllykangasc5f591d2015-01-23 11:39:01 +0100430
431* `Need Any-Label-Name`
432* `Need Another-Label-Name`
433* `Need X-Label-Name`
434* `Need Y-Label-Name`
Sasa Zivkovae50f712012-07-24 14:51:44 +0200435
436From the example above we can see a few more things:
437
438* comment in Prolog starts with the `%` character
David Myllykangasc5f591d2015-01-23 11:39:01 +0100439* there could be multiple `submit_rule` predicates. Since Prolog, by default,
440 tries to find all solutions for a query, the result will be union of all
441 solutions. Therefore, we see all 4 `need` labels in the UI.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200442
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800443=== Example 5: The 'Need ...' labels not shown when change is submittable
David Myllykangasc5f591d2015-01-23 11:39:01 +0100444This example shows that, when there is a solution for `submit_rule(X)` where all
445labels have status `ok` then Gerrit will not show any labels with the `need`
446status from any of the previous `submit_rule(X)` solutions.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200447
David Myllykangasc5f591d2015-01-23 11:39:01 +0100448`rules.pl`
449[source,prolog]
450----
451submit_rule(submit(N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100452 N = label('Some-Condition', need(_)).
453
David Myllykangasc5f591d2015-01-23 11:39:01 +0100454submit_rule(submit(OK)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200455 OK = label('Another-Condition', ok(user(ID))).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100456----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200457
David Myllykangasc5f591d2015-01-23 11:39:01 +0100458The `'Need Some-Condition'` will not be shown in the UI because of the result of
Sasa Zivkovae50f712012-07-24 14:51:44 +0200459the second rule.
460
461The same is valid if the two rules are swapped:
462
David Myllykangasc5f591d2015-01-23 11:39:01 +0100463`rules.pl`
464[source,prolog]
465----
466submit_rule(submit(OK)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200467 OK = label('Another-Condition', ok(user(ID))).
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100468
David Myllykangasc5f591d2015-01-23 11:39:01 +0100469submit_rule(submit(N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100470 N = label('Some-Condition', need(_)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100471----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200472
473The result of the first rule will stop search for any further solutions.
474
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800475=== Example 6: Make change submittable if commit author is "John Doe"
Sasa Zivkovae50f712012-07-24 14:51:44 +0200476This is the first example where we will use the Prolog facts about a change that
477are automatically exposed by Gerrit. Our goal is to make any change submittable
478when the commit author is named `'John Doe'`. In the very first
David Myllykangasc5f591d2015-01-23 11:39:01 +0100479step let's make sure Gerrit UI shows `'Need Author-is-John-Doe'` in
Sasa Zivkovae50f712012-07-24 14:51:44 +0200480the UI to clearly indicate to the user what is needed for a change to become
481submittable:
482
David Myllykangasc5f591d2015-01-23 11:39:01 +0100483`rules.pl`
484[source,prolog]
485----
486submit_rule(submit(Author)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100487 Author = label('Author-is-John-Doe', need(_)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100488----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200489
490This will show:
David Myllykangasc5f591d2015-01-23 11:39:01 +0100491
492* `Need Author-is-John-Doe`
Sasa Zivkovae50f712012-07-24 14:51:44 +0200493
494in the UI but no change will be submittable yet. Let's add another rule:
495
David Myllykangasc5f591d2015-01-23 11:39:01 +0100496`rules.pl`
497[source,prolog]
498----
499submit_rule(submit(Author)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100500 Author = label('Author-is-John-Doe', need(_)).
501
David Myllykangasc5f591d2015-01-23 11:39:01 +0100502submit_rule(submit(Author)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200503 gerrit:commit_author(A, 'John Doe', _),
504 Author = label('Author-is-John-Doe', ok(A)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100505----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200506
507In the second rule we return `ok` status for the `'Author-is-John-Doe'` label
508if there is a `commit_author` fact where the full name is `'John Doe'`. If
509author of a change is `'John Doe'` then the second rule will return a solution
510where all labels have `ok` status and the change will become submittable. If
511author of a change is not `'John Doe'` then only the first rule will produce a
David Myllykangasc5f591d2015-01-23 11:39:01 +0100512solution. The UI will show `'Need Author-is-John-Doe'` but, as expected, the
Sasa Zivkovae50f712012-07-24 14:51:44 +0200513change will not be submittable.
514
515Instead of checking by full name we could also check by the email address:
516
David Myllykangasc5f591d2015-01-23 11:39:01 +0100517`rules.pl`
518[source,prolog]
519----
520submit_rule(submit(Author)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100521 Author = label('Author-is-John-Doe', need(_)).
522
David Myllykangasc5f591d2015-01-23 11:39:01 +0100523submit_rule(submit(Author)) :-
Jonathan Niederbd42cc72017-12-27 14:18:13 -0800524 gerrit:commit_author(_, _, 'john.doe@example.com'),
525 gerrit:uploader(U),
526 Author = label('Author-is-John-Doe', ok(U)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100527----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200528
David Myllykangasc5f591d2015-01-23 11:39:01 +0100529or by user id (assuming it is `1000000`):
Sasa Zivkovae50f712012-07-24 14:51:44 +0200530
David Myllykangasc5f591d2015-01-23 11:39:01 +0100531`rules.pl`
532[source,prolog]
533----
534submit_rule(submit(Author)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100535 Author = label('Author-is-John-Doe', need(_)).
536
David Myllykangasc5f591d2015-01-23 11:39:01 +0100537submit_rule(submit(Author)) :-
Saša Živkovaa870632016-07-15 13:10:11 +0200538 U = user(1000000),
539 gerrit:commit_author(U, _, _),
540 Author = label('Author-is-John-Doe', ok(U)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100541----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200542
543or by a combination of these 3 attributes:
544
David Myllykangasc5f591d2015-01-23 11:39:01 +0100545`rules.pl`
546[source,prolog]
547----
548submit_rule(submit(Author)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100549 Author = label('Author-is-John-Doe', need(_)).
550
David Myllykangasc5f591d2015-01-23 11:39:01 +0100551submit_rule(submit(Author)) :-
Jonathan Niederbd42cc72017-12-27 14:18:13 -0800552 gerrit:commit_author(_, 'John Doe', 'john.doe@example.com'),
553 gerrit:uploader(U),
554 Author = label('Author-is-John-Doe', ok(U)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100555----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200556
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800557=== Example 7: Make change submittable if commit message starts with "Fix "
Sasa Zivkovae50f712012-07-24 14:51:44 +0200558Besides showing how to make use of the commit message text the purpose of this
559example is also to show how to match only a part of a string symbol. Similarly
560like commit author the commit message is provided as a string symbol which is
561an atom in Prolog terms. When working with an atom we could only match against
562the whole value. To match only part of a string symbol we have, at least, two
563options:
564
565* convert the string symbol into a list of characters and then perform
566 the "classical" list matching
567* use the `regex_matches/2` or, even more convenient, the
568 `gerrit:commit_message_matches/1` predicate
569
570Let's implement both options:
571
David Myllykangasc5f591d2015-01-23 11:39:01 +0100572`rules.pl`
573[source,prolog]
574----
575submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100576 Fix = label('Commit-Message-starts-with-Fix', need(_)).
577
David Myllykangasc5f591d2015-01-23 11:39:01 +0100578submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100579 gerrit:commit_message(M), name(M, L), starts_with(L, "Fix "),
Jonathan Niederbd42cc72017-12-27 14:18:13 -0800580 gerrit:uploader(U),
581 Fix = label('Commit-Message-starts-with-Fix', ok(U)).
Sasa Zivkovae50f712012-07-24 14:51:44 +0200582
David Myllykangasc5f591d2015-01-23 11:39:01 +0100583starts_with(L, []).
584starts_with([H|T1], [H|T2]) :- starts_with(T1, T2).
585----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200586
Michael Ochmann8129ece2016-07-08 11:25:25 +0200587[NOTE]
588The `name/2` embedded predicate is used to convert a string symbol into a
Sasa Zivkovae50f712012-07-24 14:51:44 +0200589list of characters. A string `abc` is converted into a list of characters `[97,
59098, 99]`. A double quoted string in Prolog is just a shortcut for creating a
591list of characters. `"abc"` is a shortcut for `[97, 98, 99]`. This is why we use
592double quotes for the `"Trivial Fix"` in the example above.
593
594The `starts_with` predicate is self explaining.
595
596Using the `gerrit:commit_message_matches` predicate is probably more efficient:
597
David Myllykangasc5f591d2015-01-23 11:39:01 +0100598`rules.pl`
599[source,prolog]
600----
601submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100602 Fix = label('Commit-Message-starts-with-Fix', need(_)).
603
David Myllykangasc5f591d2015-01-23 11:39:01 +0100604submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100605 gerrit:commit_message_matches('^Fix '),
Jonathan Niederbd42cc72017-12-27 14:18:13 -0800606 gerrit:uploader(U),
607 Fix = label('Commit-Message-starts-with-Fix', ok(U)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100608----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200609
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100610The previous example could also be written so that it first checks if the commit
611message starts with 'Fix '. If true then it sets OK for that category and stops
612further backtracking by using the cut `!` operator:
David Myllykangasc5f591d2015-01-23 11:39:01 +0100613
614`rules.pl`
615[source,prolog]
616----
617submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100618 gerrit:commit_message_matches('^Fix '),
Jonathan Niederbd42cc72017-12-27 14:18:13 -0800619 gerrit:uploader(U),
620 Fix = label('Commit-Message-starts-with-Fix', ok(U)),
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100621 !.
622
David Myllykangasc5f591d2015-01-23 11:39:01 +0100623% Message does not start with 'Fix ' so Fix is needed to submit
624submit_rule(submit(Fix)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100625 Fix = label('Commit-Message-starts-with-Fix', need(_)).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100626----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100627
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800628== The default submit policy
Sasa Zivkovae50f712012-07-24 14:51:44 +0200629All examples until now concentrate on one particular aspect of change data.
630However, in real-life scenarios we would rather want to reuse Gerrit's default
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100631submit policy and extend/change it for our specific purpose. This could be
632done in one of the following ways:
Sasa Zivkovae50f712012-07-24 14:51:44 +0200633
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100634* understand how the default submit policy is implemented and use that as a
635 template for implementing custom submit rules,
636* invoke the default submit rule implementation and then perform further
637 actions on its return result.
638
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800639=== Default submit rule implementation
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100640The default submit rule with the two default categories, `Code-Review` and
641`Verified`, can be implemented as:
642
David Myllykangasc5f591d2015-01-23 11:39:01 +0100643`rules.pl`
644[source,prolog]
645----
646submit_rule(submit(V, CR)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100647 gerrit:max_with_block(-2, 2, 'Code-Review', CR),
648 gerrit:max_with_block(-1, 1, 'Verified', V).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100649----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100650
651Once this implementation is understood it can be customized to implement
652project specific submit rules. Note, that this implementation hardcodes
653the two default categories. Introducing a new category in the database would
654require introducing the same category here or a `submit_filter` in a parent
655project would have to care about including the new category in the result of
David Myllykangasc5f591d2015-01-23 11:39:01 +0100656this `submit_rule`. On the other side, this example is easy to read and
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100657understand.
658
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800659=== Reusing the default submit policy
David Pursehouse92463562013-06-24 10:16:28 +0900660To get results of Gerrit's default submit policy we use the
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100661`gerrit:default_submit` predicate. The `gerrit:default_submit(X)` includes all
David Myllykangasc5f591d2015-01-23 11:39:01 +0100662categories from the database. This means that if we write a submit rule like
663this:
Sasa Zivkovae50f712012-07-24 14:51:44 +0200664
David Myllykangasc5f591d2015-01-23 11:39:01 +0100665`rules.pl`
666[source,prolog]
667----
668submit_rule(X) :- gerrit:default_submit(X).
669----
670
671it is equivalent to not using `rules.pl` at all. We just delegate to
Sasa Zivkovae50f712012-07-24 14:51:44 +0200672default logic. However, once we invoke the `gerrit:default_submit(X)` we can
673perform further actions on the return result `X` and apply our specific
674logic. The following pattern illustrates this technique:
675
David Myllykangasc5f591d2015-01-23 11:39:01 +0100676`rules.pl`
677[source,prolog]
678----
679submit_rule(S) :- gerrit:default_submit(R), project_specific_policy(R, S).
Sasa Zivkovae50f712012-07-24 14:51:44 +0200680
David Myllykangasc5f591d2015-01-23 11:39:01 +0100681project_specific_policy(R, S) :- ...
682----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200683
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100684In the following examples both styles will be shown.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200685
Edwin Kempin1781adb2014-04-22 10:02:40 +0200686[[NonAuthorCodeReview]]
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800687=== Example 8: Make change submittable only if `Code-Review+2` is given by a non author
Sasa Zivkovae50f712012-07-24 14:51:44 +0200688In this example we introduce a new label `Non-Author-Code-Review` and make it
689satisfied if there is at least one `Code-Review+2` from a non author. All other
690default policies like the `Verified` category and vetoing changes still apply.
691
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800692==== Reusing the `gerrit:default_submit`
Sasa Zivkovae50f712012-07-24 14:51:44 +0200693First, we invoke `gerrit:default_submit` to compute the result for the default
694submit policy and then add the `Non-Author-Code-Review` label to it. The
695`Non-Author-Code-Review` label is added with status `ok` if such an approval
696exists or with status `need` if it doesn't exist.
697
David Myllykangasc5f591d2015-01-23 11:39:01 +0100698`rules.pl`
699[source,prolog]
700----
701submit_rule(S) :-
Sasa Zivkovae50f712012-07-24 14:51:44 +0200702 gerrit:default_submit(X),
703 X =.. [submit | Ls],
704 add_non_author_approval(Ls, R),
705 S =.. [submit | R].
706
David Myllykangasc5f591d2015-01-23 11:39:01 +0100707add_non_author_approval(S1, S2) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100708 gerrit:commit_author(A),
709 gerrit:commit_label(label('Code-Review', 2), R),
Sasa Zivkovae50f712012-07-24 14:51:44 +0200710 R \= A, !,
711 S2 = [label('Non-Author-Code-Review', ok(R)) | S1].
David Myllykangasc5f591d2015-01-23 11:39:01 +0100712add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]).
713----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200714
715This example uses the `univ` operator `=..` to "unpack" the result of the
716default_submit, which is a structure of the form `submit(label('Code-Review',
Saša Živkovaa870632016-07-15 13:10:11 +0200717ok(user(ID))), label('Verified', need(_)), ...)` into a list like `[submit,
718label('Code-Review', ok(user(ID))), label('Verified', need(_)), ...]`. Then we
Sasa Zivkovae50f712012-07-24 14:51:44 +0200719process the tail of the list (the list of labels) as a Prolog list, which is
720much easier than processing a structure. In the end we use the same `univ`
721operator to convert the resulting list of labels back into a `submit` structure
722which is expected as a return result. The `univ` operator works both ways.
723
724In `add_non_author_approval` we use the `cut` operator `!` to prevent Prolog
725from searching for more solutions once the `cut` point is reached. This is
726important because in the second `add_non_author_approval` rule we just add the
727`label('Non-Author-Code-Review', need(_))` without first checking that there
728is no non author `Code-Review+2`. The second rule will only be reached
729if the `cut` in the first rule is not reached and it only happens if a
730predicate before the `cut` fails.
731
Patrick Hiesele5f64032019-03-29 09:54:39 +0100732This fact can be bypassed by users who have
733link:access-control.html#category_forge_author[Forge Author] permission.
734
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800735==== Don't use `gerrit:default_submit`
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100736Let's implement the same submit rule the other way, without reusing the
737`gerrit:default_submit`:
738
David Myllykangasc5f591d2015-01-23 11:39:01 +0100739`rules.pl`
740[source,prolog]
741----
742submit_rule(submit(CR, V)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100743 base(CR, V),
744 CR = label(_, ok(Reviewer)),
745 gerrit:commit_author(Author),
746 Author \= Reviewer,
747 !.
748
David Myllykangasc5f591d2015-01-23 11:39:01 +0100749submit_rule(submit(CR, V, N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100750 base(CR, V),
751 N = label('Non-Author-Code-Review', need(_)).
752
David Myllykangasc5f591d2015-01-23 11:39:01 +0100753base(CR, V) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100754 gerrit:max_with_block(-2, 2, 'Code-Review', CR),
755 gerrit:max_with_block(-1, 1, 'Verified', V).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100756----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100757
758The latter implementation is probably easier to understand and the code looks
759cleaner. Note, however, that the latter implementation will always return the
760two standard categories only (`Code-Review` and `Verified`) even if a new
David Pursehouse92463562013-06-24 10:16:28 +0900761category has been inserted into the database. To include the new category
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100762the `rules.pl` would need to be modified or a `submit_filter` in a parent
763project would have to care about including the new category in the result
764of this `submit_rule`.
765
766The former example, however, would include any newly added category as it
767invokes the `gerrit:default_submit` and then modifies its result.
768
769Which of these two behaviors is desired will always depend on how a particular
770Gerrit server is managed.
771
Edwin Kempin426c6a52016-04-04 11:05:51 +0200772=== Example 9: Remove the `Verified` category
Sasa Zivkovae50f712012-07-24 14:51:44 +0200773A project has no build and test. It consists of only text files and needs only
774code review. We want to remove the `Verified` category from this project so
775that `Code-Review+2` is the only criteria for a change to become submittable.
776We also want the UI to not show the `Verified` category in the table with
777votes and on the voting screen.
778
David Myllykangasc5f591d2015-01-23 11:39:01 +0100779This is quite simple without reusing the `gerrit:default_submit`:
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100780
David Myllykangasc5f591d2015-01-23 11:39:01 +0100781`rules.pl`
782[source,prolog]
783----
784submit_rule(submit(CR)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100785 gerrit:max_with_block(-2, 2, 'Code-Review', CR).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100786----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100787
788Implementing the same rule by reusing `gerrit:default_submit` is a bit more complex:
789
David Myllykangasc5f591d2015-01-23 11:39:01 +0100790`rules.pl`
791[source,prolog]
792----
793submit_rule(S) :-
Sasa Zivkovae50f712012-07-24 14:51:44 +0200794 gerrit:default_submit(X),
795 X =.. [submit | Ls],
796 remove_verified_category(Ls, R),
797 S =.. [submit | R].
798
David Myllykangasc5f591d2015-01-23 11:39:01 +0100799remove_verified_category([], []).
800remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
801remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
802----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200803
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800804=== Example 10: Combine examples 8 and 9
Sasa Zivkovae50f712012-07-24 14:51:44 +0200805In this example we want to both remove the verified and have the four eyes
Maxime Guerreiro693ce812018-06-13 12:30:13 +0000806principle. This means we want a combination of examples 8 and 9.
Sasa Zivkovae50f712012-07-24 14:51:44 +0200807
David Myllykangasc5f591d2015-01-23 11:39:01 +0100808`rules.pl`
809[source,prolog]
810----
811submit_rule(S) :-
Sasa Zivkovae50f712012-07-24 14:51:44 +0200812 gerrit:default_submit(X),
813 X =.. [submit | Ls],
814 remove_verified_category(Ls, R1),
815 add_non_author_approval(R1, R),
816 S =.. [submit | R].
David Myllykangasc5f591d2015-01-23 11:39:01 +0100817----
Sasa Zivkovae50f712012-07-24 14:51:44 +0200818
819The `remove_verified_category` and `add_non_author_approval` predicates are the
820same as defined in the previous two examples.
821
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100822Without reusing the `gerrit:default_submit` the same example may be implemented
823as:
824
David Myllykangasc5f591d2015-01-23 11:39:01 +0100825`rules.pl`
826[source,prolog]
827----
828submit_rule(submit(CR)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100829 base(CR),
830 CR = label(_, ok(Reviewer)),
831 gerrit:commit_author(Author),
832 Author \= Reviewer,
833 !.
834
David Myllykangasc5f591d2015-01-23 11:39:01 +0100835submit_rule(submit(CR, N)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100836 base(CR),
837 N = label('Non-Author-Code-Review', need(_)).
838
David Myllykangasc5f591d2015-01-23 11:39:01 +0100839base(CR) :-
Craig Znamierowskif509d9c52016-10-14 17:09:59 -0400840 gerrit:max_with_block(-2, 2, 'Code-Review', CR).
David Myllykangasc5f591d2015-01-23 11:39:01 +0100841----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100842
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800843=== Example 11: Remove the `Verified` category from all projects
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200844Example 9, implements `submit_rule` that removes the `Verified` category from
845one project. In this example we do the same but we want to remove the `Verified`
846category from all projects. This means we have to implement `submit_filter` and
847we have to do that in the `rules.pl` of the `All-Projects` project.
848
David Myllykangasc5f591d2015-01-23 11:39:01 +0100849`rules.pl`
850[source,prolog]
851----
852submit_filter(In, Out) :-
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200853 In =.. [submit | Ls],
854 remove_verified_category(Ls, R),
855 Out =.. [submit | R].
856
David Myllykangasc5f591d2015-01-23 11:39:01 +0100857remove_verified_category([], []).
858remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
859remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
860----
Sasa Zivkov3d4f0aa2012-08-07 15:11:32 +0200861
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800862=== Example 12: On release branches require DrNo in addition to project rules
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100863A new category 'DrNo' is added to the database and is required for release
David Myllykangasc5f591d2015-01-23 11:39:01 +0100864branches. To mark a branch as a release branch we use
865`drno('refs/heads/branch')`.
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100866
David Myllykangasc5f591d2015-01-23 11:39:01 +0100867`rules.pl`
868[source,prolog]
869----
870drno('refs/heads/master').
871drno('refs/heads/stable-2.3').
872drno('refs/heads/stable-2.4').
873drno('refs/heads/stable-2.5').
874drno('refs/heads/stable-2.5').
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100875
David Myllykangasc5f591d2015-01-23 11:39:01 +0100876submit_filter(In, Out) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100877 gerrit:change_branch(Branch),
878 drno(Branch),
879 !,
880 In =.. [submit | I],
881 gerrit:max_with_block(-1, 1, 'DrNo', DrNo),
882 Out =.. [submit, DrNo | I].
883
David Myllykangasc5f591d2015-01-23 11:39:01 +0100884submit_filter(In, Out) :- In = Out.
885----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100886
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800887=== Example 13: 1+1=2 Code-Review
Johan Björkef028542012-10-24 12:06:33 -0400888In this example we introduce accumulative voting to determine if a change is
David Myllykangasc5f591d2015-01-23 11:39:01 +0100889submittable or not. We modify the standard `Code-Review` to be accumulative, and
890make the change submittable if the total score is `2` or higher.
Johan Björkef028542012-10-24 12:06:33 -0400891
David Myllykangasc5f591d2015-01-23 11:39:01 +0100892The code in this example is very similar to Example 8, with the addition of
893`findall/3` and `gerrit:remove_label`.
Johan Björkef028542012-10-24 12:06:33 -0400894
David Myllykangasc5f591d2015-01-23 11:39:01 +0100895The `findall/3` embedded predicate is used to form a list of all objects that
896satisfy a specified Goal. In this example it is used to get a list of all the
897`Code-Review` scores. `gerrit:remove_label` is a built-in helper that is
898implemented similarly to the `remove_verified_category` as seen in the previous
899example.
Johan Björkef028542012-10-24 12:06:33 -0400900
David Myllykangasc5f591d2015-01-23 11:39:01 +0100901`rules.pl`
902[source,prolog]
903----
904sum_list([], 0).
905sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp.
906
907add_category_min_score(In, Category, Min, P) :-
Johan Björkef028542012-10-24 12:06:33 -0400908 findall(X, gerrit:commit_label(label(Category,X),R),Z),
909 sum_list(Z, Sum),
910 Sum >= Min, !,
Kévin Raymond6ca07262017-10-22 19:18:07 +0200911 gerrit:commit_label(label(Category, V), U),
912 V >= 1,
913 !,
914 P = [label(Category,ok(U)) | In].
Johan Björkef028542012-10-24 12:06:33 -0400915
David Myllykangasc5f591d2015-01-23 11:39:01 +0100916add_category_min_score(In, Category,Min,P) :-
Johan Björkef028542012-10-24 12:06:33 -0400917 P = [label(Category,need(Min)) | In].
918
David Myllykangasc5f591d2015-01-23 11:39:01 +0100919submit_rule(S) :-
Johan Björkef028542012-10-24 12:06:33 -0400920 gerrit:default_submit(X),
921 X =.. [submit | Ls],
922 gerrit:remove_label(Ls,label('Code-Review',_),NoCR),
923 add_category_min_score(NoCR,'Code-Review', 2, Labels),
924 S =.. [submit | Labels].
David Myllykangasc5f591d2015-01-23 11:39:01 +0100925----
Johan Björkef028542012-10-24 12:06:33 -0400926
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100927Implementing the same example without using `gerrit:default_submit`:
928
David Myllykangasc5f591d2015-01-23 11:39:01 +0100929`rules.pl`
930[source,prolog]
931----
932submit_rule(submit(CR, V)) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100933 sum(2, 'Code-Review', CR),
934 gerrit:max_with_block(-1, 1, 'Verified', V).
935
David Myllykangasc5f591d2015-01-23 11:39:01 +0100936% Sum the votes in a category. Uses a helper function score/2
937% to select out only the score values the given category.
938sum(VotesNeeded, Category, label(Category, ok(_))) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100939 findall(Score, score(Category, Score), All),
940 sum_list(All, Sum),
941 Sum >= VotesNeeded,
942 !.
David Myllykangasc5f591d2015-01-23 11:39:01 +0100943sum(VotesNeeded, Category, label(Category, need(VotesNeeded))).
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100944
David Myllykangasc5f591d2015-01-23 11:39:01 +0100945score(Category, Score) :-
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100946 gerrit:commit_label(label(Category, Score), User).
947
David Myllykangasc5f591d2015-01-23 11:39:01 +0100948% Simple Prolog routine to sum a list of integers.
949sum_list(List, Sum) :- sum_list(List, 0, Sum).
950sum_list([X|T], Y, S) :- Z is X + Y, sum_list(T, Z, S).
951sum_list([], S, S).
952----
Sasa Zivkov79b08cc2013-01-16 17:00:54 +0100953
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -0800954=== Example 14: Master and apprentice
Johan Björk87927a92012-10-25 15:00:36 -0400955The master and apprentice example allow you to specify a user (the `master`)
956that must approve all changes done by another user (the `apprentice`).
957
958The code first checks if the commit author is in the apprentice database.
David Myllykangasc5f591d2015-01-23 11:39:01 +0100959If the commit is done by an `apprentice`, it will check if there is a `+2`
Johan Björk87927a92012-10-25 15:00:36 -0400960review by the associated `master`.
961
David Myllykangasc5f591d2015-01-23 11:39:01 +0100962`rules.pl`
963[source,prolog]
964----
965% master_apprentice(Master, Apprentice).
966% Extend this with appropriate user-id for your master/apprentice setup.
967master_apprentice(user(1000064), user(1000000)).
Johan Björk87927a92012-10-25 15:00:36 -0400968
David Myllykangasc5f591d2015-01-23 11:39:01 +0100969submit_rule(S) :-
Johan Björk87927a92012-10-25 15:00:36 -0400970 gerrit:default_submit(In),
971 In =.. [submit | Ls],
972 add_apprentice_master(Ls, R),
973 S =.. [submit | R].
974
David Myllykangasc5f591d2015-01-23 11:39:01 +0100975check_master_approval(S1, S2, Master) :-
Johan Björk87927a92012-10-25 15:00:36 -0400976 gerrit:commit_label(label('Code-Review', 2), R),
977 R = Master, !,
978 S2 = [label('Master-Approval', ok(R)) | S1].
David Myllykangasc5f591d2015-01-23 11:39:01 +0100979check_master_approval(S1, [label('Master-Approval', need(_)) | S1], _).
Johan Björk87927a92012-10-25 15:00:36 -0400980
David Myllykangasc5f591d2015-01-23 11:39:01 +0100981add_apprentice_master(S1, S2) :-
Johan Björk87927a92012-10-25 15:00:36 -0400982 gerrit:commit_author(Id),
983 master_apprentice(Master, Id),
984 !,
985 check_master_approval(S1, S2, Master).
986
David Myllykangasc5f591d2015-01-23 11:39:01 +0100987add_apprentice_master(S, S).
988----
Johan Björk87927a92012-10-25 15:00:36 -0400989
Changcheng Xiaod7990902017-11-21 11:22:48 +0100990=== Example 15: Make change submittable if all comments have been resolved
Changcheng Xiaoa5d01782017-02-15 13:11:20 +0100991In this example we will use the `unresolved_comments_count` fact about a
992change. Our goal is to block the submission of any change with some
993unresolved comments. Basically, it can be achieved by the following rules:
994
995`rules.pl`
996[source,prolog]
997----
998submit_rule(submit(R)) :-
999 gerrit:unresolved_comments_count(0),
1000 !,
Jonathan Niederbd42cc72017-12-27 14:18:13 -08001001 gerrit:uploader(U),
1002 R = label('All-Comments-Resolved', ok(U)).
Changcheng Xiaoa5d01782017-02-15 13:11:20 +01001003
1004submit_rule(submit(R)) :-
1005 gerrit:unresolved_comments_count(U),
1006 U > 0,
1007 R = label('All-Comments-Resolved', need(_)).
1008----
1009
1010Suppose currently a change is submittable if it gets `+2` for `Code-Review`
1011and `+1` for `Verified`. It can be extended to support the above rules as
1012follows:
1013
1014`rules.pl`
1015[source,prolog]
1016----
1017submit_rule(submit(CR, V, R)) :-
1018 base(CR, V),
1019 gerrit:unresolved_comments_count(0),
1020 !,
Jonathan Niederbd42cc72017-12-27 14:18:13 -08001021 gerrit:uploader(U),
1022 R = label('All-Comments-Resolved', ok(U)).
Changcheng Xiaoa5d01782017-02-15 13:11:20 +01001023
1024submit_rule(submit(CR, V, R)) :-
1025 base(CR, V),
1026 gerrit:unresolved_comments_count(U),
1027 U > 0,
1028 R = label('All-Comments-Resolved', need(_)).
1029
1030base(CR, V) :-
1031 gerrit:max_with_block(-2, 2, 'Code-Review', CR),
1032 gerrit:max_with_block(-1, 1, 'Verified', V).
1033----
1034
1035Note that a new label as `All-Comments-Resolved` should not be configured.
1036It's only used to show `'Needs All-Comments-Resolved'` in the UI to clearly
1037indicate to the user that all the comments have to be resolved for the
1038change to become submittable.
1039
Changcheng Xiaod7990902017-11-21 11:22:48 +01001040=== Example 16: Make change submittable if it is a pure revert
Patrick Hiesel42db9342017-09-12 11:45:06 +02001041In this example we will use the `pure_revert` fact about a
1042change. Our goal is to block the submission of any change that is not a
1043pure revert. Basically, it can be achieved by the following rules:
1044
1045`rules.pl`
1046[source,prolog]
1047----
1048submit_rule(submit(R)) :-
1049 gerrit:pure_revert(1),
1050 !,
Jonathan Niederbd42cc72017-12-27 14:18:13 -08001051 gerrit:uploader(U),
1052 R = label('Is-Pure-Revert', ok(U)).
Patrick Hiesel42db9342017-09-12 11:45:06 +02001053
Gary Miguel141022f2019-02-07 09:39:37 -08001054submit_rule(submit(label('Is-Pure-Revert', need(_)))).
Patrick Hiesel42db9342017-09-12 11:45:06 +02001055----
1056
1057Suppose currently a change is submittable if it gets `+2` for `Code-Review`
1058and `+1` for `Verified`. It can be extended to support the above rules as
1059follows:
1060
1061`rules.pl`
1062[source,prolog]
1063----
1064submit_rule(submit(CR, V, R)) :-
Gary Miguel141022f2019-02-07 09:39:37 -08001065 base(CR, V),
1066 set_pure_revert_label(R).
Patrick Hiesel42db9342017-09-12 11:45:06 +02001067
1068base(CR, V) :-
Gary Miguel141022f2019-02-07 09:39:37 -08001069 gerrit:max_with_block(-2, 2, 'Code-Review', CR),
1070 gerrit:max_with_block(-1, 1, 'Verified', V).
1071
1072set_pure_revert_label(R) :-
1073 gerrit:pure_revert(1),
1074 !,
1075 gerrit:uploader(U),
1076 R = label('Is-Pure-Revert', ok(U)).
1077
1078set_pure_revert_label(label('Is-Pure-Revert', need(_))).
Patrick Hiesel42db9342017-09-12 11:45:06 +02001079----
1080
1081Note that a new label as `Is-Pure-Revert` should not be configured.
1082It's only used to show `'Needs Is-Pure-Revert'` in the UI to clearly
Patrick Hiesel918ecab2017-09-18 08:29:24 +02001083indicate to the user that the change has to be a pure revert in order
1084to become submittable.
Patrick Hiesel42db9342017-09-12 11:45:06 +02001085
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -08001086== Examples - Submit Type
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001087The following examples show how to implement own submit type rules.
1088
Yuxuan 'fishy' Wang61698b12013-12-20 12:55:51 -08001089=== Example 1: Set a `Cherry Pick` submit type for all changes
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001090This example sets the `Cherry Pick` submit type for all changes. It overrides
1091whatever is set as project default submit type.
1092
1093rules.pl
David Myllykangasc5f591d2015-01-23 11:39:01 +01001094[source,prolog]
1095----
1096submit_type(cherry_pick).
1097----
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001098
Edwin Kempin1781adb2014-04-22 10:02:40 +02001099[[SubmitTypePerBranch]]
Jonathan Nieder5758f182015-03-30 11:28:55 -07001100=== Example 2: `Fast Forward Only` for all `+refs/heads/stable*+` branches
1101For all `+refs/heads/stable*+` branches we would like to enforce the `Fast
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001102Forward Only` submit type. A reason for this decision may be a need to never
1103break the build in the stable branches. For all other branches, those not
Jonathan Nieder5758f182015-03-30 11:28:55 -07001104matching the `+refs/heads/stable*+` pattern, we would like to use the project's
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001105default submit type as defined on the project settings page.
1106
David Myllykangasc5f591d2015-01-23 11:39:01 +01001107`rules.pl`
1108[source,prolog]
1109----
1110submit_type(fast_forward_only) :-
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001111 gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B),
1112 !.
Dave Borowitz6ba79762015-12-16 15:41:52 -05001113submit_type(T) :- gerrit:project_default_submit_type(T).
David Myllykangasc5f591d2015-01-23 11:39:01 +01001114----
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001115
1116The first `submit_type` predicate defines the `Fast Forward Only` submit type
Jonathan Nieder5758f182015-03-30 11:28:55 -07001117for `+refs/heads/stable.*+` branches. The second `submit_type` predicate returns
Sasa Zivkovb91296d2012-11-08 14:19:12 +01001118the project's default submit type.
1119
Sasa Zivkovae50f712012-07-24 14:51:44 +02001120GERRIT
1121------
1122Part of link:index.html[Gerrit Code Review]
Yuxuan 'fishy' Wang99cb68d2013-10-31 17:26:00 -07001123
1124SEARCHBOX
1125---------