Merge request pipelines for forks
We recently introduced merge request pipelines, but these do not work with forks. This issue exists to add that support.
Note: this should be done with https://gitlab.com/gitlab-org/gitlab-ce/issues/55013. This issue should be reviewed to ensure it is not duplicate.
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.
By the time we get to this feature, we will have implemented major parts of this functionality already via https://gitlab.com/gitlab-org/gitlab-ce/issues/15310 and https://gitlab.com/gitlab-org/gitlab-ee/issues/7380. These will work as follows (https://gitlab.com/gitlab-org/gitlab-ce/issues/15310#forking-workflows):
We've left forking out of scope intentionally for now, but we will revisit once we have other MR workflows working and can revisit the more complex permissions model that would be required for supporting builds of forks.
When a user pushed a new change to an MR in a parent project, an MR pipeline will be created in the parent project
When a user pushed a new change to an MR in a forked project, an MR pipeline will be created in the forked project
This does not affect the current security-level that forked project cannot steal secret variables, specific runners, etc from the parent project.
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
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
test: script: echo Hello World only: - merge-requests
The above example would create a pipeline only on
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 appswith 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
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:
If administrator would configure runner to be used by
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
This is interesting, because then it actually allows to limit runners to be used only by
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
Allow to run merge requests from current project(default:
Allow to run merge requests from forks(default:
- 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
- We introduce
- We extend
Migrating Merge Requests
We would store in
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.