문제

I'm trying to set the current Git SHA in my project's Grunt configuration, but when I try to access it from another task it isn't available, What am I missing?

grunt.registerTask('sha', function () {
  var done   = this.async();

  grunt.util.spawn({
    cmd: 'git',
    args: ['rev-parse', '--short', 'HEAD']
  }, function (err, res) {
    if (err) {
      grunt.fail.fatal(err);
    } else {
      grunt.config.set('git', {sha: res.stdout});
      if (grunt.option('debug') || grunt.option('verbose')) {
        console.log("[sha]:", res.stdout);
      }
    }
    done();
  });
});

After running the task, I expect the config to be available in another task configuration:

requirejs: {
  dist: {
    ...
    out: '<%= app.dist %>/scripts/module_name.<%= git.sha %>.js'
    ...
  }
}

So... What's the problem?

The problem is that Require JS is writing to the file public/scripts/module_name..js, the SHA is not available in the configuration (when the filename should be public/scripts/module_name.d34dc0d3.js).

UPDATE:

The problem is that I'm running requirejs tasks with grunt-concurrent, so the Grunt configuration is not available for requirejs.

grunt.registerTask('build', [
  ...
  'getsha',
  'concurrent:dist',
  ...
]);

And the concurrent task, looks like:

concurrent: {
  dist: [
    ...
    'requirejs',
    ...
  ]
}
도움이 되었습니까?

해결책

Since grunt-concurrent will spawn tasks in child processes, they do not have access to the context of the parent process. Which is why doing grunt.config.set() within the parent context is not available in the config of the child context.

Some of the solutions to make the change available in the child context are:

Write the data to the file system
Write the data to a temporary file with grunt.file.write('./tmp/gitsha', res.stdout) and then have the task being ran in a child process read the temporary file:

out: (function() {
  var out = grunt.config('app.dist') + '/scripts/module_name.';
  if (grunt.file.exists('./tmp/gitsha')) {
    out += grunt.file.read('./tmp/gitsha');
  } else {
    out += 'unknown';
  }
  return out + '.js';
}())

Use a socket
This is a very convoluted solution but a solution nonetheless. See the net node docs: http://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener on creating a server on the parent process then have the child process connect to the socket for the data.

Or check out https://github.com/shama/blackbox for a library that makes this method a bit simpler.

Fork the parent process instead of spawn/exec
Another method is to use fork: http://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options instead of grunt-concurrent. Fork lets you send messages to child processes with child.send('gitsha') and receive them in the child with process.on('message', function(gitsha) {})

This method also can get very convoluted.

Use a proxy task
Have your sha task set the config as you're currently doing:

grunt.registerTask('sha', function() {
  grunt.config.set('git', { sha: '1234' });
});

Change your concurrent config to call a proxy task with the sha:

grunt.initConfig({
  concurrent: {
    dist: [
      'proxy:requirejs:<%= git.sha %>'
    ]
  }
});

Then create a proxy task that runs a task with setting the passed value first:

grunt.registerTask('proxy', function(task, gitsha) {
  grunt.config.set('git', { sha: gitsha });
  grunt.task.run(task);
});

The above can be simplified to set values specifically on requirejs but just shown here as a generic example that can be applied with any task.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top