Marian Harbach | ebeb154 | 2019-12-13 10:42:46 +0100 | [diff] [blame] | 1 | :linkattrs: |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 2 | = Gerrit Code Review - Prolog Submit Rules Cookbook |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 3 | |
Edwin Kempin | 1781adb | 2014-04-22 10:02:40 +0200 | [diff] [blame] | 4 | [[SubmitRule]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 5 | == Submit Rule |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 6 | A _Submit Rule_ in Gerrit is logic that defines when a change is submittable. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 7 | By default, a change is submittable when it gets at least one |
| 8 | highest vote in each voting category and has no lowest vote (aka veto vote) in |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 9 | any 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 Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 11 | submittable. |
| 12 | |
| 13 | While this rule is a good default, there are projects which need more |
| 14 | flexibility for defining when a change is submittable. In Gerrit, it is |
| 15 | possible to use Prolog based rules to provide project specific submit rules and |
| 16 | replace the default submit rules. Using Prolog based rules, project owners can |
| 17 | define a set of criteria which must be fulfilled for a change to become |
| 18 | submittable. For a change that is not submittable, the set of needed criteria |
| 19 | is displayed in the Gerrit UI. |
| 20 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 21 | [NOTE] |
| 22 | Loading and executing Prolog submit rules may be disabled by setting |
Jonathan Nieder | f0e6dc0 | 2016-02-29 13:57:23 -0800 | [diff] [blame] | 23 | `rules.enable=false` in the Gerrit config file (see |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 24 | link:config-gerrit.html#_a_id_rules_a_section_rules[rules section]) |
| 25 | |
| 26 | link:https://groups.google.com/d/topic/repo-discuss/wJxTGhlHZMM/discussion[This |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 27 | discussion thread,role=external,window=_blank] explains why Prolog was chosen for the purpose of writing |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 28 | project specific submit rules. |
| 29 | link:http://gerrit-documentation.googlecode.com/svn/ReleaseNotes/ReleaseNotes-2.2.2.html[Gerrit |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 30 | 2.2.2 ReleaseNotes,role=external,window=_blank] introduces Prolog support in Gerrit. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 31 | |
Edwin Kempin | 1781adb | 2014-04-22 10:02:40 +0200 | [diff] [blame] | 32 | [[SubmitType]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 33 | == Submit Type |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 34 | A _Submit Type_ is a strategy that is used on submit to integrate the |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 35 | change 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 43 | _Submit Type_ is a project global setting. This means that the same submit type |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 44 | is used for all changes of one project. |
| 45 | |
| 46 | Projects which need more flexibility in choosing, or enforcing, a submit type |
| 47 | can use Prolog based submit type which replaces the project's default submit |
| 48 | type. |
| 49 | |
| 50 | Prolog based submit type computes a submit type for each change. The computed |
| 51 | submit type is shown on the change screen for each change. |
| 52 | |
Dave Borowitz | 0761fd5 | 2015-12-13 21:59:04 -0500 | [diff] [blame] | 53 | When submitting changes in a batch using "Submit including ancestors" or "Submit |
| 54 | whole topic", submit type rules may not be used to mix submit types on a single |
| 55 | branch, and trying to submit such a batch will fail. This avoids potentially |
| 56 | confusing behavior and spurious submit failures. It is recommended to only use |
| 57 | submit type rules to change submit types for an entire branch, which avoids this |
| 58 | situation. |
| 59 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 60 | == Prolog Language |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 61 | This document is not a complete Prolog tutorial. |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 62 | link:http://en.wikipedia.org/wiki/Prolog[This Wikipedia page on Prolog,role=external,window=_blank] is a |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 63 | good starting point for learning the Prolog language. This document will only |
| 64 | explain some elements of Prolog that are necessary to understand the provided |
| 65 | examples. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 66 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 67 | == Prolog in Gerrit |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 68 | Gerrit uses its own link:https://gerrit.googlesource.com/prolog-cafe/[fork,role=external,window=_blank] of the |
| 69 | original link:http://kaminari.istc.kobe-u.ac.jp/PrologCafe/[prolog-cafe,role=external,window=_blank] |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 70 | project. Gerrit embeds the prolog-cafe library and can interpret Prolog programs |
| 71 | at runtime. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 72 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 73 | == Interactive Prolog Cafe Shell |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 74 | For interactive testing and playing with Prolog, Gerrit provides the |
| 75 | link:pgm-prolog-shell.html[prolog-shell] program which opens an interactive |
| 76 | Prolog interpreter shell. |
| 77 | |
Chih-Hung Hsieh | bde955c | 2019-04-01 20:05:54 -0700 | [diff] [blame] | 78 | For batch or unit tests, see the examples in Gerrit source directory |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 79 | link:https://gerrit.googlesource.com/gerrit/+/refs/heads/master/prologtests/examples/[prologtests/examples,role=external,window=_blank]. |
Chih-Hung Hsieh | bde955c | 2019-04-01 20:05:54 -0700 | [diff] [blame] | 80 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 81 | [NOTE] |
| 82 | The interactive shell is just a prolog shell, it does not load |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 83 | a gerrit server environment and thus is not intended for |
| 84 | xref:TestingSubmitRules[testing submit rules]. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 85 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 86 | == SWI-Prolog |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 87 | Instead of using the link:pgm-prolog-shell.html[prolog-shell] program one can |
Marian Harbach | 3425337 | 2019-12-10 18:01:31 +0100 | [diff] [blame] | 88 | also use the link:http://www.swi-prolog.org/[SWI-Prolog,role=external,window=_blank] environment. It |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 89 | provides a better shell interface and a graphical source-level debugger. |
| 90 | |
Edwin Kempin | 1781adb | 2014-04-22 10:02:40 +0200 | [diff] [blame] | 91 | [[RulesFile]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 92 | == The rules.pl file |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 93 | This section explains how to create and edit project specific submit rules. How |
| 94 | to actually write the submit rules is explained in the next section. |
| 95 | |
| 96 | Project 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 |
| 98 | checkout the `refs/meta/config` branch in order to create or edit the `rules.pl` |
| 99 | file: |
| 100 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 101 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 102 | $ 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 Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 108 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 109 | |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 110 | [[HowToWriteSubmitRules]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 111 | == How to write submit rules |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 112 | Whenever Gerrit needs to evaluate submit rules for a change `C` from project `P` |
| 113 | it will first initialize the embedded Prolog interpreter by: |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 114 | |
| 115 | * consulting a set of facts about the change `C` |
| 116 | * consulting the `rules.pl` from the project `P` |
| 117 | |
| 118 | Conceptually 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 |
| 120 | the change `C` will look like: |
| 121 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 122 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 123 | :- 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 Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 129 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 130 | |
| 131 | <1> Gerrit will provide its facts in a package named `gerrit`. This means we |
| 132 | have to use qualified names when writing our code and referencing these facts. |
| 133 | For 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 | |
| 138 | A complete set of facts which Gerrit provides about the change is listed in the |
| 139 | link:prolog-change-facts.html[Prolog Facts for Gerrit Change]. |
| 140 | |
| 141 | By default, Gerrit will search for a `submit_rule/1` predicate in the `rules.pl` |
| 142 | file, evaluate the `submit_rule(X)` and then inspect the value of `X` in order |
| 143 | to decide whether the change is submittable or not and also to find the set of |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 144 | needed criteria for the change to become submittable. This means that Gerrit has |
| 145 | an expectation on the format and value of the result of the `submit_rule` |
| 146 | predicate which is expected to be a `submit` term of the following format: |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 147 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 148 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 149 | submit(label(label-name, status) [, label(label-name, status)]*) |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 150 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 151 | |
| 152 | where `label-name` is usually `'Code-Review'` or `'Verified'` but could also |
| 153 | be any other string (see examples below). The `status` is one of: |
| 154 | |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 155 | * `ok(user(ID))`. This status is used to tell that this label/category has been |
| 156 | met. |
David Pursehouse | 3f91890 | 2015-05-19 09:41:02 +0900 | [diff] [blame] | 157 | * `need(_)` is used to tell that this label/category is needed for the change to |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 158 | become submittable. |
| 159 | * `reject(user(ID))`. This status is used to tell that this label/category is |
| 160 | blocking submission of the change. |
David Pursehouse | 3f91890 | 2015-05-19 09:41:02 +0900 | [diff] [blame] | 161 | * `impossible(_)` is used when the logic knows that the change cannot be submitted |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 162 | 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 Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 165 | * `may(_)` allows expression of approval categories that are optional, i.e. |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 166 | could either be set or unset without ever influencing whether the change |
| 167 | could be submitted. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 168 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 169 | [NOTE] |
| 170 | For a change to be submittable all `label` terms contained in the returned |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 171 | `submit` term must have either `ok` or `may` status. |
| 172 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 173 | [IMPORTANT] |
| 174 | Gerrit will let the Prolog engine continue searching for solutions of |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 175 | the `submit_rule(X)` query until it finds the first one where all labels in the |
| 176 | return result have either status `ok` or `may` or there are no more solutions. |
| 177 | If a solution where all labels have status `ok` is found then all previously |
| 178 | found solutions are ignored. Otherwise, all labels names with status `need` |
| 179 | from all solutions will be displayed in the UI indicating the set of conditions |
| 180 | needed for the change to become submittable. |
| 181 | |
| 182 | Here some examples of possible return values from the `submit_rule` predicate: |
| 183 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 184 | ---- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 185 | submit(label('Code-Review', ok(user(ID)))) <1> |
| 186 | submit(label('Code-Review', ok(user(ID))), |
| 187 | label('Verified', reject(user(ID)))) <2> |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 188 | submit(label('Author-is-John-Doe', need(_)) <3> |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 189 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 190 | |
| 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 196 | to the implementer of the `submit_rule` to return |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 197 | `label('Author-is-John-Doe', ok(user(ID)))` when this criteria is met. Most |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 198 | 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 Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 201 | |
| 202 | Of course, when implementing the `submit_rule` we will use the facts about the |
| 203 | change that are already provided by Gerrit. |
| 204 | |
| 205 | Another aspect of the return result from the `submit_rule` predicate is that |
| 206 | Gerrit uses it to decide which set of labels to display on the change review |
| 207 | screen for voting. If the return result contains label `'ABC'` and if the label |
Dave Borowitz | 01c1b1f | 2013-02-27 13:49:04 -0800 | [diff] [blame] | 208 | `'ABC'` is link:config-labels.html[defined for the project] then voting for the |
| 209 | label `'ABC'` will be displayed. Otherwise, it is not displayed. Note that the |
| 210 | project doesn't need a defined label for each label contained in the result of |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 211 | `submit_rule` predicate. For example, the decision whether |
| 212 | `'Author-is-John-Doe'` label is met will probably not be made by explicit voting |
| 213 | but, instead, by inspecting the facts about the change. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 214 | |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 215 | [[SubmitFilter]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 216 | == Submit Filter |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 217 | Another 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 |
| 219 | in the `rules.pl` file of the current project, the `submit_filter` will be |
| 220 | searched for in the `rules.pl` of all parent projects of the current project, |
| 221 | but not in the `rules.pl` of the current project. The search will start from the |
| 222 | immediate parent of the current project, then in the parent project of that |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 223 | project and so on until, and including, the `'All-Projects'` project. |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 224 | |
| 225 | The purpose of the submit filter is, as its name says, to filter the results |
| 226 | of the `submit_rule`. Therefore, the `submit_filter` predicate has two |
| 227 | parameters: |
| 228 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 229 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 230 | submit_filter(In, Out) :- ... |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 231 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 232 | Gerrit will invoke `submit_filter` with the `In` parameter containing a `submit` |
| 233 | structure produced by the `submit_rule` and will take the value of the `Out` |
| 234 | parameter as the result. |
| 235 | |
| 236 | The `Out` value of a `submit_filter` will become the `In` value for the |
| 237 | next `submit_filter` in the parent line. The value of the `Out` parameter |
| 238 | of the top-most `submit_filter` is the final result of the submit rule that |
| 239 | is used to decide whether a change is submittable or not. |
| 240 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 241 | [IMPORTANT] |
| 242 | `submit_filter` is a mechanism for Gerrit administrators to implement |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 243 | and enforce submit rules that would apply to all projects while `submit_rule` is |
| 244 | a mechanism for project owners to implement project specific submit rules. |
| 245 | However, 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 |
| 247 | implementing the `submit_filter` in this common parent project. This way they |
| 248 | can avoid implementing the same `submit_rule` in all their projects. |
| 249 | |
| 250 | The following "drawing" illustrates the order of the invocation and the chaining |
| 251 | of the results of the `submit_rule` and `submit_filter` predicates. |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 252 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 253 | 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 Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 267 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 268 | |
| 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` |
| 271 | project. |
| 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 |
| 274 | a `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 |
| 277 | value of the submit rule evaluation. |
| 278 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 279 | [NOTE] |
| 280 | If `MyProject` doesn't define its own `submit_rule` Gerrit will invoke the |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 281 | default implementation of submit rule that is named `gerrit:default_submit` and |
| 282 | its result will be filtered as described above. |
| 283 | |
Edwin Kempin | ca24f5c | 2013-03-26 13:23:20 +0100 | [diff] [blame] | 284 | [[HowToWriteSubmitType]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 285 | == How to write submit type |
Chris Lee | 849cbd8 | 2014-10-20 16:23:21 -0700 | [diff] [blame] | 286 | Writing custom submit type logic in Prolog is similar to |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 287 | xref:HowToWriteSubmitRules[writing submit rules]. The only difference is that |
| 288 | one has to implement a `submit_type` predicate (instead of the `submit_rule`) |
| 289 | and that the return result of the `submit_type` has to be an atom that |
| 290 | represents 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' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 298 | == Submit Type Filter |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 299 | Submit type filter works the same way as the xref:SubmitFilter[Submit Filter] |
| 300 | where the name of the filter predicate is `submit_type_filter`. |
| 301 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 302 | ---- |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 303 | submit_type_filter(In, Out). |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 304 | ---- |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 305 | |
| 306 | Gerrit will invoke `submit_type_filter` with the `In` parameter containing a |
| 307 | result of the `submit_type` and will take the value of the `Out` parameter as |
| 308 | the result. |
| 309 | |
Johan Björk | 2119f05 | 2012-10-24 12:10:45 -0400 | [diff] [blame] | 310 | [[TestingSubmitRules]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 311 | == Testing submit rules |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 312 | The prolog environment running the `submit_rule` is loaded with state describing |
| 313 | the change that is being evaluated. The easiest way to load this state is to |
| 314 | test your `submit_rule` against a real change on a running gerrit instance. The |
| 315 | command link:cmd-test-submit-rule.html[test-submit rule] loads a specific change |
| 316 | and executes the `submit_rule`. It optionally reads the rule from from `stdin` |
| 317 | to facilitate easy testing. |
Johan Björk | 2119f05 | 2012-10-24 12:10:45 -0400 | [diff] [blame] | 318 | |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 319 | ---- |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 320 | $ cat rules.pl | ssh gerrit_srv gerrit test-submit rule I45e080b105a50a625cc8e1fb5b357c0bfabe6d68 -s |
Michael Ochmann | b99feab | 2016-07-06 14:10:22 +0200 | [diff] [blame] | 321 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 322 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 323 | == Prolog vs Gerrit plugin for project specific submit rules |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 324 | Since version 2.5 Gerrit supports plugins and extension points. A plugin or an |
| 325 | extension point could also be used as another means to provide custom submit |
| 326 | rules. One could ask for a guideline when to use Prolog based submit rules and |
| 327 | when to go for writing a new plugin. Writing a Prolog program is usually much |
| 328 | faster than writing a Gerrit plugin. Prolog based submit rules can be pushed |
| 329 | to a project by project owners while Gerrit plugins could only be installed by |
| 330 | Gerrit administrators. In addition, Prolog based submit rules can be pushed |
| 331 | for review by pushing to `refs/for/refs/meta/config` branch. |
| 332 | |
| 333 | On the other hand, Prolog based submit rules get a limited amount of facts about |
| 334 | the change exposed to them. Gerrit plugins get full access to Gerrit internals |
| 335 | and can potentially check more things than Prolog based rules. |
| 336 | |
Sasa Zivkov | d0e5526 | 2013-01-16 14:26:06 +0100 | [diff] [blame] | 337 | From version 2.6 Gerrit plugins can contribute Prolog predicates. This way, we |
| 338 | can make use of the plugin provided predicates when writing Prolog based rules. |
| 339 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 340 | == Examples - Submit Rule |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 341 | The following examples should serve as a cookbook for developing own submit |
| 342 | rules. Some of them are too trivial to be used in production and their only |
| 343 | purpose is to provide step by step introduction and understanding. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 344 | |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 345 | Some of the examples will implement the `submit_rule` and some will implement |
| 346 | the `submit_filter` just to show both possibilities. Remember that |
| 347 | `submit_rule` is only invoked from the current project and `submit_filter` is |
| 348 | invoked from all parent projects. This is the most important fact in deciding |
| 349 | whether to implement `submit_rule` or `submit_filter`. |
| 350 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 351 | === Example 1: Make every change submittable |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 352 | Let's start with a most trivial example where we would make every change |
| 353 | submittable regardless of the votes it has: |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 354 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 355 | `rules.pl` |
| 356 | [source,prolog] |
| 357 | ---- |
| 358 | submit_rule(submit(W)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 359 | W = label('Any-Label-Name', ok(user(1000000))). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 360 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 361 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 362 | In this case we make no use of facts about the change. We don't need it as we |
| 363 | are simply making every change submittable. Note that, in this case, the Gerrit |
| 364 | UI 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 |
| 366 | result. The `'Any-Label-Name'` could really be any string. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 367 | |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 368 | The `user(1000000)` represents the user whose account ID is `1000000`. |
| 369 | |
| 370 | [NOTE] |
| 371 | Instead of the account ID `1000000` we could have used any other account ID. |
| 372 | The following examples will use `user(ID)` instead of `user(1000000)` because |
| 373 | it is easier to read and doesn't suggest that there is anything special with |
| 374 | the account ID `1000000`. |
| 375 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 376 | === Example 2: Every change submittable and voting in the standard categories possible |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 377 | This is continuation of the previous example where, in addition, to making |
| 378 | every change submittable we want to enable voting in the standard |
| 379 | `'Code-Review'` and `'Verified'` categories. |
| 380 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 381 | `rules.pl` |
| 382 | [source,prolog] |
| 383 | ---- |
| 384 | submit_rule(submit(CR, V)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 385 | CR = label('Code-Review', ok(user(ID))), |
| 386 | V = label('Verified', ok(user(ID))). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 387 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 388 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 389 | Since for every change all label statuses are `'ok'` every change will be |
| 390 | submittable. Voting in the standard labels will be shown in the UI as the |
| 391 | standard label names are included in the return result. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 392 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 393 | === Example 3: Nothing is submittable |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 394 | This example shows how to make all changes non-submittable regardless of the |
| 395 | votes they have. |
| 396 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 397 | `rules.pl` |
| 398 | [source,prolog] |
| 399 | ---- |
| 400 | submit_rule(submit(R)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 401 | R = label('Any-Label-Name', reject(user(ID))). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 402 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 403 | |
| 404 | Since for any change we return only one label with status `reject`, no change |
| 405 | will be submittable. The UI will, however, not indicate what is needed for a |
| 406 | change to become submittable as we return no labels with status `need`. |
| 407 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 408 | === Example 4: Nothing is submittable but UI shows several 'Need ...' criteria |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 409 | In 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 412 | `rules.pl` |
| 413 | [source,prolog] |
| 414 | ---- |
| 415 | % In the UI this will show: Need Any-Label-Name |
| 416 | submit_rule(submit(N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 417 | N = label('Any-Label-Name', need(_)). |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 418 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 419 | % We could define more "need" labels by adding more rules |
| 420 | submit_rule(submit(N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 421 | N = label('Another-Label-Name', need(_)). |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 422 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 423 | % or by providing more than one need label in the same rule |
| 424 | submit_rule(submit(NX, NY)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 425 | NX = label('X-Label-Name', need(_)), |
| 426 | NY = label('Y-Label-Name', need(_)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 427 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 428 | |
| 429 | In the UI this will show: |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 430 | |
| 431 | * `Need Any-Label-Name` |
| 432 | * `Need Another-Label-Name` |
| 433 | * `Need X-Label-Name` |
| 434 | * `Need Y-Label-Name` |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 435 | |
| 436 | From the example above we can see a few more things: |
| 437 | |
| 438 | * comment in Prolog starts with the `%` character |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 439 | * 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 Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 442 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 443 | === Example 5: The 'Need ...' labels not shown when change is submittable |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 444 | This example shows that, when there is a solution for `submit_rule(X)` where all |
| 445 | labels have status `ok` then Gerrit will not show any labels with the `need` |
| 446 | status from any of the previous `submit_rule(X)` solutions. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 447 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 448 | `rules.pl` |
| 449 | [source,prolog] |
| 450 | ---- |
| 451 | submit_rule(submit(N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 452 | N = label('Some-Condition', need(_)). |
| 453 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 454 | submit_rule(submit(OK)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 455 | OK = label('Another-Condition', ok(user(ID))). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 456 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 457 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 458 | The `'Need Some-Condition'` will not be shown in the UI because of the result of |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 459 | the second rule. |
| 460 | |
| 461 | The same is valid if the two rules are swapped: |
| 462 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 463 | `rules.pl` |
| 464 | [source,prolog] |
| 465 | ---- |
| 466 | submit_rule(submit(OK)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 467 | OK = label('Another-Condition', ok(user(ID))). |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 468 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 469 | submit_rule(submit(N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 470 | N = label('Some-Condition', need(_)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 471 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 472 | |
| 473 | The result of the first rule will stop search for any further solutions. |
| 474 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 475 | === Example 6: Make change submittable if commit author is "John Doe" |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 476 | This is the first example where we will use the Prolog facts about a change that |
| 477 | are automatically exposed by Gerrit. Our goal is to make any change submittable |
| 478 | when the commit author is named `'John Doe'`. In the very first |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 479 | step let's make sure Gerrit UI shows `'Need Author-is-John-Doe'` in |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 480 | the UI to clearly indicate to the user what is needed for a change to become |
| 481 | submittable: |
| 482 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 483 | `rules.pl` |
| 484 | [source,prolog] |
| 485 | ---- |
| 486 | submit_rule(submit(Author)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 487 | Author = label('Author-is-John-Doe', need(_)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 488 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 489 | |
| 490 | This will show: |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 491 | |
| 492 | * `Need Author-is-John-Doe` |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 493 | |
| 494 | in the UI but no change will be submittable yet. Let's add another rule: |
| 495 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 496 | `rules.pl` |
| 497 | [source,prolog] |
| 498 | ---- |
| 499 | submit_rule(submit(Author)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 500 | Author = label('Author-is-John-Doe', need(_)). |
| 501 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 502 | submit_rule(submit(Author)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 503 | gerrit:commit_author(A, 'John Doe', _), |
| 504 | Author = label('Author-is-John-Doe', ok(A)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 505 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 506 | |
| 507 | In the second rule we return `ok` status for the `'Author-is-John-Doe'` label |
| 508 | if there is a `commit_author` fact where the full name is `'John Doe'`. If |
| 509 | author of a change is `'John Doe'` then the second rule will return a solution |
| 510 | where all labels have `ok` status and the change will become submittable. If |
| 511 | author of a change is not `'John Doe'` then only the first rule will produce a |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 512 | solution. The UI will show `'Need Author-is-John-Doe'` but, as expected, the |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 513 | change will not be submittable. |
| 514 | |
| 515 | Instead of checking by full name we could also check by the email address: |
| 516 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 517 | `rules.pl` |
| 518 | [source,prolog] |
| 519 | ---- |
| 520 | submit_rule(submit(Author)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 521 | Author = label('Author-is-John-Doe', need(_)). |
| 522 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 523 | submit_rule(submit(Author)) :- |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 524 | gerrit:commit_author(_, _, 'john.doe@example.com'), |
| 525 | gerrit:uploader(U), |
| 526 | Author = label('Author-is-John-Doe', ok(U)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 527 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 528 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 529 | or by user id (assuming it is `1000000`): |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 530 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 531 | `rules.pl` |
| 532 | [source,prolog] |
| 533 | ---- |
| 534 | submit_rule(submit(Author)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 535 | Author = label('Author-is-John-Doe', need(_)). |
| 536 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 537 | submit_rule(submit(Author)) :- |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 538 | U = user(1000000), |
| 539 | gerrit:commit_author(U, _, _), |
| 540 | Author = label('Author-is-John-Doe', ok(U)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 541 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 542 | |
| 543 | or by a combination of these 3 attributes: |
| 544 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 545 | `rules.pl` |
| 546 | [source,prolog] |
| 547 | ---- |
| 548 | submit_rule(submit(Author)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 549 | Author = label('Author-is-John-Doe', need(_)). |
| 550 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 551 | submit_rule(submit(Author)) :- |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 552 | gerrit:commit_author(_, 'John Doe', 'john.doe@example.com'), |
| 553 | gerrit:uploader(U), |
| 554 | Author = label('Author-is-John-Doe', ok(U)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 555 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 556 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 557 | === Example 7: Make change submittable if commit message starts with "Fix " |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 558 | Besides showing how to make use of the commit message text the purpose of this |
| 559 | example is also to show how to match only a part of a string symbol. Similarly |
| 560 | like commit author the commit message is provided as a string symbol which is |
| 561 | an atom in Prolog terms. When working with an atom we could only match against |
| 562 | the whole value. To match only part of a string symbol we have, at least, two |
| 563 | options: |
| 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 | |
| 570 | Let's implement both options: |
| 571 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 572 | `rules.pl` |
| 573 | [source,prolog] |
| 574 | ---- |
| 575 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 576 | Fix = label('Commit-Message-starts-with-Fix', need(_)). |
| 577 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 578 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 579 | gerrit:commit_message(M), name(M, L), starts_with(L, "Fix "), |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 580 | gerrit:uploader(U), |
| 581 | Fix = label('Commit-Message-starts-with-Fix', ok(U)). |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 582 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 583 | starts_with(L, []). |
| 584 | starts_with([H|T1], [H|T2]) :- starts_with(T1, T2). |
| 585 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 586 | |
Michael Ochmann | 8129ece | 2016-07-08 11:25:25 +0200 | [diff] [blame] | 587 | [NOTE] |
| 588 | The `name/2` embedded predicate is used to convert a string symbol into a |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 589 | list of characters. A string `abc` is converted into a list of characters `[97, |
| 590 | 98, 99]`. A double quoted string in Prolog is just a shortcut for creating a |
| 591 | list of characters. `"abc"` is a shortcut for `[97, 98, 99]`. This is why we use |
| 592 | double quotes for the `"Trivial Fix"` in the example above. |
| 593 | |
| 594 | The `starts_with` predicate is self explaining. |
| 595 | |
| 596 | Using the `gerrit:commit_message_matches` predicate is probably more efficient: |
| 597 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 598 | `rules.pl` |
| 599 | [source,prolog] |
| 600 | ---- |
| 601 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 602 | Fix = label('Commit-Message-starts-with-Fix', need(_)). |
| 603 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 604 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 605 | gerrit:commit_message_matches('^Fix '), |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 606 | gerrit:uploader(U), |
| 607 | Fix = label('Commit-Message-starts-with-Fix', ok(U)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 608 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 609 | |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 610 | The previous example could also be written so that it first checks if the commit |
| 611 | message starts with 'Fix '. If true then it sets OK for that category and stops |
| 612 | further backtracking by using the cut `!` operator: |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 613 | |
| 614 | `rules.pl` |
| 615 | [source,prolog] |
| 616 | ---- |
| 617 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 618 | gerrit:commit_message_matches('^Fix '), |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 619 | gerrit:uploader(U), |
| 620 | Fix = label('Commit-Message-starts-with-Fix', ok(U)), |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 621 | !. |
| 622 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 623 | % Message does not start with 'Fix ' so Fix is needed to submit |
| 624 | submit_rule(submit(Fix)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 625 | Fix = label('Commit-Message-starts-with-Fix', need(_)). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 626 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 627 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 628 | == The default submit policy |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 629 | All examples until now concentrate on one particular aspect of change data. |
| 630 | However, in real-life scenarios we would rather want to reuse Gerrit's default |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 631 | submit policy and extend/change it for our specific purpose. This could be |
| 632 | done in one of the following ways: |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 633 | |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 634 | * 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' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 639 | === Default submit rule implementation |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 640 | The default submit rule with the two default categories, `Code-Review` and |
| 641 | `Verified`, can be implemented as: |
| 642 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 643 | `rules.pl` |
| 644 | [source,prolog] |
| 645 | ---- |
| 646 | submit_rule(submit(V, CR)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 647 | gerrit:max_with_block(-2, 2, 'Code-Review', CR), |
| 648 | gerrit:max_with_block(-1, 1, 'Verified', V). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 649 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 650 | |
| 651 | Once this implementation is understood it can be customized to implement |
| 652 | project specific submit rules. Note, that this implementation hardcodes |
| 653 | the two default categories. Introducing a new category in the database would |
| 654 | require introducing the same category here or a `submit_filter` in a parent |
| 655 | project would have to care about including the new category in the result of |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 656 | this `submit_rule`. On the other side, this example is easy to read and |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 657 | understand. |
| 658 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 659 | === Reusing the default submit policy |
David Pursehouse | 9246356 | 2013-06-24 10:16:28 +0900 | [diff] [blame] | 660 | To get results of Gerrit's default submit policy we use the |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 661 | `gerrit:default_submit` predicate. The `gerrit:default_submit(X)` includes all |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 662 | categories from the database. This means that if we write a submit rule like |
| 663 | this: |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 664 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 665 | `rules.pl` |
| 666 | [source,prolog] |
| 667 | ---- |
| 668 | submit_rule(X) :- gerrit:default_submit(X). |
| 669 | ---- |
| 670 | |
| 671 | it is equivalent to not using `rules.pl` at all. We just delegate to |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 672 | default logic. However, once we invoke the `gerrit:default_submit(X)` we can |
| 673 | perform further actions on the return result `X` and apply our specific |
| 674 | logic. The following pattern illustrates this technique: |
| 675 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 676 | `rules.pl` |
| 677 | [source,prolog] |
| 678 | ---- |
| 679 | submit_rule(S) :- gerrit:default_submit(R), project_specific_policy(R, S). |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 680 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 681 | project_specific_policy(R, S) :- ... |
| 682 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 683 | |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 684 | In the following examples both styles will be shown. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 685 | |
Edwin Kempin | 1781adb | 2014-04-22 10:02:40 +0200 | [diff] [blame] | 686 | [[NonAuthorCodeReview]] |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 687 | === Example 8: Make change submittable only if `Code-Review+2` is given by a non author |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 688 | In this example we introduce a new label `Non-Author-Code-Review` and make it |
| 689 | satisfied if there is at least one `Code-Review+2` from a non author. All other |
| 690 | default policies like the `Verified` category and vetoing changes still apply. |
| 691 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 692 | ==== Reusing the `gerrit:default_submit` |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 693 | First, we invoke `gerrit:default_submit` to compute the result for the default |
| 694 | submit 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 |
| 696 | exists or with status `need` if it doesn't exist. |
| 697 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 698 | `rules.pl` |
| 699 | [source,prolog] |
| 700 | ---- |
| 701 | submit_rule(S) :- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 702 | gerrit:default_submit(X), |
| 703 | X =.. [submit | Ls], |
| 704 | add_non_author_approval(Ls, R), |
| 705 | S =.. [submit | R]. |
| 706 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 707 | add_non_author_approval(S1, S2) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 708 | gerrit:commit_author(A), |
| 709 | gerrit:commit_label(label('Code-Review', 2), R), |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 710 | R \= A, !, |
| 711 | S2 = [label('Non-Author-Code-Review', ok(R)) | S1]. |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 712 | add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]). |
| 713 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 714 | |
| 715 | This example uses the `univ` operator `=..` to "unpack" the result of the |
| 716 | default_submit, which is a structure of the form `submit(label('Code-Review', |
Saša Živkov | aa87063 | 2016-07-15 13:10:11 +0200 | [diff] [blame] | 717 | ok(user(ID))), label('Verified', need(_)), ...)` into a list like `[submit, |
| 718 | label('Code-Review', ok(user(ID))), label('Verified', need(_)), ...]`. Then we |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 719 | process the tail of the list (the list of labels) as a Prolog list, which is |
| 720 | much easier than processing a structure. In the end we use the same `univ` |
| 721 | operator to convert the resulting list of labels back into a `submit` structure |
| 722 | which is expected as a return result. The `univ` operator works both ways. |
| 723 | |
| 724 | In `add_non_author_approval` we use the `cut` operator `!` to prevent Prolog |
| 725 | from searching for more solutions once the `cut` point is reached. This is |
| 726 | important 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 |
| 728 | is no non author `Code-Review+2`. The second rule will only be reached |
| 729 | if the `cut` in the first rule is not reached and it only happens if a |
| 730 | predicate before the `cut` fails. |
| 731 | |
Patrick Hiesel | e5f6403 | 2019-03-29 09:54:39 +0100 | [diff] [blame] | 732 | This fact can be bypassed by users who have |
| 733 | link:access-control.html#category_forge_author[Forge Author] permission. |
| 734 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 735 | ==== Don't use `gerrit:default_submit` |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 736 | Let's implement the same submit rule the other way, without reusing the |
| 737 | `gerrit:default_submit`: |
| 738 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 739 | `rules.pl` |
| 740 | [source,prolog] |
| 741 | ---- |
| 742 | submit_rule(submit(CR, V)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 743 | base(CR, V), |
| 744 | CR = label(_, ok(Reviewer)), |
| 745 | gerrit:commit_author(Author), |
| 746 | Author \= Reviewer, |
| 747 | !. |
| 748 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 749 | submit_rule(submit(CR, V, N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 750 | base(CR, V), |
| 751 | N = label('Non-Author-Code-Review', need(_)). |
| 752 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 753 | base(CR, V) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 754 | gerrit:max_with_block(-2, 2, 'Code-Review', CR), |
| 755 | gerrit:max_with_block(-1, 1, 'Verified', V). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 756 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 757 | |
| 758 | The latter implementation is probably easier to understand and the code looks |
| 759 | cleaner. Note, however, that the latter implementation will always return the |
| 760 | two standard categories only (`Code-Review` and `Verified`) even if a new |
David Pursehouse | 9246356 | 2013-06-24 10:16:28 +0900 | [diff] [blame] | 761 | category has been inserted into the database. To include the new category |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 762 | the `rules.pl` would need to be modified or a `submit_filter` in a parent |
| 763 | project would have to care about including the new category in the result |
| 764 | of this `submit_rule`. |
| 765 | |
| 766 | The former example, however, would include any newly added category as it |
| 767 | invokes the `gerrit:default_submit` and then modifies its result. |
| 768 | |
| 769 | Which of these two behaviors is desired will always depend on how a particular |
| 770 | Gerrit server is managed. |
| 771 | |
Edwin Kempin | 426c6a5 | 2016-04-04 11:05:51 +0200 | [diff] [blame] | 772 | === Example 9: Remove the `Verified` category |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 773 | A project has no build and test. It consists of only text files and needs only |
| 774 | code review. We want to remove the `Verified` category from this project so |
| 775 | that `Code-Review+2` is the only criteria for a change to become submittable. |
| 776 | We also want the UI to not show the `Verified` category in the table with |
| 777 | votes and on the voting screen. |
| 778 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 779 | This is quite simple without reusing the `gerrit:default_submit`: |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 780 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 781 | `rules.pl` |
| 782 | [source,prolog] |
| 783 | ---- |
| 784 | submit_rule(submit(CR)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 785 | gerrit:max_with_block(-2, 2, 'Code-Review', CR). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 786 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 787 | |
| 788 | Implementing the same rule by reusing `gerrit:default_submit` is a bit more complex: |
| 789 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 790 | `rules.pl` |
| 791 | [source,prolog] |
| 792 | ---- |
| 793 | submit_rule(S) :- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 794 | gerrit:default_submit(X), |
| 795 | X =.. [submit | Ls], |
| 796 | remove_verified_category(Ls, R), |
| 797 | S =.. [submit | R]. |
| 798 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 799 | remove_verified_category([], []). |
| 800 | remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !. |
| 801 | remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R). |
| 802 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 803 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 804 | === Example 10: Combine examples 8 and 9 |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 805 | In this example we want to both remove the verified and have the four eyes |
Maxime Guerreiro | 693ce81 | 2018-06-13 12:30:13 +0000 | [diff] [blame] | 806 | principle. This means we want a combination of examples 8 and 9. |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 807 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 808 | `rules.pl` |
| 809 | [source,prolog] |
| 810 | ---- |
| 811 | submit_rule(S) :- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 812 | 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 817 | ---- |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 818 | |
| 819 | The `remove_verified_category` and `add_non_author_approval` predicates are the |
| 820 | same as defined in the previous two examples. |
| 821 | |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 822 | Without reusing the `gerrit:default_submit` the same example may be implemented |
| 823 | as: |
| 824 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 825 | `rules.pl` |
| 826 | [source,prolog] |
| 827 | ---- |
| 828 | submit_rule(submit(CR)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 829 | base(CR), |
| 830 | CR = label(_, ok(Reviewer)), |
| 831 | gerrit:commit_author(Author), |
| 832 | Author \= Reviewer, |
| 833 | !. |
| 834 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 835 | submit_rule(submit(CR, N)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 836 | base(CR), |
| 837 | N = label('Non-Author-Code-Review', need(_)). |
| 838 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 839 | base(CR) :- |
Craig Znamierowski | f509d9c5 | 2016-10-14 17:09:59 -0400 | [diff] [blame] | 840 | gerrit:max_with_block(-2, 2, 'Code-Review', CR). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 841 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 842 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 843 | === Example 11: Remove the `Verified` category from all projects |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 844 | Example 9, implements `submit_rule` that removes the `Verified` category from |
| 845 | one project. In this example we do the same but we want to remove the `Verified` |
| 846 | category from all projects. This means we have to implement `submit_filter` and |
| 847 | we have to do that in the `rules.pl` of the `All-Projects` project. |
| 848 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 849 | `rules.pl` |
| 850 | [source,prolog] |
| 851 | ---- |
| 852 | submit_filter(In, Out) :- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 853 | In =.. [submit | Ls], |
| 854 | remove_verified_category(Ls, R), |
| 855 | Out =.. [submit | R]. |
| 856 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 857 | remove_verified_category([], []). |
| 858 | remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !. |
| 859 | remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R). |
| 860 | ---- |
Sasa Zivkov | 3d4f0aa | 2012-08-07 15:11:32 +0200 | [diff] [blame] | 861 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 862 | === Example 12: On release branches require DrNo in addition to project rules |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 863 | A new category 'DrNo' is added to the database and is required for release |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 864 | branches. To mark a branch as a release branch we use |
| 865 | `drno('refs/heads/branch')`. |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 866 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 867 | `rules.pl` |
| 868 | [source,prolog] |
| 869 | ---- |
| 870 | drno('refs/heads/master'). |
| 871 | drno('refs/heads/stable-2.3'). |
| 872 | drno('refs/heads/stable-2.4'). |
| 873 | drno('refs/heads/stable-2.5'). |
| 874 | drno('refs/heads/stable-2.5'). |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 875 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 876 | submit_filter(In, Out) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 877 | 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 884 | submit_filter(In, Out) :- In = Out. |
| 885 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 886 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 887 | === Example 13: 1+1=2 Code-Review |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 888 | In this example we introduce accumulative voting to determine if a change is |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 889 | submittable or not. We modify the standard `Code-Review` to be accumulative, and |
| 890 | make the change submittable if the total score is `2` or higher. |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 891 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 892 | The code in this example is very similar to Example 8, with the addition of |
| 893 | `findall/3` and `gerrit:remove_label`. |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 894 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 895 | The `findall/3` embedded predicate is used to form a list of all objects that |
| 896 | satisfy 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 |
| 898 | implemented similarly to the `remove_verified_category` as seen in the previous |
| 899 | example. |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 900 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 901 | `rules.pl` |
| 902 | [source,prolog] |
| 903 | ---- |
| 904 | sum_list([], 0). |
| 905 | sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp. |
| 906 | |
| 907 | add_category_min_score(In, Category, Min, P) :- |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 908 | findall(X, gerrit:commit_label(label(Category,X),R),Z), |
| 909 | sum_list(Z, Sum), |
| 910 | Sum >= Min, !, |
Kévin Raymond | 6ca0726 | 2017-10-22 19:18:07 +0200 | [diff] [blame] | 911 | gerrit:commit_label(label(Category, V), U), |
| 912 | V >= 1, |
| 913 | !, |
| 914 | P = [label(Category,ok(U)) | In]. |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 915 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 916 | add_category_min_score(In, Category,Min,P) :- |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 917 | P = [label(Category,need(Min)) | In]. |
| 918 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 919 | submit_rule(S) :- |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 920 | 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 Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 925 | ---- |
Johan Björk | ef02854 | 2012-10-24 12:06:33 -0400 | [diff] [blame] | 926 | |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 927 | Implementing the same example without using `gerrit:default_submit`: |
| 928 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 929 | `rules.pl` |
| 930 | [source,prolog] |
| 931 | ---- |
| 932 | submit_rule(submit(CR, V)) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 933 | sum(2, 'Code-Review', CR), |
| 934 | gerrit:max_with_block(-1, 1, 'Verified', V). |
| 935 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 936 | % Sum the votes in a category. Uses a helper function score/2 |
| 937 | % to select out only the score values the given category. |
| 938 | sum(VotesNeeded, Category, label(Category, ok(_))) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 939 | findall(Score, score(Category, Score), All), |
| 940 | sum_list(All, Sum), |
| 941 | Sum >= VotesNeeded, |
| 942 | !. |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 943 | sum(VotesNeeded, Category, label(Category, need(VotesNeeded))). |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 944 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 945 | score(Category, Score) :- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 946 | gerrit:commit_label(label(Category, Score), User). |
| 947 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 948 | % Simple Prolog routine to sum a list of integers. |
| 949 | sum_list(List, Sum) :- sum_list(List, 0, Sum). |
| 950 | sum_list([X|T], Y, S) :- Z is X + Y, sum_list(T, Z, S). |
| 951 | sum_list([], S, S). |
| 952 | ---- |
Sasa Zivkov | 79b08cc | 2013-01-16 17:00:54 +0100 | [diff] [blame] | 953 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 954 | === Example 14: Master and apprentice |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 955 | The master and apprentice example allow you to specify a user (the `master`) |
| 956 | that must approve all changes done by another user (the `apprentice`). |
| 957 | |
| 958 | The code first checks if the commit author is in the apprentice database. |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 959 | If the commit is done by an `apprentice`, it will check if there is a `+2` |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 960 | review by the associated `master`. |
| 961 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 962 | `rules.pl` |
| 963 | [source,prolog] |
| 964 | ---- |
| 965 | % master_apprentice(Master, Apprentice). |
| 966 | % Extend this with appropriate user-id for your master/apprentice setup. |
| 967 | master_apprentice(user(1000064), user(1000000)). |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 968 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 969 | submit_rule(S) :- |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 970 | gerrit:default_submit(In), |
| 971 | In =.. [submit | Ls], |
| 972 | add_apprentice_master(Ls, R), |
| 973 | S =.. [submit | R]. |
| 974 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 975 | check_master_approval(S1, S2, Master) :- |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 976 | gerrit:commit_label(label('Code-Review', 2), R), |
| 977 | R = Master, !, |
| 978 | S2 = [label('Master-Approval', ok(R)) | S1]. |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 979 | check_master_approval(S1, [label('Master-Approval', need(_)) | S1], _). |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 980 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 981 | add_apprentice_master(S1, S2) :- |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 982 | gerrit:commit_author(Id), |
| 983 | master_apprentice(Master, Id), |
| 984 | !, |
| 985 | check_master_approval(S1, S2, Master). |
| 986 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 987 | add_apprentice_master(S, S). |
| 988 | ---- |
Johan Björk | 87927a9 | 2012-10-25 15:00:36 -0400 | [diff] [blame] | 989 | |
Changcheng Xiao | d799090 | 2017-11-21 11:22:48 +0100 | [diff] [blame] | 990 | === Example 15: Make change submittable if all comments have been resolved |
Changcheng Xiao | a5d0178 | 2017-02-15 13:11:20 +0100 | [diff] [blame] | 991 | In this example we will use the `unresolved_comments_count` fact about a |
| 992 | change. Our goal is to block the submission of any change with some |
| 993 | unresolved comments. Basically, it can be achieved by the following rules: |
| 994 | |
| 995 | `rules.pl` |
| 996 | [source,prolog] |
| 997 | ---- |
| 998 | submit_rule(submit(R)) :- |
| 999 | gerrit:unresolved_comments_count(0), |
| 1000 | !, |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 1001 | gerrit:uploader(U), |
| 1002 | R = label('All-Comments-Resolved', ok(U)). |
Changcheng Xiao | a5d0178 | 2017-02-15 13:11:20 +0100 | [diff] [blame] | 1003 | |
| 1004 | submit_rule(submit(R)) :- |
| 1005 | gerrit:unresolved_comments_count(U), |
| 1006 | U > 0, |
| 1007 | R = label('All-Comments-Resolved', need(_)). |
| 1008 | ---- |
| 1009 | |
| 1010 | Suppose currently a change is submittable if it gets `+2` for `Code-Review` |
| 1011 | and `+1` for `Verified`. It can be extended to support the above rules as |
| 1012 | follows: |
| 1013 | |
| 1014 | `rules.pl` |
| 1015 | [source,prolog] |
| 1016 | ---- |
| 1017 | submit_rule(submit(CR, V, R)) :- |
| 1018 | base(CR, V), |
| 1019 | gerrit:unresolved_comments_count(0), |
| 1020 | !, |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 1021 | gerrit:uploader(U), |
| 1022 | R = label('All-Comments-Resolved', ok(U)). |
Changcheng Xiao | a5d0178 | 2017-02-15 13:11:20 +0100 | [diff] [blame] | 1023 | |
| 1024 | submit_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 | |
| 1030 | base(CR, V) :- |
| 1031 | gerrit:max_with_block(-2, 2, 'Code-Review', CR), |
| 1032 | gerrit:max_with_block(-1, 1, 'Verified', V). |
| 1033 | ---- |
| 1034 | |
| 1035 | Note that a new label as `All-Comments-Resolved` should not be configured. |
| 1036 | It's only used to show `'Needs All-Comments-Resolved'` in the UI to clearly |
| 1037 | indicate to the user that all the comments have to be resolved for the |
| 1038 | change to become submittable. |
| 1039 | |
Changcheng Xiao | d799090 | 2017-11-21 11:22:48 +0100 | [diff] [blame] | 1040 | === Example 16: Make change submittable if it is a pure revert |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1041 | In this example we will use the `pure_revert` fact about a |
| 1042 | change. Our goal is to block the submission of any change that is not a |
| 1043 | pure revert. Basically, it can be achieved by the following rules: |
| 1044 | |
| 1045 | `rules.pl` |
| 1046 | [source,prolog] |
| 1047 | ---- |
| 1048 | submit_rule(submit(R)) :- |
| 1049 | gerrit:pure_revert(1), |
| 1050 | !, |
Jonathan Nieder | bd42cc7 | 2017-12-27 14:18:13 -0800 | [diff] [blame] | 1051 | gerrit:uploader(U), |
| 1052 | R = label('Is-Pure-Revert', ok(U)). |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1053 | |
Gary Miguel | 141022f | 2019-02-07 09:39:37 -0800 | [diff] [blame] | 1054 | submit_rule(submit(label('Is-Pure-Revert', need(_)))). |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1055 | ---- |
| 1056 | |
| 1057 | Suppose currently a change is submittable if it gets `+2` for `Code-Review` |
| 1058 | and `+1` for `Verified`. It can be extended to support the above rules as |
| 1059 | follows: |
| 1060 | |
| 1061 | `rules.pl` |
| 1062 | [source,prolog] |
| 1063 | ---- |
| 1064 | submit_rule(submit(CR, V, R)) :- |
Gary Miguel | 141022f | 2019-02-07 09:39:37 -0800 | [diff] [blame] | 1065 | base(CR, V), |
| 1066 | set_pure_revert_label(R). |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1067 | |
| 1068 | base(CR, V) :- |
Gary Miguel | 141022f | 2019-02-07 09:39:37 -0800 | [diff] [blame] | 1069 | gerrit:max_with_block(-2, 2, 'Code-Review', CR), |
| 1070 | gerrit:max_with_block(-1, 1, 'Verified', V). |
| 1071 | |
| 1072 | set_pure_revert_label(R) :- |
| 1073 | gerrit:pure_revert(1), |
| 1074 | !, |
| 1075 | gerrit:uploader(U), |
| 1076 | R = label('Is-Pure-Revert', ok(U)). |
| 1077 | |
| 1078 | set_pure_revert_label(label('Is-Pure-Revert', need(_))). |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1079 | ---- |
| 1080 | |
| 1081 | Note that a new label as `Is-Pure-Revert` should not be configured. |
| 1082 | It's only used to show `'Needs Is-Pure-Revert'` in the UI to clearly |
Patrick Hiesel | 918ecab | 2017-09-18 08:29:24 +0200 | [diff] [blame] | 1083 | indicate to the user that the change has to be a pure revert in order |
| 1084 | to become submittable. |
Patrick Hiesel | 42db934 | 2017-09-12 11:45:06 +0200 | [diff] [blame] | 1085 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 1086 | == Examples - Submit Type |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1087 | The following examples show how to implement own submit type rules. |
| 1088 | |
Yuxuan 'fishy' Wang | 61698b1 | 2013-12-20 12:55:51 -0800 | [diff] [blame] | 1089 | === Example 1: Set a `Cherry Pick` submit type for all changes |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1090 | This example sets the `Cherry Pick` submit type for all changes. It overrides |
| 1091 | whatever is set as project default submit type. |
| 1092 | |
| 1093 | rules.pl |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 1094 | [source,prolog] |
| 1095 | ---- |
| 1096 | submit_type(cherry_pick). |
| 1097 | ---- |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1098 | |
Edwin Kempin | 1781adb | 2014-04-22 10:02:40 +0200 | [diff] [blame] | 1099 | [[SubmitTypePerBranch]] |
Jonathan Nieder | 5758f18 | 2015-03-30 11:28:55 -0700 | [diff] [blame] | 1100 | === Example 2: `Fast Forward Only` for all `+refs/heads/stable*+` branches |
| 1101 | For all `+refs/heads/stable*+` branches we would like to enforce the `Fast |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1102 | Forward Only` submit type. A reason for this decision may be a need to never |
| 1103 | break the build in the stable branches. For all other branches, those not |
Jonathan Nieder | 5758f18 | 2015-03-30 11:28:55 -0700 | [diff] [blame] | 1104 | matching the `+refs/heads/stable*+` pattern, we would like to use the project's |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1105 | default submit type as defined on the project settings page. |
| 1106 | |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 1107 | `rules.pl` |
| 1108 | [source,prolog] |
| 1109 | ---- |
| 1110 | submit_type(fast_forward_only) :- |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1111 | gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B), |
| 1112 | !. |
Dave Borowitz | 6ba7976 | 2015-12-16 15:41:52 -0500 | [diff] [blame] | 1113 | submit_type(T) :- gerrit:project_default_submit_type(T). |
David Myllykangas | c5f591d | 2015-01-23 11:39:01 +0100 | [diff] [blame] | 1114 | ---- |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1115 | |
| 1116 | The first `submit_type` predicate defines the `Fast Forward Only` submit type |
Jonathan Nieder | 5758f18 | 2015-03-30 11:28:55 -0700 | [diff] [blame] | 1117 | for `+refs/heads/stable.*+` branches. The second `submit_type` predicate returns |
Sasa Zivkov | b91296d | 2012-11-08 14:19:12 +0100 | [diff] [blame] | 1118 | the project's default submit type. |
| 1119 | |
Sasa Zivkov | ae50f71 | 2012-07-24 14:51:44 +0200 | [diff] [blame] | 1120 | GERRIT |
| 1121 | ------ |
| 1122 | Part of link:index.html[Gerrit Code Review] |
Yuxuan 'fishy' Wang | 99cb68d | 2013-10-31 17:26:00 -0700 | [diff] [blame] | 1123 | |
| 1124 | SEARCHBOX |
| 1125 | --------- |