Jobs in GitLab CI/CD can be set to run “manually” using the following option:
when: manual, which looks something like this in the Pipeline view:
… requiring interaction from a user to proceed.
Note that all of the examples below are tested in the context of a Merge Request using the
only: merge_requests setting on all the jobs.
The status of the pipeline itself while waiting for manual intervention depends on a few things.
||Is it the last stage?||Pipeline status when waiting|
Here’s what Blocked looks like:
Here’s what Success looks like:
Impact on Merge Request
When a pipeline is Blocked, the associated Merge Request cannot be merged at all.
Note that the “Merge When Pipeline Succeeds” button shows when then pipeline is in Running state. There’s also a “Merge Immediately” option at this point.
And only in the Success state is the simple “Merge” button shown.
Requiring Pipeline Success
So what happens if we turn on the “Pipelines must succeed” option?
In this case, the “Merge When Pipeline Succeeds” button is shown, but with a key difference - there is no option to “Merge Immediately”.
Even if the manual job is in the last stage, the Merge Request cannot be merged until it passes.
Note that if you click the “Merge When Pipeline Succeeds” button, it still won’t merge until the manual job completes successfully.
The “Pipelines must succeed” button doesn’t seem to prevent merging and pushing manually at the command line.
±[master]>> git fetch remote: Enumerating objects: 7, done. remote: Counting objects: 100% (7/7), done. remote: Compressing objects: 100% (3/3), done. remote: Total 4 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (4/4), done. From gitlab.com:fpotter/examples/manual-jobs 242f1c0..a2cb417 2-do-thing-2 -> origin/2-do-thing-2 ±[master]>> git merge origin/2-do-thing-2 Updating 242f1c0..a2cb417 Fast-forward .gitlab-ci.yml | 6 ------ README.md | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) ±[A1][master]>> git push Total 0 (delta 0), reused 0 (delta 0) To gitlab.com:fpotter/examples/manual-jobs.git 242f1c0..a2cb417 master -> master
However, if I protect the master branch so that nobody can push to it:
±[A1][master]>> git push Total 0 (delta 0), reused 0 (delta 0) remote: GitLab: You are not allowed to push code to protected branches on this project. To gitlab.com:fpotter/examples/manual-jobs.git ! [remote rejected] master -> master (pre-receive hook declined) error: failed to push some refs to 'firstname.lastname@example.org:fpotter/examples/manual-jobs.git'
Skipping CI entirely
There is still a way that developers can bypass the pipeline! That’s by passing in the
[skip ci] commit message (or, presumably, by using the
ci.skip option from the Git command line).
The only ways to prevent CI skipping are to disable it at the instance level and use a push rule.
The final setup
We had a customer ask about setting up a CI pipeline that would not run on every commit, but had to be run on the last commit in the Merge Request before the MR could be merged. Here’s the example solution.
stages: - test-light - test-heavy test-light: script: - sleep 1 stage: test-light only: - merge_requests test-heavy: script: - sleep 1 stage: test-heavy when: manual allow_failure: false only: - merge_requests
Note that the following settings must be in place for this to work as expected:
- “Pipelines must succeed”
- A Push Rule to prevent
[ci skip](in any capitalization) in commit messages
- A Gitaly setting to prevent the
ci.skipoption from being handled
- “Pipelines must succeed” checkbox is ignored if CI is skipped
- “Merge When Pipeline Succeeds” is not an option while the pipeline is blocked
- The “Merge When Pipeline Succeeds” button has a dropdown indicator that does nothing when “Pipelines must succeed” is set