Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Gulp 3.9.1 and 4.0.0, Node.js 10 #64

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
language: node_js
node_js:
- "0.10"
- "0.11"
- "node"
- "lts/*"
script:
- "node_modules/.bin/gulp lint"
- "npm test"
- "printf 'Finished testing with Gulp v4; now testing with Gulp v3\n' && npm install gulp@3 && npm test"
96 changes: 73 additions & 23 deletions bin/slush.js
Original file line number Diff line number Diff line change
@@ -16,6 +16,7 @@ var versionFlag = argv.v || argv.version;
var params = argv._.slice();
var generatorAndTasks = params.length ? params.shift().split(':') : [];
var generatorName = generatorAndTasks.shift();
var tasks = generatorAndTasks;

if (!generatorName) {
if (versionFlag) {
@@ -34,11 +35,6 @@ if (!generator) {
process.exit(1);
}

// Setting cwd and slushfile dir:
argv.cwd = process.cwd();
argv.slushfile = path.join(generator.path, 'slushfile.js');
argv._ = generatorAndTasks;

var cli = new Liftoff({
processTitle: 'slush',
moduleName: 'gulp',
@@ -54,13 +50,14 @@ cli.on('requireFail', function(name) {
gutil.log(chalk.red('Failed to load external module'), chalk.magenta(name));
});

cli.launch(handleArguments, argv);
cli.launch({
// Setting cwd and slushfile dir:
cwd: process.cwd(),
configPath: path.join(generator.path, 'slushfile.js')
}, handleArguments);

function handleArguments(env) {

var argv = env.argv;
var tasksFlag = argv.T || argv.tasks;
var tasks = argv._;
var toRun = tasks.length ? tasks : ['default'];
var args = params;

@@ -102,8 +99,31 @@ function handleArguments(env) {
process.nextTick(function() {
if (tasksFlag) {
return logTasks(generator.name, gulpInst);
} else if (gulpInst.start) {
// Gulp <= 3.9.1 (gulp.start() is unsupported and breaks under Node 10)
return gulpInst.start.apply(gulpInst, toRun);
}
gulpInst.start.apply(gulpInst, toRun);
runGulpV4Tasks(gulpInst, toRun);
});
}

// For Gulp 4, we have to bind gulpInst to task functions individually. We
// trigger our own `task_not_found` and `finished` events to maintain the same
// Slush interface between Gulp versions (rather than relying on the default
// Gulp 4 behavior).
function runGulpV4Tasks(gulpInst, toRun) {
toRun.forEach(function(task) {
var gulpTask = gulpInst.task(task);
if (gulpTask === undefined) {
gulpInst.emit('task_not_found', { task: task });
}
gulpInst.task(task, gulpTask.bind(gulpInst));
});
gulpInst.parallel(toRun)(function(err) {
if (err) {
process.exit(1);
}
gulpInst.emit('finished');
});
}

@@ -121,7 +141,8 @@ function logGenerators(generators) {
}

function logTasks(name, localGulp) {
var tree = taskTree(localGulp.tasks);
// Gulp <= 3.9.1 uses gulp.tasks; Gulp >= 4.0.0 uses gulp.tree().
var tree = localGulp.tasks ? taskTree(localGulp.tasks) : localGulp.tree();
tree.label = 'Tasks for generator ' + chalk.magenta(name);
archy(tree).split('\n').forEach(function(v) {
if (v.trim().length === 0) return;
@@ -131,38 +152,67 @@ function logTasks(name, localGulp) {

// format orchestrator errors
function formatError(e) {
if (!e.err) return e.message;
if (e.err.message) return e.err.message;
return JSON.stringify(e.err);
var err = e.err || e.error;
if (!err) return e.message;
if (err.message) return err.message;
return JSON.stringify(err);
}

// wire up logging events
function logEvents(name, gulpInst) {
gulpInst.on('task_start', function(e) {
gutil.log('Starting', "'" + chalk.cyan(name + ':' + e.task) + "'...");
var names = getEventNames(gulpInst);

gulpInst.on(names.task_start, function(e) {
gutil.log('Starting', "'" + chalk.cyan(name + ':' + taskName(e)) + "'...");
});

gulpInst.on('task_stop', function(e) {
var time = prettyTime(e.hrDuration);
gutil.log('Finished', "'" + chalk.cyan(name + ':' + e.task) + "'", 'after', chalk.magenta(time));
gulpInst.on(names.task_stop, function(e) {
gutil.log('Finished', "'" + chalk.cyan(name + ':' + taskName(e)) + "'", 'after', chalk.magenta(taskDuration(e)));
});

gulpInst.on('task_err', function(e) {
gulpInst.on(names.task_error, function(e) {
console.error('ERR', e);
var msg = formatError(e);
var time = prettyTime(e.hrDuration);
gutil.log("'" + chalk.cyan(name + ':' + e.task) + "'", 'errored after', chalk.magenta(time), chalk.red(msg));
gutil.log("'" + chalk.cyan(name + ':' + taskName(e)) + "'", 'errored after', chalk.magenta(taskDuration(e)), chalk.red(msg));
});

gulpInst.on('task_not_found', function(err) {
log(chalk.red("Task '" + err.task + "' was not defined in `slush-" + name + "` but you tried to run it."));
process.exit(1);
});

gulpInst.on('stop', function () {
gulpInst.on(names.finished, function () {
log('Scaffolding done');
});
}

function taskName(event) {
return event.task || event.name;
}

function taskDuration(event) {
return prettyTime(event.hrDuration || event.duration);
}

function getEventNames(gulpInst) {
if (gulpInst.tasks) {
// Gulp v3.9.1 and earlier
return {
task_start: 'task_start',
task_stop: 'task_stop',
task_error: 'task_err',
finished: 'stop'
};
}
// Gulp v4.0.0 and later
return {
task_start: 'start',
task_stop: 'stop',
task_error: 'error',
finished: 'finished'
};
}

function getGenerator (name) {
return getAllGenerators().filter(function (gen) {
return gen.name === name;
8 changes: 6 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
@@ -7,6 +7,10 @@ var jshint = require('gulp-jshint');

var codeFiles = ['**/*.js', '!node_modules/**'];

function taskSpec(tasks) {
return gulp.parallel ? gulp.parallel(tasks) : tasks;
}

gulp.task('lint', function() {
log('Linting Files');
return gulp.src(codeFiles)
@@ -16,7 +20,7 @@ gulp.task('lint', function() {

gulp.task('watch', function() {
log('Watching Files');
gulp.watch(codeFiles, ['lint']);
gulp.watch(codeFiles, taskSpec(['lint']));
});

gulp.task('default', ['lint', 'watch']);
gulp.task('default', taskSpec(['lint', 'watch']));
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -23,20 +23,20 @@
"slush": "./bin/slush.js"
},
"dependencies": {
"glob": "~4.0.0",
"minimist": "~0.1.0",
"glob": "^7.1.2",
"minimist": "^1.2.0",
"gulp-util": "^2.2.0",
"pretty-hrtime": "^0.2.0",
"archy": "^0.0.2",
"liftoff": "~0.10.0",
"chalk": "^0.4.0"
"pretty-hrtime": "^1.0.3",
"archy": "^1.0.0",
"liftoff": "^2.5.0",
"chalk": "^2.4.1"
},
"devDependencies": {
"mocha": "^1.17.0",
"should": "^3.1.0",
"jshint": "^2.4.1",
"gulp-jshint": "^1.4.0",
"gulp": "~3.6.2"
"mocha": "^5.2.0",
"should": "^13.2.1",
"jshint": "^2.9.5",
"gulp-jshint": "^2.1.0",
"gulp": "^4.0.0"
},
"scripts": {
"test": "node gulpfile.js && NODE_ENV=test mocha --reporter spec"
6 changes: 4 additions & 2 deletions test/slush-test/slushfile.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
'use strict';
var gulp = require('gulp');

gulp.task('default', function () {
gulp.task('default', function (done) {
console.log('default');
done();
});

gulp.task('app', function () {
gulp.task('app', function (done) {
console.log('app' + (this.args.length ? ' (' + this.args.join(', ') + ')' : ''));
done(this.args[0] === 'fail' ? new Error('forced error') : undefined);
});
139 changes: 71 additions & 68 deletions test/slush.js
Original file line number Diff line number Diff line change
@@ -4,116 +4,119 @@ var spawn = require('child_process').spawn,

describe('slush', function () {
it('should list installed generators', function (done) {
var slush = runSlush();
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(undefined, function(code, data) {
code.should.equal(0);
data.should.match(/\[slush\] bad/);
data.should.match(/\[slush\] test/);
done();
});
}, done);
});

it('should list tasks for given generator', function (done) {
var slush = runSlush(['test', '--tasks']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['test', '--tasks'], function(code, data) {
code.should.equal(0);
data.should.match(/ default/);
data.should.match(/ app/);
done();
});
}, done);
});

it('should run `default` task in generator, when task is not provided', function (done) {
var slush = runSlush(['test']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['test'], function(code, data) {
code.should.equal(0);
data.should.match(/ Starting 'test:default'\.\.\./);
data.should.match(/\ndefault\n/);
done();
});
data.should.match(/ Finished 'test:default' after /);
data.should.match(/Scaffolding done/);
}, done);
});

it('should run provided task in generator', function (done) {
var slush = runSlush(['test:app']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['test:app'], function(code, data) {
code.should.equal(0);
data.should.match(/ Starting 'test:app'\.\.\./);
data.should.match(/\napp\n/);
done();
});
data.should.match(/ Finished 'test:app' after /);
data.should.match(/Scaffolding done/);
}, done);
});

it('should run multiple tasks in generator', function (done) {
runSlush(['test:app:default'], function(code, data) {
code.should.equal(0);
data.should.match(/ Starting 'test:app'\.\.\./);
data.should.match(/\napp\n/);
data.should.match(/ Finished 'test:app' after /);
data.should.match(/ Starting 'test:default'\.\.\./);
data.should.match(/\ndefault\n/);
data.should.match(/ Finished 'test:default' after /);
data.should.match(/Scaffolding done/);
}, done);
});

it('should run provided task with arguments in generator', function (done) {
var slush = runSlush(['test:app', 'arg1', 'arg2']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['test:app', 'arg1', 'arg2'], function(code, data) {
code.should.equal(0);
data.should.match(/ Starting 'test:app'\.\.\./);
data.should.match(/\napp \(arg1, arg2\)\n/);
done();
});
data.should.match(/ Finished 'test:app' after /);
data.should.match(/Scaffolding done/);
}, done);
});

it('should fail when a task fails in generator', function (done) {
runSlush(['test:app', 'fail'], function(code, data) {
code.should.equal(1);
data.should.match(/ Starting 'test:app'\.\.\./);
data.should.match(/\napp \(fail\)\n/);
data.should.match(/ 'test:app' errored after .* forced error\n/);
data.should.not.match(/Scaffolding done/);
}, done);
});

it('should fail when running a non-existing task in a generator', function (done) {
var slush = runSlush(['test:noexist']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['test:noexist'], function(code, data) {
code.should.equal(1);
data.should.match(/\[slush\] Task 'noexist' was not defined in `slush-test`/);
done();
});
data.should.not.match(/Scaffolding done/);
}, done);
});

it('should fail when running a generator without slushfile', function (done) {
var slush = runSlush(['bad']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['bad'], function(code, data) {
code.should.equal(1);
data.should.match(/\[slush\] No slushfile found/);
data.should.match(/\[slush\].+issue with.+`slush-bad`/);
done();
});
}, done);
});

it('should fail trying to run a non-existing generator', function (done) {
var slush = runSlush(['noexist']);
var data = '';
slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
runSlush(['noexist'], function(code, data) {
code.should.equal(1);
data.should.match(/\[slush\] No generator by name: "noexist" was found/);
done();
});
}, done);
});
});

function runSlush (args) {
args = args || [];
var slush = spawn('node', [path.join(__dirname, '..', 'bin', 'slush.js')].concat(args), {cwd: __dirname});
function runSlush (args, doAssertions, done) {
var slush = spawn('node',
[path.join(__dirname, '..', 'bin', 'slush.js')].concat(args || []),
{cwd: __dirname});
var data = '';

slush.stdout.setEncoding('utf8');
return slush;

slush.stdout.on('data', function (chunk) {
data += chunk;
});
slush.stderr.on('data', function (chunk) {
data += chunk;
});
slush.on('close', function (code) {
try {
doAssertions(code, data);
done();
} catch (e) {
process.stderr.write(data);
done(e);
}
});
}