rman 1.3.0 → 2.0.0-beta.3
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.
- package/README.md +65 -31
- package/builtins/platforms/node/augmentation/rmanrc.augmentation.d.ts +83 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.d.ts +26 -0
- package/builtins/platforms/node/augmentation/system-info.augmentation.js +79 -0
- package/builtins/platforms/node/commands/ci.command.d.ts +133 -0
- package/builtins/platforms/node/commands/ci.command.js +60 -0
- package/builtins/platforms/node/commands/clean.command.d.ts +185 -0
- package/builtins/platforms/node/commands/clean.command.js +74 -0
- package/builtins/platforms/node/index.d.ts +8 -0
- package/builtins/platforms/node/index.js +8 -0
- package/builtins/platforms/node/node-config.interface.d.ts +76 -0
- package/builtins/platforms/node/node-config.interface.js +7 -0
- package/builtins/platforms/node/node-manifest.provider.d.ts +68 -0
- package/builtins/platforms/node/node-manifest.provider.js +125 -0
- package/builtins/platforms/node/node.platform.d.ts +53 -0
- package/builtins/platforms/node/node.platform.js +134 -0
- package/builtins/platforms/node/services/ci.service.d.ts +47 -0
- package/builtins/platforms/node/services/ci.service.js +213 -0
- package/builtins/platforms/node/services/clean.service.d.ts +53 -0
- package/builtins/platforms/node/services/clean.service.js +237 -0
- package/builtins/platforms/node/services/publish.service.d.ts +114 -0
- package/builtins/platforms/node/services/publish.service.js +371 -0
- package/builtins/platforms/node/services/version-plan.service.d.ts +44 -0
- package/builtins/platforms/node/services/version-plan.service.js +58 -0
- package/builtins/platforms/node/utils/workspace-range.d.ts +26 -0
- package/builtins/platforms/node/utils/workspace-range.js +28 -0
- package/builtins/presets/index.d.ts +15 -0
- package/builtins/presets/index.js +57 -0
- package/builtins/presets/node.d.ts +16 -0
- package/builtins/presets/node.js +57 -0
- package/{services → builtins/publish-targets/docker}/docker-publish.service.d.ts +52 -31
- package/{services → builtins/publish-targets/docker}/docker-publish.service.js +49 -26
- package/builtins/publish-targets/docker/docker.target.d.ts +54 -0
- package/builtins/publish-targets/docker/docker.target.js +40 -0
- package/builtins/publish-targets/docker/index.d.ts +2 -0
- package/builtins/publish-targets/docker/index.js +2 -0
- package/builtins/publish-targets/npm/index.d.ts +2 -0
- package/builtins/publish-targets/npm/index.js +2 -0
- package/builtins/publish-targets/npm/npm-publish-target.d.ts +73 -0
- package/builtins/publish-targets/npm/npm-publish-target.js +95 -0
- package/builtins/publish-targets/npm/npm-view.d.ts +48 -0
- package/builtins/publish-targets/npm/npm-view.js +71 -0
- package/cli.d.ts +8 -0
- package/cli.js +228 -93
- package/commands/build.command.d.ts +177 -3
- package/commands/build.command.js +20 -10
- package/commands/changelog.command.d.ts +296 -3
- package/commands/changelog.command.js +127 -43
- package/commands/config.command.d.ts +44 -3
- package/commands/config.command.js +53 -24
- package/commands/diff.command.d.ts +37 -3
- package/commands/diff.command.js +25 -16
- package/commands/exec.command.d.ts +193 -3
- package/commands/exec.command.js +60 -58
- package/commands/github-release.command.d.ts +154 -3
- package/commands/github-release.command.js +67 -37
- package/commands/import.command.d.ts +36 -3
- package/commands/import.command.js +28 -20
- package/commands/info.command.d.ts +35 -7
- package/commands/info.command.js +36 -30
- package/commands/lint.command.d.ts +176 -0
- package/commands/lint.command.js +34 -0
- package/commands/list.command.d.ts +163 -3
- package/commands/list.command.js +109 -71
- package/commands/publish.command.d.ts +231 -0
- package/commands/publish.command.js +304 -0
- package/commands/run.command.d.ts +186 -6
- package/commands/run.command.js +26 -72
- package/commands/test.command.d.ts +173 -3
- package/commands/test.command.js +16 -10
- package/commands/version.command.d.ts +330 -3
- package/commands/version.command.js +292 -78
- package/commands.d.ts +32 -0
- package/commands.js +28 -0
- package/constants.js +1 -1
- package/core/application.d.ts +116 -0
- package/core/application.js +160 -0
- package/core/classes/package.d.ts +219 -0
- package/core/classes/package.js +214 -0
- package/core/classes/registry.d.ts +30 -0
- package/core/classes/registry.js +47 -0
- package/core/{repository.d.ts → classes/repository.d.ts} +69 -20
- package/core/{repository.js → classes/repository.js} +195 -75
- package/core/classes/service.d.ts +49 -0
- package/core/classes/service.js +40 -0
- package/core/{version-scheme.d.ts → classes/version-scheme.d.ts} +23 -1
- package/core/{version-scheme.js → classes/version-scheme.js} +29 -1
- package/core/classes/workspace.d.ts +275 -0
- package/core/classes/workspace.js +537 -0
- package/core/command-builder.d.ts +14 -0
- package/core/command-builder.js +94 -0
- package/core/config/config-file-scope.d.ts +107 -0
- package/core/config/config-file-scope.js +226 -0
- package/core/config/config-interpolator.d.ts +164 -0
- package/core/config/config-interpolator.js +577 -0
- package/core/config/config-paths.d.ts +65 -0
- package/core/config/config-paths.js +78 -0
- package/core/config/config-reader.d.ts +192 -0
- package/core/config/config-reader.js +727 -0
- package/core/{merge-config.d.ts → config/merge-config.d.ts} +33 -34
- package/core/config/merge-config.js +260 -0
- package/core/{resolve-target.d.ts → config/resolve-config-target.d.ts} +1 -1
- package/core/{resolve-target.js → config/resolve-config-target.js} +1 -1
- package/core/{custom-command.d.ts → interfaces/custom-command.d.ts} +46 -10
- package/core/{custom-command.js → interfaces/custom-command.js} +44 -17
- package/core/{manifest.d.ts → interfaces/manifest.d.ts} +49 -27
- package/core/interfaces/manifest.js +132 -0
- package/core/interfaces/plugin.d.ts +174 -0
- package/core/interfaces/plugin.js +124 -0
- package/core/interfaces/publish-target.d.ts +136 -0
- package/core/interfaces/publish-target.js +43 -0
- package/core/{run-step.d.ts → interfaces/run-step.d.ts} +4 -4
- package/core/interfaces/run-step.js +1 -0
- package/core/plugin-loader.d.ts +25 -0
- package/core/plugin-loader.js +53 -0
- package/index.d.ts +122 -24
- package/index.js +66 -16
- package/interfaces/config-scope.interface.d.ts +223 -0
- package/interfaces/config-scope.interface.js +1 -0
- package/interfaces/rman-config.interface.d.ts +821 -203
- package/interfaces/rman-config.interface.js +78 -1
- package/package.json +3 -1
- package/services/change-hash.service.d.ts +42 -8
- package/services/change-hash.service.js +92 -13
- package/services/changelog.service.d.ts +91 -52
- package/services/changelog.service.js +460 -74
- package/services/config-service.d.ts +8 -0
- package/services/config-service.js +3 -0
- package/services/exec.service.d.ts +23 -12
- package/services/exec.service.js +14 -9
- package/services/github-release.service.d.ts +45 -34
- package/services/github-release.service.js +15 -12
- package/services/import.service.d.ts +25 -14
- package/services/import.service.js +9 -5
- package/services/list.service.d.ts +67 -13
- package/services/list.service.js +62 -15
- package/services/run.service.d.ts +35 -22
- package/services/run.service.js +316 -233
- package/services/system-info.d.ts +1 -1
- package/services/version-plan.service.d.ts +35 -8
- package/services/version-plan.service.js +96 -36
- package/services/version.service.d.ts +34 -14
- package/services/version.service.js +35 -16
- package/services.d.ts +1 -1
- package/services.js +1 -1
- package/utils/bin-path.d.ts +6 -7
- package/utils/bin-path.js +7 -18
- package/utils/branch-guard.d.ts +30 -1
- package/utils/branch-guard.js +31 -0
- package/utils/color-yaml.d.ts +8 -0
- package/utils/color-yaml.js +86 -0
- package/utils/exec.d.ts +10 -0
- package/utils/exec.js +1 -1
- package/utils/git.d.ts +26 -0
- package/utils/git.js +65 -0
- package/utils/logger.d.ts +2 -2
- package/utils/logger.js +1 -1
- package/utils/package-filter.d.ts +135 -8
- package/utils/package-filter.js +204 -16
- package/utils/printable-config.d.ts +9 -1
- package/utils/printable-config.js +46 -1
- package/utils/progress-panel.d.ts +9 -0
- package/utils/progress-panel.js +23 -1
- package/utils/release-version.d.ts +1 -1
- package/utils/run-bin.d.ts +10 -0
- package/utils/run-bin.js +1 -1
- package/utils/run-options.d.ts +97 -0
- package/utils/run-options.js +81 -0
- package/utils/version-group.d.ts +31 -0
- package/utils/version-group.js +43 -0
- package/utils/version-stamp.d.ts +1 -1
- package/utils/version-stamp.js +1 -1
- package/commands/changed.command.d.ts +0 -3
- package/commands/changed.command.js +0 -29
- package/core/config.d.ts +0 -409
- package/core/config.js +0 -939
- package/core/extends-config.d.ts +0 -27
- package/core/extends-config.js +0 -89
- package/core/manifest.js +0 -150
- package/core/merge-config.js +0 -219
- package/core/package.d.ts +0 -83
- package/core/package.js +0 -106
- package/core/plugin.d.ts +0 -112
- package/core/plugin.js +0 -189
- package/core/workspace.d.ts +0 -68
- package/core/workspace.js +0 -83
- /package/{core/run-step.js → builtins/platforms/node/augmentation/rmanrc.augmentation.js} +0 -0
|
@@ -1,11 +1,118 @@
|
|
|
1
1
|
import readline from 'node:readline/promises';
|
|
2
2
|
import colors from 'ansi-colors';
|
|
3
3
|
import EasyTable from 'easy-table';
|
|
4
|
-
import {
|
|
4
|
+
import { registerCommand } from '../interfaces/rman-config.interface.js';
|
|
5
5
|
import { VersionPlanService } from '../services/version-plan.service.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
6
|
+
import { assertAllowedBranch, branchGuardOptions, readBranchGuardOptions } from '../utils/branch-guard.js';
|
|
7
|
+
import { packageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
|
|
8
|
+
/**
|
|
9
|
+
* Hoisted out of the metadata literal so the handler can be annotated against them - see
|
|
10
|
+
* `RmanConfig.ArgsOf` for why an inferred `argv` and the metadata's own typo checking cannot both
|
|
11
|
+
* work in one signature.
|
|
12
|
+
*
|
|
13
|
+
* `as const` on the command string is load-bearing twice over: the config key is derived from it
|
|
14
|
+
* (`'version'`), and so are the positional names it declares.
|
|
15
|
+
*/
|
|
16
|
+
const COMMAND = 'version [bump]';
|
|
17
|
+
const config = {
|
|
18
|
+
/** The two shared groups, spread rather than applied - this is what
|
|
19
|
+
* `applyBranchGuardOptions(applyPackageFilterOptions(cmd))` used to say. Spread first, so an
|
|
20
|
+
* option deliberately overridden below wins. */
|
|
21
|
+
...packageFilterOptions,
|
|
22
|
+
...branchGuardOptions,
|
|
23
|
+
interactive: {
|
|
24
|
+
target: 'cli',
|
|
25
|
+
alias: 'i',
|
|
26
|
+
describe: 'Show the plan and ask for confirmation before applying (with or without an explicit bump)',
|
|
27
|
+
type: 'boolean',
|
|
28
|
+
},
|
|
29
|
+
show: {
|
|
30
|
+
target: 'cli',
|
|
31
|
+
describe: 'Show the resulting plan for the given bump without applying it - unlike omitting bump ' +
|
|
32
|
+
'entirely, this still uses the given bump keyword/version to compute the plan, ' +
|
|
33
|
+
'just never writes it.',
|
|
34
|
+
type: 'boolean',
|
|
35
|
+
conflicts: 'interactive',
|
|
36
|
+
},
|
|
37
|
+
yes: {
|
|
38
|
+
target: 'cli',
|
|
39
|
+
alias: 'y',
|
|
40
|
+
describe: 'Skip the confirmation prompt and apply the computed plan immediately - an auto-detected ' +
|
|
41
|
+
'bump included, no explicit bump keyword required (same idea as "publish --yes").',
|
|
42
|
+
type: 'boolean',
|
|
43
|
+
conflicts: 'interactive',
|
|
44
|
+
},
|
|
45
|
+
json: {
|
|
46
|
+
target: 'cli',
|
|
47
|
+
alias: 'j',
|
|
48
|
+
describe: 'Print the plan as JSON and write nothing - the machine-readable form of --show, and what ' +
|
|
49
|
+
'the removed "changed" command was for.',
|
|
50
|
+
type: 'boolean',
|
|
51
|
+
conflicts: ['interactive', 'yes'],
|
|
52
|
+
},
|
|
53
|
+
ignoreDirty: {
|
|
54
|
+
target: 'cli',
|
|
55
|
+
cliName: 'ignore-dirty',
|
|
56
|
+
describe: 'Exclude a package with uncommitted local changes instead of aborting the whole run',
|
|
57
|
+
type: 'boolean',
|
|
58
|
+
},
|
|
59
|
+
push: {
|
|
60
|
+
target: 'cli',
|
|
61
|
+
describe: 'Push the resulting commit(s) and tag(s) to the remote once applied',
|
|
62
|
+
type: 'boolean',
|
|
63
|
+
},
|
|
64
|
+
message: {
|
|
65
|
+
target: 'cli',
|
|
66
|
+
alias: 'm',
|
|
67
|
+
describe: 'Override the commit message for every group this run commits (default: .rmanrc ' +
|
|
68
|
+
'version.commitMessage, or "chore(release): v{version}") - "{version}" is substituted ' +
|
|
69
|
+
"when a commit's own group shares one version.",
|
|
70
|
+
type: 'string',
|
|
71
|
+
},
|
|
72
|
+
changelog: {
|
|
73
|
+
target: 'both',
|
|
74
|
+
describe: "Also write each bumped package's CHANGELOG.md (same as running changelog --write " +
|
|
75
|
+
'separately) and fold it into the same commit as its version bump. Default: .rmanrc ' +
|
|
76
|
+
'"version.changelog", or false - --no-changelog forces it off even when that\'s true.',
|
|
77
|
+
type: 'boolean',
|
|
78
|
+
},
|
|
79
|
+
preid: {
|
|
80
|
+
target: 'cli',
|
|
81
|
+
describe: 'Make the bump a prerelease with this identifier (e.g. "beta" -> 1.2.3-beta.0). ' +
|
|
82
|
+
'Running again with the same --preid increments it (-> 1.2.3-beta.1); a different ' +
|
|
83
|
+
'identifier starts a fresh prerelease line. Ignored when bump is an explicit version.',
|
|
84
|
+
type: 'string',
|
|
85
|
+
},
|
|
86
|
+
/**
|
|
87
|
+
* Config-only, from here down: `.rmanrc "version.*"` keys with no reason to be a flag.
|
|
88
|
+
* `--message` is `commitMessage`'s flag and is declared above; the rest are settings a repository
|
|
89
|
+
* states once, not things a single run overrides.
|
|
90
|
+
*/
|
|
91
|
+
commitMessage: {
|
|
92
|
+
target: 'config',
|
|
93
|
+
describe: 'The commit message for each group this run commits - "{version}" is substituted when a ' +
|
|
94
|
+
'commit\'s own group shares one version. Default "chore(release): v{version}".',
|
|
95
|
+
type: 'string',
|
|
96
|
+
},
|
|
97
|
+
releaseTagPattern: {
|
|
98
|
+
target: 'config',
|
|
99
|
+
describe: "Tag naming the repository's own release, as opposed to the per-package tags " +
|
|
100
|
+
'"changelog.tagPattern" names - only created when the root is on a calendar version. ' +
|
|
101
|
+
'Root-level only. Default "release-*". Must **not** match any package\'s own tag pattern, or ' +
|
|
102
|
+
"that package's changelog boundary resolves to the repository release instead of its own.",
|
|
103
|
+
type: 'string',
|
|
104
|
+
},
|
|
105
|
+
stampDockerfile: {
|
|
106
|
+
target: 'config',
|
|
107
|
+
describe: "Keep this package's Dockerfile org.opencontainers.image.version label in step with the " +
|
|
108
|
+
'version being written. Per-package cascaded. Default true - the label is by specification ' +
|
|
109
|
+
'the version of the packaged software, so there is only one correct value and "version" is ' +
|
|
110
|
+
'what knows it. Only ever rewrites a label the Dockerfile already declares.',
|
|
111
|
+
type: 'boolean',
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
const versionCommand = registerCommand(app => {
|
|
115
|
+
const repository = app.repository;
|
|
9
116
|
/** `rman version <bump|version>` is validated by the root's scheme (see `getPlan`), so the help
|
|
10
117
|
* has to name that scheme's own words rather than semver's - otherwise `--help` in a repository
|
|
11
118
|
* numbering some other way documents keywords its own planner would reject. A four-part scheme
|
|
@@ -15,77 +122,89 @@ export function initCli(repository, program) {
|
|
|
15
122
|
/** For the examples. Not `smallestBump`, which throws: `--help` must still render for a scheme
|
|
16
123
|
* that declares none, and the placeholder says what to write there. */
|
|
17
124
|
const smallest = bumpNames[0] ?? '<bump>';
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
*
|
|
22
|
-
|
|
125
|
+
return {
|
|
126
|
+
/** `as const` so the config key stays derivable from it: `CommandMetadata['command']` is a
|
|
127
|
+
* plain `string`, so without the assertion inference widens `'version [bump]'` and there is
|
|
128
|
+
* nothing left to read `'version'` out of. */
|
|
129
|
+
command: COMMAND,
|
|
23
130
|
describe: 'Bumps versions of changed packages (and their dependents), grouped via .rmanrc "group"',
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
})
|
|
61
|
-
.option('message', {
|
|
62
|
-
alias: 'm',
|
|
63
|
-
describe: 'Override the commit message for every group this run commits (default: .rmanrc ' +
|
|
64
|
-
'version.commitMessage, or "chore(release): v{version}") - "{version}" is substituted ' +
|
|
65
|
-
"when a commit's own group shares one version.",
|
|
66
|
-
type: 'string',
|
|
67
|
-
})
|
|
68
|
-
.option('changelog', {
|
|
69
|
-
describe: "Also write each bumped package's CHANGELOG.md (same as running changelog --write " +
|
|
70
|
-
'separately) and fold it into the same commit as its version bump. Default: .rmanrc ' +
|
|
71
|
-
'"version.changelog", or false - --no-changelog forces it off even when that\'s true.',
|
|
72
|
-
type: 'boolean',
|
|
73
|
-
})
|
|
74
|
-
.option('preid', {
|
|
75
|
-
describe: 'Make the bump a prerelease with this identifier (e.g. "beta" -> 1.2.3-beta.0). ' +
|
|
76
|
-
'Running again with the same --preid increments it (-> 1.2.3-beta.1); a different ' +
|
|
77
|
-
`identifier starts a fresh prerelease line. Ignored when bump is an explicit ${scheme} version.`,
|
|
78
|
-
type: 'string',
|
|
79
|
-
}),
|
|
131
|
+
/**
|
|
132
|
+
* Read, not owned - so they are named here rather than declared in `config`. `group` is a core
|
|
133
|
+
* per-package key that decides which packages move together, `changelog.*` is consulted when
|
|
134
|
+
* `--changelog` folds one into the bump commit, and `allowBranch`/`ignoreBranch` are repo-wide
|
|
135
|
+
* keys the shared branch-guard group only exposes as flags. `version` itself is not listed: it
|
|
136
|
+
* is this command's own key, derived from `command`.
|
|
137
|
+
*/
|
|
138
|
+
configKeys: ['changelog', 'group', 'allowBranch', 'ignoreBranch'],
|
|
139
|
+
config,
|
|
140
|
+
examples: [
|
|
141
|
+
{
|
|
142
|
+
command: `$0 version ${smallest} --show`,
|
|
143
|
+
description: `# Bump ${smallest} directly, applied immediately`,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
command: '$0 version',
|
|
147
|
+
description: "# Auto-detect the bump from commits, show the plan, don't write anything",
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
command: '$0 version --interactive',
|
|
151
|
+
description: '# Show the plan either way, then ask for confirmation',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
command: `$0 version ${smallest} --show`,
|
|
155
|
+
description: `# Preview what an explicit ${smallest} would do, without applying it`,
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
positionals: {
|
|
159
|
+
bump: {
|
|
160
|
+
describe: `A bump keyword (${bumps}) or an explicit ${scheme} version. ` +
|
|
161
|
+
'Omit to auto-detect from commits and only preview the plan.',
|
|
162
|
+
type: 'string',
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
/** Annotated rather than inferred - `RmanConfig.ArgsOf` records why, and the casts this
|
|
166
|
+
* replaces are the reason it is worth two hoisted declarations. */
|
|
80
167
|
handler: async (args) => {
|
|
81
168
|
await assertAllowedBranch(repository, readBranchGuardOptions(args));
|
|
82
169
|
const bump = args.bump;
|
|
83
|
-
const plan = await VersionPlanService.getPlanner().getPlan(repository, {
|
|
170
|
+
const plan = await VersionPlanService.getPlanner(app).getPlan(repository, {
|
|
84
171
|
...readPackageFilterOptions(args),
|
|
85
172
|
bump,
|
|
86
173
|
ignoreDirty: args.ignoreDirty,
|
|
87
174
|
preid: args.preid,
|
|
88
175
|
});
|
|
176
|
+
/**
|
|
177
|
+
* **The machine-readable plan, and the whole of it.** This replaced `rman changed`, which
|
|
178
|
+
* was `getPlan` filtered to `status === 'bump'` - and that one-line filter produced two
|
|
179
|
+
* silent wrongs at once, measured together on a dirty tree: the entry it returned was the
|
|
180
|
+
* repository **root** (`buildRootEntry` reports `'bump'`, and the fact that it is
|
|
181
|
+
* informational lived only in `reason`), while `pkg-a`, the package that had actually
|
|
182
|
+
* changed, was dropped because a package with uncommitted changes is `'error'`. A CI script
|
|
183
|
+
* reading that array saw one name to release and it was the one name that must never be
|
|
184
|
+
* published.
|
|
185
|
+
*
|
|
186
|
+
* So nothing is filtered here. Every entry carries its own `status`, and `isRoot` is stated
|
|
187
|
+
* rather than left to be inferred from `group === "root"` - a consumer selects what it wants
|
|
188
|
+
* and can see what it is leaving out. Printed **before** the table and before the
|
|
189
|
+
* dirty-package throw, so stdout holds one JSON document and nothing else.
|
|
190
|
+
*
|
|
191
|
+
* **Exit 0 either way, deliberately.** `--show` exits 1 on a dirty package because a person
|
|
192
|
+
* needs stopping; here the same fact is in the data, and overloading the exit code would
|
|
193
|
+
* make a pipeline bail before it could read the very rows that explain why.
|
|
194
|
+
*/
|
|
195
|
+
if (args.json) {
|
|
196
|
+
console.log(JSON.stringify(plan.map(e => ({
|
|
197
|
+
name: e.package.name,
|
|
198
|
+
selector: e.package.selector,
|
|
199
|
+
isRoot: e.package.isRoot,
|
|
200
|
+
group: e.group,
|
|
201
|
+
status: e.status,
|
|
202
|
+
from: e.from,
|
|
203
|
+
to: e.to,
|
|
204
|
+
reason: e.reason,
|
|
205
|
+
})), undefined, 2));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
89
208
|
printPlan(plan);
|
|
90
209
|
const errors = plan.filter(e => e.status === 'error');
|
|
91
210
|
if (errors.length) {
|
|
@@ -115,15 +234,16 @@ export function initCli(repository, program) {
|
|
|
115
234
|
if (!apply)
|
|
116
235
|
return;
|
|
117
236
|
const changelog = args.changelog ?? repository.config?.version?.changelog ?? false;
|
|
118
|
-
const applied = await
|
|
237
|
+
const applied = await app.getService('version').applyPlan(plan, {
|
|
119
238
|
push: args.push,
|
|
120
239
|
message: args.message,
|
|
121
240
|
changelog,
|
|
122
241
|
});
|
|
123
242
|
printApplied(applied);
|
|
124
243
|
},
|
|
125
|
-
}
|
|
126
|
-
}
|
|
244
|
+
};
|
|
245
|
+
});
|
|
246
|
+
export default versionCommand;
|
|
127
247
|
/**
|
|
128
248
|
* What the run *did* - which is deliberately not the table again.
|
|
129
249
|
*
|
|
@@ -156,18 +276,112 @@ function printApplied(result) {
|
|
|
156
276
|
}
|
|
157
277
|
function printPlan(entries) {
|
|
158
278
|
const table = new EasyTable();
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
table.cell('Reason', e.status === 'error' ? colors.red(e.reason ?? '') : colors.gray(e.reason ?? ''));
|
|
167
|
-
table.newRow();
|
|
279
|
+
let first = true;
|
|
280
|
+
for (const { members, shared } of planBlocks(entries)) {
|
|
281
|
+
if (!first)
|
|
282
|
+
table.pushDelimeter(PLAN_COLUMNS);
|
|
283
|
+
first = false;
|
|
284
|
+
for (const e of members)
|
|
285
|
+
printPlanRow(table, e, shared);
|
|
168
286
|
}
|
|
169
287
|
console.log(table.toString().trim());
|
|
170
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* The plan, split into the blocks a delimiter is drawn between: the **repository root** first, then
|
|
291
|
+
* every shared version line with its members together, then the packages that share a line with
|
|
292
|
+
* nobody.
|
|
293
|
+
*
|
|
294
|
+
* `getPlan` returns entries in *package* order, which is the order the workspace found them in -
|
|
295
|
+
* so two members of one group are adjacent only by luck. That matters more than it looks: a group
|
|
296
|
+
* releases as one version line, so "these four numbers move together" is the single fact the table
|
|
297
|
+
* exists to convey, and scattering the members leaves the `Group` column as the only thing saying
|
|
298
|
+
* so. Read top to bottom instead, each block now *is* a release.
|
|
299
|
+
*
|
|
300
|
+
* **The root is first, and it is the one row that is not a release.** Its number is the
|
|
301
|
+
* repository's identity - what the GitHub Release is named after, and on a calendar version a
|
|
302
|
+
* number no package shares - so it is the heading the rest of the table sits under rather than a
|
|
303
|
+
* footnote to it. `buildRootEntry` appends it, which is why it is pulled out by hand here; leaving
|
|
304
|
+
* it where the plan put it made it the last singleton, indistinguishable from a package that
|
|
305
|
+
* happens to be grouped with no one.
|
|
306
|
+
*
|
|
307
|
+
* **Solo packages are one block, not one block each.** `group: false` makes every package its own
|
|
308
|
+
* group of one, so a delimiter per group would draw a line between every row in exactly the
|
|
309
|
+
* repository that has nothing to group - noise standing in for structure. They share a block
|
|
310
|
+
* because what they have in common is real: none of them is tied to anyone else.
|
|
311
|
+
*
|
|
312
|
+
* `shared` travels with each block because it is also what decides whether the `Group` column is
|
|
313
|
+
* written at all - see `printPlanRow`. One partition, asked once, answering both questions; working
|
|
314
|
+
* it out again at the cell would be a second rule that could disagree with the blocks beside it.
|
|
315
|
+
*/
|
|
316
|
+
function planBlocks(entries) {
|
|
317
|
+
/**
|
|
318
|
+
* `package.isRoot` is by **directory**, which is the only reliable test - `Repository extends
|
|
319
|
+
* Package` while holding a separate `rootPackage` instance for the same directory, so an identity
|
|
320
|
+
* check answers `false` for one of the two objects that are both the root.
|
|
321
|
+
*
|
|
322
|
+
* In a single-package repository that one package *is* the root and `getPlan` pushes no root
|
|
323
|
+
* entry of its own, so it lands here and prints alone - one row, and no delimiter to draw.
|
|
324
|
+
*/
|
|
325
|
+
const root = entries.filter(e => e.package.isRoot);
|
|
326
|
+
const members = entries.filter(e => !e.package.isRoot);
|
|
327
|
+
const byGroup = new Map();
|
|
328
|
+
for (const e of members) {
|
|
329
|
+
const group = byGroup.get(e.groupKey);
|
|
330
|
+
if (group)
|
|
331
|
+
group.push(e);
|
|
332
|
+
else
|
|
333
|
+
byGroup.set(e.groupKey, [e]);
|
|
334
|
+
}
|
|
335
|
+
const shared = [];
|
|
336
|
+
const solo = [];
|
|
337
|
+
for (const group of byGroup.values()) {
|
|
338
|
+
if (group.length > 1)
|
|
339
|
+
shared.push({ members: group, shared: true });
|
|
340
|
+
else
|
|
341
|
+
solo.push(group[0]);
|
|
342
|
+
}
|
|
343
|
+
return [
|
|
344
|
+
...(root.length ? [{ members: root, shared: false }] : []),
|
|
345
|
+
...shared,
|
|
346
|
+
...(solo.length ? [{ members: solo, shared: false }] : []),
|
|
347
|
+
];
|
|
348
|
+
}
|
|
349
|
+
/** `buildRootEntry`'s display label. Named here because `printPlanRow` has to recognize the one
|
|
350
|
+
* singleton whose group is worth printing, and a bare `'root'` in a condition reads as a guess. */
|
|
351
|
+
const ROOT_GROUP = 'root';
|
|
352
|
+
/** The column names in the order `printPlanRow` writes them - `pushDelimeter` has to be handed the
|
|
353
|
+
* same set, or the dashes appear under a column that does not exist yet. */
|
|
354
|
+
const PLAN_COLUMNS = ['Status', 'Package', 'Group', 'From', '', 'To', 'Reason'];
|
|
355
|
+
function printPlanRow(table, e, shared) {
|
|
356
|
+
table.cell('Status', statusLabel(e.status));
|
|
357
|
+
table.cell('Package', colors.cyan(e.package.name));
|
|
358
|
+
/**
|
|
359
|
+
* **Blank for a package that shares its version line with nobody.** `resolveGroupKey` gives an
|
|
360
|
+
* ungrouped package a group of one named after the package, so the cell printed the Package
|
|
361
|
+
* column again, one column to the right - a word that looks like information and carries none.
|
|
362
|
+
* Worse, it made `(default)` and `(@panates/tsconfig)` read as the same *kind* of answer when one
|
|
363
|
+
* names a line four packages move along and the other names nothing at all.
|
|
364
|
+
*
|
|
365
|
+
* The root keeps its label: `root` is not its package name but what the row *is*, and it is the
|
|
366
|
+
* only thing on the line saying that the number below is the repository's identity rather than a
|
|
367
|
+
* release. So the test is `shared`, plus that one entry - not "does this string repeat the name",
|
|
368
|
+
* which would blank a genuine group that happened to be called after one of its members.
|
|
369
|
+
*/
|
|
370
|
+
table.cell('Group', shared || e.group === ROOT_GROUP ? colors.gray(`(${e.group})`) : '');
|
|
371
|
+
table.cell('From', e.from);
|
|
372
|
+
/**
|
|
373
|
+
* Gated on `to`, not on `status === 'bump'`, which is what kept the column blank on the one
|
|
374
|
+
* command whose whole job is to fill it: a dirty package aborts the run, and "you cannot
|
|
375
|
+
* release this" is only half of what the reader came for - the other half is which version it
|
|
376
|
+
* would have got. `getPlan` sets `to` on exactly the entries that earned one, so asking whether
|
|
377
|
+
* there is a version to show is the honest test. Dimmed rather than yellow when the entry is
|
|
378
|
+
* not a bump, because that number is a hypothetical and nothing is going to write it.
|
|
379
|
+
*/
|
|
380
|
+
table.cell('', e.to ? '->' : '');
|
|
381
|
+
table.cell('To', e.to ? (e.status === 'bump' ? colors.yellow(e.to) : colors.gray(e.to)) : '');
|
|
382
|
+
table.cell('Reason', e.status === 'error' ? colors.red(e.reason ?? '') : colors.gray(e.reason ?? ''));
|
|
383
|
+
table.newRow();
|
|
384
|
+
}
|
|
171
385
|
function statusLabel(status) {
|
|
172
386
|
switch (status) {
|
|
173
387
|
case 'bump':
|
package/commands.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Every built-in command, and the one place the list lives.**
|
|
3
|
+
*
|
|
4
|
+
* Imported for their side effect: each module calls `registerCommand`, which pushes its register
|
|
5
|
+
* function onto `commandRegistry`. Nothing reads the modules' exports - `runCli` walks the registry
|
|
6
|
+
* - so this import list *is* the built-in command list.
|
|
7
|
+
*
|
|
8
|
+
* **`index.ts` imports this too, and that is not tidiness.** Each module also carries a
|
|
9
|
+
* `declare module` augmentation contributing its own `.rmanrc` keys, and a type augmentation only
|
|
10
|
+
* applies where the module declaring it is part of the program. Reached only from `cli.ts`, those
|
|
11
|
+
* keys existed for rman itself and for nobody else: `rman-node` reading `pkg.config.publish` got
|
|
12
|
+
* `Property 'publish' does not exist on type 'RmanConfig'` (measured, the moment the keys stopped
|
|
13
|
+
* being hand-written centrally, in what is now `rman-config.interface.ts`).
|
|
14
|
+
*/
|
|
15
|
+
import './commands/build.command.js';
|
|
16
|
+
import './commands/changelog.command.js';
|
|
17
|
+
import './commands/config.command.js';
|
|
18
|
+
import './commands/diff.command.js';
|
|
19
|
+
import './commands/exec.command.js';
|
|
20
|
+
import './commands/github-release.command.js';
|
|
21
|
+
import './commands/import.command.js';
|
|
22
|
+
import './commands/info.command.js';
|
|
23
|
+
import './commands/lint.command.js';
|
|
24
|
+
import './commands/list.command.js';
|
|
25
|
+
import './commands/publish.command.js';
|
|
26
|
+
import './commands/run.command.js';
|
|
27
|
+
import './commands/test.command.js';
|
|
28
|
+
import './commands/version.command.js';
|
|
29
|
+
/** The config shapes a command declares by hand, where an option cannot describe them - see
|
|
30
|
+
* `RmanConfig.CommandContribution`'s `Extra`. Exported so a plugin can name one. */
|
|
31
|
+
export type { PublishExtraKeys, PublishTargetConfigs } from './commands/publish.command.js';
|
|
32
|
+
export type { VersionExtraKeys, VersionStampEntry } from './commands/version.command.js';
|
package/commands.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **Every built-in command, and the one place the list lives.**
|
|
3
|
+
*
|
|
4
|
+
* Imported for their side effect: each module calls `registerCommand`, which pushes its register
|
|
5
|
+
* function onto `commandRegistry`. Nothing reads the modules' exports - `runCli` walks the registry
|
|
6
|
+
* - so this import list *is* the built-in command list.
|
|
7
|
+
*
|
|
8
|
+
* **`index.ts` imports this too, and that is not tidiness.** Each module also carries a
|
|
9
|
+
* `declare module` augmentation contributing its own `.rmanrc` keys, and a type augmentation only
|
|
10
|
+
* applies where the module declaring it is part of the program. Reached only from `cli.ts`, those
|
|
11
|
+
* keys existed for rman itself and for nobody else: `rman-node` reading `pkg.config.publish` got
|
|
12
|
+
* `Property 'publish' does not exist on type 'RmanConfig'` (measured, the moment the keys stopped
|
|
13
|
+
* being hand-written centrally, in what is now `rman-config.interface.ts`).
|
|
14
|
+
*/
|
|
15
|
+
import './commands/build.command.js';
|
|
16
|
+
import './commands/changelog.command.js';
|
|
17
|
+
import './commands/config.command.js';
|
|
18
|
+
import './commands/diff.command.js';
|
|
19
|
+
import './commands/exec.command.js';
|
|
20
|
+
import './commands/github-release.command.js';
|
|
21
|
+
import './commands/import.command.js';
|
|
22
|
+
import './commands/info.command.js';
|
|
23
|
+
import './commands/lint.command.js';
|
|
24
|
+
import './commands/list.command.js';
|
|
25
|
+
import './commands/publish.command.js';
|
|
26
|
+
import './commands/run.command.js';
|
|
27
|
+
import './commands/test.command.js';
|
|
28
|
+
import './commands/version.command.js';
|
package/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '
|
|
1
|
+
export const version = '2.0.0-beta.3';
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { VersionPlanService } from '../services/version-plan.service.js';
|
|
2
|
+
import { Logger, type LogLevel } from '../utils/logger.js';
|
|
3
|
+
import { Registry } from './classes/registry.js';
|
|
4
|
+
import type { Repository } from './classes/repository.js';
|
|
5
|
+
import type { ServiceFactory, ServiceMap } from './classes/service.js';
|
|
6
|
+
import { type Platform, type Plugin } from './interfaces/plugin.js';
|
|
7
|
+
import type { PublishTarget } from './interfaces/publish-target.js';
|
|
8
|
+
/**
|
|
9
|
+
* **One rman invocation, and everything it holds.** Created before anything else, handed to every
|
|
10
|
+
* plugin's `init`, and the owner of every registry and service that used to be a module-level
|
|
11
|
+
* variable.
|
|
12
|
+
*
|
|
13
|
+
* The point is that nothing is process-global any more. `Manifest`, `Workspace`, `BinPath`,
|
|
14
|
+
* `RunService` and `VersionPlanService` each kept their contributions in a module-scope array, so
|
|
15
|
+
* two repositories in one process shared them - which the test suite could only survive with a
|
|
16
|
+
* root hook emptying five of them before every test, and the failure that hook prevented was:
|
|
17
|
+
* whichever spec ran first decided the answer for the rest, and the core appeared to work in tests
|
|
18
|
+
* that had registered nothing. An application starts empty and is thrown away whole, so the hook
|
|
19
|
+
* is gone.
|
|
20
|
+
*/
|
|
21
|
+
export declare class RmanApplication {
|
|
22
|
+
/**
|
|
23
|
+
* The **technologies** this invocation knows about, in `plugins` declaration order.
|
|
24
|
+
*
|
|
25
|
+
* One registry rather than the four it replaces (`manifest`, `workspace`, `binPaths`,
|
|
26
|
+
* `runSteps`): a technology is a whole, and declaring part of one was never meaningful - see
|
|
27
|
+
* `Platform`.
|
|
28
|
+
*
|
|
29
|
+
* **Flattened out of the plugins**, because this is what every seam actually iterates - a
|
|
30
|
+
* manifest is read by a platform, a workspace is laid out by a platform, a PATH is contributed by
|
|
31
|
+
* a platform. A plugin providing two of them puts two entries here, and a plugin providing none
|
|
32
|
+
* puts none.
|
|
33
|
+
*/
|
|
34
|
+
readonly platforms: Registry<Platform>;
|
|
35
|
+
/**
|
|
36
|
+
* The **plugins** themselves, in declaration order - what a config named, before the platforms
|
|
37
|
+
* were taken out of them.
|
|
38
|
+
*
|
|
39
|
+
* Kept apart from `platforms` because the two answer different questions: this is who contributed,
|
|
40
|
+
* that is what they contributed. `init` runs per plugin; nothing else reads this.
|
|
41
|
+
*/
|
|
42
|
+
readonly plugins: Registry<Plugin>;
|
|
43
|
+
/**
|
|
44
|
+
* Where a package's artifact can ship, in registration order.
|
|
45
|
+
*
|
|
46
|
+
* A registry rather than a field because the answer is a *sum*: a package may ship to npm and
|
|
47
|
+
* Docker Hub at once, and `publish` runs every target a package declares. The core contributes
|
|
48
|
+
* `docker` (nobody's ecosystem), the `node` built-in contributes `npm`, and a plugin for any other
|
|
49
|
+
* technology adds its own without either of them changing - see `PublishTarget`.
|
|
50
|
+
*/
|
|
51
|
+
readonly publishTargets: Registry<PublishTarget>;
|
|
52
|
+
/**
|
|
53
|
+
* **The planner that orchestrates a run**, not the one that answers for each package.
|
|
54
|
+
*
|
|
55
|
+
* One answer, not a sum - so a field rather than a registry, and last registration wins. What it
|
|
56
|
+
* decides is the shape of the whole plan: groups, the commit→size reading, the cross-group ripple
|
|
57
|
+
* and the root's release identity, none of which belongs to any one technology.
|
|
58
|
+
*
|
|
59
|
+
* The two decisions that *are* a technology's - `detectBoundary` and `cascade` - are asked of
|
|
60
|
+
* each package's own `Platform.versionPlanner` instead (`VersionPlanService.plannerFor`), so a
|
|
61
|
+
* polyglot repository no longer resolves both through whichever plugin registered last.
|
|
62
|
+
*/
|
|
63
|
+
versionPlanner?: VersionPlanService;
|
|
64
|
+
readonly logger: Logger;
|
|
65
|
+
/** `info` until `--log-level` or `.rmanrc "logLevel"` is resolved - which cannot happen here,
|
|
66
|
+
* since reading the config is itself work the application does. */
|
|
67
|
+
constructor(options?: {
|
|
68
|
+
logLevel?: LogLevel;
|
|
69
|
+
});
|
|
70
|
+
/** Which platform claims a directory - the first whose manifest provider recognizes it, because
|
|
71
|
+
* before a package is read there is nothing else to go on. `basePlatform` when none does, so the
|
|
72
|
+
* caller needs no guard. */
|
|
73
|
+
platformFor(dir: string): Platform;
|
|
74
|
+
/**
|
|
75
|
+
* **Not a constructor field, and that is forced by the order things happen in.** Plugins are what
|
|
76
|
+
* *find* the packages - `Repository.create` loads them before it calls `Workspace.resolve` - so
|
|
77
|
+
* the application has to exist, and be handed to every `init`, while there is still no
|
|
78
|
+
* repository to put in it.
|
|
79
|
+
*
|
|
80
|
+
* A throwing getter rather than `undefined`: a plugin reaching for packages during `init` has
|
|
81
|
+
* made a real mistake, and `undefined` would let it write a check that silently does nothing.
|
|
82
|
+
*/
|
|
83
|
+
get repository(): Repository;
|
|
84
|
+
/**
|
|
85
|
+
* The single instance of a service, built on first use.
|
|
86
|
+
*
|
|
87
|
+
* **Lazy, and for two reasons.** `rman info` has no business constructing the changelog, version
|
|
88
|
+
* and release services, which is the same laziness the config scope's `git` getter was measured
|
|
89
|
+
* to need (0 git reads with property descriptors, 1 with a spread). And services call each other -
|
|
90
|
+
* `VersionService` reaches for `RunService` and `ChangelogService`, which reaches for
|
|
91
|
+
* `ChangeHashService` - so resolving at call time is what keeps that from being a construction
|
|
92
|
+
* cycle.
|
|
93
|
+
*/
|
|
94
|
+
getService<K extends keyof ServiceMap>(name: K): ServiceMap[K];
|
|
95
|
+
/**
|
|
96
|
+
* Registers how a service is built. A plugin replacing one of the core's - a version planner that
|
|
97
|
+
* knows its own ecosystem's dependency ranges - does it here, which is why that no longer needs a
|
|
98
|
+
* seam of its own on the plugin interface.
|
|
99
|
+
*
|
|
100
|
+
* Refused once the service has been built: something is already holding the old instance, and
|
|
101
|
+
* swapping the factory then would leave two answers to one question in play.
|
|
102
|
+
*/
|
|
103
|
+
setService<K extends keyof ServiceMap>(name: K, factory: ServiceFactory<ServiceMap[K]>): void;
|
|
104
|
+
/**
|
|
105
|
+
* Called by `Repository.create`, after the plugins that find the packages have run.
|
|
106
|
+
*
|
|
107
|
+
* **One application, one repository**, and a second is refused. It was briefly "last one wins",
|
|
108
|
+
* because a single shared application made two repositories in one test collide; each
|
|
109
|
+
* `Repository.create` makes its own now, so the rule holds again and nothing in a process is
|
|
110
|
+
* shared by accident.
|
|
111
|
+
*/
|
|
112
|
+
attachRepository(repository: Repository): void;
|
|
113
|
+
private _repository?;
|
|
114
|
+
private readonly services;
|
|
115
|
+
private readonly factories;
|
|
116
|
+
}
|