GitLab CI: only trigger only merge request & specific branch - gitlab-ci

I realised that gitlab CI does not seem to allow multiple refs. It will only take the first.
E.g., for the instructions below, the merge_requests will be ignored, and will trigger whenever the develop branch is updated directly.
face-build:
stage: build
image: docker:19.03.8
services:
- docker:19.03.8-dind
script:
- sh some-scripts.sh
only:
refs:
- /^develop$/
- merge_requests
If I swap the merge_requests to be before /^develop$/ it will be triggered for all merge requests.
Is there anyway to set both to be valid?

If you are using GitLab 12.3 or later, try rules:if clause instead of only:
face-build:
stage: build
image: docker:19.03.8
services:
- docker:19.03.8-dind
script:
- sh some-scripts.sh
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ /^develop$/'
when: always
Please check Rules attributes so you can choose the most appropriat value for when (on_success, always, delayed or never).

Related

Gitlab CI conditionally override a template variable based on which files were changes in a MR

I have template that looks like this:
/templates/.copy-echo.yml:
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "master"'
variables:
FILE_PATH: /test_conf_1.txt
DESTINATION_HOST: somehost
stages:
- copy
- echo
copy step 1/2:
rules:
- changes:
- ${FILE_PATH}
stage: copy
script: |
echo "Add copy here!"
copy step 2/2:
rules:
- changes:
- ${FILE_PATH}
stage: echo
script: |
printenv
echo ${DESTINATION_HOST}
Now in my .gitlab-ci.yml:
include: '/templates/copy-echo.yml'
variables:
FILE_PATH: /test_conf_1.txt
DESTINATION_HOST: somehost2
Now what I want is conditionally assign a value to DESTINATION_HOST variable depending on which file got changed in merged request.
For e.g. if the merge request had updates to file test_conf_2.txt then the value for DESTINATION_HOST should be somehost2 and if the merge request had updates to file test_conf_3.txt then the value for DESTINATION_HOST should be somehost3.
Is it possible to achieve this?
You can use rules:variables: https://docs.gitlab.com/ee/ci/yaml/#rulesvariables
Example:
my job:
script: printenv
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- test_conf_2.txt
variables:
DESTINATION_HOST: "somehost2"
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
changes:
- test_conf_3.txt
variables:
DESTINATION_HOST: "somehost3"
But it doesn't work if you launch pipeline manually:
You should use rules: changes only with branch pipelines or merge
request pipelines. You can use rules: changes with other pipeline
types, but rules: changes always evaluates to true when there is no
Git push event. Tag pipelines, scheduled pipelines, manual pipelines,
and so on do not have a Git push event associated with them. A rules:
changes job is always added to those pipelines if there is no if that
limits the job to branch or merge request pipelines.

Gitlab CI job running on new tag despite rules say run only on master

I have a job in a pipeline as such:
msi_build:
stage: Build
script:
- cd project_name
- ls -a
- wine python setup.py bdist_msi
rules:
- if: '$CI_COMMIT_REF_NAME == $BUILD_BRANCH'
- changes:
- /*.{py, html, css, yml, json}
tags:
- pywine
artifacts:
when: on_success
paths:
- /builds/$CI_PROJECT_PATH/project_name/dist/*.msi
expire_in: 1 yrs
But this also runs when I tag a commit and push it in another branch.
BUILD_BRANCH is master. This won't run when only pushing normal commits to other branches. And it'll run when pushing to master. But for some reason unknown to me, it also runs on tagged commits. What is the cause?
If it matters I used: git push --atomic origin <branch name> <tag> when pushing to another branch.
rules:
- if: '$CI_COMMIT_REF_NAME == $BUILD_BRANCH'
- changes:
- /*.{py, html, css, yml, json}
is not
rules:
- if: '$CI_COMMIT_REF_NAME == $BUILD_BRANCH'
changes:
- /*.{py, html, css, yml, json}
The first one runs when $CI_COMMIT_REF_NAME == $BUILD_BRANCH OR when the files were changed. The second one runs the job when that and that is equal AND the files with extensions were changed. Most probably in the commit the tag is run for the files with those extensions were changed, so the command is run, ignoring the first condition, because it's "or".
It's a good idea to add when: on_success to rules: explicitly, so it's nicely visible.

How to prevent jobs from running when pushing tags and when branch is a specific one with rules

I'm a bit confused with the Gitlab I syntax.
I have some jobs that I don't want to trigger when I simply push tags like
git tag -a 1.0.0 -m "Added version 1.0.0"
git push --tags
The following works correctly, as this job is not being triggered for above scenario
build:
stage: build
script:
- dotnet restore --no-cache --force
- dotnet build --configuration Release --no-restore
artifacts:
paths:
- test
expire_in: 8 hour
rules:
- if: $CI_COMMIT_TAG
when: never
- when: always
Now I also have jobs with a rule to run conditionally depending on whether the commit branch is stable (i.e: main) or not.
Like this one
package_beta:
stage: publish
variables:
PACKAGE_UNSTABLE_SUFFIX: beta
before_script:
- mkdir $PACKAGE_OUTPUT_DIR
script:
- dotnet pack *.sln --configuration Release --output $PACKAGE_OUTPUT_DIR --version-suffix $PACKAGE_UNSTABLE_SUFFIX --include-source --include-symbols
rules:
- if: $CI_COMMIT_BRANCH != "main"
artifacts:
paths:
- $PACKAGE_OUTPUT_DIR/
expire_in: 8 hour
The above also works well. The problem is when I want to have several conditions in rules, like: I want my job to run only when branch is not main AND ALSO when the push is not a tag commit. How to do that with rules?
Here is the problem.
This does not work. It will actually run the job even when the branch is main.
rules:
- if: $CI_COMMIT_BRANCH != "main"
- if: $CI_COMMIT_TAG
when: never
This does not work either
rules:
- if: $CI_COMMIT_BRANCH != "main"
- if: $CI_COMMIT_TAG
when: never
- when: always

How to create Gitlab CI rules that are evaluated as AND instead of OR

The following gitlab ci job will run if the variable $CI_COMMIT_TAG is set OR if the ./versions.txt file has changed.
some-job:
script:
- echo "Do some fancy stuff.";
rules:
- if: $CI_COMMIT_TAG
when: always
- changes:
- ./versions.txt
However, what I need is for this job to run when $CI_COMMIT_TAG is set AND ./versions.txt is changed. I don't want the job to run if only one of these evaluates to true. This was the behaviour in only/changes feature, but the only (and except)-feature is less powerful and deprecated.
Is what I want currently possible with gitlab ci?
From Docs:
In the following example:
We run the job manually if Dockerfile or any file in docker/scripts/ has changed AND $VAR == "string value". Otherwise, the job will not be included in the pipeline.
docker build:
script: docker build -t my-image:$CI_COMMIT_REF_SLUG .
rules:
- if: '$VAR == "string value"'
changes: # Will include the job and set to when:manual if any of the follow paths match a modified file.
- Dockerfile
- docker/scripts/*
when: manual
Your code will look something like this.
some-job:
script:
- echo "Do some fancy stuff.";
rules:
- if: $CI_COMMIT_TAG
changes:
- versions.txt
when: manual

How to have a gitlab CI job to be triggred only manual on branches and always automatically on master?

I have a pages job that I want to run manual on branches, but automatically triggered on master:
pages:
stage: deploy
cache:
paths:
- public
script:
- scripts/pages.sh
artifacts:
paths:
- public
expire_in: 2 days
So I want a combination of:
only:
- master
when: always
only:
- branches
except:
- master
when: manual
Is that possible?
This should be possible to do if you use GitLab CI rules. This is an example where the shell is powershell and it shows the current time and branch/tag name:
pages:
script:
- mkdir public
- date > public\index.html
- $CI_COMMIT_REF_NAME >> public\index.html
artifacts:
paths:
- public
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- if: '$CI_COMMIT_BRANCH == null'
when: never
- when: manual
GitLab matches each individual rule from top to bottom. If the branch is named 'master', the job gets marked with when: always. If the branch name is null, this is a tag, and the job is marked with never. If this is not a branch named master, nor a tag, this is a normal branch, and the job is marked with manual.
As Aleksey Tsalolikhin described, you can remove this rule:
- if: '$CI_COMMIT_BRANCH == null'
when: never
You will then get the option to run the pipeline for your tags as well, like this:
If this is what you want or not, that is up to you.
I've tweaked the answer by MrBerta -- the third command was missing the echo command.
I also changed the slashes from backslashes to regular forward slashes so I can use the Linux shell rather than Powershell.
It now works.
Here is the gitlab-ci.yml file -- with credit to MrBerta.
pages:
script:
- mkdir public
- date > public/index.html
- echo $CI_COMMIT_REF_NAME >> public/index.html
artifacts:
paths:
- public
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- if: '$CI_COMMIT_BRANCH == null'
when: never
- when: manual
I tried pushing to master, and my GitLab Pages content was updated as expected; and I tried pushing to a feature branch, and the manual "Play" button came up in the CI/CD pipeline UI.
When I pushed a tag (with detached head, i.e., not on any branch), I could not test it -- GitLab CI did not run a pipeline automatically, and when I tried to Run Pipeline, and picked my tag, GitLab threw an error: "The form contains the following error: No stages / jobs for this pipeline."
So, I would simplify this to:
pages:
script:
- mkdir public
- date > public/index.html
- echo $CI_COMMIT_REF_NAME >> public/index.html
artifacts:
paths:
- public
rules:
- if: '$CI_COMMIT_BRANCH == "master"'
when: always
- when: manual
This pages job runs manually on branches (and tags but I couldn't test it), but automatically triggered on master, as the original poster requested.
You will need to define two stages. you can either copy/paste or use anchors:
.deploy_stage: &deploy_stage
stage: deploy
cache:
paths:
- public
script:
- scripts/pages.sh
artifacts:
paths:
- public
expire_in: 2 days
deploy_manual:
<<: *deploy_stage
only:
- branches
when: manual
deploy_master:
<<: *deploy_stage
only:
- master