Socket
Socket
Sign inDemoInstall

builder

Package Overview
Dependencies
Maintainers
25
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

builder - npm Package Compare versions

Comparing version 3.2.3 to 4.0.0

lib/utils/runner.js

4

bin/builder-core.js

@@ -8,3 +8,2 @@ "use strict";

var Task = require("../lib/task");
var runner = require("../lib/runner");
var log = require("../lib/log");

@@ -54,4 +53,3 @@

env: env,
argv: opts.argv,
runner: runner
argv: opts.argv
});

@@ -58,0 +56,0 @@

@@ -19,3 +19,3 @@ #!/usr/bin/env node

var builderPath = require.resolve("./builder-core");
var localPath = path.resolve(process.cwd(), "node_modules/builder/bin/builder-core.js");
var localPath = path.resolve("node_modules/builder/bin/builder-core.js");

@@ -32,3 +32,3 @@ // Swap to local path if different.

msgs.push({
level: "warn", type: "local-detect",
level: "info", type: "local-detect",
msg: "Error importing local builder: " + err.message

@@ -35,0 +35,0 @@ });

History
=======
## 4.0.0
**BREAKING**:
* Restrict to `node` version `4+`.
* Default to `--log-level=error` intead of `info`.
* Add `pre|post` lifecycle commands.
[#68](https://github.com/FormidableLabs/builder/issues/68)
* Error out on invalid or conflicting command line flags passed
to `builder`.
Other enhancements:
* Add `--log-level=debug`. Switch some existing logs over.
* Add more explicit behavior and tests for `--setup` flag.
## 3.2.3

@@ -5,0 +21,0 @@

"use strict";
/*eslint max-statements:[2, 20]*/
/*eslint max-statements:[2, 30]*/

@@ -72,5 +72,5 @@ /**

"log-level": {
desc: "Level to log at (`info`, `warn`, `error`, `none`)",
desc: "Level to log at (`debug`, `info`, `warn`, `error`, `none`)",
types: [String],
default: "info"
default: "error"
},

@@ -119,2 +119,9 @@ env: {

// Get all possible flag fields.
var FLAGS_ALL_FIELDS = _.chain(FLAGS) // Use `_.chain` not `_()` because of `reduce`
.values()
.reduce(function (memo, obj) { return memo.concat(_.keys(obj)); }, [])
.uniq()
.value();
// Convert our bespoke flags object into `nopt` options.

@@ -151,7 +158,9 @@ var getOpts = function (obj) {

// Option parser.
var createFn = function (flags) {
var createFn = function (flags, isGeneral) {
var opts = getOpts(flags);
var flagKeys = _.keys(flags);
return function (argv) {
argv = argv || process.argv;
var unparsedArgv = argv;

@@ -173,2 +182,5 @@ // Capture any flags after `--` like `npm run <task> -- <args>` does.

// Hack in unparsed for pristine version.
parsedOpts.argv.unparsed = unparsedArgv;
// Stash if log-level was actually set.

@@ -203,2 +215,15 @@ var logLevel = parsedOpts["log-level"];

// Validate no invalid or ambiguous flags.
var parsedKeys = _(parsedOpts).keys().without("argv").value();
var extraKeys = _.difference(parsedKeys, flagKeys);
if (isGeneral) {
// If the general command, allow flags from *any* other action.
// We'll eventually hit the right action with tighter enforcement.
extraKeys = _.difference(extraKeys, FLAGS_ALL_FIELDS);
}
if (extraKeys.length) {
throw new Error("Found invalid/conflicting keys: " + extraKeys.join(", "));
}
return _(parsedOpts)

@@ -217,5 +242,9 @@ // Camel-case flags.

version: version
}, _.mapValues(FLAGS, function (flags) {
}, _.mapValues(FLAGS, function (flags, key) {
// Merge in general flags to all other configs.
var isGeneral = key === "general";
flags = isGeneral ? flags : _.extend({}, FLAGS.general, flags);
// Add in `KEY()` methods.
return createFn(flags);
return createFn(flags, isGeneral);
}));

@@ -27,3 +27,3 @@ "use strict";

var Config = module.exports = function (opts) {
log.info("config:environment", JSON.stringify({
log.debug("config:environment", JSON.stringify({
cwd: process.cwd(),

@@ -126,3 +126,3 @@ dir: __dirname

} catch (err) {
log.error("config:load-archetype-scripts",
log.info("config:load-archetype-scripts",
"Error loading package.json for: " + chalk.gray(name) + " " +

@@ -149,3 +149,3 @@ (err.message || err.toString()));

var self = this;
var CWD_PKG = this._lazyRequire(path.join(process.cwd(), "package.json")) || {};
var CWD_PKG = this._lazyRequire(path.resolve("package.json")) || {};

@@ -152,0 +152,0 @@ // Load base packages.

@@ -28,4 +28,4 @@ "use strict";

// Node directories.
var CWD_BIN = path.join(process.cwd(), "node_modules/.bin");
var CWD_NODE_PATH = path.join(process.cwd(), "node_modules");
var CWD_BIN = path.resolve("node_modules/.bin");
var CWD_NODE_PATH = path.resolve("node_modules");

@@ -39,2 +39,3 @@ /**

* @param {Object} opts.config Configuration object
* @param {Object} opts.argv Argv object (Default `process.argv`)
* @param {Object} opts.env Environment object to mutate (Default `process.env`)

@@ -41,0 +42,0 @@ * @returns {void}

@@ -14,6 +14,7 @@ "use strict";

var LEVELS = {
info: 0,
warn: 1,
error: 2,
none: 3
debug: 0,
info: 1,
warn: 2,
error: 3,
none: 4
};

@@ -104,2 +105,6 @@

// Switch to `console.log` friendly methods.
// - `console.debug` won't normally output to stdout.
level = level === "debug" ? "log" : level;
// Call directly once level is set.

@@ -113,4 +118,5 @@ // This is also used to drain the queue.

// Actual implementation methods.
log.debug = log._wrapper.bind(log, "debug", "gray");
log.info = log._wrapper.bind(log, "info", "green");
log.warn = log._wrapper.bind(log, "warn", "yellow");
log.error = log._wrapper.bind(log, "error", "red");
"use strict";
/*eslint max-statements:[2, 30]*/
var path = require("path");
var _ = require("lodash");
var async = require("async");
var chalk = require("chalk");

@@ -9,4 +11,11 @@ var args = require("./args");

var log = require("./log");
var clone = require("./utils/clone");
var jsonParse = require("./utils/json").parse;
var Tracker = require("./utils/tracker");
var runner = require("./utils/runner");
// Paths for inference of "is builder task?"
var BUILDER_NODE_MODULES = path.normalize("node_modules/builder/bin/builder.js");
var BUILDER_BIN = path.normalize("node_modules/.bin/builder");
/**

@@ -28,3 +37,2 @@ * Task wrapper.

this._env = opts.env || new Environment();
this._runner = opts.runner;

@@ -40,7 +48,10 @@ // Infer parts.

// State
this._tracker = new Tracker();
this._setupKilled = false;
this._errors = [];
// Validation.
if (!this._config) {
throw new Error("Configuration object required");
} else if (!this._runner) {
throw new Error("Runner object required");
}

@@ -80,2 +91,4 @@

*
* Checks either `builder` or `node PATH/TO/BUILDER`.
*
* _Note_: Naive. Only captures `builder` at start of command.

@@ -91,7 +104,22 @@ * See: https://github.com/FormidableLabs/builder/issues/93

var builder = path.basename(this._script, ".js");
var taskParts = task.split(/\s+/);
var taskBin = taskParts[0];
var taskParts = (task || "").trim().split(/\s+/);
var taskBin = taskParts[0] || "";
// Note: Assumes a binary script match without `.js` extension.
return builder === taskBin;
// Case: `builder run foo`
// Compare directly if not a `node` script execution.
if (taskBin.toLowerCase() !== "node") {
return taskBin === builder;
}
// We know we're now in `node PATH/TO/BUILDER`.
taskBin = path.resolve(taskParts[1] || "");
// Case: `node CURRENT_BUILDER_PATH`
return taskBin === path.resolve(this._script) ||
// Case: `node node_modules/builder/bin/builder.js`
taskBin.substr(taskBin.length - BUILDER_NODE_MODULES.length) === BUILDER_NODE_MODULES ||
// Case: `node node_modules/.bin/builder`
taskBin.substr(taskBin.length - BUILDER_BIN.length) === BUILDER_BIN;
};

@@ -115,22 +143,58 @@

/**
* Get executable command.
*
* @param {String} cmd Script command
* @returns {Object} Command object `{ archetype, cmd }`
*/
Task.prototype.getCommand = function (cmd) {
Task.prototype._findCommand = function (cmd) {
var self = this;
// Select first non-passthrough command.
var task = _.find(this._config.getCommands(cmd), function (obj) {
return _.find(this._config.getCommands(cmd), function (obj) {
return !self.isPassthrough(obj.cmd);
});
};
// Error out if still can't find task.
if (!task) {
/**
* Get execution parameters, options, etc.
*
* @param {String} cmd Script command
* @param {String} action Action name (default `general`)
* @returns {Object} Commands obj `{ main: { archetype, cmd, opts }, pre, post }`
*/
Task.prototype.getRunParams = function (cmd, action) {
// For external use:
cmd = cmd || this._command;
action = action || "general";
// Require a `main` task.
var main = this._findCommand(cmd);
if (!main) {
if (_.isUndefined(cmd)) {
throw new Error("No task specified");
}
throw new Error("Unable to find task for: " + cmd);
}
return task;
// Gather pre|post tasks, if they aren't already pre|post-prefixed.
// **Note**: This follows `npm` behavior. `yarn` would run `prepre<task>`
// when executing `yarn run pre<task>`.
var pre = null;
var post = null;
if (!/^(pre|post)/.test(cmd)) {
pre = this._findCommand("pre" + cmd) || null;
post = this._findCommand("post" + cmd) || null;
}
// Infer execution options and enhance objects.
var taskArgs = args[action](this.argv);
if (pre) {
_.extend(pre, { opts: this.getPrePostOpts(pre, taskArgs, action) });
}
_.extend(main, { opts: this.getMainOpts(main, taskArgs) });
if (post) {
_.extend(post, { opts: this.getPrePostOpts(post, taskArgs, action) });
}
return {
pre: pre,
main: main,
post: post
};
};

@@ -145,3 +209,3 @@

*/
Task.prototype.getOpts = function (task, opts) {
Task.prototype.getMainOpts = function (task, opts) {
return _.extend({

@@ -155,2 +219,84 @@ _isBuilderTask: this.isBuilderTask(task.cmd),

/**
* Merge base options with custom options and filter out non-pre|post things.
*
* @param {Object} task Task object `{ archetype, cmd }`
* @param {Object} opts Custom options
* @param {String} action Action type to take.
* @returns {Object} Combined options
*/
Task.prototype.getPrePostOpts = function (task, opts, action) {
if (!task) { return null; }
// Action specific overrides.
var overrides = {
"envs": {
buffer: false
}
};
// Generally applicable options.
return _.extend({}, this.getMainOpts(task, opts), {
tries: 1,
setup: false,
_customFlags: null
}, overrides[action]);
};
// Expose require because with mock-fs and node 0.10, 0.12, the `require` itself
// is mocked.
Task.prototype._lazyRequire = require; // eslint-disable-line global-require
/**
*
* @param {String} taskName Setup task name
* @param {Object} shOpts Shell options
* @param {Function} callback Function `(err)` called on process end.
* @returns {Object} Process object or `null` if no setup.
*/
Task.prototype.setup = function (taskName, shOpts, callback) {
// Lazy require because `task` is a dependency.
var setup = this._lazyRequire("./utils/setup");
// Short-circuit empty task.
if (!taskName) { return null; }
// Add, invoke, and hook to final callback if setup dies early.
var self = this;
var proc = this._tracker.add(setup.create(taskName, shOpts));
if (proc) {
// If setup exit happens before normal termination, kill everything.
proc.on("exit", function (code) {
self._setupKilled = true;
callback(new Error("Setup exited with code: " + code));
});
}
return proc;
};
Task.prototype.trackAndRun = function () {
return this._tracker.add(runner.run.apply(null, arguments));
};
// Wrap all callbacks to noop if the tracker or setup are already killed.
Task.prototype._skipIfKilled = function (fn) {
var self = this;
return function (cb) {
return self._tracker.killed || self._setupKilled ? cb() : fn(cb);
};
};
// Convenience wrapper for processing errors with `opts.bail`.
Task.prototype._errOrBail = function (opts, callback) {
var self = this;
return function (err) {
if (err) {
self._errors.push(err);
}
callback(opts.bail ? err : null); // Decide if failure ends the run.
};
};
/**
* Help.

@@ -229,10 +375,36 @@ *

var env = this._env.env; // Raw environment object.
var task = this.getCommand(this._command);
var flags = args.run(this.argv);
var opts = this.getOpts(task, flags);
// Ensure only one call, so `--setup` process can call early for error.
callback = _.once(callback);
log.info(this._action, this._command + chalk.gray(" - " + task.cmd));
// Aliases
var self = this;
var shOpts = { env: this._env.env };
return this._runner.run(task.cmd, { env: env }, opts, callback);
// Get execution parameters.
var params = this.getRunParams(this._command, "run");
log.info(this._action, this._command + chalk.gray(" - " + params.main.cmd));
// Task execution sequence
async.series([
// Execute `pre<task>`
params.pre && self.trackAndRun.bind(self, params.pre.cmd, shOpts, params.pre.opts),
// Execute `--setup=<setup-task>` (spawned for lifetime of <task>)
function (cb) {
self.setup(params.main.opts.setup, shOpts, callback);
cb();
},
// Execute `<task>`
function (cb) {
var opts = _.extend({ tracker: self._tracker }, params.main.opts);
return opts.tries === 1 ?
self.trackAndRun(params.main.cmd, shOpts, opts, cb) :
runner.retry(params.main.cmd, shOpts, opts, cb);
},
// Execute `post<task>`
params.post && self.trackAndRun.bind(self, params.post.cmd, shOpts, params.post.opts)
].filter(Boolean).map(self._skipIfKilled.bind(self)), callback);
};

@@ -247,39 +419,69 @@

Task.prototype.concurrent = function (callback) {
var env = this._env.env; // Raw environment object.
// Ensure only one call, so `--setup` process can call early for error.
callback = _.once(callback);
// Aliases
var self = this;
var shOpts = { env: this._env.env };
// Get execution parameters (list).
var cmds = this._commands;
var tasks = cmds.map(this.getCommand.bind(this));
var flags = args.concurrent(this.argv);
var opts = this.getOpts(tasks[0] || {}, flags);
log.info(this._action, cmds.join(", ") + tasks.map(function (t, i) {
return "\n * " + cmds[i] + chalk.gray(" - " + t.cmd);
var paramsList = cmds.map(function (cmd) {
return self.getRunParams(cmd, "concurrent");
});
var firstParams = paramsList[0];
if (!firstParams) {
log.warn(this._action, "No tasks found");
return callback();
}
log.info(this._action, cmds.join(", ") + paramsList.map(function (t, i) {
return "\n * " + cmds[i] + chalk.gray(" - " + t.main.cmd);
}).join(""));
this._runner.concurrent(
tasks.map(function (task) { return task.cmd; }),
{ env: env }, opts, callback);
// Use first task options to slice off general concurrent information.
var queue = firstParams.main.opts.queue;
// Start setup on first of **any** main tasks.
var startSetup = _.once(function (opts) {
return opts.setup ? self.setup(opts.setup, shOpts, callback) : null;
});
log.debug("concurrent", "Starting with queue size: " + chalk.magenta(queue || "unlimited"));
async.mapLimit(paramsList, queue || Infinity, function (params, concCb) {
// Task execution sequence
async.series([
// Execute `pre<task>`
params.pre && self.trackAndRun.bind(self, params.pre.cmd, shOpts, params.pre.opts),
// (ONLY FIRST ONE) Execute `--setup=<setup-task>` (spawned for lifetime of <task>)
function (cb) {
startSetup(params.main.opts, shOpts, callback);
cb();
},
// Execute `<task1>`, `<task2>`, `...`
function (cb) {
var opts = _.extend({ tracker: self._tracker }, params.main.opts);
return opts.tries === 1 ?
self.trackAndRun(params.main.cmd, shOpts, opts, cb) :
runner.retry(params.main.cmd, shOpts, opts, cb);
},
// Execute `post<task>`
params.post && self.trackAndRun.bind(self, params.post.cmd, shOpts, params.post.opts)
// Apply --bail to **all** of this sequence by wrapping .series final callback.
].filter(Boolean).map(self._skipIfKilled.bind(self)),
self._errOrBail(params.main.opts, concCb));
}, callback);
};
/**
* Run multiple environments.
*
* @param {Function} callback Callback function `(err)`
* @returns {void}
*/
Task.prototype.envs = function (callback) {
/*eslint max-statements: [2, 20]*/
// Core setup.
var env = this._env.env;
var task = this.getCommand(this._command);
var flags = args.envs(this.argv);
var opts = this.getOpts(task, flags);
// Return validated environment object from CLI or file.
Task.prototype._getEnvsList = function (parseObj) {
// Parse envs.
var envsObj;
var envsList;
var err;
try {
envsObj = jsonParse({
str: this._commands[1], // Get task environment array.
path: opts.envsPath
});
envsList = jsonParse(parseObj);
} catch (parseErr) {

@@ -290,6 +492,6 @@ err = parseErr;

// Validation
if (!err && _.isEmpty(envsObj)) {
if (!err && _.isEmpty(envsList)) {
err = new Error("Empty/null JSON environments array.");
} else if (!err && !_.isArray(envsObj)) {
err = new Error("Non-array JSON environments object: " + JSON.stringify(envsObj));
} else if (!err && !_.isArray(envsList)) {
err = new Error("Non-array JSON environments object: " + JSON.stringify(envsList));
}

@@ -300,15 +502,103 @@

"Failed to load environments string / path with error: " + err);
return callback(err);
throw err;
}
// Stash for use in runner options.
opts._envs = envsObj;
return envsList;
};
// Run.
this._runner.envs(task.cmd, { env: env }, opts, callback);
/**
* Run multiple environments.
*
* @param {Function} callback Callback function `(err)`
* @returns {void}
*/
Task.prototype.envs = function (callback) {
// Ensure only one call, so `--setup` process can call early for error.
callback = _.once(callback);
// Aliases
var self = this;
var shOpts = { env: this._env.env };
// Get execution parameters.
var params = this.getRunParams(this._command, "envs");
log.info(this._action, this._command + chalk.gray(" - " + params.main.cmd));
// Get list of environment variable objects.
var envsList;
try {
envsList = this._getEnvsList({
str: this._commands[1], // from CLI arguments
path: params.main.opts.envsPath // from `--envs-path`
});
} catch (err) {
return void callback(err);
}
// Task execution sequence
async.series([
// Execute `pre<task>`
params.pre && self.trackAndRun.bind(self, params.pre.cmd, shOpts, params.pre.opts),
// Execute `--setup=<setup-task>` (spawned for lifetime of <task>)
function (cb) {
self.setup(params.main.opts.setup, shOpts, callback);
cb();
},
// Execute `<task>` w/ each env var.
function (cb) {
var cmd = params.main.cmd;
var cmdStr = runner.cmdStr;
var opts = _.extend({ tracker: self._tracker }, params.main.opts);
var taskEnvs = clone(envsList);
var queue = opts.queue;
log.debug("envs", "Starting with queue size: " + chalk.magenta(queue || "unlimited"));
async.mapLimit(taskEnvs, queue || Infinity, function (taskEnv, envCb) {
// Add each specific set of environment variables.
// Clone `shOpts` to turn `env` into a plain object: in Node 4+
// `process.env` is a special object which changes merge behavior.
var taskShOpts = _.merge(clone(shOpts), { env: taskEnv });
var taskOpts = _.extend({ taskEnv: taskEnv }, opts);
log.info("envs", "Starting " + cmdStr(cmd, taskOpts));
runner.retry(cmd, taskShOpts, taskOpts, self._errOrBail(taskOpts, envCb));
}, cb);
},
// Execute `post<task>`
params.post && self.trackAndRun.bind(self, params.post.cmd, shOpts, params.post.opts)
].filter(Boolean).map(self._skipIfKilled.bind(self)), callback);
};
/**
* Execute task or tasks.
* Clean up task state.
*
* - Terminate all existing processes.
* - Drain and log all accumulated errors.
*
* @param {Function} callback Callback `(err)`
* @returns {Function} Wrapped callback
*/
Task.prototype.finish = function (callback) {
var errors = this._errors;
this._tracker.kill(function () {
if (errors.length > 1) {
log.error("finish", "Hit " + chalk.red(errors.length) + " errors: \n" +
errors.map(function (errItem) {
return " * " + chalk.gray(errItem.name) + ": " + chalk.red(errItem.message);
}).join("\n"));
}
callback(errors[0]);
});
};
/**
* Execute action and cleanup.
*
* **Note**: All tasks (e.g., `run`, `concurrent`) through this gate.
*
* @param {Function} callback Callback function `(err)`

@@ -318,10 +608,20 @@ * @returns {Object} Process object for `run` or `null` otherwise / for errors

Task.prototype.execute = function (callback) {
var self = this;
var action = this._action;
// Check task action method exists.
if (!this[this._action]) {
callback(new Error("Unrecognized action: " + this._action));
return null;
if (!this[action]) {
return void callback(new Error("Unrecognized action: " + action));
}
// Call action.
return this[this._action](callback);
this[action](function (err) {
// Add errors, if any.
if (err) {
self._errors.push(err);
}
// Unconditionally cleanup.
self.finish(callback);
});
};

@@ -6,2 +6,9 @@ "use strict";

// Ignore errors: We want to kill as many procs as we can.
var ignoreError = function (cb) {
return cb ?
function () { cb(); } :
function () {}; // noop
};
/**

@@ -14,2 +21,3 @@ * Multi-process tracker.

this.procs = [];
this.killed = false;
};

@@ -28,2 +36,8 @@

// Short-circuit and kill without async wait if killed.
if (self.killed) {
treeKill(proc.pid, "SIGTERM", ignoreError());
return proc;
}
// Track.

@@ -49,9 +63,8 @@ self.procs.push(proc);

Tracker.prototype.kill = function (callback) {
this.killed = true;
if (this.procs.length === 0) { return callback(); }
async.map(this.procs, function (proc, cb) {
// Ignore errors: We want to kill as many procs as we can.
treeKill(proc.pid, "SIGTERM", function () { cb(); });
treeKill(proc.pid, "SIGTERM", ignoreError(cb));
}, callback);
};
The MIT License (MIT)
Copyright (c) 2015-2016 Formidable Labs
Copyright (c) 2015-2018 Formidable Labs

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "builder",
"version": "3.2.3",
"version": "4.0.0",
"description": "An NPM-based task runner",

@@ -15,2 +15,5 @@ "repository": {

"homepage": "https://github.com/FormidableLabs/builder",
"engines": {
"node": ">=4"
},
"scripts": {

@@ -24,4 +27,5 @@ "builder:build-md-toc": "doctoc --notitle README.md",

"builder:test-cov": "istanbul cover --config .istanbul.server.yml _mocha -- --opts test/server/mocha.opts test/server/spec",
"builder:check": "npm run builder:lint && npm run builder:test",
"builder:check-ci": "npm run builder:lint && npm run builder:test-cov"
"builder:test-func": "mocha --opts test/func/mocha.opts test/func/spec",
"builder:check": "npm run builder:lint && npm run builder:test && npm run builder:test-func",
"builder:check-ci": "npm run builder:lint && npm run builder:test-cov && npm run builder:test-func"
},

@@ -36,3 +40,3 @@ "bin": {

"lodash": "^3.10.1",
"nopt": "^3.0.6",
"nopt": "^4.0.1",
"tree-kill": "^1.0.0"

@@ -39,0 +43,0 @@ },

@@ -62,2 +62,8 @@ [![Travis Status][trav_img]][trav_site]

- [builder envs](#builder-envs)
- [Setup Task](#setup-task)
- [Task Lifecycle](#task-lifecycle)
- [The Basics](#the-basics)
- [Other Builder Actions](#other-builder-actions)
- [Builder Flags During Pre and Post](#builder-flags-during-pre-and-post)
- [Task Prefix Complexities](#task-prefix-complexities)
- [Custom Flags](#custom-flags)

@@ -281,3 +287,3 @@ - [Expanding the Archetype Path](#expanding-the-archetype-path)

* `--quiet`: Silence logging
* `--log-level`: Level to log at (`info`, `warn`, `error`, `none`)
* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)
* `--env`: JSON object of keys to add to environment.

@@ -302,3 +308,6 @@ * `--env-path`: JSON file path of keys to add to environment.

* `--tries`: Number of times to attempt a task (default: `1`)
* `--setup`: Single task to run for the entirety of `<action>`
* `--setup`: Single task to run for the entirety of `<action>`.
* **Note**: The `--setup` task is run at the start of the first main task
to actually run. This may _not_ be the first specified task however,
as `pre` tasks could end up with main tasks starting out of order.
* `--queue`: Number of concurrent processes to run (default: unlimited - `0|null`)

@@ -308,3 +317,3 @@ * `--[no-]buffer`: Buffer output until process end (default: `false`)

* `--quiet`: Silence logging
* `--log-level`: Level to log at (`info`, `warn`, `error`, `none`)
* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)
* `--env`: JSON object of keys to add to environment.

@@ -357,2 +366,6 @@ * `--env-path`: JSON file path of keys to add to environment.

* `--setup`: Single task to run for the entirety of `<action>`
* **Note**: The `--setup` task is run at the start of the first main task
to actually run. This may _not_ be the first specified task however,
as `pre` tasks could end up with main tasks per environment object
starting out of order.
* `--queue`: Number of concurrent processes to run (default: unlimited - `0|null`)

@@ -363,3 +376,3 @@ * `--[no-]buffer`: Buffer output until process end (default: `false`)

* `--quiet`: Silence logging
* `--log-level`: Level to log at (`info`, `warn`, `error`, `none`)
* `--log-level`: Level to log at (`debug`, `info`, `warn`, `error`, `none`) (default: `error`)
* `--env`: JSON object of keys to add to environment.

@@ -384,2 +397,184 @@ * `--env-path`: JSON file path of keys to add to environment.

#### Setup Task
A task specified in `--setup <task>` will have the following flags apply to
the setup task as apply to the main task:
* `--env`
* `--env-path`
* `--quiet`
* `--log-level`
The following flags do _not_ apply to a setup task:
* `--` custom flags
* `--tries`
* `--expand-archetype`
* `--queue`
* `--buffer`
That said, if you need things like `--tries`, etc., these can be always coded
into a wrapped task like:
```js
"scripts": {
"setup-alone": "while sleep 1; do echo SETUP; done",
"setup": "builder run --tries=5 setup-alone",
"test": "mocha",
"test-full": "builder run --setup=setup test"
}
```
#### Task Lifecycle
Builder executes `pre<task>` and `post<task>` tasks the same as `npm` does,
with some perhaps not completely obvious corner cases.
##### The Basics
If you have:
```js
"scripts": {
"prefoo": "echo PRE",
"foo": "echo TEMP",
"postfoo": "echo POST"
}
```
And run `builder run foo`, then just like `npm`, builder will run in order:
1. `prefoo`
2. `foo`
3. `postfoo`
assuming each task succeeds, otherwise execution is terminated.
`pre` and `post` tasks can be provided in an archetype and overridden in a root
`package.json` in the exact same manner as normal Builder tasks.
##### Other Builder Actions
`builder run` works essentially the same as `npm run`. Things get a little
messy with Builder's other execution options:
`builder envs` runs `pre|post` tasks exactly **once** regardless of how many
concurrent executions of the underlying task (with different environment
variables) occur.
`builder concurrent` runs appropriate `pre|post` tasks for each independent
task. So, for something like:
```js
"scripts": {
"prefoo": "echo PRE FOO",
"foo": "echo TEMP FOO",
"postfoo": "echo POST FOO",
"prebar": "echo PRE BAR",
"bar": "echo TEMP BAR",
"postbar": "echo POST BAR"
}
```
running `builder concurrent foo bar` would run **all** of the above tasks at
the appropriate lifecycle moment.
Note that things like a `--queue=NUM` limit on a concurrent task will have
*all* of the `pre`, main, and `post` task need to finish serial execution before
the next spot is freed up.
The `--bail` flag applies to all of a single tasks `pre`, main, and `post`
group. So if any of those fail, it's as if the main task failed.
##### Builder Flags During Pre and Post
*Applicable Flags*
When executing a `<task>` that has `pre<task>` and/or `post<task>` entries, the
following execution flags **do** apply to the `pre|post` tasks.
* `--env`
* `--env-path`
* `--quiet`
* `--log-level`
* `--expand-archetype`
These flags have mixed application:
* `--queue`: Applies for `concurrent`, but not `envs`. The flag is invalid for
`run`.
* `--buffer`: Applies for `concurrent`, but not `envs`. The flag is invalid for
`run`.
* `--bail`: Applies for `concurrent`, but not `envs`. The flag is invalid for
`run`. A `pre<task>`, `<task>`, and a `post<task>` are treated as a group, so
a failure of any short-circuits the rests and ends with failures. But with
`--bail=false` a failure doesn't stop execution of the _other_ groups.
The following flags do _not_ apply to pre/post tasks:
* `--` custom flags
* `--tries`
* `--setup`: A task specified in `--setup <task>` will not have `pre|post`
tasks apply.
We will explain a few of these situations in a bit more depth:
*Custom Flags*
The special `--` flag with any subsequent custom flags to the underlying task
are only passed to the the main `<task>` and not `pre<task>` or `post<task>`.
The rationale here is that custom command line flags most likely just apply to
a single shell command (the main one).
So, for example
```js
"scripts": {
"prefoo": "echo PRE",
"foo": "echo TEMP",
"postfoo": "echo POST"
}
```
running `builder run foo -- --hi` would produce:
```
PRE
TEMP --hi
POST
```
*Other Flags*
By contrast, the various other Builder-specific flags that can be applied to a
task like `--env`, etc., **will** apply to `pre|post` tasks, under the
assumption that control flags + environment variables will most likely want to
be used for the execution of all commands in the workflow.
So, for example:
```js
"scripts": {
"prefoo": "echo PRE $VAR",
"foo": "echo TEMP $VAR",
"postfoo": "echo POST $VAR"
}
```
running `builder run foo --env '{"VAR":"HI"}'` would produce:
```
PRE HI
TEMP HI
POST HI
```
##### Task Prefix Complexities
For the above example, if you have a task named `preprefoo`, then running
`foo` **or** even `prefoo` directly will **not** run `preprefoo`. Builder
follows `npm`'s current implementation which is roughly "add `pre|post` tasks
to current execution as long as the task itself is not prefixed with
`pre|post`". (_Note_ that `yarn` does not follow this logic in task execution).
#### Custom Flags

@@ -386,0 +581,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc