Applicatieversies met git describe

Gepubliceerd op 22 november 2011 door Martijn

Het gebruik van versienummers in Ruby on Rails applicaties is niet erg wijd verspreid. Doordat er van veel applicaties in feite maar een versie van belang is (de versie die op dat moment on-line is) wordt er geen melding gemaakt van een specifieke versie. Desondanks kan het toch nuttig zijn om de releases van de applicatie te nummeren. Dit geeft een handvat om wijzigingen naar de gebruikers te communiceren en bovendien geeft het de gebruikers het gevoel dat de applicatie actief ontwikkeld wordt.

In deze post laten we zien hoe met behulp van git describe en enkele regels code zeer eenvoudig versienummers aan een Rails applicatie kunnen worden toegevoegd.

Git describe: zoek een tag bij een commit

Ons belangrijkste hulpmiddel voor deze post is git describe. We zullen de werking demonstreren aan de hand van een voorbeeld.

De eerste stap is het opzetten van een repository in een lege directory:

    $ git init .
    Initialized empty Git repository in /Users/martijn/Developer/versies/.git/
    $ echo "Dit is nog geen versie" > README 
    $ git add README 
    $ git commit -m "Eerste commit"
    [master (root-commit) f828a77] Eerste commit
     1 files changed, 1 insertions(+), 0 deletions(-)
     create mode 100644 README

De eerste commit heeft als hash f828a77. Als we nu git describe uitvoeren op dit repository geeft deze die hash terug:

    $ git describe --always
    f828a77

We gebruiken hier de –always optie zodat git een hash gebruikt als beschrijving indien hij geen tag kan vinden.

Op het moment dat een versie klaar is om uit te brengen kunnen we een tag aanmaken voor deze versie. In de Semantic Versioning richtlijnen wordt aanbevolen om versie tags te laten beginnen met een letter v. Tevens wordt het gebruik van annotated tags in Git over het algemeen aanbevolen. Voor ons voorbeeld is dit ook van belang. We committen en taggen de update daarom als volgt:

    $ echo "Versie 0.1.0" > README ; git add README ; git commit -m "Versie update"
    [master 633b8a0] Versie update
     1 files changed, 1 insertions(+), 1 deletions(-)
    $ git tag -a "v0.1.0" -m "Versie 0.1.0"

Als we nu git describe uitvoeren zien we dat onze tag als omschrijving wordt gebruikt:

    $ git describe
    v0.1.0

Dit gegeven zouden we dus al kunnen gebruiken om de huidige versie weer te geven in onze applicatie. Daarover straks meer. Wat gebeurt er nu als we een commit maken na deze tag?

    $ echo "Versie 0.1.1" > README ; git add README ; git commit -m "Versie update"
    [master a85330d] Versie update
     1 files changed, 1 insertions(+), 1 deletions(-)
    $ git describe
    v0.1.0-1-ga85330d

Wat deze omschrijving aangeeft is dat er een commit is geweest sinds de tag en dat onze HEAD momenteel op commit a85330d zit. Dit zou geen acceptabel versienummer zijn voor een productie release, dus hier zullen we straks bij het deployen op controleren.

Om nu een geldige productie versie te maken zullen we nog even een v0.1.1 commit taggen:

    $ git tag -a "v0.1.1" -m "Versie 0.1.1"
    $ git describe
    v0.1.1

In een Git client als SourceTree zien we de tags netjes op een rij onder elkaar:

Versies in SourceTree

Versie tonen in de Rails applicatie

Om de versie te kunnen tonen in de Rails applicaite stellen we deze vast tijdens het opstarten van de applicatie. Maak hiervoor een bestaand config/initializers/app_version.rb aan met de volgende inhoud:

    APP_VERSION = `git describe --always` unless defined? APP_VERSION

Vervolgens kun je op de gewenste plek, bijvoorbeeld in de layout eenvoudig de versie opvragen, bijvoorbeeld door dit op te nemen in de layout view:

    <%= APP_VERSION %>

Versie controleren voor het deployen met Capistrano

Om er nu voor te zorgen dat een productie release altijd een correct getagde versie heeft zullen we in de deploy.rb een controle opnemen die kijkt of er een tag is.

Hier een voorbeeld stap voor een multistage setup, waarbij we voor elke stage een gelijknamige branch hebben:

task :check_tag do
  desc = `git describe #{stage} --exact-match`
  unless desc =~ /^v(\d+)\.(\d+).(\d+)/
    Capistrano::CLI.ui.say(<<-EOM)
    The branch #{stage} does not have a version tag!

    Please tag the release to enable deployment. Last tags were:
    EOM
    Capistrano::CLI.ui.say "    "+`git tag -l | head -5`.lines.to_a.join(', ').gsub("\n",'')
    exit
  else
    Capistrano::CLI.ui.say("    Releasing #{desc}")
  end
end

before "deploy", "check_tag"

Er wordt een branch en een optie –exact-match weergegeven. Deze optie zorgt ervoor dat er alleen een resultaat wordt gegeven als er een exacte tag voor de versie bestaat. Als de laatste commit in de branch niet getagged is komt er dus geen resultaat.

Met een regex controleren we of er een tag is terug gegeven met een geldig formaat. Zo niet, dan krijgt de gebruiker een waarschuwing. Voor de volledigheid geven we de laatste vijf tags weer zodat de gebruiker de volgende versie kan bepalen. Een script om automatisch de versie op te hogen zou hier een mooie toevoeging zijn.

Indien er wel een geldige tag is gevonden geeft het script hier netjes een melding van. Hierna zal in de productieapplicatie netjes de getagde versie weergegeven worden.

Door de versienummering te centraliseren in Git is beheer van versies eenvoudig en overzichtelijk. Met Semantic Versioning krijgen de versienummers een duidelijke mening voor de buitenwereld. Het bijhouden van versienummers lijkt niet overal nuttig, maar wellicht geeft het uw applicatie net dat stukje extra uitstraling.

Reacties

blog comments powered by Disqus