Skip to content
Closed
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions lib/shared/exit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

// Fix stdout truncation on windows
function exit(code) {
/* istanbul ignore next */
if (process.platform === 'win32' && process.stdout.bufferSize) {
process.stdout.once('drain', function() {
process.exit(code);
Expand Down
22 changes: 22 additions & 0 deletions lib/versioned/^3.7.0/log/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,21 @@ function logEvents(gulpInst) {

// Exit with 0 or 1
var failed = false;
var tasks = [];

process.once('exit', function(code) {
if (tasks.length) {
failed = true;

log.warn(
ansi.red('The following tasks did not complete:'),
ansi.cyan(tasks.join(', '))
);
log.warn(
ansi.red('Did you forget to signal async completion?')
);
}

if (code === 0 && failed) {
exit(1);
}
Expand All @@ -24,6 +38,8 @@ function logEvents(gulpInst) {
});

gulpInst.on('task_start', function(e) {
tasks.push(e.task);

// TODO: batch these
// so when 5 tasks start at once it only logs one time with all 5
log.info('Starting', '\'' + ansi.cyan(e.task) + '\'...');
Expand All @@ -35,6 +51,12 @@ function logEvents(gulpInst) {
'Finished', '\'' + ansi.cyan(e.task) + '\'',
'after', ansi.magenta(time)
);

var foundIndex = tasks.indexOf(e.task);
/* istanbul ignore else */
if (foundIndex >= 0) {
tasks.splice(foundIndex, 1);
}
});

gulpInst.on('task_err', function(e) {
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"lint": "eslint . && jscs index.js bin/ lib/ test/",
"prepublish": "marked-man --name gulp docs/CLI.md > gulp.1",
"pretest": "npm run lint",
"test": "mocha --async-only --timeout 5000 test/lib test",
"test": "mocha --async-only --timeout 5000 test/lib test/lib/v3.7.0 test",
"cover": "nyc --reporter=lcov --reporter=text-summary npm test",
"coveralls": "nyc --reporter=text-lcov npm test | coveralls"
},
Expand Down Expand Up @@ -64,7 +64,9 @@
"marked-man": "^0.1.3",
"mocha": "^3.2.0",
"nyc": "^10.0.0",
"rimraf": "^2.6.1"
"plugin-error": "^1.0.0",
"rimraf": "^2.6.1",
"sver-compat": "^1.5.0"
},
"keywords": [
"build",
Expand Down
274 changes: 274 additions & 0 deletions test/lib/v3.7.0/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
'use strict';

var expect = require('expect');
var EventEmitter = require('events').EventEmitter;
var os = require('os');
var log = require('gulplog');
var Semver = require('sver-compat').Semver;
var ansi = require('../../../lib/shared/ansi');

var logEvents = require('../../../lib/versioned/^3.7.0/log/events');

var infoBuf = [];
log.info = function() {
infoBuf.push([].join.call(arguments, ' '));
};
var warnBuf = [];
log.warn = function() {
warnBuf.push([].join.call(arguments, ' '));
};
var errorBuf = [];
log.error = function() {
errorBuf.push([].join.call(arguments, ' '));
};

function noColor(v) {
return v;
}
var ansiOrig = {};

var origExit = process.exit;
var origOnce = process.once;

var tmpProcess = new EventEmitter();

// See https://www.appveyor.com/docs/lang/nodejs-iojs/#garbled-or-missing-output
function isGarbledOrMissingOutput() {
if (os.platform() === 'win32') {
var currentVersion = new Semver(process.versions.node);
var minimalVersion = new Semver('0.11.12');
return currentVersion.lt(minimalVersion);
}
return false;
}

describe('lib: ^3.7.0/log/events', function() {
before(function() {
Object.keys(ansi).forEach(function(color) {
ansiOrig[color] = ansi[color];
ansi[color] = noColor;
});
});
after(function() {
Object.keys(ansi).forEach(function(color) {
ansi[color] = ansiOrig[color];
});
});
beforeEach(function() {
process.exit = function() {
expect(true).toBe(false);
};
process.once = tmpProcess.once.bind(tmpProcess);
infoBuf = [];
warnBuf = [];
errorBuf = [];
});
afterEach(function() {
process.exit = origExit;
process.once = origOnce;
});

describe('"exit" event', function() {
it('Should not call process.exit when no error', function(done) {
var ee = new EventEmitter();
logEvents(ee);
tmpProcess.emit('exit', 0);
expect(infoBuf).toEqual([]);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([]);
done();
});
});

describe('"err" event', function() {
it('Should call process.exit with exit code 1 when error', function(done) {
process.exit = function(code) {
if (!isGarbledOrMissingOutput()) {
expect(code).toBe(1);
done();
}
};

var ee = new EventEmitter();
logEvents(ee);
ee.emit('err');
tmpProcess.emit('exit', 0);
expect(infoBuf).toEqual([]);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([]);

if (isGarbledOrMissingOutput()) {
done();
}
});

it('Should not call process.exit when already exit code is not zero', function(done) {
var ee = new EventEmitter();
logEvents(ee);
ee.emit('err');
tmpProcess.emit('exit', 1);
expect(infoBuf).toEqual([]);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([]);
done();
});
});

describe('"task_start" and "task_stop" events', function() {
it('Should output logs for starting and finishing a task', function(done) {
var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_start', { task: 'task-0' });
ee.emit('task_stop', { task: 'task-0', hrDuration: [0, 12] });
tmpProcess.emit('exit', 0);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([]);
expect(infoBuf).toEqual([
'Starting \'task-0\'...',
'Finished \'task-0\' after 12 ns',
]);
done();
});

it('Should exit without error if there is no incomplete task', function(done) {
var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_start', { task: 'task-0' });
ee.emit('task_start', { task: 'task-1' });
ee.emit('task_start', { task: 'task-2' });
ee.emit('task_stop', { task: 'task-2', hrDuration: [0, 12] });
ee.emit('task_start', { task: 'task-3' });
ee.emit('task_stop', { task: 'task-1', hrDuration: [0, 12] });
ee.emit('task_stop', { task: 'task-3', hrDuration: [0, 12] });
ee.emit('task_stop', { task: 'task-0', hrDuration: [0, 12] });
tmpProcess.emit('exit', 0);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([]);
expect(infoBuf).toEqual([
'Starting \'task-0\'...',
'Starting \'task-1\'...',
'Starting \'task-2\'...',
'Finished \'task-2\' after 12 ns',
'Starting \'task-3\'...',
'Finished \'task-1\' after 12 ns',
'Finished \'task-3\' after 12 ns',
'Finished \'task-0\' after 12 ns',
]);
done();
});

it('Should exit with warning log if there are incomplete tasks', function(done) {
process.exit = function(code) {
if (!isGarbledOrMissingOutput()) {
expect(code).toBe(1);
done();
}
};

var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_start', { task: 'task-0' });
ee.emit('task_start', { task: 'task-2' });
ee.emit('task_start', { task: 'task-1' });
ee.emit('task_start', { task: 'task-3' });
tmpProcess.emit('exit', 0);
expect(errorBuf).toEqual([]);
expect(infoBuf).toEqual([
'Starting \'task-0\'...',
'Starting \'task-2\'...',
'Starting \'task-1\'...',
'Starting \'task-3\'...',
]);
expect(warnBuf).toEqual([
'The following tasks did not complete: task-0, task-2, task-1, task-3',
'Did you forget to signal async completion?',
]);

if (isGarbledOrMissingOutput()) {
done();
}
});

it('Should exit with warning log if there are incomplete tasks (2)', function(done) {
process.exit = function(code) {
if (!isGarbledOrMissingOutput()) {
expect(code).toBe(1);
done();
}
};

var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_start', { task: 'task-0' });
ee.emit('task_start', { task: 'task-2' });
ee.emit('task_start', { task: 'task-1' });
ee.emit('task_stop', { task: 'task-2', hrDuration: [0, 12] });
ee.emit('task_start', { task: 'task-3' });
ee.emit('task_stop', { task: 'task-3', hrDuration: [0, 12] });
tmpProcess.emit('exit', 0);
expect(errorBuf).toEqual([]);
expect(infoBuf).toEqual([
'Starting \'task-0\'...',
'Starting \'task-2\'...',
'Starting \'task-1\'...',
'Finished \'task-2\' after 12 ns',
'Starting \'task-3\'...',
'Finished \'task-3\' after 12 ns',
]);
expect(warnBuf).toEqual([
'The following tasks did not complete: task-0, task-1',
'Did you forget to signal async completion?',
]);

if (isGarbledOrMissingOutput()) {
done();
}
});
});

describe('"task_err" event', function() {
it('Should output log for unfound task', function(done) {
var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_err', {
task: 'task-0',
hrDuration: [0, 12],
message: 'Error Message',
});
expect(infoBuf).toEqual([]);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([
'\'task-0\' errored after 12 ns',
'Error Message',
]);
done();
});
});

describe('"task_not_found" event', function() {
it('Should output log for unfound task and call process.exit', function(done) {
process.exit = function(code) {
if (!isGarbledOrMissingOutput()) {
expect(code).toBe(1);
done();
}
};

var ee = new EventEmitter();
logEvents(ee);
ee.emit('task_not_found', { task: 'task-0' });
expect(infoBuf).toEqual([]);
expect(warnBuf).toEqual([]);
expect(errorBuf).toEqual([
'Task \'task-0\' is not in your gulpfile',
'Please check the documentation for proper gulpfile formatting',
]);

if (isGarbledOrMissingOutput()) {
done();
}
});
});

});

34 changes: 34 additions & 0 deletions test/lib/v3.7.0/format-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
'use strict';

var expect = require('expect');
var PluginError = require('plugin-error');

var formatError = require('../../../lib/versioned/^3.7.0/format-error');

describe('lib: ^3.7.0/format-error', function() {

it('Should return error message when error is not orchestrator error', function(done) {
var err = new TypeError('ERROR!');
expect(formatError(err)).toEqual('ERROR!');
done();
});

it('Should return error message when PluginError', function(done) {
var err = new PluginError('test', 'something broke');
expect(formatError({ task: 'task-0', err: err })).toEqual(err.toString());
done();
});

it('Should return error message when normal error', function(done) {
var err = new TypeError('ERROR!');
expect(formatError({ task: 'task-0', err: err })).toEqual(err.stack);
done();
});

it('Should return error message when unknown error', function(done) {
var stack = formatError({ task: 'task-0', err: 'abc' });
expect(stack.split(/\r\n|\r|\n/)[0]).toEqual('Error: abc');
done();
});
});