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.
To enable force pushes on branches that are already protected: Go to your project and select Settings > Repository. Expand Protected branches. In the list of protected branches, next to the branch, turn on the Allowed to force push toggle.
These are scripts that you choose to be run before the job is executed or after the job is executed. These can also be defined at the top level of the YAML file (where jobs are defined) and they'll apply to all jobs in the . gitlab-ci. yml file.
Protecting a branch can be done in GitLab by marking a branch as Protected. This means that people with the Developer permission level and lower are not able to push changes directly to that branch; they need to create a merge request to push changes to these branches.
Combining the workaround mentioned in the question with the new gitlab rule and workflow features I came up with an answer that seem 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 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 possibly shallow copies are removed).
Instead of using CI_COMMIT_REF_PROTECTED
which could be true also for protected tags, I hardcoded the master branch 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 master
- export IS_ON_MASTER=$(echo $CI_LOG_LINE | grep -qso "origin/master, " && echo 1 || echo 0)
# var = 1 if current commit is on any remote commit that is part of masters history
- export COMMIT_ON_MASTER=$(git branch -r --contains $CI_COMMIT_SHA | grep -Eq '^[ ]+origin/master$' && echo 1 || echo 0)
stages:
- check_update_environment
check_update_environment:
stage: check_update_environment
script:
# Lets print some debug stuff
- echo $CI_JOB_TRIGGERED
- echo $CI_PIPELINE_SOURCE
- echo $CI_COMMIT_SHA
- echo $CI_COMMIT_REF_NAME
- echo $CI_BUILD_REF
- echo $CI_COMMIT_BRANCH
- echo $CI_COMMIT_TAG
# Get the information about the state of the current commit
- git log --decorate=full| grep "^commit $CI_COMMIT_SHA[ ]" || echo "Failed???"
- git status
- git remote show
# Show current branch --> normally fails - only for kept for reference
- git symbolic-ref --short HEAD || echo "Doesn't work"
# Some more possible debug information
- git branch --contains $CI_BUILD_REF
- git tag --contains $CI_BUILD_REF
- env
# **Finally the important part**
# Exit if tag is given on none master branch early
- if [[ ! -z "$CI_COMMIT_TAG" && $COMMIT_ON_MASTER != 1 ]]; then
echo "Tags should never be applied to non master branches!" >&2;
echo "We quit early! Please delete the tag, merge the branch to master 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 master
- if: $CI_COMMIT_TAG
dependencies:
- test
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With