gruntjs/grunt

Pass callback to grunt.task.run

Opened this issue ยท 42 comments

grunt.task.run runs a task after another has finished. However I need to run a task from within a task and process things after the other task has finished. An API like this would be beautiful:

var done = this.async();
grunt.task.run('some-task', function() {
  // do things after 'some-task' finished
  done();
});

I couldn't find a way to do that with the current API.

EDIT:
What I currently do to solve this problem. I use another internal task which runs before/after my some-task. This internal task is only needed to set some dynamic config and shouldn't be called manually. Usage looks like this:

grunt.task.run('internal-task', 'some-task');
// or
grunt.task.run('some-task', 'internal-task');

FWIW, something similar is planned for v0.5. See #542

+1

๐Ÿ‘

//cc @cowboy

+1

+1

๐Ÿ‘ +1

Yes, please. Gimme two.

Please just hit "Subscribe" rather than reply with "+1" which spams everyone following the thread, thanks.

+1

+1

there should also be an argument with the task completion status code in this "finalize callback" and a possitibility to to avoid interruption of the task flow;

grunt.task.run('some-task', function (status) {
  console.log('some-task completed with status: ' + status);

  return true; // force continue
});

+1

Please just click "Subscribe" on the right instead of replying to +1 (which pings all subscribers), thanks.

I just now finished making grunt-anon-tasks to solve this problem.

grunt.task
  .run("some-task")
  .then(function () {
    // do stuff after "some-task" completes, but before "other-task" begins
  })
  .run("other-task")

Check out the repo to learn more.

+1

๐Ÿ‘

+1

+1

giano commented

+1

+1

๐Ÿ‘

Please just click the subscribe button and use the new emoji feature instead of commenting (@RickBRoss, @MusikAnimal).

I guess those days it would be better to have run method returning Promise, which than can be chained with then and so on.

Besides, mentioned workaround

grunt.task.run('internal-task', 'some-task');
// or
grunt.task.run('some-task', 'internal-task');

Will not work for tests well, because you don't have in internal-task ability to return anything, so you're forced to mangle with stdout or writing a temp file to get a value.

Well, after looking into

Task.prototype.run = function() {

I now see that this isn't that simple as simply passing a callback. task.run is just adding tasks to the queue and knows nothing about what and when will happen.

After some looking closer and testing, it turned out that

grunt.task.run(['youTask`']).start()

is synchronous. So, it is possible to do something like this

    grunt.task.run(['image_size:test']).start()
    console.log(grunt.config(buildPath.test.property))
    expect(readJSON(buildPath.test.dest)).toMatchSnapshot()

However, while it mostly works, it puts Jest in watch mode into an endless loop. I guess it has something to do with the way Grunt exits the process.

Besides, using start() will force Grunt to throw everything directly into the console and there is no straight way to capture the output.

So far I assume that it can be mitigated by introducing callback or promises to start() and passing out stdout as a resolve().

The alternative would be to use process spawning (as here), but while working mostly flawlessly, it has a major drawback โ€” you can't mutate with tasks Grunt's context and access it afterwards. Which is crucial for some tests.

+1