UPDATE
I'm currently using a solution similar to that described here for error notifications, and the 'Current workaround' below (without modifying the grunt force
option) for success notifications.
ORIGINAL QUESTION
I'm having trouble determining when a sub-task run by the grunt-contrib-watch has finished (successfully or not).
Specifically, I'm using grunt-contrib-coffee and grunt watch to compile my CoffeeScript files as they change. The compilation is working fine.
What I would like to do is notify myself of the status of the compilation. Here's what I've tried (all code in CS):
From SO Question (How can I make a Grunt task fail if one of its sub tasks fail?)
What I don't like: setting and restoring a global option seems clunky, especially since it's happening in different tasks / event handlers. Also, I have to delete the destination file every time.
Without setting the global option, I can notify a successful compilation, which is great, but I would like to notify a failed one as well.
grunt.initConfig
watch:
options: nospawn: true
coffee:
files: '<%= coffee.dev.cwd %>/<%= coffee.dev.src %>'
options:
events: ['changed', 'added']
coffee:
dev:
expand: true
cwd: 'app'
src: '**/*.coffee'
dest: 'public'
ext: '.js'
grunt.registerTask 'completedCompile', (srcFilePath, destFilePath) ->
grunt.option 'force', false
if grunt.file.exists( destFilePath )
# notify success
else
# notify failure
grunt.event.on 'watch', (action, filepath) ->
if grunt.file.isMatch grunt.config('watch.coffee.files'), filepath
filepath = # compose source filepath from config options (omitted)
dest = # compose destination filepath from config options (omitted)
if grunt.file.exists( dest )
grunt.file.delete dest # delete the destination file so we can tell in 'completedCompile' whether or not 'coffee:dev' was successful
grunt.option 'force', true # needed so 'completedCompile' runs even if 'coffee:dev' fails
grunt.config 'coffee.dev.src', filepath # compile just the one file, not all watched files
grunt.task.run 'coffee:dev'
grunt.task.run 'completedCompile:'+filepath+':'+dest # call 'completedCompile' task with args
As suggested by another SO Question (Gruntfile getting error codes from programs serially), I used grunt.util.spawn
.
This worked, but it was pretty slow (several seconds every time the CS file is saved).
grunt.event.on 'watch', (action, filepath) ->
if grunt.file.isMatch grunt.config('watch.coffee.files'), filepath
filepath = # compose source filepath from config options (omitted)
dest = # compose destination filepath from config options (omitted)
if grunt.file.exists( dest )
grunt.file.delete dest # delete the destination file so we can tell in 'completedCompile' whether or not 'coffee:dev' was successful
grunt.util.spawn {
grunt: true # use grunt to spawn
args: ['coffee:dev']
options: { stdio: 'inherit' } # print to same stdout
}, -> # coffee:dev finished
if grunt.file.exists( dest )
# notify success
else
# notify error
I tried a slew of things.
grunt.fail.errorcount
(when used in the 'completedCompile' task) is non-zero if previous compilations have failed. (Is it safe to manually reset this to zero? If yes, I wouldn't have to delete the dest file every time.) Even so, this requires setting the global option 'force' to true.grunt.initConfig
doesn't work because the 'coffee:dev' task is run after the 'watch' event handler has completed.grunt.task.current
always refers to the 'watch' task, of course
If you've made it this far, thanks for reading :).
I've also been having the same issue, trying to figure out when a watch sub task is complete.
Part of the problem it seem's is that Watch by default will spawn a new Grunt process to run the sub task. So your main Grunt process won't know about the tasks finishing. You can set 'nospawn' but this doesn't help much as watch doesn't expose the sub task itself.
The nearest I could get to this was using Grunt.util.hooker (inspired by Grunt Notify) to react when the Grunt fail 'report' method is called.
grunt.util.hooker.hook(grunt.fail, 'report', function(){});
However this contains no information on the actual task completed, which would be helpful if you wanted to do something based on specific sub tasks within your watch task.
Looking at the Grunt Watch github there seems to be some traction to implement a complete/fail event: https://github.com/gruntjs/grunt-contrib-watch/issues/131
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With