Use Grunt to push a Git tag

I use tags in git to version my code and push changes to production. Tagging is fairly simple using the git cli, but I’ve made it even easier using a simple Grunt task.

Git tags are what we use to push code to production. Whenever a new tag is pushed to origin master, our CI server (Jenkins) does a build and then pushes that new code to production. The act of tagging is fairly trivial, but it is a few different commands. Typically one would do the following:

$ git describe —tags —abbrev=0
1.200.69
$ git tag 1.200.70
$ git push origin —tags

Unfortunately, thats a tiny bit of a pain and still a manual process prone to error. Someone recently pushed 3 different tags to our master branch of “list”, “describe”, and “show”. Obviously a mistake when using git commands but still, these random tags have actually proved to be a much bigger pain in the rear than they should!

We already had Grunt setup for this particular project because we were using a simple build command to compile our SASS files. Including a new task specifically for git tagging seemed a no-brainer. Now to push a tag we simply execute:

$ grunt tag

By default it will do a :patch, but additional options can be included for minor and major i.e.:

$ grunt tag:minor

The code is fairly straightforward:

// jshint node:true
'use strict';

var semver = require('semver'),
    exec = require('exec');

module.exports = function(grunt) {
    'use strict';

    require('load-grunt-tasks')(grunt);
    var gitVersion;

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),

        shell: {
            options: {
                stdout: true,
                stderr: true
            },
            tag: {
                command: [
                    'git tag <%= grunt.option("tag") %>',
                    'git push origin --tags'
                ].join(' && ')
            }
        }
    });

    // Auto increment GIT TAG and PUSH to ORIGIN
    grunt.registerTask('tag:patch', ['tag']);

    grunt.registerTask('tag:minor', function() {
        grunt.option('tagType', 'minor');
        grunt.task.run(['tag']);
    });
    grunt.registerTask('tag:major', function() {
        grunt.option('tagType', 'major');
        grunt.task.run(['tag']);
    });

    grunt.registerTask('tag', function() {
        if (grunt.option('tagType') !== 'major' &&
            grunt.option('tagType') !== 'minor') {
            grunt.option('tagType', 'patch');
        }
        var done = this.async();
        exec('git describe --tags --abbrev=0',
            function(err, stdout, stderr) {
                if (stderr) {
                    grunt.log.error(stderr);
                } else {
                    gitVersion = semver.inc(
                        stdout.trim(),
                        grunt.option('tagType')
                    );
                    grunt.log.ok('Tagging: ' + gitVersion +
                        ' (' + grunt.option('tagType') + ')');
                    grunt.option('tag', gitVersion);
                    grunt.task.run(['shell:tag']);
                }
                done();
            }
        );
    });
};

And the devDependencies in the package.json:

"devDependencies": {
    "grunt": "^0.4.4",
    "load-grunt-tasks": "^0.4.0",
    "semver": "^2.2.1",
    "exec": "^0.1.0",
    "grunt-shell": "^0.6.4"
  }

You can download the complete Gruntfile.js from this gist:
https://gist.github.com/jkat98/10117306

Important Note: Some asked why I didn’t just use grunt-bump for this type of solution. The main problem I had was that grunt-bump wants to require the version number stored in the package.json file. If the version (or tag) changes outside of the package.json file then grunt-bump stops working properly. With a shared project repo like this particular one, with many old-school people not using (or refusing to use) Grunt, manual git tags are still pushed daily. The risk of the package.json file being out of sync (version # wise) was too high. This method forcefully uses the actual last git tag to increment.

One thought on “Use Grunt to push a Git tag

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s