TL;DR;
If you just want to make a release
or version bump commits when stuff is merged to main
, there are probably existing CLI tools that you can use in a much more simpler and well documented way.
(See Use the gitlab api
for an example)
How to do it
The necessary steps:
commitingJob:
stage: some_stage
script:
# in order to commit we have to have a user set
# this would also make it easy to distinct the CI-made commits
- git config user.name "CI Pipeline"
- git config user.email "[email protected]"
# stage some changes
- git add src/*
# We can use `-o ci.skip`, but AFAIK it doesn't work for Merge Request pipelines, while having it inside the commit message works there as well
- git commit -m "A commit message [skip ci]"
# we're on a detached head but we can push the commits we made to the remote branch like so:
- git push HEAD:$CI_COMMIT_REF_NAME
One thing missing here is authenticating with the remote. It can be setup in a number of ways (ssh, token, api). Other answers discuss a few different options. My preference would be to use an ACCESS_TOKEN, see how and why bellow
Summary and critique on the available authentication options
Adding or copying an ssh
key inside the CI steps
Compared to just using an access token, going for the ssh
way seems like too much work, for the same result
- generate an ssh key
- save the public key as Project deploy token
- save the private key as a Project CI variable
- dedicate a few CI steps on
- adding the private keys
- adding known hosts
- add/update the
ssh
remote
Overall it seems like something you'd do for a user
and not for a pipeline
You have to add the private key as a Project Level CI variable - due to pattern restrictions the variable can't be masked. It can be added as a file, but then you'd have to chmod
for proper permissions...
The positive thing I see here is the ssh
key is restricted only to the projects you add it to as deploy token
The easiest option seems to be to use an ACCESS_TOKEN
Using a token to push commits is as easy as updating the push
remote like this:
git remote set-url --push origin "https://$TOKEN_NAME:[email protected]/<project>.git"
TOKEN_NAME - the name you set for the token in gitlab (preferably pick a name without space characters)
ACCESS_TOKEN - this can be a personal access token (Free Tier) or a project access token (Premium Tier)
It would have to be stored as Project Level CI variable, and it can be masked.
I would just save a variable like CI_COMMITTER_USER_AND_TOKEN
containing both <token_name>:<access_token>
content
⚠ Warning about Personal Access Tokens
This is too broad permission to give to a CI Runner even if the runner should commit to multiple repositories, I'll prefer separate access tokens per project with only the minimum permissions needed
Keep in mind that if someone takes hold of your personal access token, they can do stuff (like committing in this case) on your behalf. Giving the write_repository
permission means you can use the token to write to any repository you're account has access too.
CI_JOB_TOKEN
If you're wondering whether you can use the CI_JOB_TOKEN
to push commits - you can't. You can only pull
with that thing
(You can also use it to publish packages and images, but not push commits)
Why git remote set-url --push origin
We can add a separate remote for CI made commits, but keep in mind it might get cached, so if we just do
script:
- git remote add ci "https://$TOKEN_NAME:[email protected]/<project>.git"
the next time the pipeline runs we'll get an error from git remote add
, because the remote we're trying to add is already added
set-url
on the existing origin
makes sure you use the latest url
To achieve the same with git remote add
we'd have to first try to remove the ci
remote and then add it back
script:
- git remote remove ci || true
- git remote add ci "https://$TOKEN_NAME:[email protected]/<project>.git"
Use the gitlab api
to push changes
This works pretty much the same way as the ACCESS_TOKEN
way, but instead of the write_repository
the token has the api
permission
If the reason to commit and push as part of CI is releasing a new version on merge to main
then using CLI tools and a guide like this might be a better option than setting up the committing and pushing yourself: https://docs.gitlab.com/ee/ci/examples/semantic-release.html
The above guide setups a version bump, package updates, and release notes.
Note how this step instructs us to create an Access Token with api
permission in order for the underlying CLIs to commit the changes: https://docs.gitlab.com/ee/ci/examples/semantic-release.html#set-up-cicd-variables