Gitlab is a huge DevOps platform that allows us to build any kind of application, regardless of complexity. But we also need to build our application according to some rules. In this article, we will talk about the gitlab ci rules. Those conditions on Gitlab define if the pipeline will be a trigger or not, according to the conditions specified on the CI/CD configuration file.
GitLab CI Rules Basics
Before we start, let’s see the basic operations that we can do with variables to build our rules.
We can use the equality operators like == and != to compare a variable value with a given string. Here, single quotes and double quotes can be applied. The variable can be first, or the string can be first; the order doesn’t matter.
- if: $VAR == “some value”
- if: $VAR != “some value”
- if: “some value” == $VAR
- Another especial cases:
- if: $VAR == null # check if the $VAR is undefined
- if: $VARIABLE # check if the $VAR exists
Gitlab CI Rules Regex Variable
Expressions result as true if:
- If the content is found when using =~.
- Matches are not found when using !~.
- $VAR =~ /^string.*/
- $VAR1 !~ /^string.*/
By default, the regex is case-sensitive. However, we can use the i flag modifier to evaluate the regex using case-insensitive.
For instance: /content/i.
How to determine when a Job run
Gitlab offers different approaches to define when a job runs. The default behavior is if we don’t specify one rule or condition, all jobs from one pipeline will be triggered.
We can determine jobs to run based on the value of the pipeline variables.
To set a job to be included or excluded from particular pipelines, we can use the following:
Use needs to set a job to start as soon as the before jobs it relies on finish running.
Also, we will see the when keyword that we can use to specify if a job will run manually or not.
Gitlab CI Rules
So, we can use rules to run or skip jobs in pipelines.
Gitlab CI Rules are interpreted in order until the first condition is true. In other words, when a condition is satisfied, the job is either started or skipped from the pipeline, relying on the configuration.
Gitlab CI Rules Multiple IF, example:
job: script: python script.py rules: - if: '$CI_COMMIT_REF_NAME == "branch_name"' when: manual allow_failure: true - if: '$CI_COMMIT_REF_NAME == "another_branch"'
Let me explain the process described above:
If the pipeline belongs to the “branch_name,” the first rule is valid. So the job is added to the pipeline, and the attribute:
- when: manual (This is a manual Job, so we need to trigger manually after the pipeline is created).
- allow_failure: true (the pipeline will continue even if the manual job is not running)
So, If the pipeline is not from the “branch_name”, it means that the first rule doesn’t match, and the second rule will be evaluated. Here, if the pipeline belongs to the “another_branch,” the job will be triggered. We didn’t specify any attribute for this rule, so the default attributes will be used in place:
- when: on_success (as the default value)
- allow_failure: false (as the default value)
In scenarios where no rules match, the job is not triggered or added to the pipeline.
In the example above, we use predefined variables from Gitlab. But we can use our own variables or any other predefined variables. Also, we can add more Gitlab CI Rules sequentially.
Also, still talking about the previous example, we can quickly invert the logic by changing the when from manual to never, so we will not add the job to the pipeline if the branch name matches “branch_name.”
Gitlab CI Manual Pipeline
It’s worth highlighting the importance of manual keywords. We know that Gitlab is not only about building applications. We can also perform the deployment of those applications regardless of complexity and Cloud Provider.
For example, our previous article discusses how to build a pipeline to execute a terraform script.
In pipelines to deploy applications, it’s crucial to set up the pipeline to be triggered manually because we don’t want to deploy our application to production if we commit one file every time. After all, maybe we are preparing the script, and we are not ready to do it.
Gitlab CI Complex Pipeline
You can utilize all rules keywords in the same rule, like changes and exists. The rule is interpreted as true only when all used keywords are true.
Gitlab CI Rules Changes
variables: MODE: BUILD build: script: mvn package -U rules: - if: '$MODE == "BUILD"' changes: # Add the job and set to when:manual if any of the paths bellow match with the modified files. - src/main/java/* - src/scripts/* when: manual
In this example above, we are building one java application using Maven.
If any file in src/main/java and in src/script has changed and $MODE == “BUILD,” then the job runs manually.
Gitlab CI if File Exists
Another good feature is triggering a job only if a specific file exists.
variable: VERSION: v1 job: script: docker build -t app:$VERSION . rules: - exists: - Dockerfile
The job runs if a Dockerfile exists anywhere in the project in the example above. The exists keyword is an array of file paths, so we can specify more files to be checked. Important: The paths are relative to the repository directory ($CI_PROJECT_DIR) and can’t directly link outside it.
Gitlab CI Rules OR
A new feature was added to Gitlab 13.3, where we can create complex expressions with OR or AND logic using several variables in the same expression. Of course, we must use parentheses with || (OR) and && (AND) to accomplish that.
compile: script: - make && make install rules: if: ($CI_COMMIT_BRANCH == "release" || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH) && $ANOTHER_VARIABLE
Gitlab CI Rules Except
Sometimes, we only focus on a scenario where we don’t want to execute a job. And to define a rule to skip a job, we can use except keyword.
lint: script: - lint src/ except: variables: - $CI_PIPELINE_SOURCE == api
In the example above, we are skipping the job (lint) when the commit was triggered using an API call.
Gitlab has a vast collection of predefined variables that we can use in our pipeline. in our example above, we used the $CI_PIPELINE_SOURCE, where Gitlab automatically populates its value for us, according to with source from where the pipeline was triggered.
The possible values of CI_PIPELINE_SOURCE:
API, chat, external, external_pull_request_event, merge_request_event, parent_pipeline, pipeline, push, schedule, trigger, web, webide.
Gitlab CI Rules If Merge Request
To detect if a pipeline was triggered by a Merge Request, we can either use $CI_PIPELINE_SOURCE == “merge_request_event” or, like the example:
build: script: docker build -t app:v2 . only: refs: - merge_requests changes: - Dockerfile - scripts/**/*
In the example above, combine the keywords only: [merge_requests]. Besides checking if it’s a merge request, we also look at whether some specific files were changed to effectively trigger the job.