From a733b4790d4d37c585a545cf36855a091fb4bd48 Mon Sep 17 00:00:00 2001 From: Sean Kelley Date: Wed, 3 Jan 2024 05:50:17 -0500 Subject: [PATCH] Add second level of --verbose to `workspaces foreach` to permit specifying less logging. (#6034) **What's the problem this PR addresses?** Fixes #6033. **How did you fix it?** Changes the `-v,--verbose` flag in `workspaces foreach` to be a counter rather than a boolean. With one level it prints prefixes, with two levels it additionally prints start/finish/timing information (as was the behavior before). The default TTY behavior has not changed (maximum verbosity). The behavior with a single `--verbose` _has_ changed, to be less verbose. **Checklist** - [x] I have read the [Contributing Guide](https://yarnpkg.com/advanced/contributing). - [x] I have set the packages that need to be released for my changes to be effective. - [x] I will check that all automated PR checks pass before the PR gets reviewed. --- .yarn/versions/07edaf86.yml | 23 ++++++++++++++ .../__snapshots__/foreach.test.js.snap | 18 ++++++++++- .../commands/workspaces/foreach.test.js | 27 +++++++++++++---- .../sources/commands/foreach.ts | 30 ++++++++++--------- 4 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 .yarn/versions/07edaf86.yml diff --git a/.yarn/versions/07edaf86.yml b/.yarn/versions/07edaf86.yml new file mode 100644 index 000000000000..de601d77a36d --- /dev/null +++ b/.yarn/versions/07edaf86.yml @@ -0,0 +1,23 @@ +releases: + "@yarnpkg/cli": minor + "@yarnpkg/plugin-workspace-tools": minor + +declined: + - "@yarnpkg/plugin-compat" + - "@yarnpkg/plugin-constraints" + - "@yarnpkg/plugin-dlx" + - "@yarnpkg/plugin-essentials" + - "@yarnpkg/plugin-init" + - "@yarnpkg/plugin-interactive-tools" + - "@yarnpkg/plugin-nm" + - "@yarnpkg/plugin-npm-cli" + - "@yarnpkg/plugin-pack" + - "@yarnpkg/plugin-patch" + - "@yarnpkg/plugin-pnp" + - "@yarnpkg/plugin-pnpm" + - "@yarnpkg/plugin-stage" + - "@yarnpkg/plugin-typescript" + - "@yarnpkg/plugin-version" + - "@yarnpkg/builder" + - "@yarnpkg/core" + - "@yarnpkg/doctor" diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/__snapshots__/foreach.test.js.snap b/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/__snapshots__/foreach.test.js.snap index 6bb53c06fe45..8353b9034d86 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/__snapshots__/foreach.test.js.snap +++ b/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/__snapshots__/foreach.test.js.snap @@ -230,7 +230,7 @@ Done } `; -exports[`Commands workspace foreach should prefix the output with run with --verbose 1`] = ` +exports[`Commands workspace foreach should prefix the output and include timing information when run with -vv (two verbose levels) 1`] = ` { "code": 0, "stderr": "", @@ -266,6 +266,22 @@ Done } `; +exports[`Commands workspace foreach should prefix the output when run with one --verbose 1`] = ` +{ + "code": 0, + "stderr": "", + "stdout": "[workspace-a]: Test Workspace A +[workspace-b]: Test Workspace B +[workspace-c]: Test Workspace C +[workspace-d]: Test Workspace D +[workspace-e]: Test Workspace E +[workspace-f]: Test Workspace F +[workspace-g]: Test Workspace G +Done +", +} +`; + exports[`Commands workspace foreach should run execute global scripts even on workspaces that don't declare them 1`] = ` { "code": 0, diff --git a/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/foreach.test.js b/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/foreach.test.js index e688aada1b93..fe405426a710 100644 --- a/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/foreach.test.js +++ b/packages/acceptance-tests/pkg-tests-specs/sources/commands/workspaces/foreach.test.js @@ -216,8 +216,9 @@ describe(`Commands`, () => { ), ); + test( - `should prefix the output with run with --verbose`, + `should prefix the output when run with one --verbose`, makeTemporaryEnv( { private: true, @@ -232,6 +233,22 @@ describe(`Commands`, () => { ), ); + test( + `should prefix the output and include timing information when run with -vv (two verbose levels)`, + makeTemporaryEnv( + { + private: true, + workspaces: [`packages/*`], + }, + async ({path, run}) => { + await setupWorkspaces(path); + await run(`install`); + + await expect(run(`workspaces`, `foreach`, `--all`, `-vv`, `run`, `print`)).resolves.toMatchSnapshot(); + }, + ), + ); + test( `should not include the prefix or a ➤ character when run with --no-verbose`, makeTemporaryEnv( @@ -259,7 +276,7 @@ describe(`Commands`, () => { await setupWorkspaces(path); await run(`install`); - await expect(run(`workspaces`, `foreach`, `--all`, `--verbose`, `--include`, `workspace-a`, `--include`, `packages/workspace-b`, `run`, `print`)).resolves.toMatchSnapshot(); + await expect(run(`workspaces`, `foreach`, `--all`, `-vv`, `--include`, `workspace-a`, `--include`, `packages/workspace-b`, `run`, `print`)).resolves.toMatchSnapshot(); }, ), ); @@ -275,7 +292,7 @@ describe(`Commands`, () => { await setupWorkspaces(path); await run(`install`); - await expect(run(`workspaces`, `foreach`, `--all`, `--verbose`, `--include`, `packages/workspace-c/**`, `run`, `print`)).resolves.toMatchSnapshot(); + await expect(run(`workspaces`, `foreach`, `--all`, `-vv`, `--include`, `packages/workspace-c/**`, `run`, `print`)).resolves.toMatchSnapshot(); }, ), ); @@ -291,7 +308,7 @@ describe(`Commands`, () => { await setupWorkspaces(path); await run(`install`); - await expect(run(`workspaces`, `foreach`, `--all`, `--verbose`, `--exclude`, `workspace-a`, `--exclude`, `packages/workspace-b`, `run`, `print`)).resolves.toMatchSnapshot(); + await expect(run(`workspaces`, `foreach`, `--all`, `-vv`, `--exclude`, `workspace-a`, `--exclude`, `packages/workspace-b`, `run`, `print`)).resolves.toMatchSnapshot(); }, ), ); @@ -359,7 +376,7 @@ describe(`Commands`, () => { await setupWorkspaces(path); await run(`install`); - const {code, stdout, stderr} = await run(`workspaces`, `foreach`, `--all`, `--parallel`, `--jobs`, `unlimited`, `--verbose`, `run`, `print`); + const {code, stdout, stderr} = await run(`workspaces`, `foreach`, `--all`, `--parallel`, `--jobs`, `unlimited`, `-vv`, `run`, `print`); // We don't care what order they start in, just that they all started at the beginning. const first7Lines = stdout.split(`\n`).slice(0, 7).sort().join(`\n`); diff --git a/packages/plugin-workspace-tools/sources/commands/foreach.ts b/packages/plugin-workspace-tools/sources/commands/foreach.ts index 0d88a4223049..47668fc447c8 100644 --- a/packages/plugin-workspace-tools/sources/commands/foreach.ts +++ b/packages/plugin-workspace-tools/sources/commands/foreach.ts @@ -42,7 +42,7 @@ export default class WorkspacesForeachCommand extends BaseCommand { - The command may apply to only some workspaces through the use of \`--include\` which acts as a whitelist. The \`--exclude\` flag will do the opposite and will be a list of packages that mustn't execute the script. Both flags accept glob patterns (if valid Idents and supported by [micromatch](https://github.com/micromatch/micromatch)). Make sure to escape the patterns, to prevent your own shell from trying to expand them. - Adding the \`-v,--verbose\` flag (automatically enabled in interactive terminal environments) will cause Yarn to print more information; in particular the name of the workspace that generated the output will be printed at the front of each line. + The \`-v,--verbose\` flag can be passed up to twice: once to prefix output lines with the originating workspace's name, and again to include start/finish/timing log lines. Maximum verbosity is enabled by default in terminal environments. If the command is \`run\` and the script being run does not exist the child workspace will be skipped without error. `, @@ -83,8 +83,8 @@ export default class WorkspacesForeachCommand extends BaseCommand { description: `Run the command on all workspaces of the current worktree`, }); - verbose = Option.Boolean(`-v,--verbose`, { - description: `Prefix each output line with the name of the originating workspace`, + verbose = Option.Counter(`-v,--verbose`, { + description: `Increase level of logging verbosity up to 2 times`, }); parallel = Option.Boolean(`-p,--parallel`, false, { @@ -275,8 +275,10 @@ export default class WorkspacesForeachCommand extends BaseCommand { if (this.dryRun) return 0; - // --verbose is automatically enabled in TTYs - const verbose = this.verbose ?? (this.context.stdout as WriteStream).isTTY; + // Default to maximum verbosity in terminal environments. + const verbosity = this.verbose ?? ((this.context.stdout as WriteStream).isTTY ? Infinity : 0); + const label = verbosity > 0; + const timing = verbosity > 1; const concurrency = this.parallel ? (this.jobs === `unlimited` @@ -308,17 +310,17 @@ export default class WorkspacesForeachCommand extends BaseCommand { if (abortNextCommands) return -1; - if (!parallel && verbose && commandIndex > 1) + if (!parallel && timing && commandIndex > 1) report.reportSeparator(); - const prefix = getPrefix(workspace, {configuration, verbose, commandIndex}); + const prefix = getPrefix(workspace, {configuration, label, commandIndex}); const [stdout, stdoutEnd] = createStream(report, {prefix, interlaced}); const [stderr, stderrEnd] = createStream(report, {prefix, interlaced}); try { - if (verbose) - report.reportInfo(null, `${prefix} Process started`); + if (timing) + report.reportInfo(null, `${prefix ? `${prefix} ` : ``}Process started`); const start = Date.now(); @@ -335,9 +337,9 @@ export default class WorkspacesForeachCommand extends BaseCommand { await stderrEnd; const end = Date.now(); - if (verbose) { + if (timing) { const timerMessage = configuration.get(`enableTimers`) ? `, completed in ${formatUtils.pretty(configuration, end - start, formatUtils.Type.DURATION)}` : ``; - report.reportInfo(null, `${prefix} Process exited (exit code ${exitCode})${timerMessage}`); + report.reportInfo(null, `${prefix ? `${prefix} ` : ``}Process exited (exit code ${exitCode})${timerMessage}`); } if (exitCode === 130) { @@ -475,11 +477,11 @@ function createStream(report: Report, {prefix, interlaced}: {prefix: string | nu type GetPrefixOptions = { configuration: Configuration; commandIndex: number; - verbose: boolean; + label: boolean; }; -function getPrefix(workspace: Workspace, {configuration, commandIndex, verbose}: GetPrefixOptions) { - if (!verbose) +function getPrefix(workspace: Workspace, {configuration, commandIndex, label}: GetPrefixOptions) { + if (!label) return null; const name = structUtils.stringifyIdent(workspace.anchoredLocator);