Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running grunt-contrib-jshint only on recently modified files

We're going through refactoring the code on a very large site. I would like to enforce linting on any files that get changed, but ignore the rest (as many of them will end up being removed so it's a waste of time to tidy them up).

I would like to have a grunt task that checks that a file's modified date is more recent than its created (*fetched from repo) date and lints it if this is the case (would be good also to have grunt update a json list of files to be linted).

I haven't used node much apart from grunt and its plugins. I'm going to use http://gruntjs.com/creating-tasks as a starting point, but could someone sketch out for me how I might approach writing this task, in particular any considerations to do with asynchronisity.

like image 463
wheresrhys Avatar asked Dec 21 '22 03:12

wheresrhys


1 Answers

A couple options:

1 - You can use a custom filter function to filter the list of files returned by your jshint file pattern. Something like this:

module.exports = function(grunt) {
  var fs = require('fs');

  var myLibsPattern = ['./mylibs/**/*.js'];

  // on linux, at least, ctime is not retained after subsequent modifications,
  // so find the date/time of the earliest-created file matching the filter pattern
  var creationTimes = grunt.file.expand( myLibsPattern ).map(function(f) { return new Date(fs.lstatSync(f).ctime).getTime() });
  var earliestCreationTime = Math.min.apply(Math, creationTimes);
  // hack: allow for 3 minutes to check out from repo
  var filterSince = (new Date(earliestCreationTime)).getTime() + (3 * 60 * 1000);

  grunt.initConfig({
    options: {
      eqeqeq: true,
      eqnull: true
    },
    jshint: {
      sincecheckout: {
        src: myLibsPattern,
        // filter based on whether it's newer than our repo creation time
        filter: function(filepath) {
          return (fs.lstatSync(filepath).mtime > filterSince);
        },
      },
    },
  });

  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.registerTask('default', ['jshint']);
};

2 - use the grunt-contrib-watch plugin to detect when files are changing. Then you can read the list of files from the event, as described in this comment by Kyle Robinson Young ("shama"):

grunt.initConfig({
  watch: {
    all: {
      files: ['<%= jshint.all.src %>'],
      tasks: ['jshint'],
      options: { nospawn: true }
    }
  },
  jshint: { all: { src: ['Gruntfile.js', 'lib/**/*.js'] } }
});
// On watch events, inject only the changed files into the config
grunt.event.on('watch', function(action, filepath) {
  grunt.config(['jshint', 'all', 'src'], [filepath]);
});

This doesn't exactly meet your requirements since it depends on having the watch running as soon as you start modifying files, but it might fit better with the overall Grunt approach.

See also this question but beware some of it relates to older version of Grunt and to coffeescript.

UPDATE: there's now a grunt-newer plugin which handles all this in a more elegant way

like image 149
explunit Avatar answered Dec 28 '22 03:12

explunit