I have a self-hosted GitLab repo with a protected development branch. I want our staging environment to always be in sync with the head of the development branch. Thus, on each successful merge into the development branch, we create a tag in GitLab that triggers another pipeline for deployment to our staging environment. These tags are currently created manually.
We have a lot of different projects that use the same scripting fragments. Because of compatibility with our other projects, I need the tag to trigger the pipeline for deployment.
Just to be clear: no-one is allowed to push directly to the development branch. Instead, developers are supposed to present their work in a merge request, which includes some quality assurance checks/pipelines. This also means force-pushing to the branch is not allowed.
Our self-hosted GitLab uses http
(instead of https
).
I want to eliminate the need for manually adding a tag to the repo each time a merge request has been merged into the development branch. This will help standardize our tags and make sure we never forget to push a tag anymore.
However, the tagging pipeline we created is not allowed to push a new tag to the development branch and fails. We haven't yet found a way to automatically push a tag to the protected branch. We have adapted our pipeline script from this post:
tagging:
stage: deploy
rules:
- if: $CI_COMMIT_BRANCH == $DEV_BRANCH_NAME
script:
- git config --local user.name "${GITLAB_USER_NAME}"
- git config --local user.email "${GITLAB_USER_EMAIL}"
- tag="dev-$CI_COMMIT_SHA"
- git tag "$tag"
- git push --tags http://gitlab-ci-token:$CI_JOB_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$DEV_BRANCH_NAME
resulting in this pipeline output:
$ git config --global user.name "${GITLAB_USER_NAME}"
$ git config --global user.email "${GITLAB_USER_EMAIL}"
$ tag="dev-$CI_COMMIT_SHA"
$ git tag "$tag"
$ git push --tags http://gitlab-ci-token:$CI_JOB_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git HEAD:$DEV_BRANCH_NAME
remote: You are not allowed to upload code.
fatal: unable to access 'http://[self_hosted_url]/[path_to_service]/[service].git/': The requested URL returned error: 403
ERROR: Job failed: exit code 128
We first tried with the original script I mentioned above, but we got the error message remote: HTTP Basic: Access denied. The provided password or token is incorrect or your account has 2FA enabled and you must use a personal access token instead of a password. // fatal: Authentication failed for [correct url].
Is it possible to circumvent the protection of the development branch, so we can run the above script while still keeping the merge requests requirement and the branch protected from direct pushes by developers, or can we alter the above script such that it allows us to push the tag to the repo?
Tags are not related to branches. When you push a tag, you are not pushing to a branch. Therefore, branch protection rules do not apply here (though if you have protected tags, that would apply). The primary issue is the permissions of the credentials you are using. CI_JOB_TOKEN
s do not have repository write permissions so you won't be able to use git to push commits or tags. Though, these tokens do have some limited API permissions.
In a bit of irony, you cannot create tags using the CI_JOB_TOKEN
however, you can create releases (which, in turn, can create tags). You can either use the API to create a release or use the release:
keyword. This obviously has the primary effect of creating a release, but it will also create a git tag if it does not already exist.
myjob:
rules:
- if $CI_COMMIT_BRANCH == $DEV_BRANCH_NAME
# ...
script:
- echo "noop"
release:
tag_name: dev-$CI_COMMIT_SHORT_SHA
description: dev release for $CI_COMMIT_SHA
All the release keyword does is run a script in the job that uses the gitlab release-cli which leverages the GitLab API to create the release. In principle, you could also just use release API yourself instead of using the release:
keyword.
You can also use the API to create a tag without creating a release, but last I checked, the CI_JOB_TOKEN
is not allowed to use those endpoints. So, if you want to create a tag without creating a release, you may need to create an appropriate token with API scope authorized (such as a project access token, group access token, personal access token, or similar) and use that in your job.