Skip to content

Commit

Permalink
Add the first version.
Browse files Browse the repository at this point in the history
  • Loading branch information
mysticatea committed Mar 23, 2015
1 parent 98eca08 commit b77f1a5
Show file tree
Hide file tree
Showing 13 changed files with 363 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"env": {
"node": true,
"es6": true
},
"ecmaFeatures": {
"arrowFunctions": true,
"binaryLiterals": true,
"blockBindings": true,
"classes": true,
"defaultParams": true,
"destructuring": true,
"forOf": true,
"generators": true,
"modules": true,
"objectLiteralComputedProperties": true,
"objectLiteralDuplicateProperties": true,
"objectLiteralShorthandMethods": true,
"objectLiteralShorthandProperties": true,
"octalLiterals": true,
"regexUFlag": true,
"regexYFlag": true,
"superInFunctions": true,
"templateStrings": true,
"unicodeCodePointEscapes": true,
"globalReturn": true
}
}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/node_modules
/lib
3 changes: 3 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
language: node_js
node_js:
- "0.12"
58 changes: 58 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "npm-run-all",
"version": "1.0.0",
"description": "A CLI tool to run multiple npm-scripts on sequential or parallel.",
"main": "lib/index.js",
"bin": {
"npm-run-all": "lib/command.js"
},
"files": [
"lib"
],
"config": {
"test": "OK"
},
"scripts": {
"build": "eslint src && babel src --out-dir lib",
"lint": "eslint src && eslint test",
"test": "npm run build && mocha test/*.js --compilers js:espower-babel/guess --timeout 10000",
"testing": "run-all \"npm run testing:babel\" \"npm run testing:mocha\"",
"testing:babel": "babel src --out-dir lib --watch --source-maps-inline",
"testing:mocha": "mocha test/*.js --compilers js:espower-babel/guess --timeout 10000 --watch --colors",

"test-task:env-check": "node test/tasks/env-check.js",
"test-task:append-a": "node test/tasks/append.js a",
"test-task:append-b": "node test/tasks/append.js b",
"test-task:error": "node test/tasks/error.js"
},
"repository": {
"type": "git",
"url": "https://github.com/mysticatea/npm-run-all.git"
},
"keywords": [
"cli",
"command",
"commandline",
"tool",
"npm",
"npm-scripts",
"run",
"sequential",
"parallel",
"task"
],
"author": "Toru Nagashima",
"license": "MIT",
"bugs": {
"url": "https://github.com/mysticatea/npm-run-all/issues"
},
"homepage": "https://github.com/mysticatea/npm-run-all",
"devDependencies": {
"babel": "^4.7.16",
"eslint": "^0.17.1",
"espower-babel": "^1.4.0",
"mocha": "^2.2.1",
"power-assert": "^0.10.2",
"run-all": "^1.0.1"
}
}
76 changes: 76 additions & 0 deletions src/command.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
#!/usr/bin/env node

import {readFileSync} from "fs";
import {join as joinPath} from "path";
import runAll from "./index";

if (require.main === module) {
main(process.argv.slice(2));
}

function printHelp() {
console.log(`
Usage: npm-run-all [OPTIONS] <task> [...tasks]
Run specified tasks on sequential.
Options:
-h, --help Print this text.
-p, --parallel <task> [...tasks] Run specified tasks on parallel.
-v, --version Print version number.
See Also:
https://github.com/mysticatea/npm-run-all
`);
}

function printVersion() {
const version = JSON.parse(
readFileSync(
joinPath(__dirname, "../package.json"),
{encoding: "utf8"}
)
).version;

console.log("v" + version);
}

function findParallelOptionIndex(args) {
for (let i = 0, end = args.length; i < end; ++i) {
const arg = args[i];
if (arg === "-p" || arg === "--parallel") {
return i;
}
}
return -1;
}

/*eslint no-process-exit:0*/
function main(args) {
switch (args[0]) {
case undefined:
case "-h":
case "--help":
printHelp();
process.exit(0);
break;

case "-v":
case "--version":
printVersion();
process.exit(0);
break;
}

const pIndex = findParallelOptionIndex(args);
const seqTasks = (pIndex < 0 ? args : args.slice(0, pIndex));
const parTasks = (pIndex < 0 ? [] : args.slice(1 + pIndex));
const seqOptions =
{stdout: process.stdout, stderr: process.stderr, parallel: false};
const parOptions =
{stdout: process.stdout, stderr: process.stderr, parallel: true};

runAll(seqTasks, seqOptions)
.then(() => runAll(parTasks, parOptions))
.catch(() => process.exit(1));
}
63 changes: 63 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {spawn} from "child_process";

function toArray(x) {
if (x == null) {
return [];
}
return Array.isArray(x) ? x : [x];
}

function defineExec() {
if (process.platform === "win32") {
const FILE = process.env.comspec || "cmd.exe";
const OPTIONS = {windowsVerbatimArguments: true};
return command => spawn(FILE, ["/s", "/c", `"${command}"`], OPTIONS);
}
else {
return command => spawn("/bin/sh", ["-c", command]);
}
}

const exec = defineExec();

function runTask(task, stdout, stderr) {
return new Promise((resolve, reject) => {
// Execute.
const cp = exec(`npm run-script ${task}`);

// Piping stdio.
if (stdout) { cp.stdout.pipe(stdout); }
if (stderr) { cp.stderr.pipe(stderr); }

// Register
cp.on("exit", code => {
if (code) {
reject(new Error(`${task}: None-Zero Exit(${code});`));
}
else {
resolve(null);
}
});
cp.on("error", reject);
});
}

export default function runAll(_tasks, _options) {
const tasks = toArray(_tasks);
if (tasks.length === 0) {
return Promise.resolve(null);
}

const options = _options || {};
const parallel = Boolean(options.parallel);
const stdout = options.stdout || null;
const stderr = options.stderr || null;

if (parallel) {
return Promise.all(tasks.map(task => runTask(task, stdout, stderr)));
}
return (function next() {
const task = tasks.shift();
return task && runTask(task, stdout, stderr).then(next);
})();
}
3 changes: 3 additions & 0 deletions test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"env": {"mocha": true}
}
26 changes: 26 additions & 0 deletions test/lib/util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
var fs = require("fs");

var FILE_NAME = "test.txt";

exports.result = function result() {
try {
return fs.readFileSync(FILE_NAME, {encoding: "utf8"});
}
catch (err) {
console.error(err.message);
return null;
}
}

exports.appendResult = function appendResult(content) {
fs.appendFileSync(FILE_NAME, content);
}

exports.removeResult = function removeResult() {
try {
fs.unlinkSync(FILE_NAME);
}
catch (err) {
// ignore.
}
}
27 changes: 27 additions & 0 deletions test/parallel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {execSync} from "child_process";
import assert from "power-assert";
import {result, removeResult} from "./lib/util";

// Test targets.
import runAll from "../lib/index";
import "../lib/command";

describe("npm-run-all", () => {
beforeEach(removeResult);
after(removeResult);

describe("should run tasks on parallel when was given --parallel option:", () => {
it("lib version", () => {
return runAll(["test-task:append-a", "test-task:append-b"], {parallel: true})
.then(() => {
assert(result() === "abab" || result() === "baba");
});
});

it("command version", () => {
execSync("node lib/command.js --parallel test-task:append-a test-task:append-b");
assert(result() === "abab" || result() === "baba");
});
});

});
59 changes: 59 additions & 0 deletions test/sequential.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {execSync} from "child_process";
import assert from "power-assert";
import {result, removeResult} from "./lib/util";

// Test targets.
import runAll from "../lib/index";
import "../lib/command";

describe("npm-run-all", () => {
beforeEach(removeResult);
after(removeResult);

describe("should run a task by npm:", () => {
it("lib version", () => {
return runAll("test-task:env-check", {parallel: false})
.then(() => {
assert(result() === "OK");
});
});

it("command version", () => {
execSync("node lib/command.js test-task:env-check");
assert(result() === "OK");
});
});

describe("should fail to run when tasks exited with non-zero code:", () => {
it("lib version", () => {
return runAll("test-task:error", {parallel: false})
.then(
() => {
assert(false, "should fail");
},
() => {
// OK.
return Promise.resolve(null);
});
});

it("command version", () => {
assert.throws(() => execSync("node lib/command.js test-task:error"));
});
});

describe("should run tasks on sequential:", () => {
it("lib version", () => {
return runAll(["test-task:append-a", "test-task:append-b"], {parallel: false})
.then(() => {
assert(result() === "aabb");
});
});

it("command version", () => {
execSync("node lib/command.js test-task:append-a test-task:append-b");
assert(result() === "aabb");
});
});

});
8 changes: 8 additions & 0 deletions test/tasks/append.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var appendResult = require("../lib/util").appendResult;

function append() {
appendResult(process.argv[2]);
}

append();
setTimeout(append, 500);
8 changes: 8 additions & 0 deletions test/tasks/env-check.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
var appendResult = require("../lib/util").appendResult;

if (process.env.npm_package_config_test === "OK") {
appendResult("OK");
}
else {
appendResult("NOT OK");
}
2 changes: 2 additions & 0 deletions test/tasks/error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/*eslint no-process-exit:0*/
process.exit(1);

0 comments on commit b77f1a5

Please sign in to comment.