CI should build the future merge result of a merge request
Summary
CI builds should happen on the resulting merge commit of a merge request, not on the head of the merge request.
Overview
Currently, when you create a merge request, a hidden ref is created with the name refs/merge-requests/<number>/head
:
$ git graph --all
* 3704a55 - (6 minutes ago) Call feature3 from main - Jonathon Reinhart (refs/merge-requests/2/head, feature3)
* ff388af - (7 minutes ago) Add feature.[ch] and add to build. - Jonathon Reinhart
* 3439681 - (5 months ago) Move artifacts to right location - Jonathon Reinhart (HEAD -> master, tag: v0.0.3)
This "merge request head" is the commit that is built by GitLab CI, and that build result is what is shown in the merge request.
The problem: This isn't really Continuous Integration per se, as we haven't yet integrated anything.
GitHub approach
GitHub does something similar, and stores their pull request head at refs/pull/<number>/head
. But, they take this one step further, and actually store another ref to the would-be result of the merge at refs/pull/<number>/merge
:
$ git graph --all
* 59b8038 - (3 minutes ago) Merge 3704a5525f244c001c877e00b1966a0bdb5063b9 into 343968161ada14f77ff12b2ecacd9ef226e086e6 - Jonathon Reinhart (refs/pull/1/merge)
|\
| * 3704a55 - (21 minutes ago) Call feature3 from main - Jonathon Reinhart (refs/pull/1/head, feature3)
| * ff388af - (22 minutes ago) Add feature.[ch] and add to build. - Jonathon Reinhart
|/
* 3439681 - (5 months ago) Move artifacts to right location - Jonathon Reinhart (HEAD -> master)
Here, 59b8038
is the commit whose tree matches what will happen if you click the "Merge pull request" button in GitHub.
Here's the magical part: Travis will perform a build on this commit and it is the result of this build that gives the red/green light on the PR.
Now let's say we update master
(committing changes to it, or accepting other PRs). GitHub will re-attempt the merge and update refs/pull/<number>/head
:
* 6c49f34 - (20 seconds ago) Merge 3704a5525f244c001c877e00b1966a0bdb5063b9 into e8fa3b194ca4018a9993ff4510ec5a9e4ddd8a29 - Jonathon Reinhart (refs/pull/1/merge)
|\
| * 3704a55 - (38 minutes ago) Call feature3 from main - Jonathon Reinhart (refs/pull/1/head, feature3)
| * ff388af - (39 minutes ago) Add feature.[ch] and add to build. - Jonathon Reinhart
* | e8fa3b1 - (39 seconds ago) Pointless change to README - Jonathon Reinhart (HEAD -> master)
|/
* 3439681 - (5 months ago) Move artifacts to right location - Jonathon Reinhart
Note that 6c49f34
has replaced 59b8038
as refs/pull/1/merge
.
What GitHub doesn't do, is re-trigger Travis to build on this updated merge due to an updated upstream target.
Solution
GitLab has the "accept merge request" button, which means it has already tested the merge-ability of the MR head. It should simply store the result of this merge at refs/merge-requests/<number>/head
.
Then, a build should be triggered for refs/merge-requests/<number>/head
, and this build should be the red-light/green-light indicator shown on the MR page.
Going Further
GitLab CI should go the final step and trigger a build every time that a branch is re-merged because of an updated upstream target (see above).
Implementing this will make GitLab CI superior to GitHub + Travis by having a true Continuous Integration suite.