rman 1.0.10 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +116 -85
  2. package/cli.js +225 -14
  3. package/commands/build.command.js +1 -0
  4. package/commands/changed.command.js +2 -2
  5. package/commands/changelog.command.js +13 -15
  6. package/commands/config.command.js +60 -0
  7. package/commands/diff.command.js +9 -4
  8. package/commands/exec.command.js +2 -8
  9. package/commands/github-release.command.js +1 -0
  10. package/commands/info.command.d.ts +9 -0
  11. package/commands/info.command.js +12 -2
  12. package/commands/run.command.js +5 -8
  13. package/commands/test.command.js +1 -0
  14. package/commands/version.command.js +53 -14
  15. package/constants.js +1 -1
  16. package/core/config.d.ts +257 -6
  17. package/core/config.js +409 -17
  18. package/core/custom-command.d.ts +133 -0
  19. package/core/custom-command.js +99 -0
  20. package/core/extends-config.d.ts +27 -0
  21. package/core/extends-config.js +89 -0
  22. package/core/manifest.d.ts +222 -0
  23. package/core/manifest.js +150 -0
  24. package/core/merge-config.d.ts +57 -0
  25. package/core/merge-config.js +146 -0
  26. package/core/package.d.ts +73 -7
  27. package/core/package.js +86 -24
  28. package/core/plugin.d.ts +112 -0
  29. package/core/plugin.js +189 -0
  30. package/core/repository.d.ts +85 -4
  31. package/core/repository.js +258 -81
  32. package/core/resolve-target.d.ts +12 -0
  33. package/core/resolve-target.js +33 -0
  34. package/core/version-scheme.d.ts +134 -0
  35. package/core/version-scheme.js +148 -0
  36. package/core/workspace.d.ts +68 -0
  37. package/core/workspace.js +83 -0
  38. package/index.d.ts +54 -8
  39. package/index.js +42 -7
  40. package/interfaces/rman-config.interface.d.ts +226 -28
  41. package/package.json +15 -7
  42. package/services/change-hash.service.d.ts +88 -0
  43. package/services/change-hash.service.js +112 -0
  44. package/services/changelog.service.d.ts +8 -13
  45. package/services/changelog.service.js +12 -11
  46. package/services/conventional-commits.service.d.ts +73 -0
  47. package/services/conventional-commits.service.js +116 -0
  48. package/services/docker-publish.service.js +1 -1
  49. package/services/exec.service.js +1 -1
  50. package/services/github-release.service.d.ts +2 -2
  51. package/services/github-release.service.js +10 -5
  52. package/services/list.service.js +5 -2
  53. package/services/run.service.d.ts +68 -3
  54. package/services/run.service.js +162 -70
  55. package/services/system-info.d.ts +22 -7
  56. package/services/system-info.js +8 -23
  57. package/services/version-plan.service.d.ts +244 -0
  58. package/services/version-plan.service.js +414 -0
  59. package/services/version.service.d.ts +92 -82
  60. package/services/version.service.js +233 -383
  61. package/services.d.ts +5 -3
  62. package/services.js +5 -3
  63. package/utils/bin-path.d.ts +59 -0
  64. package/utils/bin-path.js +82 -0
  65. package/utils/child-tracker.d.ts +16 -0
  66. package/utils/child-tracker.js +30 -0
  67. package/utils/exec.d.ts +13 -2
  68. package/utils/exec.js +17 -17
  69. package/utils/git.d.ts +9 -3
  70. package/utils/git.js +10 -2
  71. package/utils/package-filter.d.ts +33 -2
  72. package/utils/package-filter.js +47 -7
  73. package/utils/release-version.js +3 -3
  74. package/utils/run-bin.d.ts +46 -0
  75. package/utils/run-bin.js +63 -0
  76. package/utils/version-stamp.d.ts +48 -0
  77. package/utils/version-stamp.js +88 -0
  78. package/commands/ci.command.js +0 -30
  79. package/commands/clean.command.d.ts +0 -3
  80. package/commands/clean.command.js +0 -36
  81. package/commands/publish.command.d.ts +0 -3
  82. package/commands/publish.command.js +0 -225
  83. package/rmanrc.schema.json +0 -375
  84. package/services/ci.service.d.ts +0 -40
  85. package/services/ci.service.js +0 -204
  86. package/services/clean.service.d.ts +0 -42
  87. package/services/clean.service.js +0 -226
  88. package/services/publish.service.d.ts +0 -79
  89. package/services/publish.service.js +0 -207
  90. package/utils/change-hash.d.ts +0 -68
  91. package/utils/change-hash.js +0 -98
  92. package/utils/conventional-commits.d.ts +0 -52
  93. package/utils/conventional-commits.js +0 -90
  94. package/utils/npm-run-path.d.ts +0 -67
  95. package/utils/npm-run-path.js +0 -63
  96. package/utils/workspace-range.d.ts +0 -17
  97. package/utils/workspace-range.js +0 -28
  98. /package/commands/{ci.command.d.ts → config.command.d.ts} +0 -0
@@ -1,19 +1,22 @@
1
1
  import colors from 'ansi-colors';
2
+ import { ChangeHashService } from '../services/change-hash.service.js';
2
3
  import { ChangelogService } from '../services/changelog.service.js';
3
4
  import { Logger, resolveRootLogLevel } from '../utils/logger.js';
4
- import { applyPackageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
5
+ import { applyPackageFilterOptions, applyRootOption, readPackageFilterOptions } from '../utils/package-filter.js';
5
6
  export function initCli(repository, program) {
6
7
  program.command({
7
8
  command: 'changelog',
9
+ configKeys: ['changelog', 'publish.skip'],
8
10
  describe: 'Generates a changelog per package from unreleased commits',
9
- builder: cmd => applyPackageFilterOptions(cmd)
11
+ builder: cmd => applyRootOption(applyPackageFilterOptions(cmd), 'Generate')
10
12
  .example('$0 changelog', "# Auto-detects each package's own last release tag (or npm version)")
11
13
  .example('$0 changelog --from <hash> --write', '# Since a specific commit, written to file')
12
14
  .option('from', {
13
15
  describe: 'Generate the changelog since this commit/hash, applied the same way to every package. ' +
14
- 'Default (also "npm" explicitly): auto-detect per package from its own most recent release ' +
15
- 'tag - same as "version"/"changed" - falling back to its published npm version (no tag yet), ' +
16
- "then to its whole history for a package that's never been released at all",
16
+ 'Default (also "auto" explicitly): auto-detect per package from its own most recent release ' +
17
+ 'tag - same as "version"/"changed" - falling back to the version its own ecosystem\'s ' +
18
+ "registry reports (no tag yet), then to its whole history for a package that's never been " +
19
+ 'released at all',
17
20
  type: 'string',
18
21
  })
19
22
  .option('write', {
@@ -24,12 +27,6 @@ export function initCli(repository, program) {
24
27
  describe: "With --write, the file to prepend into, relative to each package's own directory " +
25
28
  '(default: "CHANGELOG.md", or .rmanrc "changelog.filePath")',
26
29
  type: 'string',
27
- })
28
- .option('root', {
29
- alias: 'r',
30
- describe: 'Generate for the whole repository even when the current directory is inside a single ' +
31
- 'package (which otherwise scopes it to just that package). No effect elsewhere.',
32
- type: 'boolean',
33
30
  })
34
31
  .option('include-skipped', {
35
32
  describe: 'Also generate for a package with .rmanrc "publish.skip" - excluded by default',
@@ -46,10 +43,11 @@ export function initCli(repository, program) {
46
43
  const from = args.from;
47
44
  const write = args.write;
48
45
  const logger = new Logger(args.logLevel ?? resolveRootLogLevel(repository));
49
- if (!from || from === 'npm') {
50
- // Auto-detection is mostly local git work, but the npm fallback it can reach for (only
51
- // when a package has no tag at all) is a network round trip per package - without this,
52
- // the command looks hung for that stretch instead of just busy.
46
+ if (!from || from === ChangeHashService.AUTO) {
47
+ // Auto-detection is mostly local git work, but the registry fallback it can reach for
48
+ // (only when a package has no tag at all, and only if the package's own ecosystem provides
49
+ // one) is a network round trip per package - without this, the command looks hung for that
50
+ // stretch instead of just busy.
53
51
  logger.info(colors.gray("Detecting each package's last release..."));
54
52
  }
55
53
  const options = {
@@ -0,0 +1,60 @@
1
+ import path from 'node:path';
2
+ import colors from 'ansi-colors';
3
+ import * as yaml from 'js-yaml';
4
+ import { DEFERRED_PATHS } from '../core/config.js';
5
+ import { applyRootOption, readRootOption } from '../utils/package-filter.js';
6
+ export function initCli(repository, program) {
7
+ program.command({
8
+ command: 'config',
9
+ describe: 'Prints the effective .rmanrc config for the package of the current directory',
10
+ builder: cmd => applyRootOption(cmd, 'Print the config for')
11
+ .example('$0 config', '# The config of the package you are standing in')
12
+ .example('$0 config --root', "# The repository root's own config instead")
13
+ .example('$0 config --json | jq .version', '# Machine-readable')
14
+ .option('json', {
15
+ describe: 'Print as JSON instead of YAML - nothing else on stdout, so it can be piped.',
16
+ type: 'boolean',
17
+ default: false,
18
+ }),
19
+ handler: args => {
20
+ const target = (!readRootOption(args) && repository.currentPackage) || repository.rootPackage;
21
+ if (args.json) {
22
+ console.log(JSON.stringify(target.config, undefined, 2));
23
+ return;
24
+ }
25
+ /**
26
+ * **Colour only on a terminal, and here that is correctness rather than taste.** The header
27
+ * and notes are YAML `#` comments so the whole output stays loadable - and an escape sequence
28
+ * inside one makes it *unloadable*: `rman config > rmanrc.yml` wrote a file js-yaml rejects
29
+ * with "the stream contains non-printable characters" (measured; `ansi-colors` does not turn
30
+ * itself off for a pipe here). The repository's own convention for this is
31
+ * `process.stdout.isTTY`, as `run`/`exec`'s progress panel uses.
32
+ */
33
+ const comment = (text) => (process.stdout.isTTY ? colors.gray(text) : text);
34
+ const relativeDir = path.relative(repository.dirname, target.dirname) || '.';
35
+ console.log(comment(`# ${target.name} (${relativeDir})`));
36
+ for (const note of deferredNotes(target))
37
+ console.log(comment(`# ${note}`));
38
+ /** `noRefs`: a value appearing twice in the config is the *same object* after merging, and
39
+ * js-yaml would otherwise emit the second as an `*anchor` reference - valid YAML that reads
40
+ * as a mistake in something meant to be looked at. */
41
+ console.log(yaml.dump(target.config, { noRefs: true, lineWidth: 100 }).trimEnd());
42
+ },
43
+ });
44
+ }
45
+ /**
46
+ * The one honest caveat about this output: **`version.before`/`.exec`/`.after` are printed raw**,
47
+ * expressions and all, because they are the paths in `DEFERRED_PATHS` - `${{ pkg.targetVersion }}`
48
+ * cannot be evaluated until `version` has computed a plan, so the repository deliberately leaves
49
+ * them unevaluated at load. Without saying so, a reader sees an uninterpolated `${{ ... }}` sitting
50
+ * among interpolated values and concludes interpolation is broken.
51
+ */
52
+ function deferredNotes(pkg) {
53
+ const raw = DEFERRED_PATHS.filter(p => valueAt(pkg.config, p) !== undefined);
54
+ if (!raw.length)
55
+ return [];
56
+ return [`${raw.join(', ')}: printed raw - evaluated by "version" itself, once it knows the target version`];
57
+ }
58
+ function valueAt(config, dotted) {
59
+ return dotted.split('.').reduce((node, key) => (node == null ? undefined : node[key]), config);
60
+ }
@@ -1,14 +1,16 @@
1
1
  import path from 'node:path';
2
2
  import colors from 'ansi-colors';
3
- import { findLatestTag } from '../utils/change-hash.js';
3
+ import { ChangeHashService } from '../services/change-hash.service.js';
4
4
  import { GitHelper } from '../utils/git.js';
5
+ import { applyRootOption, readRootOption } from '../utils/package-filter.js';
5
6
  export function initCli(repository, program) {
6
7
  program.command({
7
8
  command: 'diff [package]',
8
9
  describe: "Shows the git diff since a package's (or the whole repository's) last release tag",
9
- builder: cmd => cmd
10
+ builder: cmd => applyRootOption(cmd, 'Diff')
10
11
  .example('$0 diff', "# Since the repository's own last tag")
11
12
  .example('$0 diff pkg-a', "# Since pkg-a's own last tag, scoped to its directory")
13
+ .example('$0 diff --root', '# The whole repository, from inside a package')
12
14
  .positional('package', {
13
15
  describe: 'Package name - diffs just that package, since its own last tag. Omit to diff the whole ' +
14
16
  "repository since its own last tag (or the current directory's package, if standing inside one).",
@@ -31,11 +33,14 @@ export function initCli(repository, program) {
31
33
  target = pkg;
32
34
  pathspec = path.relative(repository.dirname, pkg.dirname);
33
35
  }
34
- else if (repository.currentPackage) {
36
+ else if (!readRootOption(args) && repository.currentPackage) {
37
+ /** The measured gap this closes: `diff` narrowed to the current package like `run` and
38
+ * `changelog` do, but offered no way to say "the whole repository" without naming a
39
+ * package - and no package name means the repository, so there was nothing to type. */
35
40
  target = repository.currentPackage;
36
41
  pathspec = path.relative(repository.dirname, target.dirname);
37
42
  }
38
- const tag = await findLatestTag(git, target);
43
+ const tag = await ChangeHashService.findLatestTag(git, target);
39
44
  if (!tag) {
40
45
  console.log(colors.gray(`No release tag found for "${target.name}" - nothing to diff against.`));
41
46
  return;
@@ -1,11 +1,11 @@
1
1
  import { ExecService } from '../services/exec.service.js';
2
2
  import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
3
- import { applyPackageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
3
+ import { applyPackageFilterOptions, applyRootOption, readPackageFilterOptions } from '../utils/package-filter.js';
4
4
  export function initCli(repository, program) {
5
5
  program.command({
6
6
  command: 'exec [command..]',
7
7
  describe: 'Runs an arbitrary shell command in each package - unlike run, not tied to any npm script',
8
- builder: cmd => applyBranchGuardOptions(applyPackageFilterOptions(cmd))
8
+ builder: cmd => applyRootOption(applyBranchGuardOptions(applyPackageFilterOptions(cmd)), 'Run')
9
9
  .parserConfiguration({ 'populate--': true, 'unknown-options-as-args': true })
10
10
  .example('$0 exec rm -rf dist', '# Not an npm script - runs directly in every package')
11
11
  .example('$0 exec --scope pkg-a -- ls -la', '# "--" needed only if the command shares a flag name with exec\'s own')
@@ -50,12 +50,6 @@ export function initCli(repository, program) {
50
50
  .option('changed-since', {
51
51
  describe: 'Only run in packages that have changed since the given git commit/hash',
52
52
  type: 'string',
53
- })
54
- .option('root', {
55
- alias: 'r',
56
- describe: 'Run across the whole repository even when the current directory is inside a single ' +
57
- 'package (which otherwise scopes the run to just that package). No effect elsewhere.',
58
- type: 'boolean',
59
53
  })
60
54
  .conflicts('changed', 'changed-since'),
61
55
  handler: async (args) => {
@@ -5,6 +5,7 @@ import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions }
5
5
  export function initCli(repository, program) {
6
6
  program.command({
7
7
  command: 'github-release',
8
+ configKeys: ['githubRelease', 'version.releaseTagPattern'],
8
9
  describe: "Creates the repository's GitHub Release for the version that just shipped",
9
10
  builder: cmd => applyBranchGuardOptions(cmd)
10
11
  .example('$0 github-release', '# Show what would be released, then ask for confirmation')
@@ -1,3 +1,12 @@
1
1
  import type { Argv } from 'yargs';
2
2
  import type { Repository } from '../core/repository.js';
3
+ /**
4
+ * `rman info` - environment and repository, and back in the core because most of what it reports
5
+ * (OS, CPU, shell, git, the repository's own shape) is true of any repository.
6
+ *
7
+ * The Node half is not here at all: installing `rman-node` augments `SystemInfo` and the package
8
+ * manager, `npmPackages` and this plugin's own version start appearing. Without it nothing
9
+ * npm-shaped is asked for or printed, which is the right answer for a repository in any other
10
+ * language.
11
+ */
3
12
  export declare function initCli(repository: Repository, program: Argv): void;
@@ -1,6 +1,5 @@
1
1
  import colors from 'ansi-colors';
2
2
  import semver from 'semver';
3
- import { CiService } from '../services/ci.service.js';
4
3
  import { SystemInfo } from '../services/system-info.js';
5
4
  function printSystemInfo(systemInfo) {
6
5
  const maxName = Object.keys(systemInfo).reduce((l, p) => Object.keys(systemInfo[p]).reduce((i, x) => Math.max(i, x.length), l), 0);
@@ -36,6 +35,15 @@ function printRepositoryInfo(info) {
36
35
  console.log(' ' + colors.reset('Packages') + ' :', colors.yellowBright(String(info.packageCount)), colors.gray('(run "list" to see them)'));
37
36
  }
38
37
  }
38
+ /**
39
+ * `rman info` - environment and repository, and back in the core because most of what it reports
40
+ * (OS, CPU, shell, git, the repository's own shape) is true of any repository.
41
+ *
42
+ * The Node half is not here at all: installing `rman-node` augments `SystemInfo` and the package
43
+ * manager, `npmPackages` and this plugin's own version start appearing. Without it nothing
44
+ * npm-shaped is asked for or printed, which is the right answer for a repository in any other
45
+ * language.
46
+ */
39
47
  export function initCli(repository, program) {
40
48
  program.command({
41
49
  command: 'info',
@@ -49,7 +57,9 @@ export function initCli(repository, program) {
49
57
  type: 'boolean',
50
58
  }),
51
59
  handler: async (args) => {
52
- const systemInfo = await SystemInfo.getSystemInfo(CiService.resolvePackageManager(repository));
60
+ /** Only the repository - which package manager to report, if any, is a question the core
61
+ * cannot ask. `rman-node`'s augmentation reads `.rmanrc "packageManager"` off this. */
62
+ const systemInfo = await SystemInfo.getSystemInfo({ repository });
53
63
  const repositoryInfo = SystemInfo.getRepositoryInfo(repository);
54
64
  if (args.json) {
55
65
  console.log(JSON.stringify({ ...systemInfo, repository: repositoryInfo }, undefined, 2));
@@ -1,8 +1,8 @@
1
1
  import { RunService } from '../services/run.service.js';
2
2
  import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
3
- import { applyPackageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
3
+ import { applyPackageFilterOptions, applyRootOption, readPackageFilterOptions } from '../utils/package-filter.js';
4
4
  export function applyRunOptions(cmd) {
5
- return applyBranchGuardOptions(applyPackageFilterOptions(cmd))
5
+ return applyRootOption(applyBranchGuardOptions(applyPackageFilterOptions(cmd)), 'Run')
6
6
  .option('parallel', {
7
7
  describe: 'Max packages to build at once: omit/true for CPU count (or .rmanrc run.<script>.concurrency), ' +
8
8
  'a number for that many, false to run serially. Packages always build in dependency order.',
@@ -39,12 +39,6 @@ export function applyRunOptions(cmd) {
39
39
  .option('changed-since', {
40
40
  describe: 'Only run in packages that have changed since the given git commit/hash',
41
41
  type: 'string',
42
- })
43
- .option('root', {
44
- alias: 'r',
45
- describe: 'Run across the whole repository even when the current directory is inside a single ' +
46
- 'package (which otherwise scopes the run to just that package). No effect elsewhere.',
47
- type: 'boolean',
48
42
  })
49
43
  .conflicts('changed', 'changed-since');
50
44
  }
@@ -64,6 +58,9 @@ export function readRunOptions(args) {
64
58
  export function initCli(repository, program) {
65
59
  program.command({
66
60
  command: 'run <script>',
61
+ /** Which `.rmanrc` `--config` shows for this command: the script's own block, whichever
62
+ * script was asked for. */
63
+ configKeys: (args) => ['run.' + args.script],
67
64
  describe: 'Run an npm script in each package',
68
65
  builder: cmd => applyRunOptions(cmd)
69
66
  .example('$0 run build', '')
@@ -4,6 +4,7 @@ import { applyRunOptions, readRunOptions } from './run.command.js';
4
4
  export function initCli(repository, program) {
5
5
  program.command({
6
6
  command: 'test',
7
+ configKeys: ['run.test'],
7
8
  describe: 'Alias for "run test"',
8
9
  builder: cmd => applyRunOptions(cmd).example('$0 test', '# Tests packages'),
9
10
  handler: async (args) => {
@@ -2,19 +2,32 @@ import readline from 'node:readline/promises';
2
2
  import colors from 'ansi-colors';
3
3
  import EasyTable from 'easy-table';
4
4
  import { VersionService } from '../services/version.service.js';
5
+ import { VersionPlanService } from '../services/version-plan.service.js';
5
6
  import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
6
7
  import { applyPackageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
7
8
  export function initCli(repository, program) {
9
+ /** `rman version <bump|version>` is validated by the root's scheme (see `getPlan`), so the help
10
+ * has to name that scheme's own words rather than semver's - otherwise `--help` in a repository
11
+ * numbering some other way documents keywords its own planner would reject. A four-part scheme
12
+ * lists four here. */
13
+ const { name: scheme, bumpNames } = repository.rootPackage.versionScheme;
14
+ const bumps = bumpNames.map(n => `"${n}"`).join('/');
15
+ /** For the examples. Not `smallestBump`, which throws: `--help` must still render for a scheme
16
+ * that declares none, and the placeholder says what to write there. */
17
+ const smallest = bumpNames[0] ?? '<bump>';
8
18
  program.command({
9
19
  command: 'version [bump]',
20
+ /** `changelog` too: `--changelog` folds one into the bump commit, and `group` is what decides
21
+ * which packages move together. */
22
+ configKeys: ['version', 'changelog', 'group'],
10
23
  describe: 'Bumps versions of changed packages (and their dependents), grouped via .rmanrc "group"',
11
24
  builder: cmd => applyBranchGuardOptions(applyPackageFilterOptions(cmd))
12
- .example('$0 version patch', '# Bump patch severity directly, applied immediately')
13
- .example('$0 version', "# Auto-detect severity from commits, show the plan, don't write anything")
25
+ .example(`$0 version ${smallest}`, `# Bump ${smallest} directly, applied immediately`)
26
+ .example('$0 version', "# Auto-detect the bump from commits, show the plan, don't write anything")
14
27
  .example('$0 version --interactive', '# Show the plan either way, then ask for confirmation')
15
- .example('$0 version patch --show', '# Preview what an explicit patch bump would do, without applying it')
28
+ .example(`$0 version ${smallest} --show`, `# Preview what an explicit ${smallest} would do, without applying it`)
16
29
  .positional('bump', {
17
- describe: 'A release-type keyword ("patch"/"minor"/"major") or an explicit semver version. ' +
30
+ describe: `A bump keyword (${bumps}) or an explicit ${scheme} version. ` +
18
31
  'Omit to auto-detect from commits and only preview the plan.',
19
32
  type: 'string',
20
33
  })
@@ -25,15 +38,15 @@ export function initCli(repository, program) {
25
38
  })
26
39
  .option('show', {
27
40
  describe: 'Show the resulting plan for the given bump without applying it - unlike omitting bump ' +
28
- 'entirely, this still uses the given release-type keyword/version to compute the plan, ' +
41
+ 'entirely, this still uses the given bump keyword/version to compute the plan, ' +
29
42
  'just never writes it.',
30
43
  type: 'boolean',
31
44
  })
32
45
  .conflicts('show', 'interactive')
33
46
  .option('yes', {
34
47
  alias: 'y',
35
- describe: 'Skip the confirmation prompt and apply the computed plan immediately - auto-detected ' +
36
- 'severity included, no explicit bump keyword required (same idea as "publish --yes").',
48
+ describe: 'Skip the confirmation prompt and apply the computed plan immediately - an auto-detected ' +
49
+ 'bump included, no explicit bump keyword required (same idea as "publish --yes").',
37
50
  type: 'boolean',
38
51
  })
39
52
  .conflicts('yes', 'interactive')
@@ -61,13 +74,13 @@ export function initCli(repository, program) {
61
74
  .option('preid', {
62
75
  describe: 'Make the bump a prerelease with this identifier (e.g. "beta" -> 1.2.3-beta.0). ' +
63
76
  'Running again with the same --preid increments it (-> 1.2.3-beta.1); a different ' +
64
- 'identifier starts a fresh prerelease line. Ignored when bump is an explicit semver version.',
77
+ `identifier starts a fresh prerelease line. Ignored when bump is an explicit ${scheme} version.`,
65
78
  type: 'string',
66
79
  }),
67
80
  handler: async (args) => {
68
81
  await assertAllowedBranch(repository, readBranchGuardOptions(args));
69
82
  const bump = args.bump;
70
- const plan = await VersionService.getPlan(repository, {
83
+ const plan = await VersionPlanService.getPlanner().getPlan(repository, {
71
84
  ...readPackageFilterOptions(args),
72
85
  bump,
73
86
  ignoreDirty: args.ignoreDirty,
@@ -107,14 +120,40 @@ export function initCli(repository, program) {
107
120
  message: args.message,
108
121
  changelog,
109
122
  });
110
- for (const entry of applied) {
111
- if (entry.status === 'bump') {
112
- console.log(colors.green('updated'), colors.cyan(entry.package.name), entry.from, '->', colors.yellow(entry.to));
113
- }
114
- }
123
+ printApplied(applied);
115
124
  },
116
125
  });
117
126
  }
127
+ /**
128
+ * What the run *did* - which is deliberately not the table again.
129
+ *
130
+ * The plan is printed above, so repeating `name from -> to` per package said nothing: `applyPlan`
131
+ * returned the same array it was handed, so the second list could not have differed. What it never
132
+ * reported is everything below - the commits (one per group, plus the root's informational sync),
133
+ * the tags, a tag that already existed and was left alone, and whether any of it was pushed. A
134
+ * release that is committed but not pushed looks identical to one that is, until someone looks.
135
+ */
136
+ function printApplied(result) {
137
+ const count = result.updated.length;
138
+ console.log(`\n${colors.green('updated')} ${count} package${count === 1 ? '' : 's'}`);
139
+ for (const commit of result.commits) {
140
+ console.log(`${colors.green('commit')} ${colors.yellow(commit.sha)} ${colors.gray(commit.message.split('\n')[0])}`);
141
+ }
142
+ if (result.tags.length) {
143
+ const label = (tag) => colors.cyan(tag.name) + (tag.created ? '' : colors.gray(' (existing, left alone)'));
144
+ const release = result.tags.filter(t => t.release);
145
+ const perPackage = result.tags.filter(t => !t.release);
146
+ if (perPackage.length)
147
+ console.log(`${colors.green('tags')} ${perPackage.map(label).join(', ')}`);
148
+ /** Listed on its own line: it belongs to the repository rather than to any package, which is
149
+ * the whole reason it exists. */
150
+ if (release.length)
151
+ console.log(`${colors.green('tags')} ${release.map(label).join(', ')} ${colors.gray('(repository release)')}`);
152
+ }
153
+ console.log(result.pushed
154
+ ? `${colors.green('push')} pushed, with tags`
155
+ : `${colors.gray('push')} ${colors.gray('not pushed - run with --push, or push it yourself')}`);
156
+ }
118
157
  function printPlan(entries) {
119
158
  const table = new EasyTable();
120
159
  for (const e of entries) {
package/constants.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.0.10';
1
+ export const version = '1.1.1';