diff --git a/README.md b/README.md index 9450126..25a6653 100644 --- a/README.md +++ b/README.md @@ -704,5 +704,106 @@ Default value: none. Without an optional `path` parameter, all files and subdirectories of the current working directory are included in the archive. If one or more paths are specified, only these are included. + + +## The "gitsubmoduleupdate" task + +Updates submodules in the repository (via git submodule update). + +### Overview +In your project's Gruntfile, add a section named `gitsubmoduleupdate` to the data object passed into `grunt.initConfig()`. + +```js +grunt.initConfig({ + gitsubmoduleupdate: { + your_target: { + options: { + // Target-specific options go here. + } + } + } +}) +``` + +### Options + +More detailed descriptions of these options are available at http://git-scm.com/docs/git-submodule. + +#### options.init +Type: `boolean` +Default value: `false` + +Initialize all submodules for which "git submodule init" has not been called so far before updating. + +#### options.remote +Type: `Boolean` +Default value: `false` + +Instead of using the superproject's recorded SHA-1 to update the submodule, use the status of the submodule's remote-tracking branch. + +#### options.force +Type: `Boolean` +Default value: `false` + +Throw away local changes in submodules when switching to a different commit. + +#### options.rebase +Type: `Boolean` +Default value: `false` + +Rebase the current branch onto the commit recorded in the superproject. + +#### options.merge +Type: `Boolean` +Default value: `false` + +Merge the commit recorded in the superproject into the current branch of the submodule. + +#### options.reference +Type: `String` +Default value: `null` + +This option will be passed to the ``git-clone()`` command used during an *update --init* + +#### options.recursive +Type: `Boolean` +Default value: `false` + +Traverse submodules recursively. + +#### options.depth +Type: `Integer` +Default value: `null` + +Create a 'shallow' clone with a history truncated to the specified number of revisions. + +#### options.path +Type: `String` +Default value: `null` + +path to the submodule to be updated. All submodules will be updated if path is not specified. + +#### options.noFetch +Type: `Boolean` +Default value: `false` + +Don't fetch new objects from the remote site. + +### Usage Examples + +```js +grunt.initConfig({ + gitsubmoduleupdate: { + task: { + options: { + init: true, + recursive: true + } + } + } +}); +``` + + ## Contributing In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [Grunt](http://gruntjs.com/). diff --git a/lib/command_submodule_update.js b/lib/command_submodule_update.js new file mode 100644 index 0000000..3a6685c --- /dev/null +++ b/lib/command_submodule_update.js @@ -0,0 +1,49 @@ +'use strict'; + +var async = require('grunt').util.async; +var grunt = require('grunt'); +var stringUtil = require('underscore.string'); + +module.exports = function (task, exec, done) { + var optionKey; + var allowedOptions = { + init: false, + remote: false, + force: false, + rebase: false, + merge: false, + reference: null, + depth: null, + recursive: false, + noFetch: false + }; + + var options = task.options(allowedOptions); + + var args = ['submodule', 'update']; + + + // Loop through allowable cli flags in options and add to args + for (optionKey in allowedOptions) { + if (options[optionKey] !== undefined && options[optionKey] !== null && options[optionKey] !== false) { + // Add flag + args.push('--' + stringUtil.dasherize(optionKey)); + // If not a boolean, add the value after the flag + if (typeof options[optionKey] !== 'boolean') { + args.push(options[optionKey]); + } + } + } + + // If a path was specified, add it now: + if (options.path) { + args.push(options.path); + } + + // Add callback + args.push(done); + + exec.apply(this, args); +}; + +module.exports.description = 'Update git submodules.'; diff --git a/lib/commands.js b/lib/commands.js index b45cf29..5e5b3c8 100644 --- a/lib/commands.js +++ b/lib/commands.js @@ -10,5 +10,6 @@ module.exports = { rebase: require('./command_rebase'), reset: require('./command_reset'), stash: require('./command_stash'), - tag: require('./command_tag') + tag: require('./command_tag'), + submoduleupdate: require('./command_submodule_update') }; diff --git a/package.json b/package.json index 406f28c..d7b3c5c 100644 --- a/package.json +++ b/package.json @@ -42,5 +42,8 @@ }, "keywords": [ "gruntplugin" - ] + ], + "dependencies": { + "underscore.string": "~2.3.3" + } } diff --git a/test/submodule_update_test.js b/test/submodule_update_test.js new file mode 100644 index 0000000..a5fc91d --- /dev/null +++ b/test/submodule_update_test.js @@ -0,0 +1,115 @@ +'use strict'; + +var command = require('../lib/commands').submoduleupdate; +var Test = require('./_common'); + +describe('submodule update', function () { + it('should update submodules', function (done) { + var options = { + }; + + new Test(command, options) + .expect(['submodule', 'update']) + .run(done); + }); + + it('should accept init option', function (done) { + var options = { + init: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--init']) + .run(done); + }); + + it('should accept remote option', function (done) { + var options = { + remote: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--remote']) + .run(done); + }); + + it('should accept no-fetch option', function (done) { + var options = { + noFetch: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--no-fetch']) + .run(done); + }); + + it('should accept force option', function (done) { + var options = { + force: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--force']) + .run(done); + }); + + it('should accept rebase option', function (done) { + var options = { + rebase: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--rebase']) + .run(done); + }); + + it('should accept merge option', function (done) { + var options = { + merge: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--merge']) + .run(done); + }); + + it('should accept reference option', function (done) { + var options = { + reference: 'https://myrepo.com/repo.git' + }; + + new Test(command, options) + .expect(['submodule', 'update', '--reference', 'https://myrepo.com/repo.git']) + .run(done); + }); + + it('should accept depth option', function (done) { + var options = { + depth: 0 + }; + + new Test(command, options) + .expect(['submodule', 'update', '--depth', '0']) + .run(done); + }); + + it('should accept recursive option', function (done) { + var options = { + recursive: true + }; + + new Test(command, options) + .expect(['submodule', 'update', '--recursive']) + .run(done); + }); + + it('should accept path option', function (done) { + var options = { + path: '/test/path' + }; + + new Test(command, options) + .expect(['submodule', 'update', '/test/path']) + .run(done); + }); +});