Merge trains MVC (one at a time)
Problem to solve
https://gitlab.com/gitlab-org/gitlab-ee/issues/7380 introduces running a build on the result of the merged code prior to merging, as a way to keep master green. There's a scenario, however, for teams with a high number of changes in the target branch (typically master
) where in many or even all cases, by the time the merged code is validated another commit has made it to master, invalidating the merged result.
We need some kind of queuing, cancellation or retry mechanism for these scenarios in order to ensure an orderly flow of changes into the target branch.
See also: https://github.com/bors-ng/bors-ng
Target audience
Development teams
Proposal
For this MVC we will introduce merge trains that run sequentially only, which is an important step forward for this feature. A clear optimization would be to optimistically run these in parallel; this will be introduced in the follow up issue https://gitlab.com/gitlab-org/gitlab-ee/issues/11222. Depending on your usage pattern, this MVC iteration may not be usable because it would result in unacceptable queue lengths. However, if your pipelines run quickly or rate of pushes is relatively low, this MVC can be a good solution.
Until we have more strategies, however, one at a time is not sufficiently workable for enough cases that this feature can be on by default. The plan is eventually to make this the case, though.
Hybrid Merge Train
Adapted from @sytses / https://gitlab.com/gitlab-org/gitlab-ce/issues/4176#note_36341526
This is an approach that forms a merge train, of which there can be only one per target branch. It behaves as follows:
Given there is no other merge request pipeline running targeting the target branch, and no merge train created to the target branch:
- If the pipeline to the target branch is green or red, the MR gets a button "Merge".
- If the pipeline to the target branch is still running, the MR gets a button "Merge when the pipeline succeeds".
Given there is one merge request pipeline running targeting the target branch, or a merge train already created to the target branch:
- If the pipeline to the target branch is green or red, the MR gets a button "Add to merge train".
- If the pipeline to the target branch is still running, the MR gets a button "Add to merge train when the pipeline succeeds"
We still allow a merge when the pipeline is red (failed) because there might be situations where you have to merge. For example, there is an error in the target branch that causes the failure, but you want to merge it because the actual fix is going to be done separately.
When the first MR clicks on "Merge", the pipeline and all jobs start running normally. When that pipeline is completed, the next pipeline in the merge train starts. https://gitlab.com/gitlab-org/gitlab-ee/issues/11222 will introduce an optimization (optimistic pipelines) to make this more efficient.
UX Proposal
User story | Acceptance criteria | Prototype |
---|---|---|
Merge train is not activated | We will show merge widget as normal (no changes) | N/A |
As a user, I want to activate/deactivate the Merge Trains functionality | In the project settings > General > an option to activate/deactivate Merge Trains should be added. Merge Trains should be linked to the Merge When Pipeline Succeed configuration. By activating the Merge Trains options, the merge requests should start following the Merge Trains strategy. - Depends on https://gitlab.com/gitlab-org/gitlab-ee/issues/10725 |
|
As a user, I want to start a merge train | Given there are no other merge request pipeline running targeting the target branch, and no previous merge train was created to the target branch: - User sees a Start merge train button dropdown. Clicking the button should display the options: Start merge train and Merge immediately - Clicking Start merge train should run a pipeline. A new log should be added to the Discussions tab of the merge request. - If the pipeline succeeds, the merge request will automatically be merged. The merge request will be placed in position 1 in the Merge train. - If the pipeline fails, nothing should be merged. |
|
As a user, I want to add my merge request to a merge train | - User sees a Add to merge train button dropdown. Clicking the button should display the options: Add to merge train and Merge immediately - Clicking Add to merge train should change the button to an in progress state. Once the action finishes, the pipeline runs with the merge train. - A new log should be added to the Discussions tab of the merge request. - The new pipeline won't start until the previous one finishes. If the pipeline succeeds, the merge request will automatically be merged. The merge request will be placed in position n in the Merge Train and a helper text is added under the pipeline block. - If the pipeline fails, the train will need to be rebuilt with the first non-failing item as the first. |
|
As a user, I want to start a merge train when the pipeline succeeds | Given there are no other merge request pipeline running targeting the target branch, and no merge train created to the target branch: - User sees a Start merge train when pipeline succeeds dropdown button. Clicking the button should display the options: Start merge train when pipeline succeeds and Merge immediately - Clicking Start merge train when pipeline succeeds should change the button to an in progress state. Once the action finishes, the pipeline will wait until it succeeds to run with the merge train. - A new log should be added to the Discussions tab of the merge request. - When the pipeline succeeds, the merge request for the merge train will run. If it succeeds the merge request will be automatically merged. The merge request will be placed in position n in the Merge Train and a helper text is added under the pipeline block. - If the pipeline fails, the train will need to be rebuilt with the first non-failing item as the first. |
|
As a user, I want add my merge request to a merge train when the pipeline succeeds | Given there is one/multiple merge request pipeline(s) running targeting the target branch, creating a merge train: - User sees a Add to merge train when pipeline succeeds button dropdown. Clicking the button should display the options: Add to merge train when pipeline succeeds and Merge immediately - Clicking Add to merge train when pipeline succeeds should change the button to an in progress state. Once the action finishes, the pipeline will wait until it succeeds to run with the merge train. - A new log should be added to the Discussions tab of the merge request. - When the pipeline succeeds, the merge request for the merge train will run. If it succeeds the merge request will be added to the merge train. The merge request will be placed in position n in the Merge Train and a helper text is added under the pipeline block. - If the pipeline fails, the next MR in line should take the place of the failed one. |
|
Fork merge request | - Warning Merge trains are enabled but will not initiate because this is a fork merge request - Warning merge button (Merge when pipeline succeeds will also be warning colored as we rely on a normal branch pipeline in those cases) |
|
System notes | - System notes should be added to the Discussion tab of a merge request. The notes should inform when a merge train is started / a merge request is added to a merge train. |
System notes
Scenario | Message |
---|---|
If no existing merge train exists: | *John Doe* @jdoe started a merge train |
If a merge train already exists: | *John Doe* @jdoe added this merge request to the merge train at index #{merge_train_index} |
When a user removes a merge request from a merge train: | *John Doe* @jdoe removed this merge request from the merge train |
When the pipeline of a merge request on the merge train fails: | This merge request has been removed from the merge train because #{failure_reason}` |
What does success look like, and how can we measure that?
TBD
Links / references
cc @joshlambert @nolith @darbyfrey