Gitlab CI/CD has multiple 'pipeline sources', and some of the Predefined Variables only exist for certain sources.
For example, if you simply push a new commit to the remote, the value of CI_PIPELINE_SOURCE
will be push
. For push
pipelines, many of the Predefined Variables will not exist, such as CI_COMMIT_TAG
, CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
, CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME
, etc.
However if you create a Git Tag either in the GitLab UI or from a git push --tags
command, it will create a Tag pipeline, and variables like CI_COMMIT_TAG
will exist, but CI_COMMIT_BRANCH
will not.
One variable that will always be present regardless what triggered the pipeline is CI_COMMIT_REF_NAME
. For Push sources where the commit is tied to a branch, this variable will hold the branch name. If the commit isn't tied to a branch (ie, there was once a branch for that commit but now it's been deleted) it will hold the full commit SHA. Or, if the pipeline is for a tag, it will hold the tag name.
For more information, read through the different Pipeline Sources (in the description of the CI_PIPELINE_SOURCE
variable) and the other variables in the docs linked above.
What I would do is move this check to the script
section so we can make it more complex for our benefit, and either immediately exit 0
so that the job doesn't run and it doesn't fail, or run the rest of the script.
Build and publish docker image:
stage: build
image: alpine:latest
script:
- if [ $CI_PIPELINE_SOURCE != 'push' ]; then exit 0 fi
- if [ $CI_COMMIT_REF_NAME != 'develop' && $CI_COMMIT_TAG == '' ]; then exit 0 fi
- if [ $CI_COMMIT_TAG != '' ]; then git branch --contains $CI_COMMIT_TAG | grep main; TAG_ON_MAIN=$? fi
- if [ $TAG_ON_MAIN -ne 0 ]; then exit 0 fi
- echo $TAG
- ...<other commands>
This is a bit confusing, so here it is line by line:
- If the
$CI_PIPELINE_SOURCE
variable isn't 'push', we exit 0
.
- If the
$CI_COMMIT_REF_NAME
(again, either a commit SHA, tag name, or branch name) isn't develop
and $CI_COMMIT_TAG
is empty, exit 0
- If
$CI_COMMIT_TAG
isn't empty, we run a command to see if the tag was based on main
, git branch --contains <tag_name>
. This will return all the branches this tag is a part of (which is, the branch it was created from, and all branches that exist after the tag was made). We then pass the results through grep
to look for main
. If main
is in the result list, the exit code is 0
which we can get with the special variable $?
(always returns the previous command's exit code). We then set this exit code to a variable to use in the next conditional.
- We check to see if the exit code of the
grep
from step 3.
is non-0 (that is, if main
is not in the list of branches <tag_name>
is part of), and we exit 0
.
After all of these, we can be sure that the Pipeline Source is push
, that either there is a tag and it's on the main
branch, or that there isn't a tag and the pipeline is for the develop
branch.