Skip to content

Introduce --fail-fast flag for npm run in workspaces #8323

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: latest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions lib/commands/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ class RunScript extends BaseCommand {
'ignore-scripts',
'foreground-scripts',
'script-shell',
'fail-fast'
]

static name = 'run'
Expand Down Expand Up @@ -49,6 +50,7 @@ class RunScript extends BaseCommand {

async execWorkspaces (args) {
await this.setWorkspaces()
const shouldFailFast = this.npm.config.get('fail-fast') ?? false;

const ws = [...this.workspaces.entries()]
for (const [workspace, path] of ws) {
Expand Down Expand Up @@ -80,6 +82,9 @@ class RunScript extends BaseCommand {
if (!last) {
output.error('')
}
if (shouldFailFast) {
return;
}
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions tap-snapshots/test/lib/commands/config.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ exports[`test/lib/commands/config.js TAP config list --json > output matches sna
"engine-strict": false,
"expect-result-count": null,
"expect-results": null,
"fail-fast": false,
"fetch-retries": 2,
"fetch-retry-factor": 10,
"fetch-retry-maxtimeout": 60000,
Expand Down Expand Up @@ -214,6 +215,7 @@ editor = "{EDITOR}"
engine-strict = false
expect-result-count = null
expect-results = null
fail-fast = false
fetch-retries = 2
fetch-retry-factor = 10
fetch-retry-maxtimeout = 60000
Expand Down
8 changes: 8 additions & 0 deletions tap-snapshots/test/lib/commands/run.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ Scripts available in x@1.2.3 via \`npm run\`:
echo doing the glerp glop
`

exports[`test/lib/commands/run.js TAP workspaces failed workspace run fails fast > should log error msgs for each workspace script 1`] = `
Lifecycle script \`glorp\` failed with error:
code ERR
workspace a@1.0.0
location {CWD}/prefix/packages/a
ERR
`

exports[`test/lib/commands/run.js TAP workspaces failed workspace run with succeeded runs > should log error msgs for each workspace script 1`] = `
Lifecycle script \`glorp\` failed with error:
code ERR
Expand Down
22 changes: 21 additions & 1 deletion tap-snapshots/test/lib/docs.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,23 @@ true (expect some results) or false (expect no results).

This config can not be used with: \`expect-result-count\`

#### \`fail-fast\`

* Default: false
* Type: Boolean

Designed to be used with the \`--workspaces\` or multiple \`--workspace\`
option.

If true, when executing commands with the \`run\` across a workspace. Rather
than the default behavior of running the command in all packages in the
workspace and logging the failure, on the first failing package, exit with
the error code of the failing command. This is helpful if packages have
relationship and the work should not continue if the previous package
failed.



#### \`fetch-retries\`

* Default: 2
Expand Down Expand Up @@ -2129,6 +2146,7 @@ Array [
"engine-strict",
"expect-result-count",
"expect-results",
"fail-fast",
"fetch-retries",
"fetch-retry-factor",
"fetch-retry-maxtimeout",
Expand Down Expand Up @@ -2389,6 +2407,7 @@ exports[`test/lib/docs.js TAP config > keys that are not flattened 1`] = `
Array [
"expect-result-count",
"expect-results",
"fail-fast",
"init-author-email",
"init-author-name",
"init-author-url",
Expand Down Expand Up @@ -4038,7 +4057,7 @@ npm run <command> [-- <args>]
Options:
[-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
[--workspaces] [--include-workspace-root] [--if-present] [--ignore-scripts]
[--foreground-scripts] [--script-shell <script-shell>]
[--foreground-scripts] [--script-shell <script-shell>] [--fail-fast]

aliases: run-script, rum, urn

Expand All @@ -4057,6 +4076,7 @@ aliases: run-script, rum, urn
#### \`ignore-scripts\`
#### \`foreground-scripts\`
#### \`script-shell\`
#### \`fail-fast\`
`

exports[`test/lib/docs.js TAP usage sbom > must match snapshot 1`] = `
Expand Down
22 changes: 22 additions & 0 deletions test/lib/commands/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -759,4 +759,26 @@ t.test('workspaces', async t => {
},
])
})

t.test('failed workspace run fails fast', async t => {
const { cleanLogs, RUN_SCRIPTS, prefix } = await mockWorkspaces(t, {
runScript: (opts) => {
if (opts.pkg.name === 'a') {
throw new Error('ERR')
}
},
exec: ['glorp'],
workspaces: ['a', 'b'],
'fail-fast': true
})

t.matchSnapshot(
cleanLogs(),
'should log error msgs for each workspace script'
)

t.match(RUN_SCRIPTS(), [])
})
})


14 changes: 14 additions & 0 deletions workspaces/config/lib/definitions/definitions.js
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,20 @@ const definitions = {
Can be either true (expect some results) or false (expect no results).
`,
}),
'fail-fast': new Definition('fail-fast', {
default: false,
type: Boolean,
description: `
Designed to be used with the \`--workspaces\` or multiple \`--workspace\` option.

If true, when executing commands with the \`run\` across a workspace.
Rather than the default behavior of running the command in all packages
in the workspace and logging the failure, on the first failing package,
exit with the error code of the failing command. This is helpful if
packages have relationship and the work should not continue if the
previous package failed.
`
}),
'fetch-retries': new Definition('fetch-retries', {
default: 2,
type: Number,
Expand Down