Sep 27

Sensible Auto Git Tagging Deployments to Production on Jenkins

Tue, 09/27/2016 - 07:03 — peter

The Problem

You've built your code, and you have a spiffy Jenkins setup to pull from git and run your tests for you, and you want to keep track of the pushes you do to your production environment. By default, Jenkins produces a local tag on the job's workspace named something like this: jenkins-<job-name>-<sequence-number>. However that doesn't tell you much. And that is not pushed to the remote repo.

As a developer, I'd prefer to just look at the list of tags on a repo and know which ones refer to pushes to production, and also know some more information about them without having to check them out and without having to inspect their logs. As you must know, according to Uber-Geek Larry Wall, developers are lazy! And impatient! And full of hubris! And that is a very good thing!

The Solution

The ideal solution for me would be to have a git tag that:

  1. would tell me which date the code was pushed
  2. would tell me the date of the last commit to that push, as we only push code that has been tested and QA'd and approved by the stakeholders, and that can sometimes take more than a day
  3. would tell me the sequence number of the push for that day, in case there are two pushes with the same dates
  4. had the following format: vC<date-of-last-commit-being-pushed>-P<date-of-the-actual-push>-<sequence-number>
  5. would prevent a new tag to be created if the same commit happened to be pushed twice to production

Of course your ideal format may differ, and that is fine, as you can adjust the concept presented here to fit your particular use-case.

To get this setup in Jenkins, add a new execute shell build step, and set it as the last step, then add the following code in it:

cd $WORKSPACE
COMMIT=`git log -n 1 --oneline --no-color --format=format:'%H'`
LASTTAG=`git log -n 1 --oneline --no-color --format=format:'%H' --tags=v*`
 
if [ $COMMIT == $LASTTAG ]; then
  echo "Tag already created, exiting..."
  exit 0
fi  
 
COMMITDAY=`git log -n 1 --oneline --no-color --format=format:'%ai' $COMMIT`
COMMITDAY=${COMMITDAY:0:10}
TODAY=`date '+%Y-%m-%d'`
TAGSEQUENCE=`git tag|grep $TODAY|wc -l`
(( TAGSEQUENCE += 1 ))
 
NEWTAG="vC$COMMITDAY-P$TODAY-$TAGSEQUENCE"
echo "Creating tag..."
git tag -a $NEWTAG -m "Code push #$TAGSEQUENCE from $TODAY" $COMMIT
 
git push origin $NEWTAG

The code above fulfill all of my requirements, and now I get something that looks like this:

git tag
...
vC2016-04-07-P2016-04-07-2
vC2016-04-08-P2016-04-08-1
vC2016-04-08-P2016-04-18-1
vC2016-04-15-P2016-04-19-1
vC2016-04-15-P2016-04-20-1
vC2016-04-19-P2016-04-19-2
vC2016-04-21-P2016-04-21-1
vC2016-04-25-P2016-04-25-1
vC2016-04-25-P2016-04-25-2
vC2016-04-25-P2016-04-25-3
...

This solution assumes you have the right setup to let Jenkins push the tags back to your git repo. If you would like to know how that part is setup, stay tuned for a future write-up on it!

Easy Peasy!

What do you do for git tagging? Do you have any other cool git, Jenkins or general automation tricks? Tell me about it!