Tâche gulp pour mettre à jour la version et créer un commit Git

Le sujet de cet article sera autour d'une tâche Gulp afin de mettre à jour la version de votre projet NodeJs, et aussi de créer automatiquement un commit Git.

Pour rappel, la numérotation d'un module NodeJs se repose sur la convention semver. Le principe est simple: nous avons une version basé sur trois chiffres, séparés par des points.

Le premier chiffre est le "major version". Cela veut dire que lorsque ce numéro change, nous avons un changement majeur dans le module, apportant potentiellement des "breaking changes". Donc en générale, quand nous mettons à jour un module dont le premier chiffre change, nous pouvons nous attendre à avoir à réadapter notre code.

Le second est le "minor version". En somme, c'est tout simplement une version stable. Mettre à jour un module dont seul le deuxième numéro change devrait poser peu de problèmes (tout dépend si le développeur respect le principe du semver :) ).

Et enfin le dernier est le "patch version". Alors, attention: danger. Cela veut dire que nous avons corriger un patch, et que du coup nous publions une version de correction. Mais cela n'induit pas forcément que nous n'allons pas importer d'autres bugs. Du coup, faites bien attention qaund vous mettez à jour un module dont seul la dernière version change (dans le monde Gulp, je peux vous assurer que j'ai eu de nombreux problèmes en voulant naïvement mettre à jour des modules où visiblement, des patchs avaient été appliqués).

A noter que le flag "-snapshot" est toléré. Cela n'est pas vraiment dans la convention semver, mais ce n'est pas rare de le voir (peut-être des influences du monde Maven ?). Si vous voyez une version avec ce flag, cela veut dire que c'est une version en cours de développement. Tout simplement.

Du coup, notre tâche Gulp aura pour objectif de nous aider à gérer cette version semver (sans le flag snapshot). Pour mieux aider l'utilisateur, nous allons utiliser inquirer. Ce module NodeJs permet d'afficher un prompt afin de guider le choix. De plus, une fois le choix fait, nous allons essayer de mettre à jour les fichiers suivants:
  • package.json
  • bower.json (si votre projet est une application Web ou à destination du Web)
  • npm-shrinkwrap (si vous figer les dépendances de votre module. Pour plus d'explication, c'est par ici).

Et enfin, nous allons créer un commit Git avec un message prédéfini.

Voyons un peu notre structure de projet:

Nous utilisons le plugin gulp-load-tasks qui permet de découper notre tâche Gulp en plusieurs fichiers (ici dans le répertoire "config"). Ce qui est intéressant, est que par convention, le nom du fichier dans le répertoire config sera le nom de la tâche à appeler. En l’occurrence ici, la tâche "bump". Et c'est d'autant plus intéressant ici, c'est que le chargement de la tâche se fera plutôt rapidement, car nous n'importerons que ce que nous avons besoin pour réaliser celle-ci.

Maintenant, regardons le fichier "package.json":

{
  "name": "node-gulp-bump",
  "description": "An example to declare a bump gulp task",
  "version": "0.0.1",
  "private": false,
  "scripts": {
    "bump": "npm run gulp bump",
    "gulp": "node node_modules/gulp/bin/gulp.js",
    "shrinkwrap": "npm shrinkwrap --dev"
  },
  "contributors": [
    {
      "name": "Julien Roche",
      "email": "roche.jul@gmail.com"
    }
  ],
  "keywords": [
    "node"
  ],
  "dependencies": {},
  "peerDependencies": {},
  "devDependencies": {
    "event-stream": "3.3.1",
    "gulp": "3.9.0",
    "gulp-bump": "0.1.11",
    "gulp-git": "0.5.6",
    "gulp-load-tasks": "0.8.4",
    "gulp-util": "3.0.6",
    "inquirer": "0.8.0",
    "run-sequence": "1.1.2",
    "semver": "5.0.3"
  },
  "license": "MIT",
  "engines": {
    "node": ">=0.11.13",
    "npm": ">=1.4.28"
  }
}

Comme vous pouvez le constater, nous importons bien inquirer, ainsi que semver pour nous permettre de calculer le prochain numéro de version, et de gulp-bump pour modifier les fichiers "package.json", "bower.json" et "npm-shrinkwrap.json", ainsi que gulp-git pour créer un commit Git.

Voyons le fichier "Gulpfile.js," pour voir son usage (qui vous avez le voir, est très simple):

/*eslint-env node *//*global require: true*/
/** * Gulp file declaration */
'use strict';

var gulp = require('gulp');

// Load gulp tasks automaticallyrequire('gulp-load-tasks')('config');

// A very basic default task.gulp.task('default', function () {
    console.log('Logging some stuff...');
});

Et enfin le fichier "gulp-options.js", afin de partager des paramètres entre tâches Gulp (très utile quand vous avez beaucoup de fichiers JS dans le répertoire config, et que vous voulez changer une valeur rapidement):

/*eslint-env node *//*global module: true */
'use strict';

module.exports = {
    'currentProject': './'
};


Si nous regardons les commit Git courant, nous avons:


Voici désormais le contenu de notre tâche "bump":

/*eslint-env node *//*global module: true */
/** * This module will initialize the gulp task for bumping * * @author Julien Roche * @version 1.0 */
'use strict';

// Imports
var    gutil = require('gulp-util'),
    gulp = require('gulp'),
    gulpOptions = require('../gulp-options'),
    bump = require('gulp-bump'),
    git = require('gulp-git'),
    inquirer = require('inquirer'),
    runSequence = require('run-sequence'),
    semver = require('semver');

// Constants
var
    FILES_TO_UPDATE = ['package.json', 'bower.json', 'npm-shrinkwrap.json'];

// Private functions
function _getCurrentVersion() {

    delete require.cache[require.resolve('../package.json')];
    // To load always the current version, not from cache    return require('../package.json').version;
}

// Tasks
gulp.task('bump:interactive', function (callback) {
    var currentVersion = _getCurrentVersion();

    gutil.log('Current Version: ', currentVersion);

    inquirer.prompt(
        [
            {
                'type': 'list',
                'name': 'bump',
                'message': 'What type of bump would you like to do?',
                'choices': ['major', 'minor', 'patch']
            }
        ],
        function (responses) {
            var nextVersion = semver.inc(currentVersion, responses.bump);

            gutil.log('Future Version: ', nextVersion);

            gulp.src(FILES_TO_UPDATE, { 'cwd': gulpOptions.currentProject })
                .pipe(bump({ 'version': nextVersion, 'key': 'version' }))
                .pipe(gulp.dest(gulpOptions.currentProject))
                .on('end', callback);
        }
    );
});

gulp.task('bump:git', function () {
    var currentVersion = _getCurrentVersion();

    gulp.src(FILES_TO_UPDATE, { 'cwd': gulpOptions.currentProject })
        .pipe(git.commit('Version ' + currentVersion));
});

module.exports = function(callback) {
    return runSequence(
        'bump:interactive',
        'bump:git',
        callback
    );
};


Comme vous pouvez le voir, le script est plutôt simple. Tapons maintenant la commande "npm run bump" que nous avons déclaré dans le fichier "package.json" pour voir comment cela réagit:


Le script a détecté que notre version courante est "0.0.1". Nous avons alors un prompt qui nous demande quelle évolution nous souhaitons faire. Nous allons sélectionner "minor", et nous devrions avoir alors la version "0.1.0" dans le fichier "package.json" (vu que nous n'avons de fichier "bower.json", ni "npm-shrinkwrap.json" pour l'instant).


La tâche s'est bien terminé, en mettant bien comme nous l'espérions la bonne version. Si nous analysons les commits Git, nous voyons bien un nouveau commit:


Et si nous regardons le fichier impacté, c'est bien notre fichier "package.json" due à la modification de la propriété "version avec la valeur "0.1.0":



Voilà, c'est une petite tâche Gulp qui est toujours très utile pour nos projets :)



Commentaires

Posts les plus consultés de ce blog

ISO: liens & outils utiles

NodeJs et SSL: une petite analyse

Plusieurs vraies instances de Chrome sur son poste