Pass params to an grunt task from an alias task - gruntjs

Is there a way to pass an argument from a alias task like this into on of the calling tasks:
grunt.registerTask('taskA', ['taskB', 'taskC'])
grunt taskA:test
so that task taskB and taskC will be called with the parameter test?

You can create a dynamic alias task like this:
grunt.registerTask('taskA', function(target) {
var tasks = ['taskB', 'taskC'];
if (target == null) {
grunt.warn('taskA target must be specified, like taskA:001.');
}
grunt.task.run.apply(grunt.task, tasks.map(function(task) {
return task + ':' + target;
}));
});
Here is the FAQ with another example in the Grunt docs: http://gruntjs.com/frequently-asked-questions#dynamic-alias-tasks

Related

Run parametrized task using grunt.task.run(taskname)

I did stackoverflow search and looked at Grunt API docs but couldn't find a way to run a parametrized task using grunt.task.run(taskname).
I have a simple task which accepts a parameter and prints the message on console:
grunt.registerTask('hello', 'greeting task', function(name) {
if(!name || !name.length)
grunt.warn('you need to provide a name');
console.log('hello ' + name + '!');
});
I call the above task using below task which validates the task and if task exists then it runs it:
grunt.registerTask('validateandruntask', 'if task available then run given task', function(taskname) {
if(!taskname || !taskname.length) {
grunt.warn('task name is needed to run this task');
}
if(!grunt.task.exists(taskname)) {
grunt.log.writeln('this task does not exist!');
} else {
grunt.log.writeln(taskname + ' exists. Going to run this task');
grunt.task.run(taskname);
}
});
Now from command line, I am passing 'hello' task as parameter to 'validateandruntask' but I am not been able to pass the parameter to 'hello' task from command line:
This is what I tried on command line but it didn't work:
grunt validateandruntask:hello=foo
grunt validateandruntask:hello:param=name
First thing, the way to pass an arg through the command line is to use :.
For example to call hello directly:
grunt hello:you
To call it with multiple arguments, just separate them by :, like
grunt hello:mister:president
And to use these multiple arguments in the task, you do the same as plain Javascript: use arguments (all details here):
grunt.registerTask('hello', 'greeting task', function(name) {
if(!name || !name.length)
grunt.warn('you need to provide a name');
// unfortunately arguments is not an array,
// we need to convert it to use array methods like join()
var args = Array.prototype.slice.call(arguments);
var greet = 'hello ' + args.join(' ') + '!';
console.log(greet);
});
Then you want to call grunt validateandruntask:hello:mister:president, and modify your code to handle the variable parameters as well:
grunt.registerTask('validateandruntask', 'if task available then run given task', function(taskname) {
if(!taskname || !taskname.length) {
grunt.fail.fatal('task name is needed to run this task');
}
var taskToCall = taskname;
for(var i = 1; i < arguments.length; i++) {
taskToCall += ':' + arguments[i];
}
console.log(taskToCall);
if(!grunt.task.exists(taskname)) {
grunt.log.writeln('this task does not exist!');
} else {
grunt.log.writeln(taskname + ' exists. Going to run this task');
grunt.task.run(taskToCall);
}
});

Run a command after a grunt task finishes?

I want to run a command but after a task finishes in grunt.
uglify: {
compile: {
options: {...},
files: {...}
}
?onFinish?: {
cmd: 'echo done!',
// or even just a console.log
run: function(){
console.log('done!');
}
}
},
Either run a command in shell, or even just be able to console.log. Is this possible?
Grunt does not support before and after callbacks, but next version could implement events that would work in the same way, as discussed in issue #542.
For now, you should go the task composition way, this is, create tasks for those before and after actions, and group them with a new name:
grunt.registerTask('newuglify', ['before:uglify', 'uglify', 'after:uglify']);
Then remember to run newuglify instead of uglify.
Another option is not to group them but remember to add the before and after tasks individually to a queue containing uglify:
grunt.registerTask('default', ['randomtask1', 'before:uglify', 'uglify', 'after:uglify', 'randomtask2']);
For running commands you can use plugins like grunt-exec or grunt-shell.
If you only want to print something, try grunt.log.
The grunt has one of the horrible code that I've ever seen. I don't know why it is popular. I would never use it even as a joke. This is not related to "legacy code" problem. It is defected by design from the beginning.
var old_runTaskFn = grunt.task.runTaskFn;
grunt.task.runTaskFn = function(context, fn, done, asyncDone) {
var callback;
var promise = new Promise(function(resolve, reject) {
callback = function (err, success) {
if (success) {
resolve();
} else {
reject(err);
}
return done.apply(this, arguments);
};
});
something.trigger("new task", context.name, context.nameArgs, promise);
return old_runTaskFn.call(this, context, fn, callback, asyncDone);
}
You can use callback + function instead of promise + trigger. This function will request the new callback wrapper for new task.

How to extract common code from gradle jar task to a mthod

I have two task nativeJar and native64Jar, manifest and doLast closers are same for both the tasks except the file names. So is It possible to extract that code in a common method and pass two file names as a method parameter and call that common method from both tasks or call that method from dolast clouser.
task nativeJar( type: Jar ) {
doFirst {
delete fileTree(dir: "$releaseDir", include: "*.jar")
}
baseName = 'NativeLibs'
destinationDir = new File(releaseDir)
from files(releaseDir + 'jar_merge/signedNativeLibs')
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'abc', 'Application-Name' : 'WorkBench', 'Codebase' : '*.abc.com'
}
doLast {
ant.signjar( jar: "$releaseDir/NativeLibs.jar", alias:"WorkBench", keystore: "WorkBench.jks", signedjar: "$releaseDir/signedNativeLibs.jar", storepass: "freddie" )
}
}
// Create signedNativeLibs64.jar file
task native64Jar( type: Jar , dependsOn: 'nativeJar' ) {
baseName = 'NativeLibs64'
destinationDir = new File(releaseDir)
from files(releaseDir + 'jar_merge/signedNativeLibs64')
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'abc', 'Application-Name' : 'WorkBench', 'Codebase' : '*.abc.com'
}
doLast {
ant.signjar( jar: "$releaseDir/NativeLibs64.jar", alias:"WorkBench", keystore: "WorkBench.jks", signedjar: "$releaseDir/signedNativeLibs64.jar", storepass: "freddie" )
}
}
I would recommend splitting out the signing as a separate task so that you get proper up-to-date checks from Gradle. As you have it now, you'll always sign the jar every time you build. And if you delete the signed jar, it won't generate again until you clean the native jar too.
You can share configuration closures between tasks. E.g.,
[ task1, task2 ].each { task ->
task.configure {
// shared closure
}
}
There are a few other best practices I'd follow.
Don't use new File() since it makes your script dependent on the current working directory.
Refer to outputs via the task versus recreating the full path (e.g., what you're doing with $releaseDir/NativeLibs.jar). Gradle is able to infer dependencies that way.
Use a custom task class vs an ad-hoc task with doFirst()/doLast(). Since you're delegating all the work to the ant task, this should be really simple.
I'm not sure why you need your particular file names, but I left them as-is. If they're not important, removing them would make this even simpler.
I took a stab at your example (disclaimer: I didn't try it):
task nativeJar( type: Jar ) {
baseName = 'NativeLibs'
from files(releaseDir + 'jar_merge/signedNativeLibs')
}
task native64Jar( type: Jar ) {
baseName = 'NativeLibs64'
from files(releaseDir + 'jar_merge/signedNativeLibs64')
}
[ nativeJar, native64Jar ].each { task ->
task.configure {
destinationDir = file(releaseDir)
manifest {
attributes 'Permissions' : 'all-permissions', 'Publisher' : 'Financial Engineering', 'Application-Name' : 'WorkBench', 'Codebase' : '*.fhlmc.com'
}
}
}
// this class definition should go at the top of your build.gradle script else it will through an exception mentioned in comments
class SignJarTask extends DefaultTask {
#InputFile File inputFile
#OutputFile File outputFile
#TaskAction
void signJar() {
ant.signjar( jar: inputFile, alias:"WorkBench", keystore: "WorkBench.jks", signedjar: outputFile, storepass: "freddie" )
}
}
task signJar(type: SignJarTask) {
inputFile = file("$releaseDir/NativeLibs.jar")
outputFile = file("$releaseDir/signedNativeLibs.jar")
}
task sign64Jar(type: SignJarTask) {
inputFile = file("$releaseDir/NativeLibs64.jar")
outputFile = file("$releaseDir/signedNativeLibs64.jar")
}

passing grunt parameters from one task to another

I'm trying to pass the configuration values returned from the server(zookeeper) into compass (cdnHost, environment, etc) and seem to be having a hard time using the right approach.
I looked at ways to pass around args from one task to another on this page as a starting point
http://gruntjs.com/frequently-asked-questions#how-can-i-share-parameters-across-multiple-tasks
module.exports = function(grunt) {
grunt.initConfig({
compass: {
dist: {
//options: grunt.option('foo')
//options: global.bar
options: grunt.config.get('baz')
}
},
...
grunt.registerTask('compassWithConfig', 'Run compass with external async config loaded first', function () {
var done = this.async();
someZookeeperConfig( function () {
// some global.CONFIG object from zookeeper
var config = CONFIG;
// try grunt.option
grunt.option('foo', config);
// try config setting
grunt.config.set('bar', config);
// try global
global['baz'] = config;
done(true);
});
});
...
grunt.registerTask('default', ['clean', 'compassWithConfig', 'compass']);
I also tried calling the compass task directly, and it made no difference.
grunt.task.run('compass');
Any insights would be greatly appreciated. (e.g. way to use initConfig and have the value be available).
Thanks
When you write:
grunt.initConfig({
compass: {
dist: {
options: grunt.config.get('baz')
}
}
... grunt.config is called right away, and returns the value of baz as it is right now. Altering it (later) in another task simply won't get picked-up.
How to solve that?
#1: update compass.dist.options instead of updating baz
grunt.registerTask('compassWithConfig', 'Run compass with external async config loaded first', function () {
var done = this.async();
someZookeeperConfig( function () {
// some global.CONFIG object from zookeeper
var config = CONFIG;
grunt.config.set('compass.dist.options', config);
done();
});
});
Now, running task compassWithConfig first, then task compass will get the result you expect.
#2: wrap-up compass task execution in order to abstract away config mapping
grunt.registerTask('wrappedCompass', '', function () {
grunt.config.set('compass.dist.options', grunt.config.get('baz'));
grunt.task.run('compass');
});
// Then, you can manipulate 'baz' without knowing how it needs to be mapped for compass
grunt.registerTask('globalConfigurator', '', function () {
var done = this.async();
someZookeeperConfig( function () {
// some global.CONFIG object from zookeeper
var config = CONFIG;
grunt.config.set('baz', config);
done();
});
});
Finally, running task globalConfigurator then wrappedCompass will get you to the result.

Lazily evaluate Grunt task options

I have the following Grunt tasks (simplified):
rev: {
files: {
src: ['dist/**/*.{js,css}']
}
},
processhtml: {
dev: {
options: {
data: {
appJs: grunt.file.expand('dist/**/*.js')
}
},
files: {
'dist/index.html': 'app/index.html'
}
}
}
The grunt-rev task is run first, which takes regular JS and prepends a hash code to the filename. Then the grunt-processhtml task is run, which for this case I want to get all JS filenames generated by grunt-rev, and pass them as custom data.
The issue with this code is it seems the grunt.file.expand method is eagerly executed when the gruntfile is first executed, and not when the processhtml task is run, so it means I get a different list of files from grunt.file.expand than I would expect, as it doesn't take into account the result from the grunt-rev task.
Is there a way to force lazy evaluation of a value when a task is actually run?
I would define a custom task that would (when called) set options for the processhtml task and run it.
Something in the line of:
grunt.task.registerTask('foo', 'My foo task.', function() {
grunt.config("processhtml.dev", {
options: {
data: {
appJsgrunt: file.expand('dist/**/*.js')
}
}
});
grunt.task.run("processhtml.dev");
});

Resources