I am trying to get the maven release process (release:prepare and release:perform) working with the GitLab CI.
I have the following in my .gitlab-ci.yml
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-release-plugin:2.5.3:prepare (default-cli) on project test-1: An error is occurred in the checkin process: Exception while executing SCM command. Detecting the current branch failed: fatal: ref HEAD is not a symbolic ref -> [Help 1]
Just answering my question here and documenting what I did to get this working.
Maven release plugin needs to commit and push changes to pom.xml for the versions used for release and subsequent development.
For this, we need to set up a user that has the permissions to do so on the repo.
Add the userâs SSH Key as a VARIABLE with name SSH_PRIVATE_KEY in the repositories settings
This key should NOT have a pass phrase
Next, if you are using a Docker image to run the build operations, you need to set up an ssh agent and pass on the SSH_PRIVATE_KEY
Example:
stage: deploy
image: java:8u102-jdk
script:
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
# Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)
# Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
- ssh-add <(echo "$SSH_PRIVATE_KEY")
# For Docker builds disable host key checking. Be aware that by adding that
# you are susceptible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
...
only:
- master
Gitlab CI runner works on DETACHED HEAD, but maven release plugin needs to be on a branch
So, set the VARIABLE with the name CI_BUILD_REF_NAME with the branch from which you want to release
Add the script to checkout that branch as shown below:
stage: deploy
image: java:8u102-jdk
script:
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
# Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)
# Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
- ssh-add <(echo "$SSH_PRIVATE_KEY")
# For Docker builds disable host key checking. Be aware that by adding that
# you are susceptible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
- git checkout -B "$CI_BUILD_REF_NAME"
...
only:
- master
Finally, add the release prepare and perform steps
stage: deploy
image: java:8u102-jdk
script:
# Install ssh-agent if not already installed, it is required by Docker.
# (change apt-get to yum if you use a CentOS-based image)
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
# Run ssh-agent (inside the build environment)
- eval $(ssh-agent -s)
# Add the SSH key stored in SSH_PRIVATE_KEY variable to the agent store
- ssh-add <(echo "$SSH_PRIVATE_KEY")
# For Docker builds disable host key checking. Be aware that by adding that
# you are susceptible to man-in-the-middle attacks.
# WARNING: Use this only with the Docker executor, if you use it with shell
# you will overwrite your user's SSH config.
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
- git checkout -B "$CI_BUILD_REF_NAME"
- mvn release:prepare --settings .ci/settings.xml -B -DskipTests=true
- mvn release:perform --settings .ci/settings.xml -B -DskipTests=true
only:
- master
Hi @vpothnis, thanks for your detailed explanation.
Iâm beginning with gitlab-ci and maven release plugin. My gitlab runner is dockerized, and Iâm having trouble understanding where exactly do you need to set up the user (with the permission to do whatever on the repo) and how to add the SSH key.
Any help is appreciated,
Regards!
The user is only special in how they are used â other than that they look like you or me. You would add the ssh key and grant access to this user as you would any user.
Hello @vpothnis , your proposal works perfect but only the first part. Once the release is finished, a new change is generated in the master branch with the next SNAPSHOT version. So the process runs automatically again and again. How did you organize the configuration so that it does not run infinitely?
Well, tagging afterwards is harder.
I would build only releases from master using the versions-maven-plugin and she pipeline id. You coiuld push the tag after alll your tests ran successfully⌠We use a staging Maven repository and promote the binaries later on after the test. We keep all git Tags as they consume almost no resources.
Yes, I think that promoting binaries from staging to production maven repository is the missing link. You can then handle potentially âbadâ and âgoodâ releases later on.
Hi all, I have been using this discussion to setup my gitlap pipeline with mvn release plugin and it works perfectly. However, I am encountering a problem: in the release step, maven prepare tries to push a tag and it fails (updates were rejected because the tip of your current branch is behind).
I saw that someone else pushed on master in between my pipeline was running and this should be the problem. I thought that I might solve this allowing maven to âgit push --forceâ or blocking commits while the release pipeline is running.
Any idea or suggestion about this?
Thank you @vpothnis for answering your own question.
I faced a similar issue trying to setup this npm package release-it to create releases in my pipeline.
The command git checkout -B master helped resolve a serie of issues I had with a dangling git HEAD
It looks like this also has a problem if you have when: manual to run the release task. Since we are only checking out master, if anyone pushes to master before the user manually runs the release, we will get the head of master, not the commit associated with this build.
That in fact could happen even if the release runs automatically, if someone pushes while earlier jobs in the pipeline are running.
I think that could be resolved by branching from the commit and building in that branch. You would want to merge back to master to get the new version numbers, which is going to fail (or be very complicated) if anyone has pushed to master in the meantime.
Additional benefit: you do not spoil the masterâs commit history with the two release-commits.
Of course now you need to bump your version somehow.
You could use the ci_pipeline_id approach via inclusion of https://github.com/1and1/ono-maven-shared/blob/master/README.md
This is not a perfect solution as the automatic jobs will still run. But they will run only once because the manual job will be skipped breaking the chain.