blob: d8fb41de790c705d435808e705373bd023230c2f [file] [log] [blame] [view]
---
title: "Design Doc - CI Reboot: Composable Submit Requirements - Solution"
permalink: design-docs/ci-reboot-composable-submit-requirements-solution.html
hide_sidebar: true
hide_navtoggle: true
toc: false
---
# Solution - Composable Submit Requirements
## <a id="objective"> Objective
Make clear to users why a change is not submittable and what can be done to make
it submittable. Make it easy for admins to configure what makes a change
submittable.
## <a id="background"> Background
In Gerrit, admins can write Prolog code to define what makes a change
submittable. Its hard for admins - most of whom have never used Prolog before -
to get this right. On repo-discuss as well as googlesource.com we are paying a
constant support cost to help users. In addition, the Prolog engine has led to
outages in the past that are hard to diagnose (e.g. when reaching the max.
reduction limit). The UX also leaves a lot to be desired.
In 2018, the SubmitRule interface was added as an alternative to Prolog, but the
adoption suffered from an important shortcoming: Since SubmitRules need to be
implemented as a plugin, the plugin implementor needs to control when a given
rule is active, e.g. through a config flag. This makes them inflexible.
## <a id="overview"> Overview
Allow composing Submit Predicates to Submit Requirements using a lightweight,
boolean query language that defines when a requirement is applicable and when
its blocking. Provide a bridge between Submit Requirements and some existing
Change Predicates to have more out-of-the-box rules. Migrate all existing
rules.pl files on Gerrit-on-Borg to use Submit Rules. Disable Prolog on
googlesource.com deployment.
## <a id="scope"> Scope
This document defines the high-level design of the new system, but is by no
means complete. Smaller-scale decisions will be made during the implementation.
This document is part of a wider effort around CI integration.
## <a id="requirements"> Requirements
This document is based on a collection of requirements that involved many
community members and was led by Ben Rohlfs.
## <a id="interface"> Interface and Data Model
With this project, we add a layer on top of the existing `SubmitRule`
interface.
The existing interface is renamed to `SubmitPredicate`. The new layer is called
`SubmitRequirement` and references `SubmitPredicate` in different queries.
Plugins can continue to contribute `SubmitPredicate`.
Submit Requirements (SRs) are independent of each other and all submit
requirements must either pass or declare they aren't applicable for a change to
be submittable. SRs have three queries that work in the same way as change
queries do. One that defines applicability and one that defines a blocking
condition. The queries are built of Submit Predicates or Change Index Predicates
that can be composed together using AND, OR and NOT.
Similar to existing change queries, we do not support nesting of predicates
(using the result of one predicate as input for another) or variables:
```
// Example of a supported query
label:Code-Review+1 AND owner:foo@example.com
// Example of a unsupported query (nesting of functions/operators)
label:(find_label(),+2) AND owner:foo@example.com
// Example of a unsupported query (variables)
var lbl = label:Code-Review+1;
label:lbl AND owner:foo@example.com
```
SubmitRequirements are defined as (proto representation chosen only for
illustrative purposes):
```
message SubmitRequirement {
string name = 1; // Name of the condition
string description = 2; // (Markdown, HTML?) Long-form description
string applicable_condition = 3; // Query, that if it evaluates to false
// will regard this requirement as irrelevant.
string fulfilled_condition = 4; // Query, that if it evaluates to false will
// make this requirement block submission.
string override_condition = 5; // Query, that if it evaluates to true will
// make this requirement not block submission
// and mark it as overridden.
bool can_override = 6 // If true, child projects can remove or modify
[default = true]; // this requirement.
}
```
This data model was validated against large, complex `rules.pl` setups on
googlesource.com including Android, Fuchsia and Chromium's current rules.
Submit requirements are inherited by default and can be overridden and
deactivated in child projects unless can_override is set to false. This is
the equivalent of `submit_rule/submit_filter` in Prolog. We use the same
inheritance model as for labels: A rule can only be overridden in full or
disabled in full, never in parts.
Example Submit Requirement:
|Name |API Review |
|---------------------|--------------------------------------------------------------------------------------------------------------------------------------|
|Description |This requirement ensures that changes that modify the API got an additional API review. API reviews are based on <url with guidelines>. Bot accounts are exempt from this requirement. Build cops can override this requirement by voting `Build-Cop-Override +1`.|
|Applicable Condition |`NOT commit_author:'service-account@google.com' AND commit_filepath_contains:'/api/.*'` |
|Fulfilled Condition |`label:API-Review,MAX_WITH_BLOCK` |
|Override Condition |`label:Build-Cop-Override,MAX_WITH_BLOCK` |
|Can Override |`false` |
## <a id="labels"> Labels
Labels will serve solely as state definition and votes as state. Thus labels by
themselves have no impact on the submittability of a change. We will migrate
existing label functions, branch, ignoreSelfApproval out of label definitions
into their own SubmitRequirements. What remains inside the label definition is
score-copy configuration, name and scores as well as permissions on who can vote
(kept separately). **SubmitRequirements will then be the sole authority of
submitability.**
A new label SubmitPredicate allows to write a SubmitRequirement referencing
label votes and existing functions.
```
// Using existing function
label:Code-Review,MAX_WITH_BLOCK
// Working directly with votes
label:Code-Review+2 AND NOT label:Code-Review-2
```
Through this predicate, Gerrit will also know the relation between labels and
Submit Requirements and can base UX decisions on that. For example: Show a vote
button next to the SubmitRequirement or highlight labels that are currently
blocking submission.
It will still be possible to have labels that serve only as markers (e.g.
CQ-Ready) and have no impact on submittabilty.
## <a id="auditability"> Persistence, Auditability and Caching
Submit requirements are persisted in NoteDb when a change gets merged to enable
after-the-fact audits. SubmitRequirements dont get re-evaluated for merged
changes, instead the state-upon-merge is presented.
SubmitRequirements will not be cached since the evaluation of the boolean
expressions is cheap. The evaluation of most predicates is cheap as well since
they are solely based on cached state of the change. Complex predicates - such
as Code Owners - have to define a caching strategy on their own, based on the
domain knowledge of the implementation.
We will continue to store the evaluation result of submit requirements in the
change index but switch from JSON to proto serialization to be in line with how
we serialize the Change entity and have a standard model for field deprecation.
## <a id="predicates"> Predicates and Evaluation
We will implement a bridge between change index predicates and submit predicates
that allows us to expose selected change index predicates as submit predicates.
This allows for a good set of base predicates. Well further implement any
remaining predicates from the Prolog implementation. Plugins can contribute
their own SubmitPredicates.
```
// Example of a plugin-provided predicate used together with a core predicate
pluginName:argument AND NOT label:Code-Review-2
```
The evaluation of Submit Requirements will use the existing Antlr integration
used for search queries to evaluate submit requirement queries.
Prolog allows admins to return a custom label that is used to communicate
extra information back to the user. An example for this is that the owners
plugin uses this string to inform the user about who can provide missing
owners approvals. We will retain this option either through the
SubmitPredicate interface or a separate interface.
## <a id="prolog"> Prolog Support
We will implement a prolog()” SubmitPredicate that can be used to call out to
the Prolog engine from a requirement. This predicate will be able to return an
additional field (“labels”) that we serve as labels alongside the actual
labels on the API. This preserves the current behavior and allows for an online
migration of each rule implemented in Prolog to a new Submit Requirement. We
will continue to support this behavior for the time being.
## <a id="submit-types"> Conditional Submit Type
The current Prolog implementation allows to define the SubmitType at runtime.
We will therefore implement a plugin endpoint to allow plugins to change the
submit type of a change. The two use cases (change in directory, branch or by
certain user) will be catered by a single plugin. This will also allow moving
the Prolog interpreter into a plugin.
## <a id="submittability-mergeability"> Submittability and Mergeability
Submittability is whether or not a change has all required approvals and meets
the bar for being submitted. Mergeability is whether or not a change is
mergeable without a conflict in git, irrespective of any approvals it might
need. While this distinction will remain, the UI will show Mergeability as an
additional submit requirement. Computing Mergeability is much slower than
evaluating submit requirements, which is why we keep these concepts separate and
augment them only on the change page.
## <a id="ui"> UI Support for project owners
Gerrit currently offers a poor experience for admins that want to write and test
their Prolog rules forcing them to write rules.pl locally and perform a Git push
and debug in production.
For composable submit requirements, we will offer a UI to write, test and save
submit requirements. The UI will allow for project owners to add SRs. Illegal
queries will be called out directly and the UI will offer to test the
modifications against existing changes to see if they would pass or fail on
these changes. Direct modification of the configs will still be possible and
Gerrit will ensure that SRs contain valid queries using validation listeners
that act upon push.
## <a id="migration"> Migration
There are three flavours that we have to migrate to the new world:
1) Projects that only use Labels and functions, no Prolog and no custom SubmitRules
Well implement a SchemaMigration to migrate existing label functions to
SubmitRequirements as an online migration. The migration will create one
submit requirement for each existing, blocking label. A cleanup will remove
Label functions.
2) Projects that use Prolog
Well implement a PrologPredicate as outlined above. The migration from (1)
will create a Prolog requirement for each project that has a rules.pl file
on the evaluation path. This allows for an online migration 1-by-1 of parts
of the Prolog rule to a dedicated SubmitRequirement.
Plugins that currently expose a custom prolog fact will need to expose a
custom submit predicate instead.
3) Projects that use custom SubmitRules by implementing the existing interface
There arent many implementations of SubmitRule as of now. Well change the
API of SubmitRules to SubmitPredicates. The new interface is very close to
the old. This requires implementers of SubmitRule to make only minimal
changes.
On the REST API and in the Gerrit UI, we will work only with the new entities.
The Prolog glue code will be contained in the backend and is narrow-scoped.
While we want to remove Prolog support from Gerrit-on-Borg, we will continue to
support the existing implementation in an open-source plugin, so that projects
that like Prolog aren't forced to move over.
## <a id="futurework"> Future Work
In a future iteration, we want to allow SubmitRequirements to expose actions
to the frontend. These turn into buttons for the user to work towards resolving
an unfulfilled requirement. For example: Users can invite reviewers who have
the permission to vote on a required label or code-owners whose approval is
missing.
## <a id="alternatives"> Alternatives Considered
* **Single query, no separation**: Instead of having individual submit rules
that are composed of predicates, we could just have a single query per project
composed of predicates that defines submittability. This would make it much
harder to show actionable results to the user or would complicate the query
evaluation to generate actionable output.
* **One query per requirement**: We could skip the
applicability_query/override_query and just have a single query that blocks if
it evaluates to false. However, we think it’s an important UX decision to make
that not all requirements apply to a given change. It also allows admins to
write simpler, more concise queries.
## <a id="commitment"> Project Plan and Commitment
The Gerrit@Google team will work on this in Q4/2020 and Q1/2021. The target
release is 3.4.