Grunt – task pro automatický release nové verze

Dělám na několika doplňcích pro WordPress. Kámen úrazu je verzování. S vydáním nové verze jsem musel přepisovat verzi ve zdrojovém kódu, vytvořit nový tag v Gitu a tuto změnu commitnout a pushnout. Ale protože jsem lajdák vždy jsem na něco zapoměl…

Při vydání nové verze dělám:

  • nastavit novou verzi ve zdrojových souborech ( Version: 0.0.1 => Version: 0.0.2 )
  • coomitnout tuto změnu
  • vytvořit nový tag ( 0.0.2 )
  • pushnout tyto změny

To jsem dělal ručně do doby než jsem poznal Grunt. Nyní mám tento proces automatizovaný a tuto nudnou opičí práci za mne udělá Grunt.

Pojďme si ukázat jak. Předpokládejme nainstalovaný Grunt (o instalaci Gruntu zase někdy jindy).

Vytvoříme soubor package.json:

npm init

Nainstalujeme grunt-version:

npm install grunt-version --save-dev

Vytvoříme soubor Gruntfile.js:

module.exports = function(grunt) {
   grunt.loadNpmTasks('grunt-version');
 
   grunt.initConfig({
      version: {
         php: {
            options: {
               prefix: '\Version:\\s+'
            },
            src: [ 'my-file.php' ]
         }
      }
   });

   // Release task
   grunt.registerTask( 'release', [ 'version' ]); 
};

Příkazem grunt release nastavíme v souboru my-file.php novou verzi uvedenou v package.json:

Version:           0.0.1 se změní na verzi zadanou v souboru package.json

To je solidní základ 🙂 Ale mne to nestačí. Verzi kterou chci vydat musím zapsat do souboru package.json a příliš práce to za mne neudělá…

Dělám různé releasy:

  • patch (1.2.X)
  • minor (1.X.0)
  • major (X.0.0)

Pojďmě si napsat script který bude automaticky zvyšovat verzi v souboru package.json v závislosti na vydávané verzi. Vužijeme modul grunt-update-json

npm install grunt-update-json --save-dev

Použijeme tento kód:

module.exports = function(grunt) {

   grunt.loadNpmTasks('grunt-version');
	
   grunt.initConfig({
      pkg: grunt.file.readJSON( 'package.json' ),
         version: {
            php: {
               options: {
                  prefix: '\Version:\\s+'
               },
                  src: [ 'my-file.php' ]
               }
            }
         });
         // Release task		
         grunt.registerTask('release:patch', 'Release patch version', function( target ) {
            release( "patch" );
         });

         grunt.registerTask('release:minor', 'Release minor version', function( target ) {
            release( "minor" );
         });

         grunt.registerTask('release:major', 'Release major version', function( target ) {
            release( "major" );
         });

         function release( type )
         {
            var version = grunt.config.data.pkg.version;
            var aVersion = version.split(".");
            if( type == "patch" )
            {
               aVersion[ 2 ] = ( 1 * aVersion[ 2 ] ) + 1;
            }
            else if( type == "minor" )
            {
               aVersion[ 2 ] = 0;
               aVersion[ 1 ] = ( 1 * aVersion[ 1 ] ) + 1;
            }
               else if( type == "major" )
            {
               aVersion[ 2 ] = 0;
               aVersion[ 1 ] = 0;
               aVersion[ 0 ] = ( 1 * aVersion[ 0 ] ) + 1;
            }
            var newVersion = aVersion.join(".");
            grunt.log.writeln('Release ' + type + ' version: ' + version + ' => ' + newVersion );

            //save new version to package.json
            grunt.config.data.pkg.version = newVersion;		
            grunt.file.write( './package.json', JSON.stringify( grunt.config.data.pkg, null, '  ') + '\n');
		
            //change version in source code
            grunt.task.run(['version']);
		
            //@TODO commit
            //@TODO create TAG
            //@TODO push
         }
};

To už je lepší. Můžeme použít následující příkaz:

  • grunt release:patch
  • grunt release:minor
  • grunt release:major

K dokonalosti chybí pouze commit, vytvořit tag s novou verzí a push. K tomu využijeme grunt-git

npm install grunt-git --save-dev

Do souboru package.json přidáme následující kód:

gitcommit: {
   version: {
      options: {
         message: 'New version: <%= pkg.version %>'
      },
      files: {
         // Specify the files you want to commit
         src: ['my-file.php', 'package.json']
      }
   }
},
gittag: {
   version: {
      options: {
         tag: '<%= pkg.version %>',
         message: 'Tagging version <%= pkg.version %>'
      }
   }
},
gitpush: {
   version: {},
   tag: {
      options: {
         tags: true
      }
   }
},

Celý kód nakonec vypadá takto:

module.exports = function(grunt) {

   grunt.loadNpmTasks('grunt-version');
   grunt.loadNpmTasks('grunt-git');
	
   grunt.initConfig({
      pkg: grunt.file.readJSON( 'package.json' ),
         version: {
            php: {
               options: {
                  prefix: '\Version:\\s+'
               },
               src: [ 'my-file.php' ]
            }
         },
         gitcommit: {
            version: {
               options: {
                  message: 'New version: <%= pkg.version %>'
               },
               files: {
                  src: ['my-file.php', 'package.json']
               }
            }
         },
         gittag: {
            version: {
               options: {
                  tag: '<%= pkg.version %>',
                  message: 'Tagging version <%= pkg.version %>'
               }
            }
         },
         gitpush: {
            version: {},
            tag: {
               options: {
                  tags: true
               }
            }
         }		
      });

      grunt.registerTask('release:patch', 'Release patch version', function( target ) {
         release( "patch" );
      });

      grunt.registerTask('release:minor', 'Release minor version', function( target ) {
         release( "minor" );
      });

      grunt.registerTask('release:major', 'Release major version', function( target ) {
         release( "major" );
      });

      function release( type )
      {
         var version = grunt.config.data.pkg.version;
         var aVersion = version.split(".");
         if( type == "patch" )
         {
            aVersion[ 2 ] = ( 1 * aVersion[ 2 ] ) + 1;
         }
         else if( type == "minor" )
         {
            aVersion[ 2 ] = 0;
            aVersion[ 1 ] = ( 1 * aVersion[ 1 ] ) + 1;
         }
         else if( type == "major" )
         {
            aVersion[ 2 ] = 0;
            aVersion[ 1 ] = 0;
            aVersion[ 0 ] = ( 1 * aVersion[ 0 ] ) + 1;
         }
         var newVersion = aVersion.join(".");
         grunt.log.writeln('Release ' + type + ' version: ' + version + ' => ' + newVersion );

         //save new version to package.json
         grunt.config.data.pkg.version = newVersion;		
         grunt.file.write( './package.json', JSON.stringify( grunt.config.data.pkg, null, '  ') + '\n');
		
         //change version in source code
         grunt.task.run(['version']);
		
         //git commit
         grunt.task.run(['gitcommit:version']);
         //git create TAG
         grunt.task.run(['gittag:version']);
         //git push
         grunt.task.run(['gitpush']);
      }
};