Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create new submodule update target to run git submodule update #61

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/).
49 changes: 49 additions & 0 deletions lib/command_submodule_update.js
Original file line number Diff line number Diff line change
@@ -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,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a potential problem: if depth is specified and set to zero, then it will not be set in the loop below (since it will be skipped on line 26: if (... options[optionKey])). We can avoid this by changing line 26 to be:

if (options.hasOwnProperty(optionKey) && (options[optionKey] || options[optionKey] === 0))

Alternatively, we could remove depth from this object, and specify it explicitly down where path and noFetch are specified.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been resolved by explicitly filtering out undefined, false and null in the loop below, and allowing 0 to pass through.

recursive: false,
noFetch: false
};

var options = task.options(allowedOptions);

var args = ['submodule', 'update'];


// Loop through allowable cli flags in options and add to args
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where I feel like I've done things differently than you would have, @rubenv ;-)

If you prefer, I am happy to change this to explicitly pushing individual args onto the args array, rather than doing so in a loop.

Notice that we are looping through allowedOptions, not options. This will ensure that only the supported options are added to the args array.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it's cool, it cuts back on the amount of lines. Might be a good future improvement to convert all binary options everywhere to a logic similar to this.

We'd need to handle dashes: no-merge -> noMerge.

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.';
3 changes: 2 additions & 1 deletion lib/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -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')
};
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,8 @@
},
"keywords": [
"gruntplugin"
]
],
"dependencies": {
"underscore.string": "~2.3.3"
}
}
115 changes: 115 additions & 0 deletions test/submodule_update_test.js
Original file line number Diff line number Diff line change
@@ -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);
});
});