GitLab CI/CD stage run only on main branch and tags matches pattern - gitlab

I want to run the release only on main branch and tag matches /^v\d+\.\d+\.\d+$/. I have below stage, If I tag non main branch this stage runs. how can I match both rules.
run-release:
stage: run-release
image: busybox
rules:
- if: ( $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/ && $CI_DEFAULT_BRANCH == "main" )
script:
- echo "Run release"
Thanks

Related

Simplify rules in GitLab CI/CD pipeline

I see this kind of syntax for rules:if and rules:when in GitLab CI/CD pipeline a lot:
job:
script: echo "This job does NOT create double pipelines!"
rules:
- if: $CI_PIPELINE_SOURCE == "push"
when: never
- when: always
Is that also equivalent to this?
job:
script: echo "This job does NOT create double pipelines!"
rules:
- if: $CI_PIPELINE_SOURCE != "push"
- when: always
rules mean that job is evaluated in order until the first match.
first rules
rules:
- if: $CI_PIPELINE_SOURCE == "push"
when: never
- when: always
are equivalent second rules
rules:
- if: $CI_PIPELINE_SOURCE != "push"
but, I recommend using the first rules, because it is easy to know and easy to read.
I have a test for their two rules. first, I set the IS_JOB_ON variable to off, that pipeline only test job 3 create, and second set IS_JOB_ON to on, three jobs are created.
first .gitlab-ci.yml and Pipeline
second .gitlab-ci.yml and Pipeline
sample:
variables:
IS_JOB_ON: 'off'
test job 1:
script:
- echo "run job 1"
rules:
- if: $IS_JOB_ON == "off"
when: never
- when: always
test job 2:
script:
- echo "run job 2"
rules:
- if: $IS_JOB_ON != "off"
test job 3:
script:
- echo "run job 3 always run"

Changes not triggering workflow and jobs based on defined condition

I have following workflow configurations:
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "master"'
changes:
- /*script.yaml
variables:
CI_COMMIT_TIMESTAMP: $CI_COMMIT_TIMESTAMP
ROOT_DIR: ${CI_PROJECT_DIR}
SCRIPT_PATH: /etc/executable/scripts/
A_REPOSITORY_SCRIPT_PATH: /folder/a/script.yaml
B_REPOSITORY_SCRIPT_PATH: /folder/b/script.yaml
stages:
- init
# A Workflow:
deploycheck a 1/6:
rules:
- changes:
- ${A_REPOSITORY_SCRIPT_PATH}
stage: init
script: |
[ -f "${SCRIPT_PATH}/script.yaml" ] && cp -v "${SCRIPT_PATH}/script.yaml" ${SCRIPT_PATH}/SCRIPT_yaml_$CI_COMMIT_TIMESTAMP.txt
# B Workflow:
deploycheck b 1/6:
rules:
- changes:
- ${B_REPOSITORY_SCRIPT_PATH}
stage: init
script: |
[ -f "${SCRIPT_PATH}/script.yaml" ] && cp -v "${SCRIPT_PATH}/script.yaml" ${SCRIPT_PATH}/SCRIPT_yaml_$CI_COMMIT_TIMESTAMP.txt
I want this workflow to trigger when a change is made to any script.yaml file anywhere inside the repository and pushed to master branch.
And once the workflow is triggers depending on the path and which script.yaml was changes respective jobs should run.
However, nothing happens with this and no matter which script.yaml I change this workflow never gets triggered.
What am I missing here?
Your glob pattern would only match the root directory.
To match in any directory, use "**/script.yaml"

Gitlab CI CD only run Pipeline Step when certain criteria is met

I am trying to configure my CI/CD pipeline so that a certain step is only executed if some conditions are met.
My current rule definition looks like this:
rules:
- if: '($CI_PIPELINE_SOURCE == "push" || $CI_PIPELINE_SOURCE == "web" || $CI_PIPELINE_SOURCE == "merge_request_event") && $CI_COMMIT_BRANCH == "develop" '
exists:
- $MY_FILE
What I want to achieve:
Execute step only if a merge from branch_x was done into develop
Or Execute step when pipeline triggered over the GitLab UI
Or Execute step if a commit is pushed directly to develop
And the file in $MY_FILE is present in the repository
Other than expected, the step gets not executed on
Push
Merge Branch_X into develop
Manually trigger over GitLab UI
The corresponding file exists within the repository.
The step work is if I change back to
only:
- develop
But then I can not set the condition that the file needs to be present.
Part of the issue you're running into is that some Predefined Variables only exist in certain types of pipelines. For example, the CI_COMMIT_TAG variable, which would hold the name of a tag, only exists if the pipeline is a "Tag pipeline" (ran after a tag is created). However, if a tag points to a commit that is the HEAD of a branch that is the Source of a Merge Request, it is still just a Tag pipeline, so none of the Merge Request specific variables will exist.
Due to this, your conditional will get slightly more complex since we'll need some more parenthesis, or more if clauses for our rules section:
rules:
- if: ($CI_PIPELINE_SOURCE == 'push' || $CI_PIPELINE_SOURCE == 'web') && $CI_COMMIT_REF_NAME == 'develop'
exists:
- $MY_FILE
when: always
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'develop'
exists:
- $MY_FILE
when: always
- when: never
Note: you could write this using only one if clause and just use more parenthesis.
Let's look at these changes one by one.
First, the push and web pipeline sources are more or less identical in terms of how the pipeline is ran, and which Predefined Variables are available.
Second, the variable $CI_COMMIT_BRANCH is only available in certain pipelines. Most noticeably, it only exists when there is a Branch. If the pipeline runs for a tag, the variable will not exist, it's not just empty. If it's a merge request event, the variable will not exist. $CI_COMMIT_REF_NAME is more reliable, even though it can have more values (Commit SHAs, Branch names, or Tag names).
Third, the merge_request_event source is a totally different animal compared to the other sources we're dealing with here. The Predefined Variables available are totally different since there are now two branches (the source and the target). Also, a merge_request_event pipeline can only ever run if you have rules in your pipeline definition for merge_request_event's.
I ran some tests with this rules scenario, with this pipeline definition:
stages:
- run
Run Job:
stage: run
image: alpine:latest
script:
- echo $CI_PIPELINE_SOURCE
- echo $CI_COMMIT_REF_NAME
- echo $CI_COMMIT_BRANCH
- echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
- echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
Second Run Job:
stage: run
image: alpine:latest
rules:
- if: ($CI_PIPELINE_SOURCE == 'push' || $CI_PIPELINE_SOURCE == 'web') && $CI_COMMIT_REF_NAME == 'develop'
exists:
- 'a_file'
when: always
- if: $CI_PIPELINE_SOURCE == 'merge_request_event' && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == 'new_branch'
exists:
- 'a_file'
when: always
- when: never
script:
- echo $CI_PIPELINE_SOURCE
- echo $CI_COMMIT_REF_NAME
- echo $CI_COMMIT_BRANCH
- echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
- echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
Here's the job output for a normal Push event to a branch other than develop:
Executing "step_script" stage of the job script
00:02
$ echo $CI_PIPELINE_SOURCE
push
$ echo $CI_COMMIT_REF_NAME
other_branch
$ echo $CI_COMMIT_BRANCH
other_branch
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
Note: only the first job runs since the branch isn't develop. If the branch is develop and a_file exists, both jobs run, and the output is identical.
Here's the output of a job with the 'web' source, to a branch other than develop:
Executing "step_script" stage of the job script
00:00
$ echo $CI_PIPELINE_SOURCE
web
$ echo $CI_COMMIT_REF_NAME
other_branch
$ echo $CI_COMMIT_BRANCH
other_branch
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
Again, in this case there is only one job in the pipeline. If instead we hit Run Pipeline for the develop branch and a_file exists, we run both jobs and the output is identical:
Executing "step_script" stage of the job script
00:00
$ echo $CI_PIPELINE_SOURCE
web
$ echo $CI_COMMIT_REF_NAME
develop
$ echo $CI_COMMIT_BRANCH
develop
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
Lastly, if we push to a branch that's the source of a merge request targeting develop with a_file in the repository, we get the merge_request_event, but only get the second job due to the way Merge Request Pipelines work:
Executing "step_script" stage of the job script
00:01
$ echo $CI_PIPELINE_SOURCE
merge_request_event
$ echo $CI_COMMIT_REF_NAME
some_other_branch
$ echo $CI_COMMIT_BRANCH
$ echo $CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
some_other_branch
$ echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME
new_branch
Here's the documentation for Merge Request Pipelines for more information.

How to run Gitlab CI only for specific branches and some rules?

I am trying to build ci according to the following criteria:
Run only when pushing to master branch - already implemented
Run on commit [run ci] - already implemented
Manual launch from the Run pipeline - already implemented
do not launch when pushing to the master branch when only Tag changes
do not start in other cases if they do not fall under the first 3 options
The tag may change without changes in other files and do not need to run the assembly, I tried this
if: $CI_COMMIT_BRANCH == "master" && $CI_COMMIT_TAG =~ /^$/
but it doesn't work if there are changes in both files and tags.
I will be glad to help
My .gitlab-ci.yml
image: busybox:latest
build1:
stage: build
rules:
- if: $CI_COMMIT_MESSAGE =~ /\[run ci\]/
- if: $CI_COMMIT_BRANCH == "master"
- when: manual
allow_failure: false
script:
- echo "Do your build here"
test1:
stage: test
rules:
- if: $CI_COMMIT_MESSAGE =~ /\[run ci\]/
- if: $CI_COMMIT_BRANCH == "master"
- allow_failure: false
script:
- echo "Do a test here"
- echo "For example run a test suite"
deploy:
stage: deploy
rules:
- if: $CI_COMMIT_MESSAGE =~ /\[run ci\]/
- if: $CI_COMMIT_BRANCH == "master"
- allow_failure: false
script:
- echo "Do a test here"
- echo "For example run a test suite"

Porting from `only/except`: How to run a gitlab-ci job only for tags excluding a pattern with `rules` in .gitlab-ci.yml?

I am trying to convert a .gitlab-ci.yml job from the deprecated only/except pattern to rules, specifically I want to run a job only if it's for a tag but not if that tag starts with config-.
Currently we use this, which at least works1.
build_image:
stage: build_image
only:
- tags
except:
- /^config-.*$/
I have tried the rules based approach as follows, but that runs for every tag, including config:
build_image:
stage: build_image
rules:
# only tags, except config
- if: $CI_COMMIT_TAG
when: on_success
- if: '$CI_COMMIT_TAG =~ /^config-.*$/'
when: never
- when: never
Additionally I tried to use negative lookahead regex - without success, since gitlab's ci linter screams jobs:build_image:rules:rule if invalid expression syntax.
build_image:
stage: build_image
rules:
# only tags, except config (using negative lookahead)
- if: '$CI_COMMIT_TAG =~ /^(?!config-).*$/'
when: on_success
- when: never
So how can I trigger a job only for tags excluding a pattern with the new rules based approach?
1: apart from not being able to be combined with other rules later on
You just have to combine the unlike operator !~ with the regular tag check $CI_COMMIT_TAG:
build_image:
stage: build_image
rules:
# only tags and only those not starting with config-
- if: '$CI_COMMIT_TAG && ($CI_COMMIT_TAG !~ /^config-.*$/ )'
when: on_success
- when: never
This rules worked for me (with Gitlab 13.12) :
rules:
- if: '$CI_COMMIT_TAG && $CI_COMMIT_TAG !~ /^config-.*$/'

Resources