Hi, welcome to Word of Mike, my little corner of the internet. I am a Software/Web Developer working in North Yorkshire. I mainly write about programming but my other passion is politics so beware. (click to hide)

2015-02-27 17:46:45 UTC

Rake Tasks to Version Your Rails App


I've used git tags to store the version number of my app for a while now. It's a minor inconvenience to see what the current/last version number is, as git tag lists them alphabetically meaning that v4.5.21 comes before v4.5.4 for example, even though it's a later version. This can lead to people tagging commits wrongly, so to avoid this I wrote some a small set of rake tasks to do the versioning for me.

LEVELS = [:major, :minor, :patch]

def version
  @version ||= begin
    v = `git describe --always --tags`
    {}.tap do |h|
      h[:major], h[:minor], h[:patch], h[:rev], h[:rev_hash] = v[1..-1].split(/[.-]/)
    end
  end
end

def increment(level)
  v = version.dup
  v[level] = v[level].to_i + 1

  to_zero = LEVELS[LEVELS.index(level)+1..LEVELS.size]
  to_zero.each{ |z| v[z] = 0 }

  Rake::Task["version:set"].invoke(v[:major], v[:minor], v[:patch])
end

desc "Display version"
task :version do
  puts "Current version: #{`git describe --always --tags`}"
end

namespace :version do
  LEVELS.each do |l|
    desc "Increment #{l} version"
    task l.to_sym do increment(l.to_sym) end
  end

  desc "Set specific major, minor and patch"
  task :set, [:major, :minor, :patch] do |_, args|
    sh "git tag v#{args[:major]}.#{args[:minor]}.#{args[:patch]} && git push --tags"
  end
end

Gist

They're based on the format I use for tags which is "v<major>.<minor>.<patch>", but as you can see it's fairly simple so you can change it to suit.

You simply invoke the appropriate task from the following:

rake version:major                      # Increment major version
rake version:minor                      # Increment minor version
rake version:patch                      # Increment patch version
rake version:set[major,minor,patch]     # Set specific major, minor and patch

I will probably hook it in to Capistrano so I can set a command line option when I'm deploying which will bump the version number prior to deployment.

Update 4/9/15: I've done that Capistrano hook:

In my config/deploy.rb I've placed:

namespace :deploy do
  before :starting, :version_update do
    if !ENV['version']
      ask :version_update, "none"
    else
      set :version_update, ENV['version']
    end

    case fetch(:version_update)
    when "none"
    when "patch", "minor", "major"
      Rake::Task.invoke("version:#{fetch(:version_update)}")
    else
      raise "Please choose either 'none', patch', 'minor', 'major' for version_update."
    end
  end
end

This checks for

ENV['version']
, which you can use like so:

cap production deploy version=patch

If you don't pass anything, it will prompt you at the command line during deploy for either 'patch', 'minor', 'major', or 'none' (none is default).

Because it uses the same tasks defined above, you'll need to import them in your Capfile:

import 'lib/tasks/versioning.rake'