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):
Current workaround
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
Another option (so slow)
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
Other attempts
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.- Anything involving specifying the 'watch.coffee.tasks' options in
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 :).