diff --git a/.gitignore b/.gitignore index 6779c56..73502b5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/.idea /.nyc_output /coverage /jsdoc diff --git a/lib/index.js b/lib/index.js index e36a605..4f5c322 100644 --- a/lib/index.js +++ b/lib/index.js @@ -205,6 +205,10 @@ function maxLength(length, name) { * @param {string} options.npmPath - * The path to npm. * Default is `process.env.npm_execpath`. + * @param {string} options.labels - + * A comma separated string. Each item is used as a label for a task. + * The amount and order must match with the task list. + * Default is an empty string, which will use the command as name. * @returns {Promise} * A promise object which becomes fullfilled when all npm-scripts are completed. */ @@ -225,6 +229,7 @@ module.exports = function npmRunAll(patternOrPatterns, options) { //eslint-disab const maxParallel = parallel ? ((options && options.maxParallel) || 0) : 1 const aggregateOutput = Boolean(options && options.aggregateOutput) const npmPath = options && options.npmPath + const taskNameString = (config && config.labels) || null try { const patterns = parsePatterns(patternOrPatterns, args) if (patterns.length === 0) { @@ -243,6 +248,8 @@ module.exports = function npmRunAll(patternOrPatterns, options) { //eslint-disab throw new Error("Invalid options.race; It requires options.parallel") } + const taskNames = (taskNameString && taskNameString.split(/,/g)) || [] + const prefixOptions = [].concat( silent ? ["--silent"] : [], packageConfig ? toOverwriteOptions(packageConfig) : [], @@ -257,8 +264,13 @@ module.exports = function npmRunAll(patternOrPatterns, options) { //eslint-disab return readPackageJson() }) .then(x => { - const tasks = matchTasks(x.taskList, patterns) - const labelWidth = tasks.reduce(maxLength, 0) + const tasks = {} + matchTasks(x.taskList, patterns).forEach((command, index) => { + const taskName = taskNames.length - 1 >= index ? taskNames[index] : command + + tasks[taskName] = command + }) + const labelWidth = Object.keys(tasks).reduce(maxLength, 0) return runTasks(tasks, { stdin, diff --git a/lib/run-task.js b/lib/run-task.js index 8cabc03..1a09fdc 100644 --- a/lib/run-task.js +++ b/lib/run-task.js @@ -107,7 +107,7 @@ function cleanTaskArg(arg) { * The return value is a promise which has an extra method: `abort()`. * The `abort()` kills the child process to run the npm-script. * - * @param {string} task - A npm-script name to run. + * @param {object} task - A npm-script name to run. * @param {object} options - An option object. * @param {stream.Readable|null} options.stdin - * A readable stream to send messages to stdin of child process. @@ -135,10 +135,10 @@ function cleanTaskArg(arg) { */ module.exports = function runTask(task, options) { let cp = null - const promise = new Promise((resolve, reject) => { + const promise = new Promise((resolve, reject) => { //eslint-disable-line complexity const stdin = options.stdin - const stdout = wrapLabeling(task, options.stdout, options.labelState) - const stderr = wrapLabeling(task, options.stderr, options.labelState) + const stdout = wrapLabeling(task.name, options.stdout, options.labelState) + const stderr = wrapLabeling(task.name, options.stderr, options.labelState) const stdinKind = detectStreamKind(stdin, process.stdin) const stdoutKind = detectStreamKind(stdout, process.stdout) const stderrKind = detectStreamKind(stderr, process.stderr) @@ -147,7 +147,7 @@ module.exports = function runTask(task, options) { // Print task name. if (options.printName && stdout != null) { stdout.write(createHeader( - task, + task.name, options.packageInfo, options.stdout.isTTY )) @@ -169,7 +169,7 @@ module.exports = function runTask(task, options) { else if (options.prefixOptions.indexOf("--silent") !== -1) { spawnArgs.push("--silent") } - Array.prototype.push.apply(spawnArgs, parseArgs(task).map(cleanTaskArg)) + Array.prototype.push.apply(spawnArgs, parseArgs(task.command).map(cleanTaskArg)) cp = spawn(execPath, spawnArgs, spawnOptions) diff --git a/lib/run-tasks.js b/lib/run-tasks.js index 64a4506..fc5a938 100644 --- a/lib/run-tasks.js +++ b/lib/run-tasks.js @@ -41,20 +41,21 @@ function remove(array, x) { * * If a npm-script exited with a non-zero code, this aborts other all npm-scripts. * - * @param {string} tasks - A list of npm-script name to run in parallel. + * @param {object} tasks - A list of npm-script name to run in parallel. * @param {object} options - An option object. * @returns {Promise} A promise object which becomes fullfilled when all npm-scripts are completed. * @private */ module.exports = function runTasks(tasks, options) { return new Promise((resolve, reject) => { - if (tasks.length === 0) { + const taskNames = Object.keys(tasks) + if (taskNames.length === 0) { resolve([]) return } - const results = tasks.map(task => ({ name: task, code: undefined })) - const queue = tasks.map((task, index) => ({ name: task, index })) + const results = taskNames.map(taskName => ({ name: taskName, code: undefined })) + const queue = taskNames.map((taskName, index) => ({ name: taskName, command: tasks[taskName], index })) const promises = [] let error = null let aborted = false @@ -119,7 +120,7 @@ module.exports = function runTasks(tasks, options) { } const task = queue.shift() - const promise = runTask(task.name, optionsClone) + const promise = runTask(task, optionsClone) promises.push(promise) promise.then( @@ -168,8 +169,8 @@ module.exports = function runTasks(tasks, options) { const max = options.maxParallel const end = (typeof max === "number" && max > 0) - ? Math.min(tasks.length, max) - : tasks.length + ? Math.min(taskNames.length, max) + : taskNames.length for (let i = 0; i < end; ++i) { next() } diff --git a/test/custom-labels.js b/test/custom-labels.js new file mode 100644 index 0000000..ede1b27 --- /dev/null +++ b/test/custom-labels.js @@ -0,0 +1,110 @@ +"use strict" + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const assert = require("power-assert") +const util = require("./lib/util") +const BufferStream = require("./lib/buffer-stream") +const removeResult = util.removeResult +const runPar = util.runPar + +//------------------------------------------------------------------------------ +// Test +//------------------------------------------------------------------------------ + +describe("[custom labels]", () => { + before(() => process.chdir("test-workspace")) + after(() => process.chdir("..")) + + beforeEach(removeResult) + + describe("should use the given label instead of script name", () => { + const EXPECTED_LINES = [ + "[Unit Test ] abcabc", + "[Unit Test ] abc", + "[Unit Test ] abcabc", + "[Unit Test ] abc", + "[Unit Test ] abc", + "[Unit Test ] abc", + "[Unit Test ] abc", + "[Unit Test ] abc", + "[Unit Test ] ", + "[Unit Test ] abc", + "[Unit Test ] abcabc", + "[Unit Test ] ", + "[Unit Test ] ", + "[Unit Test ] ", + "[Unit Test ] abc", + + "[test-task:echo def] defdef", + "[test-task:echo def] def", + "[test-task:echo def] defdef", + "[test-task:echo def] def", + "[test-task:echo def] def", + "[test-task:echo def] def", + "[test-task:echo def] def", + "[test-task:echo def] def", + "[test-task:echo def] ", + "[test-task:echo def] def", + "[test-task:echo def] defdef", + "[test-task:echo def] ", + "[test-task:echo def] ", + "[test-task:echo def] ", + "[test-task:echo def] def", + ] + + it("npm-run-all --labels=\"Unit Test\"", async () => { + const stdout = new BufferStream() + await runPar(["test-task:echo abc", "test-task:echo def", "--silent", "--print-label", "--labels=Unit Test"], stdout) + for (const line of stdout.value.split(/\n\r?/g)) { + assert(EXPECTED_LINES.includes(line), `Missing line: ${line}`) + } + }) + }) + + describe("should use all given label instead of script name", () => { + const EXPECTED_LINES = [ + "[Unit Test 1] abcabc", + "[Unit Test 1] abc", + "[Unit Test 1] abcabc", + "[Unit Test 1] abc", + "[Unit Test 1] abc", + "[Unit Test 1] abc", + "[Unit Test 1] abc", + "[Unit Test 1] abc", + "[Unit Test 1] ", + "[Unit Test 1] abc", + "[Unit Test 1] abcabc", + "[Unit Test 1] ", + "[Unit Test 1] ", + "[Unit Test 1] ", + "[Unit Test 1] abc", + + "[Unit Test 2] defdef", + "[Unit Test 2] def", + "[Unit Test 2] defdef", + "[Unit Test 2] def", + "[Unit Test 2] def", + "[Unit Test 2] def", + "[Unit Test 2] def", + "[Unit Test 2] def", + "[Unit Test 2] ", + "[Unit Test 2] def", + "[Unit Test 2] defdef", + "[Unit Test 2] ", + "[Unit Test 2] ", + "[Unit Test 2] ", + "[Unit Test 2] def", + ] + + it("npm-run-all --labels=\"Unit Test 1,Unit Test 2\"", async () => { + const stdout = new BufferStream() + await runPar(["test-task:echo abc", "test-task:echo def", "--silent", "--print-label", "--labels=Unit Test 1,Unit Test 2"], stdout) + for (const line of stdout.value.split(/\n\r?/g)) { + assert(EXPECTED_LINES.includes(line), `Missing line: ${line}`) + } + }) + }) +})