Git tag with jenkins2 pipeline

I started seting up an instance of Jenkins 2 and moving projects to the new pipeline functionnality. This is really interesting and provides a much more robust and repeatable tool chain. Howerver, it is not feature complete yet and if you plane to use it, it will feel a little bit clumsy compare to Jenkins 1.

The pipeline is a completely separate process and not all jenkins functionnalities and plugins have a pipeline equivalent. This means that you quickly end up combining a bunch of command line instructions. Using git is one example that you quickly run into.

Basic Git operation

Checkout code is prety straightforward and provided by Jenkins but this is the only thing you will get. Want to know the current Git Commit ? You have to use git :

gitCommit = sh('git rev-parse HEAD')

Want to create a tag to mark the release you just deployed ? Again, call the command line.

sh('git tag -a v2.3.0')
sh('git push --tags')

If you are lucky, this might work straight away but chances are it won’t.

Problems start…

I encountered different problems. First, git username and email were not set. I tried setting it in Jenkins administration and directly on the jenkins server but none worked. The username was always related to the tomcat user running Jenkins. The only solution was to set it directly into the pipeline script

sh("git config user.name 'Jenkins'")
sh("git config user.email 'jenkins@mycompany.com'")

Pushing to the server: authentication

Once identity is correct, you have to push this tag to your remote. This always requires some kind of authentication.

If your repo use a username/password system, you can enclose your command into the withCredentials step which will load credentials stored in your Jenkins configuration and set them as environnement variables.

withCredentials([[$class: 'UsernamePasswordMultiBinding', 
                credentialsId: 'MyID', 
                usernameVariable: 'GIT_USERNAME', 
                passwordVariable: 'GIT_PASSWORD']]) {    
    sh('git push https://${GIT_USERNAME}:${GIT_PASSWORD}@repo_url --tags')
}

What I don’t like in this method is that it forces you to write you git url into the pipeline script. This is a duplicate of your jenkins job configuration and lead to a difficult maintenance as you now have two places to update if a change occurs.

If your repo is using ssh keys for authentication, you will need to install thesshagent plugin which provides a new step to use an ssh key defined in your Jenkins configuration :

sshagent(['8d756129d-8f6d-4a91-b129-aa8d9dfc0e19']) {
    sh("git push --tags")
}

And here stops most explainations on the web.

The missing piece

My repository use ssh keys and the above was not working. In the logs, I saw the ssh agent started and loaded the key but it stopped immediately and the git push command failed.

One little piece was missing. For the sshagent to work, you need to define you git repository url with the ssh protocol in the jenkins job configuration:

ssh://git@server/path/to/your/repo
Jenkins git url configuration screen

 

Once the url is correctly set in the job configuration, everything works as expected and you have tags in your repo for each release deployed.

One last thing

If for any reason you need to run a job twice and deploy again the exact same version of your application, the previous code might make your job fail. The git tag plugin on jenkins 1 is able to automatically replace an existing tag with the same name. In the pipeline, you need to add the –force option to your command lines :

sh('git tag -f -a v2.3.0')
sshagent(['8d756129d-8f6d-4a91-b129-aa8d9dfc0e19']) {
    sh("git push -f --tags")
}

The jenkins pipeline is great and I won’t go back but once again, this feels a little bit clumsy and I’m eager to see this kind of action more integrated into the product.