Documentation: prolog-cookbook, Update style
Update style and formatting Wrap lines at 80 chars Change-Id: Ib3cae9f26d484842fa9cf092ff8c2af2458a0fc1
This commit is contained in:
@@ -2,11 +2,11 @@
|
|||||||
|
|
||||||
[[SubmitRule]]
|
[[SubmitRule]]
|
||||||
== Submit Rule
|
== Submit Rule
|
||||||
A 'Submit Rule' in Gerrit is logic that defines when a change is submittable.
|
A _Submit Rule_ in Gerrit is logic that defines when a change is submittable.
|
||||||
By default, a change is submittable when it gets at least one
|
By default, a change is submittable when it gets at least one
|
||||||
highest vote in each voting category and has no lowest vote (aka veto vote) in
|
highest vote in each voting category and has no lowest vote (aka veto vote) in
|
||||||
any category. Typically, this means that a change needs 'Code-Review+2',
|
any category. Typically, this means that a change needs `Code-Review+2`,
|
||||||
'Verified+1' and has neither 'Code-Review-2' nor 'Verified-1' to become
|
`Verified+1` and has neither `Code-Review-2` nor `Verified-1` to become
|
||||||
submittable.
|
submittable.
|
||||||
|
|
||||||
While this rule is a good default, there are projects which need more
|
While this rule is a good default, there are projects which need more
|
||||||
@@ -29,7 +29,7 @@ link:http://gerrit-documentation.googlecode.com/svn/ReleaseNotes/ReleaseNotes-2.
|
|||||||
|
|
||||||
[[SubmitType]]
|
[[SubmitType]]
|
||||||
== Submit Type
|
== Submit Type
|
||||||
A 'Submit Type' is a strategy that is used on submit to integrate the
|
A _Submit Type_ is a strategy that is used on submit to integrate the
|
||||||
change into the destination branch. Supported submit types are:
|
change into the destination branch. Supported submit types are:
|
||||||
|
|
||||||
* `Fast Forward Only`
|
* `Fast Forward Only`
|
||||||
@@ -38,7 +38,7 @@ change into the destination branch. Supported submit types are:
|
|||||||
* `Cherry Pick`
|
* `Cherry Pick`
|
||||||
* `Rebase If Necessary`
|
* `Rebase If Necessary`
|
||||||
|
|
||||||
'Submit Type' is a project global setting. This means that the same submit type
|
_Submit Type_ is a project global setting. This means that the same submit type
|
||||||
is used for all changes of one project.
|
is used for all changes of one project.
|
||||||
|
|
||||||
Projects which need more flexibility in choosing, or enforcing, a submit type
|
Projects which need more flexibility in choosing, or enforcing, a submit type
|
||||||
@@ -51,14 +51,15 @@ submit type is shown on the change screen for each change.
|
|||||||
== Prolog Language
|
== Prolog Language
|
||||||
This document is not a complete Prolog tutorial.
|
This document is not a complete Prolog tutorial.
|
||||||
link:http://en.wikipedia.org/wiki/Prolog[This Wikipedia page on Prolog] is a
|
link:http://en.wikipedia.org/wiki/Prolog[This Wikipedia page on Prolog] is a
|
||||||
good starting point for learning the Prolog language. This document will only explain
|
good starting point for learning the Prolog language. This document will only
|
||||||
some elements of Prolog that are necessary to understand the provided examples.
|
explain some elements of Prolog that are necessary to understand the provided
|
||||||
|
examples.
|
||||||
|
|
||||||
== Prolog in Gerrit
|
== Prolog in Gerrit
|
||||||
Gerrit uses its own link:https://code.google.com/p/prolog-cafe/[fork] of the
|
Gerrit uses its own link:https://code.google.com/p/prolog-cafe/[fork] of the
|
||||||
original link:http://kaminari.istc.kobe-u.ac.jp/PrologCafe/[prolog-cafe]
|
original link:http://kaminari.istc.kobe-u.ac.jp/PrologCafe/[prolog-cafe]
|
||||||
project. Gerrit embeds the prolog-cafe library and can interpret Prolog programs at
|
project. Gerrit embeds the prolog-cafe library and can interpret Prolog programs
|
||||||
runtime.
|
at runtime.
|
||||||
|
|
||||||
== Interactive Prolog Cafe Shell
|
== Interactive Prolog Cafe Shell
|
||||||
For interactive testing and playing with Prolog, Gerrit provides the
|
For interactive testing and playing with Prolog, Gerrit provides the
|
||||||
@@ -66,7 +67,8 @@ link:pgm-prolog-shell.html[prolog-shell] program which opens an interactive
|
|||||||
Prolog interpreter shell.
|
Prolog interpreter shell.
|
||||||
|
|
||||||
NOTE: The interactive shell is just a prolog shell, it does not load
|
NOTE: The interactive shell is just a prolog shell, it does not load
|
||||||
a gerrit server environment and thus is not intended for xref:TestingSubmitRules[testing submit rules].
|
a gerrit server environment and thus is not intended for
|
||||||
|
xref:TestingSubmitRules[testing submit rules].
|
||||||
|
|
||||||
== SWI-Prolog
|
== SWI-Prolog
|
||||||
Instead of using the link:pgm-prolog-shell.html[prolog-shell] program one can
|
Instead of using the link:pgm-prolog-shell.html[prolog-shell] program one can
|
||||||
@@ -94,8 +96,8 @@ file:
|
|||||||
|
|
||||||
[[HowToWriteSubmitRules]]
|
[[HowToWriteSubmitRules]]
|
||||||
== How to write submit rules
|
== How to write submit rules
|
||||||
Whenever Gerrit needs to evaluate submit rules for a change `C` from project `P` it
|
Whenever Gerrit needs to evaluate submit rules for a change `C` from project `P`
|
||||||
will first initialize the embedded Prolog interpreter by:
|
it will first initialize the embedded Prolog interpreter by:
|
||||||
|
|
||||||
* consulting a set of facts about the change `C`
|
* consulting a set of facts about the change `C`
|
||||||
* consulting the `rules.pl` from the project `P`
|
* consulting the `rules.pl` from the project `P`
|
||||||
@@ -126,9 +128,9 @@ link:prolog-change-facts.html[Prolog Facts for Gerrit Change].
|
|||||||
By default, Gerrit will search for a `submit_rule/1` predicate in the `rules.pl`
|
By default, Gerrit will search for a `submit_rule/1` predicate in the `rules.pl`
|
||||||
file, evaluate the `submit_rule(X)` and then inspect the value of `X` in order
|
file, evaluate the `submit_rule(X)` and then inspect the value of `X` in order
|
||||||
to decide whether the change is submittable or not and also to find the set of
|
to decide whether the change is submittable or not and also to find the set of
|
||||||
needed criteria for the change to become submittable. This means that Gerrit has an
|
needed criteria for the change to become submittable. This means that Gerrit has
|
||||||
expectation on the format and value of the result of the `submit_rule` predicate
|
an expectation on the format and value of the result of the `submit_rule`
|
||||||
which is expected to be a `submit` term of the following format:
|
predicate which is expected to be a `submit` term of the following format:
|
||||||
|
|
||||||
====
|
====
|
||||||
submit(label(label-name, status) [, label(label-name, status)]*)
|
submit(label(label-name, status) [, label(label-name, status)]*)
|
||||||
@@ -141,13 +143,13 @@ be any other string (see examples below). The `status` is one of:
|
|||||||
used to tell that this label/category has been met.
|
used to tell that this label/category has been met.
|
||||||
* `need(_)` is used to tell that this label/category is needed for change to
|
* `need(_)` is used to tell that this label/category is needed for change to
|
||||||
become submittable
|
become submittable
|
||||||
* `reject(user(ID))` or just `reject(_)`. This status is used to tell that label/category
|
* `reject(user(ID))` or just `reject(_)`. This status is used to tell that
|
||||||
is blocking change submission
|
label/category is blocking change submission
|
||||||
* `impossible(_)` is used when the logic knows that the change cannot be submitted as-is.
|
* `impossible(_)` is used when the logic knows that the change cannot be
|
||||||
Administrative intervention is probably required. This is meant for cases
|
submitted as-is. Administrative intervention is probably required. This is
|
||||||
where the logic requires members of "FooEng" to score "Code-Review +2" on a
|
meant for cases where the logic requires members of "FooEng" to score
|
||||||
change, but nobody is in group "FooEng". It is to hint at permissions
|
`Code-Review +2` on a change, but nobody is in group "FooEng". It is to hint
|
||||||
misconfigurations.
|
at permissions misconfigurations.
|
||||||
* `may(_)` allows expression of approval categories that are optional, i.e.
|
* `may(_)` allows expression of approval categories that are optional, i.e.
|
||||||
could either be set or unset without ever influencing whether the change
|
could either be set or unset without ever influencing whether the change
|
||||||
could be submitted.
|
could be submitted.
|
||||||
@@ -176,10 +178,11 @@ Here some examples of possible return values from the `submit_rule` predicate:
|
|||||||
<2> label `'Verified'` is rejected. Change is not submittable.
|
<2> label `'Verified'` is rejected. Change is not submittable.
|
||||||
<3> label `'Author-is-John-Doe'` is needed for the change to become submittable.
|
<3> label `'Author-is-John-Doe'` is needed for the change to become submittable.
|
||||||
Note that this tells nothing about how this criteria will be met. It is up
|
Note that this tells nothing about how this criteria will be met. It is up
|
||||||
to the implementer of the `submit_rule` to return `label('Author-is-John-Doe',
|
to the implementer of the `submit_rule` to return
|
||||||
ok(_))` when this criteria is met. Most likely, it will have to match
|
`label('Author-is-John-Doe', ok(_))` when this criteria is met. Most
|
||||||
against `gerrit:commit_author` in order to check if this criteria is met.
|
likely, it will have to match against `gerrit:commit_author` in order to
|
||||||
This will become clear through the examples below.
|
check if this criteria is met. This will become clear through the examples
|
||||||
|
below.
|
||||||
|
|
||||||
Of course, when implementing the `submit_rule` we will use the facts about the
|
Of course, when implementing the `submit_rule` we will use the facts about the
|
||||||
change that are already provided by Gerrit.
|
change that are already provided by Gerrit.
|
||||||
@@ -190,9 +193,9 @@ screen for voting. If the return result contains label `'ABC'` and if the label
|
|||||||
`'ABC'` is link:config-labels.html[defined for the project] then voting for the
|
`'ABC'` is link:config-labels.html[defined for the project] then voting for the
|
||||||
label `'ABC'` will be displayed. Otherwise, it is not displayed. Note that the
|
label `'ABC'` will be displayed. Otherwise, it is not displayed. Note that the
|
||||||
project doesn't need a defined label for each label contained in the result of
|
project doesn't need a defined label for each label contained in the result of
|
||||||
`submit_rule` predicate. For example, the decision whether `'Author-is-John-Doe'`
|
`submit_rule` predicate. For example, the decision whether
|
||||||
label is met will probably not be made by explicit voting but, instead, by
|
`'Author-is-John-Doe'` label is met will probably not be made by explicit voting
|
||||||
inspecting the facts about the change.
|
but, instead, by inspecting the facts about the change.
|
||||||
|
|
||||||
[[SubmitFilter]]
|
[[SubmitFilter]]
|
||||||
== Submit Filter
|
== Submit Filter
|
||||||
@@ -202,7 +205,7 @@ in the `rules.pl` file of the current project, the `submit_filter` will be
|
|||||||
searched for in the `rules.pl` of all parent projects of the current project,
|
searched for in the `rules.pl` of all parent projects of the current project,
|
||||||
but not in the `rules.pl` of the current project. The search will start from the
|
but not in the `rules.pl` of the current project. The search will start from the
|
||||||
immediate parent of the current project, then in the parent project of that
|
immediate parent of the current project, then in the parent project of that
|
||||||
project and so on until, and including, the 'All-Projects' project.
|
project and so on until, and including, the `'All-Projects'` project.
|
||||||
|
|
||||||
The purpose of the submit filter is, as its name says, to filter the results
|
The purpose of the submit filter is, as its name says, to filter the results
|
||||||
of the `submit_rule`. Therefore, the `submit_filter` predicate has two
|
of the `submit_rule`. Therefore, the `submit_filter` predicate has two
|
||||||
@@ -290,14 +293,15 @@ the result.
|
|||||||
|
|
||||||
[[TestingSubmitRules]]
|
[[TestingSubmitRules]]
|
||||||
== Testing submit rules
|
== Testing submit rules
|
||||||
The prolog environment running the `submit_rule` is loaded with state describing the
|
The prolog environment running the `submit_rule` is loaded with state describing
|
||||||
change that is being evaluated. The easiest way to load this state is to test your
|
the change that is being evaluated. The easiest way to load this state is to
|
||||||
`submit_rule` against a real change on a running gerrit instance. The command
|
test your `submit_rule` against a real change on a running gerrit instance. The
|
||||||
link:cmd-test-submit-rule.html[test-submit rule] loads a specific change and executes
|
command link:cmd-test-submit-rule.html[test-submit rule] loads a specific change
|
||||||
the `submit_rule`. It optionally reads the rule from from `stdin` to facilitate easy testing.
|
and executes the `submit_rule`. It optionally reads the rule from from `stdin`
|
||||||
|
to facilitate easy testing.
|
||||||
|
|
||||||
====
|
====
|
||||||
cat rules.pl | ssh gerrit_srv gerrit test-submit rule I45e080b105a50a625cc8e1fb5b357c0bfabe6d68 -s
|
$ cat rules.pl | ssh gerrit_srv gerrit test-submit rule I45e080b105a50a625cc8e1fb5b357c0bfabe6d68 -s
|
||||||
====
|
====
|
||||||
|
|
||||||
== Prolog vs Gerrit plugin for project specific submit rules
|
== Prolog vs Gerrit plugin for project specific submit rules
|
||||||
@@ -318,9 +322,9 @@ From version 2.6 Gerrit plugins can contribute Prolog predicates. This way, we
|
|||||||
can make use of the plugin provided predicates when writing Prolog based rules.
|
can make use of the plugin provided predicates when writing Prolog based rules.
|
||||||
|
|
||||||
== Examples - Submit Rule
|
== Examples - Submit Rule
|
||||||
The following examples should serve as a cookbook for developing own submit rules.
|
The following examples should serve as a cookbook for developing own submit
|
||||||
Some of them are too trivial to be used in production and their only purpose is
|
rules. Some of them are too trivial to be used in production and their only
|
||||||
to provide step by step introduction and understanding.
|
purpose is to provide step by step introduction and understanding.
|
||||||
|
|
||||||
Some of the examples will implement the `submit_rule` and some will implement
|
Some of the examples will implement the `submit_rule` and some will implement
|
||||||
the `submit_filter` just to show both possibilities. Remember that
|
the `submit_filter` just to show both possibilities. Remember that
|
||||||
@@ -329,49 +333,49 @@ invoked from all parent projects. This is the most important fact in deciding
|
|||||||
whether to implement `submit_rule` or `submit_filter`.
|
whether to implement `submit_rule` or `submit_filter`.
|
||||||
|
|
||||||
=== Example 1: Make every change submittable
|
=== Example 1: Make every change submittable
|
||||||
Let's start with a most trivial example where we would make every change submittable
|
Let's start with a most trivial example where we would make every change
|
||||||
regardless of the votes it has:
|
submittable regardless of the votes it has:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(W)) :-
|
submit_rule(submit(W)) :-
|
||||||
W = label('Any-Label-Name', ok(_)).
|
W = label('Any-Label-Name', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
In this case we make no use of facts about the change. We don't need it as we are simply
|
In this case we make no use of facts about the change. We don't need it as we
|
||||||
making every change submittable. Note that, in this case, the Gerrit UI will not show
|
are simply making every change submittable. Note that, in this case, the Gerrit
|
||||||
the UI for voting for the standard `'Code-Review'` and `'Verified'` categories as labels
|
UI will not show the UI for voting for the standard `'Code-Review'` and
|
||||||
with these names are not part of the return result. The `'Any-Label-Name'` could really
|
`'Verified'` categories as labels with these names are not part of the return
|
||||||
be any string.
|
result. The `'Any-Label-Name'` could really be any string.
|
||||||
|
|
||||||
=== Example 2: Every change submittable and voting in the standard categories possible
|
=== Example 2: Every change submittable and voting in the standard categories possible
|
||||||
This is continuation of the previous example where, in addition, to making
|
This is continuation of the previous example where, in addition, to making
|
||||||
every change submittable we want to enable voting in the standard
|
every change submittable we want to enable voting in the standard
|
||||||
`'Code-Review'` and `'Verified'` categories.
|
`'Code-Review'` and `'Verified'` categories.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(CR, V)) :-
|
submit_rule(submit(CR, V)) :-
|
||||||
CR = label('Code-Review', ok(_)),
|
CR = label('Code-Review', ok(_)),
|
||||||
V = label('Verified', ok(_)).
|
V = label('Verified', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
Since for every change all label statuses are `'ok'` every change will be submittable.
|
Since for every change all label statuses are `'ok'` every change will be
|
||||||
Voting in the standard labels will be shown in the UI as the standard label names are
|
submittable. Voting in the standard labels will be shown in the UI as the
|
||||||
included in the return result.
|
standard label names are included in the return result.
|
||||||
|
|
||||||
=== Example 3: Nothing is submittable
|
=== Example 3: Nothing is submittable
|
||||||
This example shows how to make all changes non-submittable regardless of the
|
This example shows how to make all changes non-submittable regardless of the
|
||||||
votes they have.
|
votes they have.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(R)) :-
|
submit_rule(submit(R)) :-
|
||||||
R = label('Any-Label-Name', reject(_)).
|
R = label('Any-Label-Name', reject(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
Since for any change we return only one label with status `reject`, no change
|
Since for any change we return only one label with status `reject`, no change
|
||||||
will be submittable. The UI will, however, not indicate what is needed for a
|
will be submittable. The UI will, however, not indicate what is needed for a
|
||||||
@@ -381,9 +385,9 @@ change to become submittable as we return no labels with status `need`.
|
|||||||
In this example no change is submittable but here we show how to present 'Need
|
In this example no change is submittable but here we show how to present 'Need
|
||||||
<label>' information to the user in the UI.
|
<label>' information to the user in the UI.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
% In the UI this will show: Need Any-Label-Name
|
% In the UI this will show: Need Any-Label-Name
|
||||||
submit_rule(submit(N)) :-
|
submit_rule(submit(N)) :-
|
||||||
N = label('Any-Label-Name', need(_)).
|
N = label('Any-Label-Name', need(_)).
|
||||||
@@ -396,52 +400,51 @@ In this example no change is submittable but here we show how to present 'Need
|
|||||||
submit_rule(submit(NX, NY)) :-
|
submit_rule(submit(NX, NY)) :-
|
||||||
NX = label('X-Label-Name', need(_)),
|
NX = label('X-Label-Name', need(_)),
|
||||||
NY = label('Y-Label-Name', need(_)).
|
NY = label('Y-Label-Name', need(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
In the UI this will show:
|
In the UI this will show:
|
||||||
****
|
|
||||||
* Need Any-Label-Name
|
* `Need Any-Label-Name`
|
||||||
* Need Another-Label-Name
|
* `Need Another-Label-Name`
|
||||||
* Need X-Label-Name
|
* `Need X-Label-Name`
|
||||||
* Need Y-Label-Name
|
* `Need Y-Label-Name`
|
||||||
****
|
|
||||||
|
|
||||||
From the example above we can see a few more things:
|
From the example above we can see a few more things:
|
||||||
|
|
||||||
* comment in Prolog starts with the `%` character
|
* comment in Prolog starts with the `%` character
|
||||||
* there could be multiple `submit_rule` predicates. Since Prolog, by default, tries to find
|
* there could be multiple `submit_rule` predicates. Since Prolog, by default,
|
||||||
all solutions for a query, the result will be union of all solutions.
|
tries to find all solutions for a query, the result will be union of all
|
||||||
Therefore, we see all 4 `need` labels in the UI.
|
solutions. Therefore, we see all 4 `need` labels in the UI.
|
||||||
|
|
||||||
=== Example 5: The 'Need ...' labels not shown when change is submittable
|
=== Example 5: The 'Need ...' labels not shown when change is submittable
|
||||||
This example shows that, when there is a solution for `submit_rule(X)` where all labels
|
This example shows that, when there is a solution for `submit_rule(X)` where all
|
||||||
have status `ok` then Gerrit will not show any labels with the `need` status from
|
labels have status `ok` then Gerrit will not show any labels with the `need`
|
||||||
any of the previous `submit_rule(X)` solutions.
|
status from any of the previous `submit_rule(X)` solutions.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(N)) :-
|
submit_rule(submit(N)) :-
|
||||||
N = label('Some-Condition', need(_)).
|
N = label('Some-Condition', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(OK)) :-
|
submit_rule(submit(OK)) :-
|
||||||
OK = label('Another-Condition', ok(_)).
|
OK = label('Another-Condition', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
The 'Need Some-Condition' will not be shown in the UI because of the result of
|
The `'Need Some-Condition'` will not be shown in the UI because of the result of
|
||||||
the second rule.
|
the second rule.
|
||||||
|
|
||||||
The same is valid if the two rules are swapped:
|
The same is valid if the two rules are swapped:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(OK)) :-
|
submit_rule(submit(OK)) :-
|
||||||
OK = label('Another-Condition', ok(_)).
|
OK = label('Another-Condition', ok(_)).
|
||||||
|
|
||||||
submit_rule(submit(N)) :-
|
submit_rule(submit(N)) :-
|
||||||
N = label('Some-Condition', need(_)).
|
N = label('Some-Condition', need(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
The result of the first rule will stop search for any further solutions.
|
The result of the first rule will stop search for any further solutions.
|
||||||
|
|
||||||
@@ -449,81 +452,80 @@ The result of the first rule will stop search for any further solutions.
|
|||||||
This is the first example where we will use the Prolog facts about a change that
|
This is the first example where we will use the Prolog facts about a change that
|
||||||
are automatically exposed by Gerrit. Our goal is to make any change submittable
|
are automatically exposed by Gerrit. Our goal is to make any change submittable
|
||||||
when the commit author is named `'John Doe'`. In the very first
|
when the commit author is named `'John Doe'`. In the very first
|
||||||
step let's make sure Gerrit UI shows 'Need Author-is-John-Doe' in
|
step let's make sure Gerrit UI shows `'Need Author-is-John-Doe'` in
|
||||||
the UI to clearly indicate to the user what is needed for a change to become
|
the UI to clearly indicate to the user what is needed for a change to become
|
||||||
submittable:
|
submittable:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
Author = label('Author-is-John-Doe', need(_)).
|
Author = label('Author-is-John-Doe', need(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
This will show:
|
This will show:
|
||||||
****
|
|
||||||
* Need Author-is-John-Doe
|
* `Need Author-is-John-Doe`
|
||||||
****
|
|
||||||
|
|
||||||
in the UI but no change will be submittable yet. Let's add another rule:
|
in the UI but no change will be submittable yet. Let's add another rule:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
Author = label('Author-is-John-Doe', need(_)).
|
Author = label('Author-is-John-Doe', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
gerrit:commit_author(_, 'John Doe', _),
|
gerrit:commit_author(_, 'John Doe', _),
|
||||||
Author = label('Author-is-John-Doe', ok(_)).
|
Author = label('Author-is-John-Doe', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
In the second rule we return `ok` status for the `'Author-is-John-Doe'` label
|
In the second rule we return `ok` status for the `'Author-is-John-Doe'` label
|
||||||
if there is a `commit_author` fact where the full name is `'John Doe'`. If
|
if there is a `commit_author` fact where the full name is `'John Doe'`. If
|
||||||
author of a change is `'John Doe'` then the second rule will return a solution
|
author of a change is `'John Doe'` then the second rule will return a solution
|
||||||
where all labels have `ok` status and the change will become submittable. If
|
where all labels have `ok` status and the change will become submittable. If
|
||||||
author of a change is not `'John Doe'` then only the first rule will produce a
|
author of a change is not `'John Doe'` then only the first rule will produce a
|
||||||
solution. The UI will show 'Need Author-is-John-Doe' but, as expected, the
|
solution. The UI will show `'Need Author-is-John-Doe'` but, as expected, the
|
||||||
change will not be submittable.
|
change will not be submittable.
|
||||||
|
|
||||||
Instead of checking by full name we could also check by the email address:
|
Instead of checking by full name we could also check by the email address:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
Author = label('Author-is-John-Doe', need(_)).
|
Author = label('Author-is-John-Doe', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
gerrit:commit_author(_, _, 'john.doe@example.com'),
|
gerrit:commit_author(_, _, 'john.doe@example.com'),
|
||||||
Author = label('Author-is-John-Doe', ok(_)).
|
Author = label('Author-is-John-Doe', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
or by user id (assuming it is 1000000):
|
or by user id (assuming it is `1000000`):
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
Author = label('Author-is-John-Doe', need(_)).
|
Author = label('Author-is-John-Doe', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
gerrit:commit_author(user(1000000), _, _),
|
gerrit:commit_author(user(1000000), _, _),
|
||||||
Author = label('Author-is-John-Doe', ok(_)).
|
Author = label('Author-is-John-Doe', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
or by a combination of these 3 attributes:
|
or by a combination of these 3 attributes:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
Author = label('Author-is-John-Doe', need(_)).
|
Author = label('Author-is-John-Doe', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(Author)) :-
|
submit_rule(submit(Author)) :-
|
||||||
gerrit:commit_author(_, 'John Doe', 'john.doe@example.com'),
|
gerrit:commit_author(_, 'John Doe', 'john.doe@example.com'),
|
||||||
Author = label('Author-is-John-Doe', ok(_)).
|
Author = label('Author-is-John-Doe', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 7: Make change submittable if commit message starts with "Fix "
|
=== Example 7: Make change submittable if commit message starts with "Fix "
|
||||||
Besides showing how to make use of the commit message text the purpose of this
|
Besides showing how to make use of the commit message text the purpose of this
|
||||||
@@ -540,9 +542,9 @@ options:
|
|||||||
|
|
||||||
Let's implement both options:
|
Let's implement both options:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Fix)) :-
|
submit_rule(submit(Fix)) :-
|
||||||
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
||||||
|
|
||||||
@@ -552,7 +554,7 @@ Let's implement both options:
|
|||||||
|
|
||||||
starts_with(L, []).
|
starts_with(L, []).
|
||||||
starts_with([H|T1], [H|T2]) :- starts_with(T1, T2).
|
starts_with([H|T1], [H|T2]) :- starts_with(T1, T2).
|
||||||
====
|
----
|
||||||
|
|
||||||
NOTE: The `name/2` embedded predicate is used to convert a string symbol into a
|
NOTE: The `name/2` embedded predicate is used to convert a string symbol into a
|
||||||
list of characters. A string `abc` is converted into a list of characters `[97,
|
list of characters. A string `abc` is converted into a list of characters `[97,
|
||||||
@@ -564,23 +566,24 @@ The `starts_with` predicate is self explaining.
|
|||||||
|
|
||||||
Using the `gerrit:commit_message_matches` predicate is probably more efficient:
|
Using the `gerrit:commit_message_matches` predicate is probably more efficient:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(Fix)) :-
|
submit_rule(submit(Fix)) :-
|
||||||
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
||||||
|
|
||||||
submit_rule(submit(Fix)) :-
|
submit_rule(submit(Fix)) :-
|
||||||
gerrit:commit_message_matches('^Fix '),
|
gerrit:commit_message_matches('^Fix '),
|
||||||
Fix = label('Commit-Message-starts-with-Fix', ok(_)).
|
Fix = label('Commit-Message-starts-with-Fix', ok(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
The previous example could also be written so that it first checks if the commit
|
The previous example could also be written so that it first checks if the commit
|
||||||
message starts with 'Fix '. If true then it sets OK for that category and stops
|
message starts with 'Fix '. If true then it sets OK for that category and stops
|
||||||
further backtracking by using the cut `!` operator:
|
further backtracking by using the cut `!` operator:
|
||||||
.rules.pl
|
|
||||||
[caption=""]
|
`rules.pl`
|
||||||
====
|
[source,prolog]
|
||||||
|
----
|
||||||
submit_rule(submit(Fix)) :-
|
submit_rule(submit(Fix)) :-
|
||||||
gerrit:commit_message_matches('^Fix '),
|
gerrit:commit_message_matches('^Fix '),
|
||||||
Fix = label('Commit-Message-starts-with-Fix', ok(_)),
|
Fix = label('Commit-Message-starts-with-Fix', ok(_)),
|
||||||
@@ -589,7 +592,7 @@ further backtracking by using the cut `!` operator:
|
|||||||
% Message does not start with 'Fix ' so Fix is needed to submit
|
% Message does not start with 'Fix ' so Fix is needed to submit
|
||||||
submit_rule(submit(Fix)) :-
|
submit_rule(submit(Fix)) :-
|
||||||
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
Fix = label('Commit-Message-starts-with-Fix', need(_)).
|
||||||
====
|
----
|
||||||
|
|
||||||
== The default submit policy
|
== The default submit policy
|
||||||
All examples until now concentrate on one particular aspect of change data.
|
All examples until now concentrate on one particular aspect of change data.
|
||||||
@@ -606,13 +609,13 @@ done in one of the following ways:
|
|||||||
The default submit rule with the two default categories, `Code-Review` and
|
The default submit rule with the two default categories, `Code-Review` and
|
||||||
`Verified`, can be implemented as:
|
`Verified`, can be implemented as:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(V, CR)) :-
|
submit_rule(submit(V, CR)) :-
|
||||||
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
||||||
gerrit:max_with_block(-1, 1, 'Verified', V).
|
gerrit:max_with_block(-1, 1, 'Verified', V).
|
||||||
====
|
----
|
||||||
|
|
||||||
Once this implementation is understood it can be customized to implement
|
Once this implementation is understood it can be customized to implement
|
||||||
project specific submit rules. Note, that this implementation hardcodes
|
project specific submit rules. Note, that this implementation hardcodes
|
||||||
@@ -625,25 +628,27 @@ understand.
|
|||||||
=== Reusing the default submit policy
|
=== Reusing the default submit policy
|
||||||
To get results of Gerrit's default submit policy we use the
|
To get results of Gerrit's default submit policy we use the
|
||||||
`gerrit:default_submit` predicate. The `gerrit:default_submit(X)` includes all
|
`gerrit:default_submit` predicate. The `gerrit:default_submit(X)` includes all
|
||||||
categories from the database. This means that if we write a submit rule like:
|
categories from the database. This means that if we write a submit rule like
|
||||||
|
this:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(X) :- gerrit:default_submit(X).
|
submit_rule(X) :- gerrit:default_submit(X).
|
||||||
====
|
----
|
||||||
then this is equivalent to not using `rules.pl` at all. We just delegate to
|
|
||||||
|
it is equivalent to not using `rules.pl` at all. We just delegate to
|
||||||
default logic. However, once we invoke the `gerrit:default_submit(X)` we can
|
default logic. However, once we invoke the `gerrit:default_submit(X)` we can
|
||||||
perform further actions on the return result `X` and apply our specific
|
perform further actions on the return result `X` and apply our specific
|
||||||
logic. The following pattern illustrates this technique:
|
logic. The following pattern illustrates this technique:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(S) :- gerrit:default_submit(R), project_specific_policy(R, S).
|
submit_rule(S) :- gerrit:default_submit(R), project_specific_policy(R, S).
|
||||||
|
|
||||||
project_specific_policy(R, S) :- ...
|
project_specific_policy(R, S) :- ...
|
||||||
====
|
----
|
||||||
|
|
||||||
In the following examples both styles will be shown.
|
In the following examples both styles will be shown.
|
||||||
|
|
||||||
@@ -659,9 +664,9 @@ submit policy and then add the `Non-Author-Code-Review` label to it. The
|
|||||||
`Non-Author-Code-Review` label is added with status `ok` if such an approval
|
`Non-Author-Code-Review` label is added with status `ok` if such an approval
|
||||||
exists or with status `need` if it doesn't exist.
|
exists or with status `need` if it doesn't exist.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(S) :-
|
submit_rule(S) :-
|
||||||
gerrit:default_submit(X),
|
gerrit:default_submit(X),
|
||||||
X =.. [submit | Ls],
|
X =.. [submit | Ls],
|
||||||
@@ -674,11 +679,11 @@ exists or with status `need` if it doesn't exist.
|
|||||||
R \= A, !,
|
R \= A, !,
|
||||||
S2 = [label('Non-Author-Code-Review', ok(R)) | S1].
|
S2 = [label('Non-Author-Code-Review', ok(R)) | S1].
|
||||||
add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]).
|
add_non_author_approval(S1, [label('Non-Author-Code-Review', need(_)) | S1]).
|
||||||
====
|
----
|
||||||
|
|
||||||
This example uses the `univ` operator `=..` to "unpack" the result of the
|
This example uses the `univ` operator `=..` to "unpack" the result of the
|
||||||
default_submit, which is a structure of the form `submit(label('Code-Review',
|
default_submit, which is a structure of the form `submit(label('Code-Review',
|
||||||
ok(_)), label('Verified', need(_)) ...)` into a list like `[submit,
|
ok(_)), label('Verified', need(_)), ...)` into a list like `[submit,
|
||||||
label('Code-Review', ok(_)), label('Verified', need(_)), ...]`. Then we
|
label('Code-Review', ok(_)), label('Verified', need(_)), ...]`. Then we
|
||||||
process the tail of the list (the list of labels) as a Prolog list, which is
|
process the tail of the list (the list of labels) as a Prolog list, which is
|
||||||
much easier than processing a structure. In the end we use the same `univ`
|
much easier than processing a structure. In the end we use the same `univ`
|
||||||
@@ -697,9 +702,9 @@ predicate before the `cut` fails.
|
|||||||
Let's implement the same submit rule the other way, without reusing the
|
Let's implement the same submit rule the other way, without reusing the
|
||||||
`gerrit:default_submit`:
|
`gerrit:default_submit`:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(CR, V)) :-
|
submit_rule(submit(CR, V)) :-
|
||||||
base(CR, V),
|
base(CR, V),
|
||||||
CR = label(_, ok(Reviewer)),
|
CR = label(_, ok(Reviewer)),
|
||||||
@@ -714,7 +719,7 @@ Let's implement the same submit rule the other way, without reusing the
|
|||||||
base(CR, V) :-
|
base(CR, V) :-
|
||||||
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
||||||
gerrit:max_with_block(-1, 1, 'Verified', V).
|
gerrit:max_with_block(-1, 1, 'Verified', V).
|
||||||
====
|
----
|
||||||
|
|
||||||
The latter implementation is probably easier to understand and the code looks
|
The latter implementation is probably easier to understand and the code looks
|
||||||
cleaner. Note, however, that the latter implementation will always return the
|
cleaner. Note, however, that the latter implementation will always return the
|
||||||
@@ -730,28 +735,27 @@ invokes the `gerrit:default_submit` and then modifies its result.
|
|||||||
Which of these two behaviors is desired will always depend on how a particular
|
Which of these two behaviors is desired will always depend on how a particular
|
||||||
Gerrit server is managed.
|
Gerrit server is managed.
|
||||||
|
|
||||||
Example 9: Remove the `Verified` category
|
==== Example 9: Remove the `Verified` category
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
A project has no build and test. It consists of only text files and needs only
|
A project has no build and test. It consists of only text files and needs only
|
||||||
code review. We want to remove the `Verified` category from this project so
|
code review. We want to remove the `Verified` category from this project so
|
||||||
that `Code-Review+2` is the only criteria for a change to become submittable.
|
that `Code-Review+2` is the only criteria for a change to become submittable.
|
||||||
We also want the UI to not show the `Verified` category in the table with
|
We also want the UI to not show the `Verified` category in the table with
|
||||||
votes and on the voting screen.
|
votes and on the voting screen.
|
||||||
|
|
||||||
This is quite simple without reusing the 'gerrit:default_submit`:
|
This is quite simple without reusing the `gerrit:default_submit`:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(CR)) :-
|
submit_rule(submit(CR)) :-
|
||||||
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
|
gerrit:max_with_block(-2, 2, 'Code-Review', CR).
|
||||||
====
|
----
|
||||||
|
|
||||||
Implementing the same rule by reusing `gerrit:default_submit` is a bit more complex:
|
Implementing the same rule by reusing `gerrit:default_submit` is a bit more complex:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(S) :-
|
submit_rule(S) :-
|
||||||
gerrit:default_submit(X),
|
gerrit:default_submit(X),
|
||||||
X =.. [submit | Ls],
|
X =.. [submit | Ls],
|
||||||
@@ -761,22 +765,22 @@ Implementing the same rule by reusing `gerrit:default_submit` is a bit more comp
|
|||||||
remove_verified_category([], []).
|
remove_verified_category([], []).
|
||||||
remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
|
remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
|
||||||
remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
|
remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 10: Combine examples 8 and 9
|
=== Example 10: Combine examples 8 and 9
|
||||||
In this example we want to both remove the verified and have the four eyes
|
In this example we want to both remove the verified and have the four eyes
|
||||||
principle. This means we want a combination of examples 7 and 8.
|
principle. This means we want a combination of examples 7 and 8.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(S) :-
|
submit_rule(S) :-
|
||||||
gerrit:default_submit(X),
|
gerrit:default_submit(X),
|
||||||
X =.. [submit | Ls],
|
X =.. [submit | Ls],
|
||||||
remove_verified_category(Ls, R1),
|
remove_verified_category(Ls, R1),
|
||||||
add_non_author_approval(R1, R),
|
add_non_author_approval(R1, R),
|
||||||
S =.. [submit | R].
|
S =.. [submit | R].
|
||||||
====
|
----
|
||||||
|
|
||||||
The `remove_verified_category` and `add_non_author_approval` predicates are the
|
The `remove_verified_category` and `add_non_author_approval` predicates are the
|
||||||
same as defined in the previous two examples.
|
same as defined in the previous two examples.
|
||||||
@@ -784,9 +788,9 @@ same as defined in the previous two examples.
|
|||||||
Without reusing the `gerrit:default_submit` the same example may be implemented
|
Without reusing the `gerrit:default_submit` the same example may be implemented
|
||||||
as:
|
as:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(CR)) :-
|
submit_rule(submit(CR)) :-
|
||||||
base(CR),
|
base(CR),
|
||||||
CR = label(_, ok(Reviewer)),
|
CR = label(_, ok(Reviewer)),
|
||||||
@@ -800,7 +804,7 @@ as:
|
|||||||
|
|
||||||
base(CR) :-
|
base(CR) :-
|
||||||
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
gerrit:max_with_block(-2, 2, 'Code-Review', CR),
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 11: Remove the `Verified` category from all projects
|
=== Example 11: Remove the `Verified` category from all projects
|
||||||
Example 9, implements `submit_rule` that removes the `Verified` category from
|
Example 9, implements `submit_rule` that removes the `Verified` category from
|
||||||
@@ -808,27 +812,27 @@ one project. In this example we do the same but we want to remove the `Verified`
|
|||||||
category from all projects. This means we have to implement `submit_filter` and
|
category from all projects. This means we have to implement `submit_filter` and
|
||||||
we have to do that in the `rules.pl` of the `All-Projects` project.
|
we have to do that in the `rules.pl` of the `All-Projects` project.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_filter(In, Out) :-
|
submit_filter(In, Out) :-
|
||||||
In =.. [submit | Ls],
|
In =.. [submit | Ls],
|
||||||
remove_verified_category(Ls, R),
|
remove_verified_category(Ls, R),
|
||||||
Out =.. [submit | R].
|
Out =.. [submit | R].
|
||||||
|
|
||||||
remove_verified_category([], []).
|
remove_verified_category([], []).
|
||||||
remove_verified_category([label('Verified', _) | T], R) :-
|
remove_verified_category([label('Verified', _) | T], R) :- remove_verified_category(T, R), !.
|
||||||
remove_verified_category(T, R), !.
|
|
||||||
remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
|
remove_verified_category([H|T], [H|R]) :- remove_verified_category(T, R).
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 12: On release branches require DrNo in addition to project rules
|
=== Example 12: On release branches require DrNo in addition to project rules
|
||||||
A new category 'DrNo' is added to the database and is required for release
|
A new category 'DrNo' is added to the database and is required for release
|
||||||
branches. To mark a branch as a release branch we use `drno('refs/heads/branch')`.
|
branches. To mark a branch as a release branch we use
|
||||||
|
`drno('refs/heads/branch')`.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
drno('refs/heads/master').
|
drno('refs/heads/master').
|
||||||
drno('refs/heads/stable-2.3').
|
drno('refs/heads/stable-2.3').
|
||||||
drno('refs/heads/stable-2.4').
|
drno('refs/heads/stable-2.4').
|
||||||
@@ -844,23 +848,25 @@ branches. To mark a branch as a release branch we use `drno('refs/heads/branch')
|
|||||||
Out =.. [submit, DrNo | I].
|
Out =.. [submit, DrNo | I].
|
||||||
|
|
||||||
submit_filter(In, Out) :- In = Out.
|
submit_filter(In, Out) :- In = Out.
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 13: 1+1=2 Code-Review
|
=== Example 13: 1+1=2 Code-Review
|
||||||
In this example we introduce accumulative voting to determine if a change is
|
In this example we introduce accumulative voting to determine if a change is
|
||||||
submittable or not. We modify the standard Code-Review to be accumulative, and make the
|
submittable or not. We modify the standard `Code-Review` to be accumulative, and
|
||||||
change submittable if the total score is 2 or higher.
|
make the change submittable if the total score is `2` or higher.
|
||||||
|
|
||||||
The code in this example is very similar to Example 8, with the addition of findall/3
|
The code in this example is very similar to Example 8, with the addition of
|
||||||
and gerrit:remove_label.
|
`findall/3` and `gerrit:remove_label`.
|
||||||
The findall/3 embedded predicate is used to form a list of all objects that satisfy a
|
|
||||||
specified Goal. In this example it is used to get a list of all the 'Code-Review' scores.
|
|
||||||
gerrit:remove_label is a built-in helper that is implemented similarly to the
|
|
||||||
'remove_verified_category' as seen in the previous example.
|
|
||||||
|
|
||||||
.rules.pl
|
The `findall/3` embedded predicate is used to form a list of all objects that
|
||||||
[caption=""]
|
satisfy a specified Goal. In this example it is used to get a list of all the
|
||||||
====
|
`Code-Review` scores. `gerrit:remove_label` is a built-in helper that is
|
||||||
|
implemented similarly to the `remove_verified_category` as seen in the previous
|
||||||
|
example.
|
||||||
|
|
||||||
|
`rules.pl`
|
||||||
|
[source,prolog]
|
||||||
|
----
|
||||||
sum_list([], 0).
|
sum_list([], 0).
|
||||||
sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp.
|
sum_list([H | Rest], Sum) :- sum_list(Rest,Tmp), Sum is H + Tmp.
|
||||||
|
|
||||||
@@ -879,13 +885,13 @@ gerrit:remove_label is a built-in helper that is implemented similarly to the
|
|||||||
gerrit:remove_label(Ls,label('Code-Review',_),NoCR),
|
gerrit:remove_label(Ls,label('Code-Review',_),NoCR),
|
||||||
add_category_min_score(NoCR,'Code-Review', 2, Labels),
|
add_category_min_score(NoCR,'Code-Review', 2, Labels),
|
||||||
S =.. [submit | Labels].
|
S =.. [submit | Labels].
|
||||||
====
|
----
|
||||||
|
|
||||||
Implementing the same example without using `gerrit:default_submit`:
|
Implementing the same example without using `gerrit:default_submit`:
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(submit(CR, V)) :-
|
submit_rule(submit(CR, V)) :-
|
||||||
sum(2, 'Code-Review', CR),
|
sum(2, 'Code-Review', CR),
|
||||||
gerrit:max_with_block(-1, 1, 'Verified', V).
|
gerrit:max_with_block(-1, 1, 'Verified', V).
|
||||||
@@ -906,21 +912,21 @@ Implementing the same example without using `gerrit:default_submit`:
|
|||||||
sum_list(List, Sum) :- sum_list(List, 0, Sum).
|
sum_list(List, Sum) :- sum_list(List, 0, Sum).
|
||||||
sum_list([X|T], Y, S) :- Z is X + Y, sum_list(T, Z, S).
|
sum_list([X|T], Y, S) :- Z is X + Y, sum_list(T, Z, S).
|
||||||
sum_list([], S, S).
|
sum_list([], S, S).
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 14: Master and apprentice
|
=== Example 14: Master and apprentice
|
||||||
The master and apprentice example allow you to specify a user (the `master`)
|
The master and apprentice example allow you to specify a user (the `master`)
|
||||||
that must approve all changes done by another user (the `apprentice`).
|
that must approve all changes done by another user (the `apprentice`).
|
||||||
|
|
||||||
The code first checks if the commit author is in the apprentice database.
|
The code first checks if the commit author is in the apprentice database.
|
||||||
If the commit is done by an apprentice, it will check if there is a +2
|
If the commit is done by an `apprentice`, it will check if there is a `+2`
|
||||||
review by the associated `master`.
|
review by the associated `master`.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
% master_apprentice(Master, Apprentice).
|
% master_apprentice(Master, Apprentice).
|
||||||
% Extend this with appropriate user-id's for your master/apprentice setup.
|
% Extend this with appropriate user-id for your master/apprentice setup.
|
||||||
master_apprentice(user(1000064), user(1000000)).
|
master_apprentice(user(1000064), user(1000000)).
|
||||||
|
|
||||||
submit_rule(S) :-
|
submit_rule(S) :-
|
||||||
@@ -942,17 +948,17 @@ review by the associated `master`.
|
|||||||
check_master_approval(S1, S2, Master).
|
check_master_approval(S1, S2, Master).
|
||||||
|
|
||||||
add_apprentice_master(S, S).
|
add_apprentice_master(S, S).
|
||||||
====
|
----
|
||||||
|
|
||||||
=== Example 15: Only allow Author to submit change
|
=== Example 15: Only allow Author to submit change
|
||||||
This example adds a new needed category `Patchset-Author` for any user that is
|
This example adds a new needed category `Only-Author-Can-Submit` for any user
|
||||||
not the author of the patch. This effectively blocks all users except the author
|
that is not the author of the patch. This effectively blocks all users except
|
||||||
from submitting the change. This could result in an impossible situation if the
|
the author from submitting the change. This could result in an impossible
|
||||||
author does not have permissions for submitting the change.
|
situation if the author does not have permissions for submitting the change.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_rule(S) :-
|
submit_rule(S) :-
|
||||||
gerrit:default_submit(In),
|
gerrit:default_submit(In),
|
||||||
In =.. [submit | Ls],
|
In =.. [submit | Ls],
|
||||||
@@ -964,8 +970,8 @@ author does not have permissions for submitting the change.
|
|||||||
gerrit:current_user(Id),
|
gerrit:current_user(Id),
|
||||||
!.
|
!.
|
||||||
|
|
||||||
only_allow_author_to_submit(S1, [label('Patchset-Author', need(_)) | S1]).
|
only_allow_author_to_submit(S1, [label('Only-Author-Can-Submit', need(_)) | S1]).
|
||||||
====
|
----
|
||||||
|
|
||||||
== Examples - Submit Type
|
== Examples - Submit Type
|
||||||
The following examples show how to implement own submit type rules.
|
The following examples show how to implement own submit type rules.
|
||||||
@@ -975,48 +981,47 @@ This example sets the `Cherry Pick` submit type for all changes. It overrides
|
|||||||
whatever is set as project default submit type.
|
whatever is set as project default submit type.
|
||||||
|
|
||||||
rules.pl
|
rules.pl
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_type(cherry_pick).
|
submit_type(cherry_pick).
|
||||||
====
|
----
|
||||||
|
|
||||||
|
|
||||||
[[SubmitTypePerBranch]]
|
[[SubmitTypePerBranch]]
|
||||||
=== Example 2: `Fast Forward Only` for all `refs/heads/stable*` branches
|
=== Example 2: `Fast Forward Only` for all `refs/heads/stable*` branches
|
||||||
For all `refs/heads/stable.*` branches we would like to enforce the `Fast
|
For all `refs/heads/stable*` branches we would like to enforce the `Fast
|
||||||
Forward Only` submit type. A reason for this decision may be a need to never
|
Forward Only` submit type. A reason for this decision may be a need to never
|
||||||
break the build in the stable branches. For all other branches, those not
|
break the build in the stable branches. For all other branches, those not
|
||||||
matching the `refs/heads/stable.*` pattern, we would like to use the project's
|
matching the `refs/heads/stable*` pattern, we would like to use the project's
|
||||||
default submit type as defined on the project settings page.
|
default submit type as defined on the project settings page.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_type(fast_forward_only) :-
|
submit_type(fast_forward_only) :-
|
||||||
gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B),
|
gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B),
|
||||||
!.
|
!.
|
||||||
submit_type(T) :- gerrit:project_default_submit_type(T)
|
submit_type(T) :- gerrit:project_default_submit_type(T)
|
||||||
====
|
----
|
||||||
|
|
||||||
The first `submit_type` predicate defines the `Fast Forward Only` submit type
|
The first `submit_type` predicate defines the `Fast Forward Only` submit type
|
||||||
for `refs/heads/stable.*` branches. The second `submit_type` predicate returns
|
for `refs/heads/stable.*` branches. The second `submit_type` predicate returns
|
||||||
the project's default submit type.
|
the project's default submit type.
|
||||||
|
|
||||||
=== Example 3: Don't require `Fast Forward Only` if only documentation was changed
|
=== Example 3: Don't require `Fast Forward Only` if only documentation was changed
|
||||||
Like in the previous example we want the `Fast Forward Only` submit type for
|
Like in the previous example we want the `Fast Forward Only` submit type for the
|
||||||
the `refs/heads/stable*` branches. However, if only documentation was changed
|
`refs/heads/stable*` branches. However, if only documentation was changed
|
||||||
(only `*.txt` files), then we allow project's default submit type for such
|
(only `*.txt` files), then we allow project's default submit type for such
|
||||||
changes.
|
changes.
|
||||||
|
|
||||||
.rules.pl
|
`rules.pl`
|
||||||
[caption=""]
|
[source,prolog]
|
||||||
====
|
----
|
||||||
submit_type(fast_forward_only) :-
|
submit_type(fast_forward_only) :-
|
||||||
gerrit:commit_delta('(?<!\.txt)$'),
|
gerrit:commit_delta('(?<!\.txt)$'),
|
||||||
gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B),
|
gerrit:change_branch(B), regex_matches('refs/heads/stable.*', B),
|
||||||
!.
|
!.
|
||||||
submit_type(T) :- gerrit:project_default_submit_type(T)
|
submit_type(T) :- gerrit:project_default_submit_type(T)
|
||||||
====
|
----
|
||||||
|
|
||||||
The `gerrit:commit_delta('(?<!\.txt)$')` succeeds if the change contains a file
|
The `gerrit:commit_delta('(?<!\.txt)$')` succeeds if the change contains a file
|
||||||
whose name doesn't end with `.txt` The rest of this rule is same like in the
|
whose name doesn't end with `.txt` The rest of this rule is same like in the
|
||||||
|
Reference in New Issue
Block a user