Skip to content
This repository has been archived by the owner on Mar 4, 2022. It is now read-only.

Commit

Permalink
Merge f22dca0 into 390eaa4
Browse files Browse the repository at this point in the history
  • Loading branch information
ryan-roemer committed Feb 13, 2018
2 parents 390eaa4 + f22dca0 commit ed57c51
Show file tree
Hide file tree
Showing 22 changed files with 742 additions and 114 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

.DS_Store
.project
.vscode
bower_components
node_modules
npm-debug.log*
Expand Down
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ script:
- npm --version
- npm run builder:check-ci

# Do some primitive bash functional tests.
- bash test/func/test.sh

# Manually send coverage reports to coveralls.
# - Aggregate client results
# - Single server and func test results
Expand Down
6 changes: 6 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
History
=======

## Unreleased MAJOR

* Add more explicit behavior and tests for `--setup` flag.
* **Breaking**: Add `pre|post` lifecycle commands.
[#68](https://github.com/FormidableLabs/builder/issues/68)

## 3.2.3

* Account for `PATH` vs. `Path` env var differences in MinGW vs. cmd on
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015-2016 Formidable Labs
Copyright (c) 2015-2018 Formidable Labs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
168 changes: 168 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ the rough goals and motivations behind the project.
- [builder run](#builder-run)
- [builder concurrent](#builder-concurrent)
- [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)
- [Expanding the Archetype Path](#expanding-the-archetype-path)
- [Tasks](#tasks)
Expand Down Expand Up @@ -375,6 +381,168 @@ The environment variable `FOO` will have a value of `"ENVS"` with the single
environment object array item given to `builder envs` overriding the `--env`
flag value.

#### 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`

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.

##### 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` TODO_TEST
* `--env-path` TODO_TEST
* `--quiet` TODO_TEST
* `--log-level` TODO_TEST

The following flags do _not_ apply to a setup task:

* `--` custom flags TODO_TEST
* `--tries` TODO_TEST
* `--expand-archetype` TODO_TEST
* `--setup`: A task specified in `--setup <task>` will not have `pre|post`
tasks apply. TODO_TEST

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 `--tries`, `--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

Just like [`npm run <task> [-- <args>...]`](https://docs.npmjs.com/cli/run-script),
Expand Down
4 changes: 2 additions & 2 deletions bin/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var msgs = [];

// Infer if we are global and there is a local version available.
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");

// Swap to local path if different.
if (builderPath !== localPath) {
Expand All @@ -28,7 +28,7 @@ if (builderPath !== localPath) {
});
} catch (err) {
msgs.push({
level: "warn", type: "local-detect",
level: "info", type: "local-detect",
msg: "Error importing local builder: " + err.message
});
msgs.push({
Expand Down
2 changes: 1 addition & 1 deletion lib/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ Config.prototype._loadArchetypePkg = function (name) {
*/
Config.prototype._loadPkgs = function (archetypes) {
var self = this;
var CWD_PKG = this._lazyRequire(path.join(process.cwd(), "package.json")) || {};
var CWD_PKG = this._lazyRequire(path.resolve("package.json")) || {};

// Load base packages.
var pkgs = [_.extend({ name: "ROOT" }, CWD_PKG)].concat(_.chain(archetypes)
Expand Down
4 changes: 2 additions & 2 deletions lib/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ var splitPath = function (val) {
var uniqueVals = function (val, i, vals) { return vals.indexOf(val) === i; };

// 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");

/**
* Environment wrapper.
Expand Down
34 changes: 16 additions & 18 deletions lib/runner.js
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,12 @@ var run = function (cmd, shOpts, opts, callback) {
shOpts.windowsVerbatimArguments = true;
}

var env = shOpts.env;

// Mutation steps for command. Separated for easier ordering / testing.
//
// Mutate env and return new command w/ `--` custom flags.
cmd = cmdWithCustom(cmd, opts, env);
cmd = cmdWithCustom(cmd, opts, shOpts.env);
// Mutate env and return new command w/ file paths from the archetype itself.
cmd = expandArchetype(cmd, opts, env);
cmd = expandArchetype(cmd, opts, shOpts.env);

log.info("proc:start", cmdStr(cmd, opts));
var proc = spawn(sh, [shFlag, cmd], shOpts, function (err) {
Expand Down Expand Up @@ -278,14 +276,9 @@ var retry = function (cmd, shOpts, opts, callback) {
*/
var addSetup = function (setup, shOpts) {
if (!setup) { return null; }
log.info("setup:start", "Starting setup task: " + setup);

var done = _.once(function (code) {
code = code || 0;
var level = code === 0 ? "info" : "error";
log[level]("setup:end", "Setup command ended with code: " + code);
});

// Create a `Task` object specifically for setup.
// Create a `Task` object to just infer the _command_ we need.
//
// **Note**: Could refactor this out to a higher-level `create` method or
// something that could be reused by `builder-core.js`
Expand All @@ -299,17 +292,22 @@ var addSetup = function (setup, shOpts) {
var task = new Task({
config: config,
env: env,
argv: ["node", "builder", "run", setup],
argv: [null, "builder", "run", setup],
runner: runner
});

log.info("setup:start", "Starting setup task: " + setup);
// Now, use the task to unpack and create a raw shell `run`.
var main = task.getCommand().main;

// Task `run` will return the child process, which we pass back here.
var proc = task.execute(done);
if (!proc) {
throw new Error("Must create a trackable setup process object");
}
// Finishing state.
var done = _.once(function (code) {
code = code || 0;
var level = code === 0 ? "info" : "error";
log[level]("setup:end", "Setup command ended with code: " + code);
});

// Run it!
var proc = run(main.cmd, { env: env.env }, {}, done);
proc.on("exit", done);

return proc;
Expand Down

0 comments on commit ed57c51

Please sign in to comment.