Skip to content

Commit

Permalink
Add run-s and run-p commands
Browse files Browse the repository at this point in the history
`npm-run-all` is getting complexity step by step. So I experiment to
separate it to 2 simple commands -- `run-s` and `run-p`.

- `run-s` - Run specific tasks sequentially.
- `run-p` - Run specific tasks in parallel.

Those commands don't have the ability of combinations of parallel and
sequential.
  • Loading branch information
mysticatea committed Apr 26, 2016
1 parent d4f68e5 commit 40554ef
Show file tree
Hide file tree
Showing 17 changed files with 791 additions and 320 deletions.
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"extends": ["mysticatea/nodejs"],
"plugins": ["node"],
"rules": {
"no-param-reassign": [2, {"props": false}],
"node/no-missing-import": 2,
"node/no-missing-require": 2,
"node/no-unpublished-import": 2,
Expand Down
62 changes: 32 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,36 +33,38 @@ npm install npm-run-all
## Usage

```
Usage: npm-run-all [...tasks] [OPTIONS]
Run specified tasks.
Options:
-h, --help Print this text.
-v, --version Print version number.
-c, --continue-on-error Set the flag to ignore errors to the current
group of tasks.
-l, --print-label Set the flag to print the task name as a prefix
on each line of output, to the current group of
tasks.
-n, --print-name Set the flag to print the task name before
running each task, to the current group of
tasks.
--silent Set "silent" to the log level of npm.
-p, --parallel [...tasks] Run a group of tasks in parallel.
e.g. 'npm-run-all -p foo bar' is similar to
'npm run foo & npm run bar'.
-P [...tasks] Run a group of tasks in parallel as ignoring
errors. This is shorthand of '-p -c [...tasks]'.
-s, --sequential [...tasks] Run a group of tasks in sequential.
--serial [...tasks] '--serial' is a synonym of '--sequential'.
e.g. 'npm-run-all -s foo bar' is similar to
'npm run foo && npm run bar'.
-S [...tasks] Run a group of tasks in sequential as ignoring
errors. This is shorthand of '-s -c [...tasks]'.
Usage:
$ npm-run-all [--help | -h | --version | -v]
$ npm-run-all [tasks] [OPTIONS]
Run specified tasks in parallel or sequential.
<tasks> : A list of npm-scripts' names and Glob-like patterns.
Options:
-c, --continue-on-error - Set the flag to continue executing
other/subsequent tasks even if a task threw an
error. 'npm-run-all' itself will exit with
non-zero code if one or more tasks threw error(s)
-l, --print-label - - - - Set the flag to print the task name as a prefix
on each line of output. Tools in tasks may stop
coloring their output if this option was given.
-n, --print-name - - - - Set the flag to print the task name before
running each task.
-p, --parallel <tasks> - Run a group of tasks in parallel.
e.g. 'npm-run-all -p foo bar' is similar to
'npm run foo & npm run bar'.
-s, --sequential <tasks> - Run a group of tasks sequentially.
--serial <tasks> e.g. 'npm-run-all -s foo bar' is similar to
'npm run foo && npm run bar'.
'--serial' is a synonym of '--sequential'.
--silent - - - - - - - - Set 'silent' to the log level of npm.
Examples:
$ npm-run-all --serial clean lint build:**
$ npm-run-all --parallel watch:**
$ npm-run-all clean lint --parallel "build:** -- --watch"
$ npm-run-all -l -p start-server start-browser start-electron
```

### Run tasks sequentially / serially
Expand Down
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
"name": "npm-run-all",
"version": "1.8.0",
"description": "A CLI tool to run multiple npm-scripts in parallel or sequential / serial.",
"bin": "bin/npm-run-all.js",
"bin": {
"run-p": "bin/run-p/index.js",
"run-s": "bin/run-s/index.js",
"npm-run-all": "bin/npm-run-all/index.js"
},
"files": [
"bin",
"lib",
Expand All @@ -13,7 +17,7 @@
"postversion": "git push && git push --tags",
"clean": "rimraf bin coverage docs lib",
"lint": "eslint src test test-workspace",
"build": "babel-node src/bin/npm-run-all.js clean lint build:*",
"build": "babel-node src/bin/run-s/index.js clean lint build:*",
"build:babel": "babel src --out-dir .",
"build:esdoc": "esdoc -c esdoc.json",
"test": "npm run lint && babel-node node_modules/isparta/bin/isparta cover node_modules/mocha/bin/_mocha -- test/*.js --timeout 60000",
Expand All @@ -25,8 +29,10 @@
"chalk": "^1.1.3",
"cross-spawn-async": "^2.1.9",
"minimatch": "^3.0.0",
"object-assign": "^4.0.1",
"ps-tree": "^1.0.1",
"read-pkg": "^1.1.0",
"read-pkg-up": "^1.0.1",
"shell-quote": "^1.4.3",
"string.prototype.padend": "^3.0.0"
},
Expand Down
218 changes: 218 additions & 0 deletions src/bin/common/parse-cli-args.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
/**
* @author Toru Nagashima
* @copyright 2016 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

import assign from "object-assign";

//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------

const OVERWRITE_OPTION = /^--([^:]+?):([^=]+?)(?:=(.+))?$/;
const CONFIG_PATTERN = /^npm_package_config_(.+)$/;
const CONCAT_OPTIONS = /^-[chlnpPsSv]+$/;

/**
* Overwrites a specified package config.
*
* @param {object} config - A config object to be overwritten.
* @param {string} packageName - A package name to overwrite.
* @param {string} variable - A variable name to overwrite.
* @param {string} value - A new value to overwrite.
* @returns {void}
*/
function overwriteConfig(config, packageName, variable, value) {
const scope = config[packageName] || (config[packageName] = {}); // eslint-disable-line no-param-reassign
scope[variable] = value;
}

/**
* Creates a package config object.
* This checks `process.env` and creates the default value.
*
* @returns {object} Created config object.
*/
function createPackageConfig() {
const retv = {};
const packageName = process.env.npm_package_name;
if (!packageName) {
return retv;
}

for (const key of Object.keys(process.env)) {
const m = CONFIG_PATTERN.exec(key);
if (m != null) {
overwriteConfig(retv, packageName, m[1], process.env[key]);
}
}

return retv;
}

/**
* Adds a new group into a given list.
*
* @param {object[]} groups - A group list to add.
* @param {object} initialValues - A key-value map for the default of new value.
* @returns {void}
*/
function addGroup(groups, initialValues) {
groups.push(assign(
{
continueOnError: false,
parallel: false,
patterns: [],
printLabel: false,
printName: false
},
initialValues
));
}

/**
* ArgumentSet is values of parsed CLI arguments.
* This class provides the getter to get the last group.
*/
class ArgumentSet {
/**
* @param {object} initialValues - A key-value map for the default of new value.
* @param {object} options - A key-value map for the options.
*/
constructor(initialValues = {}, options = {}) {
this.groups = [];
this.help = false;
this.silent = process.env.npm_config_loglevel === "silent";
this.version = false;
this.singleMode = Boolean(options.singleMode);
this.packageConfig = createPackageConfig();

addGroup(this.groups, initialValues);
}

get lastGroup() {
return this.groups[this.groups.length - 1];
}
}

/**
* Parses CLI arguments.
*
* @param {ArgumentSet} set - The parsed CLI arguments.
* @param {string[]} args - CLI arguments.
* @returns {ArgumentSet} set itself.
*/
function parseCLIArgsCore(set, args) { // eslint-disable-line complexity
for (let i = 0; i < args.length; ++i) {
const arg = args[i];

switch (arg) {
case "-c":
case "--continue-on-error":
set.lastGroup.continueOnError = true;
break;

case "-h":
case "--help":
set.help = true;
break;

case "-l":
case "--print-label":
set.lastGroup.printLabel = true;
break;

case "-n":
case "--print-name":
set.lastGroup.printName = true;
break;

case "--silent":
set.silent = true;
break;

case "-v":
case "--version":
set.version = true;
break;

case "--color":
case "--no-color":
// do nothing.
break;

case "-S":
case "-s":
case "--sequential":
case "--serial":
if (set.singleMode && arg === "-s") {
set.silent = true;
break;
}
if (set.singleMode) {
throw new Error(`Invalid Option: ${arg}`);
}
addGroup(set.groups, {
continueOnError: arg === "-S"
});
break;

case "-P":
case "-p":
case "--parallel":
if (set.singleMode) {
throw new Error(`Invalid Option: ${arg}`);
}
addGroup(set.groups, {
parallel: true,
continueOnError: arg === "-P"
});
break;

default: {
const matched = OVERWRITE_OPTION.exec(arg);
if (matched) {
overwriteConfig(
set.packageConfig,
matched[1],
matched[2],
matched[3] || args[++i]
);
}
else if (CONCAT_OPTIONS.test(arg)) {
parseCLIArgsCore(
set,
arg.slice(1).split("").map(c => `-${c}`)
);
}
else if (arg[0] === "-") {
throw new Error(`Invalid Option: ${arg}`);
}
else {
set.lastGroup.patterns.push(arg);
}

break;
}
}
}

return set;
}

/**
* Parses CLI arguments.
*
* @param {string[]} args - CLI arguments.
* @param {object} initialValues - A key-value map for the default of new value.
* @param {object} options - A key-value map for the options.
* @returns {ArgumentSet} The parsed CLI arguments.
*/
export default function parseCLIArgs(args, initialValues, options) {
return parseCLIArgsCore(new ArgumentSet(initialValues, options), args);
}
30 changes: 30 additions & 0 deletions src/bin/common/version.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* @author Toru Nagashima
* @copyright 2016 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

import {sync as readPkgUp} from "read-pkg-up";

//------------------------------------------------------------------------------
// Public Interface
//------------------------------------------------------------------------------

/**
* Print a version text.
*
* @param {stream.Writable} output - A writable stream to print.
* @returns {Promise} Always a fulfilled promise.
* @private
*/
export default function printVersion(output) {
const version = readPkgUp(__dirname).pkg.version;

output.write(`v${version}\n`);

return Promise.resolve(null);
}

0 comments on commit 40554ef

Please sign in to comment.