Pipelines for Merge Requests
This is description of proposal for implementing first-class support for Pipelines to be executed in context of Merge Requests with exact steps to do and expected behavior.
How it works now?
Currently when we do git push
we create a pipeline for a branch.
When we create a merge request we look for a pipelines created
for that branch in that source project.
The CI builds are always executed in context of source project (fork). The fork needs to have it's own runners that would be executing these builds.
How it would work?
We would always create a pipeline for a merge request in context of target project.
We would make these CI builds for merge request to be run using target project's runners.
We would limit the Secure Variables
exposed to CI builds for merge requests.
We would still allow to execute builds for branches and merge requests.
This behavior could be limited with only:
and except:
.
We would fire pipeline creation when:
- a new merge request is open,
- a merge request is updated.
We would leave that up to the user to limit when pipeline is executed.
Let's look at current way of running CI builds for merge request:
test:
script: echo Hello World
only:
- branches
The new way would require to use a special merge-requests
syntax:
test:
script: echo Hello World
only:
- merge-requests
The above example would create a pipeline only on merge-requests
.
The defaults for only:
would stay the same as today:
- Run on every tag,
- Run on every branch,
- Run for every merge-request (as it is now).
To limit a number of builds, ex. to make them to run only on merge-requests or on branches this syntax could be used:
test:
script: echo Hello World
only:
- master
- merge-requests
Why doing that?
This allows us to solve a number of problems:
- We run merge requests in context of parent project, making it possible to use a runners of this project.
- It allows us to show the pipelines that were created specifically for merge requests,
- It allows us to limit when we actually create a builds (specific branch, or only for merge-requests) (customer requested feature),
- It allows to create a highly optimised and secure runners infrastracture that would be used to run all community contributions (ex. GitLab contributions),
- It allows us later to introduce triggers that would be executed on merge request actions: creation, update, closing. Allowing us to extend
review apps
with being closed on merge request. - It allows us later to introduce tests on merge results. Thus allows to require testing against latest master. If the pipeline succeeds and it get merged we could introduce an optimisation to the process that we would not run the pipeline on master for that merge request.
- It allows us to show the merge request link in a number of places, like: list of pipelines, list of environments.
How builds on runners would be executed?
This changes the approach moving merge request builds execution from source to target project of merge request. This makes it a little more complicated and requires us to introduce a new option for runners configuration. The same option would be available for specifc
and shared
runners.
Option 1: Runner access-level
Make runner accessible by user level: every pipeline is executed by the user. We also do look at permissions of the user. This system makes it possible to make runner to be useable only by specific user-level in context of that project.
Lets assume that we have an option: User access level
(I don't really have a good idea about name for it yet).
This option can have access levels of the user: guest
, reporter
, developer
, master
.
If administrator would configure runner to be used by developer
.
Only developers (members of the project) could use this runners.
If developer does create a fork, but it's still developer member of the project
he could use that runner to create builds.
If user is not developer of the project, but this project is public and he creates a fork, from perspective of this project he is considered to be guest.
To make it possible to run merge request builds from forked projects the user would have to be guest
.
This is interesting, because then it actually allows to limit runners to be used only by masters
.
As an outcome of that change allowing to limit who can do deployments to target system
if we assume that only one of the specific runners is configured to access production servers.
Option 2: Explicit options
Since the Option 1 can not be very clear how it works there's also a different approach that is much simpler to understand.
We could introduce two options that would hide complexity of Option 1
:
-
Allow to run merge requests from current project
(default:true
), -
Allow to run merge requests from forks
(default:false
).
Final assumptions
- We create a new pipeline when a new merge request is opened,
- We create a new pipeline for every merge request that gets updated by push,
- We create a pipeline in context of parent project,
- We make runners to be aware that they are executing pipeline for merge request,
- We add an option to limit which runners can be used for merge requests: when source_project is the same as target, and when these are different,
- For now we don't pass Secure Variables to builds for merge requests,
- We add
CI_MERGE_REQUEST_IID
andCI_MERGE_REQUEST_TARGET_BRANCH
, - We introduce
merge-requests
toonly:
andexcept:
, - We extend
Ci::Pipeline
andDeployment
withmerge_request
relation
Migrating Merge Requests
We would store in Ci::Pipeline
and MergeRequest
information that a pipeline got created with
a new workflow requiring to use only: merge-requests
if only:
is specified.
We would leave the previous approach of finding merge_requests
for past pipelines
so they behavior would be backward compatible.
All new pipelines would require to use merge_requests
after doing system update.