I would like to create a pipeline that is only run if both of the following conditions are met:
I've tried:
publish:
stage: publish
script:
- echo "Publish!"
rules:
# Only publish if tag given and commit is present on a protected branch
- if: '$CI_COMMIT_TAG && $CI_COMMIT_REF_PROTECTED == "true"'
Which does not work as either the $CI_COMMIT_TAG
is set or the $CI_COMMIT_REF_PROTECTED
is set to true.
I am aware of the similar Questions: Gitlab ci run job on master with release tag only and How to run a gitlab-ci.yml job only on a tagged branch?.
Also I know there is/was a wide discussion in the issues from gitlab, with some solution (or something close to this) like this.
The general problem seems to be that it is not possible in gitlab to determine reliable if a commit if on a given branch as the information (git history) for this is not given.
This question is to keep track of a proper solution within gitlab CI for this common use case.
Combining the workaround mentioned in the question with the new gitlab rule and workflow features I came up with an answer that seems satisfying for me.
The person originally posting the workaround mentioned that there are cases in which git branch contains
does not give the correct results.
So I made sure, that git fetch
does not make a shallow copy (note for the beginning it could be useful to change the GIT_STRATEGY
to clone, so that old possible shallow copies are removed).
Instead of using CI_COMMIT_REF_PROTECTED
which could be true also for protected tags, I hardcoded the $CI_DEFAULT_BRANCH
(thx to [Gostega) as protected.
# Be quite strict in what can trigger a pipeline, actually only pushes of
# branches or version tags should trigger anything - otherwise we need to catch
# too many edge cases.
workflow:
rules:
# Do no allow manually triggered pipelines to prevent duplicates!
# Instead rerun the pipeline created with the last push
- if: $CI_PIPELINE_SOURCE != "push"
when: never
# Only execute when a valid version tag like v1.0, 2.3 or similar is given
# Required is always one point like 1.0
- if: $CI_COMMIT_TAG =~ /^v?[0-9]+[.][0-9]+([.][0-9]+)?$/
- if: $CI_COMMIT_BRANCH
variables:
# Make sure we don't get a shallow copy
GIT_DEPTH: 0
# Fetch is default just to make clear what is used
GIT_STRATEGY: fetch
# make sure we fetch everything and also see what is happening
GIT_FETCH_EXTRA_FLAGS: -f --tags --prune --update-head-ok
default:
before_script:
- export CI_LOG_LINE=$(git log --decorate=full| grep "^commit $CI_COMMIT_SHA[ ]")
# var = 1 if the current commit is the **latest** on the default branch
- export IS_ON_MAIN=$(echo $CI_LOG_LINE | grep -qso "origin/${CI_DEFAULT_BRANCH}, " && echo 1 || echo 0)
# var = 1 if current commit is on any remote commit that is part of default branchs history
- export COMMIT_ON_MAIN=$(git branch -r --contains $CI_COMMIT_SHA | grep -Eq "^[ ]+origin/${CI_DEFAULT_BRANCH}$" && echo 1 || echo 0)
stages:
- check_update_environment
- test
- publish
check_update_environment:
stage: check_update_environment
script:
# Exit if tag is given on none main branch early
# Check for
- if [[ ! -z "$CI_COMMIT_TAG" && $COMMIT_ON_MAIN != 1 ]]; then
echo "Tags should never be applied to non main branches!" >&2;
echo "We quit early! Please delete the tag, merge the branch to main and recreate the tag to continue" >&2;
exit 1;
fi
test:
stage: test
script:
- echo "Doing testing..."
dependencies:
- check_update_environment
publish:
stage: publish
script:
- echo "Publishing..."
rules:
# Run always if there is version tag. The version tag is defined
# in the workflow rules
# Due to the fail early in the environment check this is never done for
# branches that aren't the default branch
- if: $CI_COMMIT_TAG
dependencies:
- test