rman 1.3.0 → 2.0.0-beta.2
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 +63 -19
- package/cli.d.ts +5 -0
- package/cli.js +214 -88
- package/commands/build.command.d.ts +177 -3
- package/commands/build.command.js +20 -10
- package/commands/changed.command.d.ts +80 -3
- package/commands/changed.command.js +19 -12
- package/commands/changelog.command.d.ts +192 -3
- package/commands/changelog.command.js +87 -43
- package/commands/config.command.d.ts +44 -3
- package/commands/config.command.js +30 -19
- 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/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 +317 -3
- package/commands/version.command.js +149 -69
- 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 +143 -0
- package/core/command-builder.d.ts +14 -0
- package/core/command-builder.js +78 -0
- package/core/config.d.ts +140 -19
- package/core/config.js +258 -74
- package/core/core-services.d.ts +14 -0
- package/core/core-services.js +30 -0
- package/core/core-targets.d.ts +14 -0
- package/core/core-targets.js +16 -0
- package/core/custom-command.d.ts +42 -6
- package/core/custom-command.js +44 -17
- package/core/extends-config.d.ts +13 -5
- package/core/extends-config.js +52 -12
- package/core/load-config-module.d.ts +28 -0
- package/core/load-config-module.js +42 -0
- package/core/manifest.d.ts +47 -25
- package/core/manifest.js +51 -69
- package/core/merge-config.d.ts +33 -34
- package/core/merge-config.js +137 -92
- package/core/package.d.ts +145 -17
- package/core/package.js +128 -36
- package/core/plugin-loader.d.ts +65 -0
- package/core/plugin-loader.js +234 -0
- package/core/plugin.d.ts +135 -90
- package/core/plugin.js +70 -173
- package/core/publish-target.d.ts +124 -0
- package/core/publish-target.js +30 -0
- package/core/registry.d.ts +30 -0
- package/core/registry.js +47 -0
- package/core/repository.d.ts +72 -9
- package/core/repository.js +293 -44
- package/core/resolve-target.d.ts +1 -1
- package/core/resolve-target.js +1 -1
- package/core/service.d.ts +49 -0
- package/core/service.js +40 -0
- package/core/version-scheme.d.ts +23 -1
- package/core/version-scheme.js +29 -1
- package/core/workspace.d.ts +84 -33
- package/core/workspace.js +63 -22
- package/index.d.ts +111 -14
- package/index.js +85 -9
- package/interfaces/rman-config.interface.d.ts +725 -202
- package/interfaces/rman-config.interface.js +61 -1
- package/package.json +2 -1
- package/plugins/builtins.d.ts +44 -0
- package/plugins/builtins.js +33 -0
- package/plugins/detect.d.ts +78 -0
- package/plugins/detect.js +70 -0
- package/plugins/node/augmentation/rman.augmentation.d.ts +84 -0
- package/plugins/node/augmentation/rman.augmentation.js +1 -0
- package/plugins/node/augmentation/system-info.augmentation.d.ts +26 -0
- package/plugins/node/augmentation/system-info.augmentation.js +79 -0
- package/plugins/node/commands/ci.command.d.ts +131 -0
- package/plugins/node/commands/ci.command.js +59 -0
- package/plugins/node/commands/clean.command.d.ts +183 -0
- package/plugins/node/commands/clean.command.js +73 -0
- package/plugins/node/index.d.ts +29 -0
- package/plugins/node/index.js +40 -0
- package/plugins/node/node-config.interface.d.ts +77 -0
- package/plugins/node/node-config.interface.js +7 -0
- package/plugins/node/node-manifest.provider.d.ts +68 -0
- package/plugins/node/node-manifest.provider.js +125 -0
- package/plugins/node/node.platform.d.ts +53 -0
- package/plugins/node/node.platform.js +134 -0
- package/plugins/node/npm-publish-target.d.ts +73 -0
- package/plugins/node/npm-publish-target.js +96 -0
- package/plugins/node/services/ci.service.d.ts +47 -0
- package/plugins/node/services/ci.service.js +213 -0
- package/plugins/node/services/clean.service.d.ts +53 -0
- package/plugins/node/services/clean.service.js +237 -0
- package/plugins/node/services/publish.service.d.ts +114 -0
- package/plugins/node/services/publish.service.js +371 -0
- package/plugins/node/services/version-plan.service.d.ts +44 -0
- package/plugins/node/services/version-plan.service.js +58 -0
- package/plugins/node/utils/npm-view.d.ts +48 -0
- package/plugins/node/utils/npm-view.js +71 -0
- package/plugins/node/utils/workspace-range.d.ts +26 -0
- package/plugins/node/utils/workspace-range.js +28 -0
- package/services/change-hash.service.d.ts +2 -2
- package/services/change-hash.service.js +2 -2
- package/services/changelog.service.d.ts +62 -51
- package/services/changelog.service.js +14 -11
- package/services/docker-publish.service.d.ts +50 -29
- package/services/docker-publish.service.js +43 -20
- package/services/exec.service.d.ts +23 -12
- package/services/exec.service.js +14 -9
- package/services/github-release.service.d.ts +44 -33
- package/services/github-release.service.js +13 -10
- package/services/import.service.d.ts +25 -14
- package/services/import.service.js +9 -5
- package/services/list.service.d.ts +62 -10
- package/services/list.service.js +62 -15
- package/services/run.service.d.ts +22 -13
- package/services/run.service.js +262 -223
- package/services/version-plan.service.d.ts +27 -4
- package/services/version-plan.service.js +42 -15
- package/services/version.service.d.ts +31 -11
- package/services/version.service.js +29 -13
- package/targets/docker.target.d.ts +53 -0
- package/targets/docker.target.js +40 -0
- package/utils/bin-path.d.ts +6 -7
- package/utils/bin-path.js +7 -18
- package/utils/branch-guard.d.ts +29 -0
- package/utils/branch-guard.js +31 -0
- package/utils/exec.d.ts +10 -0
- package/utils/exec.js +1 -1
- package/utils/logger.d.ts +1 -1
- package/utils/logger.js +1 -1
- package/utils/package-filter.d.ts +127 -7
- package/utils/package-filter.js +197 -16
- package/utils/printable-config.d.ts +1 -1
- package/utils/printable-config.js +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-stamp.d.ts +1 -1
- package/utils/version-stamp.js +1 -1
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import readline from 'node:readline/promises';
|
|
2
|
+
import colors from 'ansi-colors';
|
|
3
|
+
import { unknownTargets } from '../core/publish-target.js';
|
|
4
|
+
import { registerCommand } from '../interfaces/rman-config.interface.js';
|
|
5
|
+
import { assertAllowedBranch, branchGuardOptions, readBranchGuardOptions } from '../utils/branch-guard.js';
|
|
6
|
+
import { packageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
|
|
7
|
+
/** Hoisted for `ArgsOf` - see `version.command.ts` and `RmanConfig.ArgsOf` for why. */
|
|
8
|
+
const COMMAND = 'publish';
|
|
9
|
+
/**
|
|
10
|
+
* **The options that belong to publishing, rather than to any one registry.**
|
|
11
|
+
*
|
|
12
|
+
* Everything npm-shaped that used to sit beside them - `--access`, `--tag`, `--otp`, `--registry`,
|
|
13
|
+
* `--userconfig`, `--contents`, `--package-manager` - is declared by the `npm` target now, and
|
|
14
|
+
* `--docker-namespace` by the `docker` one. They are merged in at build time (see below), so
|
|
15
|
+
* `rman publish --help` lists exactly the flags the targets this repository actually has.
|
|
16
|
+
*/
|
|
17
|
+
const config = {
|
|
18
|
+
...packageFilterOptions,
|
|
19
|
+
...branchGuardOptions,
|
|
20
|
+
yes: {
|
|
21
|
+
target: 'cli',
|
|
22
|
+
alias: 'y',
|
|
23
|
+
describe: 'Skip the confirmation prompt and publish immediately',
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
},
|
|
26
|
+
dryRun: {
|
|
27
|
+
target: 'cli',
|
|
28
|
+
cliName: 'dry-run',
|
|
29
|
+
describe: 'Only show the plan - never publishes, regardless of --yes',
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
},
|
|
32
|
+
json: {
|
|
33
|
+
target: 'cli',
|
|
34
|
+
alias: 'j',
|
|
35
|
+
describe: 'Print the plan as JSON instead of text - one entry per package and target. Combine with ' +
|
|
36
|
+
'--dry-run to ask "is there anything to publish?" without publishing (e.g. a CI release gate).',
|
|
37
|
+
type: 'boolean',
|
|
38
|
+
},
|
|
39
|
+
ignoreDirty: {
|
|
40
|
+
target: 'cli',
|
|
41
|
+
cliName: 'ignore-dirty',
|
|
42
|
+
describe: 'Exclude a package with uncommitted local changes instead of aborting the whole run',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
},
|
|
45
|
+
/**
|
|
46
|
+
* `target: 'both'` because it is genuinely both: `--target docker` for one run, `publish.target`
|
|
47
|
+
* in a `.rmanrc` for a package's standing answer. Its `choices` cannot be written here - which
|
|
48
|
+
* targets exist is whatever the repository's plugins contribute - so they are filled in from the
|
|
49
|
+
* registry where the command is built.
|
|
50
|
+
*/
|
|
51
|
+
target: {
|
|
52
|
+
target: 'both',
|
|
53
|
+
describe: 'Restrict this run to just these publish target(s) (repeatable) - default: every target ' +
|
|
54
|
+
'each package itself is configured for (.rmanrc "publish.target"), or the targets that claim ' +
|
|
55
|
+
"it when it configures none. A package that opts into a target but leaves out that target's " +
|
|
56
|
+
'own config errors clearly instead of being silently skipped.',
|
|
57
|
+
type: 'array',
|
|
58
|
+
},
|
|
59
|
+
skip: {
|
|
60
|
+
target: 'config',
|
|
61
|
+
describe: 'Excludes this package from publish entirely (every target), regardless of "target" or ' +
|
|
62
|
+
'"private" - a single, explicit "never published" statement. "changelog" honours it too.',
|
|
63
|
+
type: 'boolean',
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* `rman publish` - the repository's half of question B: which packages' current version is not out
|
|
68
|
+
* there yet, and pushing the ones that are not.
|
|
69
|
+
*
|
|
70
|
+
* **This was `rman-node`'s command until the targets became contributions**, and that had the
|
|
71
|
+
* ownership backwards. Everything here is about a repository - which packages are candidates, what
|
|
72
|
+
* order to push them in (dependencies first), the plan/confirm/apply shape, `--dry-run`, the JSON a
|
|
73
|
+
* CI gate reads - and none of it is npm's. What *is* npm's is one answer to "is this version on the
|
|
74
|
+
* registry, and how do I push it", which is `PublishTarget`. The measured consequence of the old
|
|
75
|
+
* arrangement: `publish --target docker` in a repository with no JavaScript in it required
|
|
76
|
+
* installing a Node plugin to reach a Docker push the core had implemented all along.
|
|
77
|
+
*
|
|
78
|
+
* Never looks at whether `version` ran - it inspects what is on disk and on each registry, so it
|
|
79
|
+
* behaves the same right after a bump or days later, and re-running is safe.
|
|
80
|
+
*/
|
|
81
|
+
const publishCommand = registerCommand(app => {
|
|
82
|
+
const repository = app.repository;
|
|
83
|
+
const targets = app.publishTargets.all;
|
|
84
|
+
return {
|
|
85
|
+
command: COMMAND,
|
|
86
|
+
describe: 'Publishes every package to its configured target(s) - see .rmanrc "publish.target"',
|
|
87
|
+
/** `group` is not read here, but `allowBranch`/`ignoreBranch` are - through the shared
|
|
88
|
+
* branch-guard group, which only exposes them as flags. */
|
|
89
|
+
configKeys: ['allowBranch', 'ignoreBranch'],
|
|
90
|
+
config: {
|
|
91
|
+
...config,
|
|
92
|
+
/** Filled in from the registry: `--target` can only offer what this repository installed. */
|
|
93
|
+
target: { ...config.target, choices: targets.map(t => t.name) },
|
|
94
|
+
...targetOptions(targets),
|
|
95
|
+
},
|
|
96
|
+
examples: [
|
|
97
|
+
{ command: '$0 publish', description: '# Show the plan, then ask for confirmation' },
|
|
98
|
+
{ command: '$0 publish --yes', description: '# Publish immediately, no confirmation' },
|
|
99
|
+
{ command: '$0 publish --dry-run', description: '# Only show the plan, never publish' },
|
|
100
|
+
...(targets.length > 1
|
|
101
|
+
? [
|
|
102
|
+
{
|
|
103
|
+
command: `$0 publish --target ${targets[targets.length - 1].name}`,
|
|
104
|
+
description: '# Only the packages configured for that one target',
|
|
105
|
+
},
|
|
106
|
+
]
|
|
107
|
+
: []),
|
|
108
|
+
],
|
|
109
|
+
handler: async (args) => {
|
|
110
|
+
await assertAllowedBranch(repository, readBranchGuardOptions(args));
|
|
111
|
+
const requested = args.target;
|
|
112
|
+
const selected = selectTargets(targets, requested);
|
|
113
|
+
const ctx = {
|
|
114
|
+
app,
|
|
115
|
+
repository,
|
|
116
|
+
options: { ...readPackageFilterOptions(args), ignoreDirty: args.ignoreDirty },
|
|
117
|
+
args: args,
|
|
118
|
+
};
|
|
119
|
+
assertDeclaredTargetsExist(app, repository.getPackages());
|
|
120
|
+
const plans = new Map();
|
|
121
|
+
for (const target of selected)
|
|
122
|
+
plans.set(target, await target.getPlan(ctx));
|
|
123
|
+
if (args.json) {
|
|
124
|
+
console.log(JSON.stringify(jsonPlan(plans), undefined, 2));
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
for (const [target, plan] of plans)
|
|
128
|
+
printPlan(plan, target.name);
|
|
129
|
+
}
|
|
130
|
+
/** An explicitly requested target that matched nothing is a mistake worth reporting: the run
|
|
131
|
+
* asked for something by name and silently got an empty plan back. */
|
|
132
|
+
if (requested?.length) {
|
|
133
|
+
const empty = [...plans].filter(([, plan]) => !plan.length).map(([target]) => target.name);
|
|
134
|
+
if (empty.length) {
|
|
135
|
+
throw logged(`--target ${empty.join(', ')} was given, but no package ships there ` + '(see .rmanrc "publish.target").');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const all = [...plans.values()].flat();
|
|
139
|
+
const errors = all.filter(e => e.status === 'error');
|
|
140
|
+
if (errors.length) {
|
|
141
|
+
const allDirty = errors.every(e => e.reason === 'uncommitted local changes');
|
|
142
|
+
throw logged(allDirty
|
|
143
|
+
? `${errors.length} package(s) have uncommitted local changes ` +
|
|
144
|
+
'(pass --ignore-dirty to exclude them instead of aborting)'
|
|
145
|
+
: `${errors.length} package(s) failed to prepare for publish - see the errors above`);
|
|
146
|
+
}
|
|
147
|
+
if (!all.some(e => e.status === 'publish')) {
|
|
148
|
+
if (!args.json)
|
|
149
|
+
console.log(colors.gray('Nothing to publish.'));
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
if (args.dryRun)
|
|
153
|
+
return;
|
|
154
|
+
let proceed = !!args.yes;
|
|
155
|
+
if (!proceed) {
|
|
156
|
+
if (!process.stdout.isTTY) {
|
|
157
|
+
console.log(colors.gray('Not a TTY - refusing to prompt. Pass --yes to publish non-interactively.'));
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
proceed = await confirm('Publish these packages?');
|
|
161
|
+
}
|
|
162
|
+
if (!proceed)
|
|
163
|
+
return;
|
|
164
|
+
let failed = false;
|
|
165
|
+
for (const [target, plan] of plans) {
|
|
166
|
+
const applied = await target.applyPlan(ctx, plan);
|
|
167
|
+
if (printApplied(applied, plan, target.name))
|
|
168
|
+
failed = true;
|
|
169
|
+
}
|
|
170
|
+
if (failed)
|
|
171
|
+
throw logged('"publish" failed');
|
|
172
|
+
},
|
|
173
|
+
};
|
|
174
|
+
});
|
|
175
|
+
export default publishCommand;
|
|
176
|
+
/**
|
|
177
|
+
* Every registered target's own flags, flattened into one block.
|
|
178
|
+
*
|
|
179
|
+
* **A collision is refused rather than resolved.** Two targets both wanting `--registry` is a real
|
|
180
|
+
* possibility (npm has one, so does a hypothetical Cargo), and any rule for picking a winner -
|
|
181
|
+
* registration order, prefixing, last wins - produces a flag that silently means the other
|
|
182
|
+
* target's thing. Naming it for the target (`--docker-namespace`) is the fix, and the error says so.
|
|
183
|
+
*/
|
|
184
|
+
function targetOptions(targets) {
|
|
185
|
+
const merged = {};
|
|
186
|
+
const owners = new Map();
|
|
187
|
+
for (const target of targets) {
|
|
188
|
+
for (const [key, option] of Object.entries(target.options ?? {})) {
|
|
189
|
+
const owner = owners.get(key);
|
|
190
|
+
if (owner) {
|
|
191
|
+
throw new Error(`Publish targets "${owner}" and "${target.name}" both declare an option named "${key}" - ` +
|
|
192
|
+
'name it for the target it belongs to (e.g. "docker-namespace").');
|
|
193
|
+
}
|
|
194
|
+
owners.set(key, target.name);
|
|
195
|
+
merged[key] = option;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return merged;
|
|
199
|
+
}
|
|
200
|
+
/** `--target` narrows the run; omitting it means every registered target, each of which then
|
|
201
|
+
* decides for itself which packages are its own. */
|
|
202
|
+
function selectTargets(targets, requested) {
|
|
203
|
+
if (!requested?.length)
|
|
204
|
+
return [...targets];
|
|
205
|
+
const known = new Map(targets.map(t => [t.name, t]));
|
|
206
|
+
return requested.map(name => {
|
|
207
|
+
const target = known.get(name);
|
|
208
|
+
if (!target) {
|
|
209
|
+
throw logged(`Unknown publish target "${name}" - this repository has: ${[...known.keys()].join(', ')}.`);
|
|
210
|
+
}
|
|
211
|
+
return target;
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A package naming a target nothing implements.
|
|
216
|
+
*
|
|
217
|
+
* This used to be impossible to get wrong - `publish.target` was typed `'npm' | 'docker'` and
|
|
218
|
+
* `--target` had those two as `choices`. With targets contributed, the core cannot enumerate them,
|
|
219
|
+
* so the check moves to where the facts are. Silence here would mean a package quietly publishing
|
|
220
|
+
* nowhere, which is the failure mode `publish` exists to rule out.
|
|
221
|
+
*/
|
|
222
|
+
function assertDeclaredTargetsExist(app, packages) {
|
|
223
|
+
const offenders = packages
|
|
224
|
+
.map(pkg => ({ pkg, unknown: unknownTargets(app, pkg) }))
|
|
225
|
+
.filter(({ unknown }) => unknown.length);
|
|
226
|
+
if (!offenders.length)
|
|
227
|
+
return;
|
|
228
|
+
const installed = app.publishTargets.all.map(t => t.name).join(', ') || '(none)';
|
|
229
|
+
throw logged(offenders.map(({ pkg, unknown }) => `"${pkg.name}" declares publish target(s) ${unknown.join(', ')}`).join('; ') +
|
|
230
|
+
` - this repository has: ${installed}.`);
|
|
231
|
+
}
|
|
232
|
+
/** One `--json` row per package *and target*: a package shipping to two registries needs two, or a
|
|
233
|
+
* consumer cannot tell which of them still has something to do. */
|
|
234
|
+
function jsonPlan(plans) {
|
|
235
|
+
return [...plans].flatMap(([target, plan]) => plan.map(entry => ({
|
|
236
|
+
name: entry.package.name,
|
|
237
|
+
target: target.name,
|
|
238
|
+
status: entry.status,
|
|
239
|
+
version: entry.version,
|
|
240
|
+
detail: entry.detail,
|
|
241
|
+
reason: entry.reason,
|
|
242
|
+
})));
|
|
243
|
+
}
|
|
244
|
+
function printPlan(entries, label) {
|
|
245
|
+
const prefix = colors.gray(`[${label}] `);
|
|
246
|
+
for (const e of entries) {
|
|
247
|
+
const name = prefix + colors.cyan(e.package.name);
|
|
248
|
+
switch (e.status) {
|
|
249
|
+
case 'publish':
|
|
250
|
+
/** `detail` belongs on this line, not only on the "published" one after the fact: it is
|
|
251
|
+
* where a target says *where* the package is going - npm's dist-tag, docker's resolved
|
|
252
|
+
* `<namespace>/<image>` - and the plan is what the reader is being asked to confirm. */
|
|
253
|
+
console.log(colors.green('publish'), name, e.version, ...(e.detail ? [colors.cyan(e.detail)] : []), colors.gray(e.reason ?? ''));
|
|
254
|
+
break;
|
|
255
|
+
case 'up-to-date':
|
|
256
|
+
console.log(colors.gray('up-to-date'), name, e.version);
|
|
257
|
+
break;
|
|
258
|
+
case 'skip':
|
|
259
|
+
console.log(colors.cyan('skip'), name, colors.gray(e.reason ?? ''));
|
|
260
|
+
break;
|
|
261
|
+
case 'error':
|
|
262
|
+
console.log(colors.red('error'), name, colors.red(e.reason ?? ''));
|
|
263
|
+
break;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* What one target actually did. Returns whether anything it was asked to publish failed.
|
|
269
|
+
*
|
|
270
|
+
* An `'error'` is only reported when the *plan* said `'publish'` for that package: an entry that
|
|
271
|
+
* was already an error before anything ran has been printed once by `printPlan`, and printing it
|
|
272
|
+
* again under "failed" would read as a push that was attempted and did not work.
|
|
273
|
+
*/
|
|
274
|
+
function printApplied(applied, plan, label) {
|
|
275
|
+
const prefix = colors.gray(`[${label}] `);
|
|
276
|
+
let failed = false;
|
|
277
|
+
for (const entry of applied) {
|
|
278
|
+
if (entry.status === 'publish') {
|
|
279
|
+
console.log(colors.green('published'), prefix + colors.cyan(entry.package.name), entry.detail ?? entry.version);
|
|
280
|
+
}
|
|
281
|
+
else if (entry.status === 'error' && plan.find(e => e.package === entry.package)?.status === 'publish') {
|
|
282
|
+
failed = true;
|
|
283
|
+
console.log(colors.red('failed'), prefix + colors.cyan(entry.package.name), colors.red(entry.reason ?? ''));
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return failed;
|
|
287
|
+
}
|
|
288
|
+
/** The `logged` convention: printed here, so `runCli`'s catch does not print it a second time. */
|
|
289
|
+
function logged(message) {
|
|
290
|
+
console.log(colors.red(message));
|
|
291
|
+
const err = new Error(message);
|
|
292
|
+
err.logged = true;
|
|
293
|
+
return err;
|
|
294
|
+
}
|
|
295
|
+
async function confirm(question) {
|
|
296
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
297
|
+
try {
|
|
298
|
+
const answer = await rl.question(`${question} (y/N) `);
|
|
299
|
+
return /^y(es)?$/i.test(answer.trim());
|
|
300
|
+
}
|
|
301
|
+
finally {
|
|
302
|
+
rl.close();
|
|
303
|
+
}
|
|
304
|
+
}
|
|
@@ -1,6 +1,186 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { type RmanConfig } from '../interfaces/rman-config.interface.js';
|
|
2
|
+
declare const COMMAND: "run <script>";
|
|
3
|
+
declare const config: {
|
|
4
|
+
parallel: {
|
|
5
|
+
target: "cli";
|
|
6
|
+
describe: string;
|
|
7
|
+
coerce: (v: unknown) => boolean | number | undefined;
|
|
8
|
+
};
|
|
9
|
+
bail: {
|
|
10
|
+
target: "cli";
|
|
11
|
+
describe: string;
|
|
12
|
+
type: "boolean";
|
|
13
|
+
};
|
|
14
|
+
topo: {
|
|
15
|
+
target: "cli";
|
|
16
|
+
describe: string;
|
|
17
|
+
type: "boolean";
|
|
18
|
+
};
|
|
19
|
+
progress: {
|
|
20
|
+
target: "cli";
|
|
21
|
+
describe: string;
|
|
22
|
+
type: "boolean";
|
|
23
|
+
};
|
|
24
|
+
changed: {
|
|
25
|
+
target: "cli";
|
|
26
|
+
alias: string;
|
|
27
|
+
describe: string;
|
|
28
|
+
type: "boolean";
|
|
29
|
+
};
|
|
30
|
+
changedSince: {
|
|
31
|
+
target: "cli";
|
|
32
|
+
cliName: string;
|
|
33
|
+
describe: string;
|
|
34
|
+
type: "string";
|
|
35
|
+
conflicts: string;
|
|
36
|
+
};
|
|
37
|
+
fromRoot: {
|
|
38
|
+
target: "cli";
|
|
39
|
+
cliName: string;
|
|
40
|
+
alias: string;
|
|
41
|
+
describe: string;
|
|
42
|
+
type: "boolean";
|
|
43
|
+
};
|
|
44
|
+
allowBranch: {
|
|
45
|
+
target: "cli";
|
|
46
|
+
cliName: string;
|
|
47
|
+
describe: string;
|
|
48
|
+
type: "string";
|
|
49
|
+
};
|
|
50
|
+
ignoreBranch: {
|
|
51
|
+
target: "cli";
|
|
52
|
+
cliName: string;
|
|
53
|
+
describe: string;
|
|
54
|
+
type: "string";
|
|
55
|
+
};
|
|
56
|
+
scope: {
|
|
57
|
+
target: "cli";
|
|
58
|
+
describe: string;
|
|
59
|
+
type: "string";
|
|
60
|
+
};
|
|
61
|
+
ignore: {
|
|
62
|
+
target: "cli";
|
|
63
|
+
describe: string;
|
|
64
|
+
type: "string";
|
|
65
|
+
};
|
|
66
|
+
platform: {
|
|
67
|
+
target: "cli";
|
|
68
|
+
describe: string;
|
|
69
|
+
type: "string";
|
|
70
|
+
};
|
|
71
|
+
deps: {
|
|
72
|
+
target: "cli";
|
|
73
|
+
describe: string;
|
|
74
|
+
type: "boolean";
|
|
75
|
+
};
|
|
76
|
+
dependents: {
|
|
77
|
+
target: "cli";
|
|
78
|
+
describe: string;
|
|
79
|
+
type: "boolean";
|
|
80
|
+
};
|
|
81
|
+
};
|
|
82
|
+
type Args = RmanConfig.ArgsOf<typeof config, typeof COMMAND>;
|
|
83
|
+
declare const runCommand: (app: import("../index.js").RmanApplication) => {
|
|
84
|
+
command: "run <script>";
|
|
85
|
+
describe: string;
|
|
86
|
+
/**
|
|
87
|
+
* The one command whose `--config` keys depend on argv: the script's own block, whichever script
|
|
88
|
+
* was asked for. Read, not owned - `run.<script>.*` is keyed by script name, so it is the one
|
|
89
|
+
* config shape a flat option map cannot describe and it stays hand-written in `RmanConfig`.
|
|
90
|
+
*/
|
|
91
|
+
configKeys: (args: any) => string[];
|
|
92
|
+
config: {
|
|
93
|
+
parallel: {
|
|
94
|
+
target: "cli";
|
|
95
|
+
describe: string;
|
|
96
|
+
coerce: (v: unknown) => boolean | number | undefined;
|
|
97
|
+
};
|
|
98
|
+
bail: {
|
|
99
|
+
target: "cli";
|
|
100
|
+
describe: string;
|
|
101
|
+
type: "boolean";
|
|
102
|
+
};
|
|
103
|
+
topo: {
|
|
104
|
+
target: "cli";
|
|
105
|
+
describe: string;
|
|
106
|
+
type: "boolean";
|
|
107
|
+
};
|
|
108
|
+
progress: {
|
|
109
|
+
target: "cli";
|
|
110
|
+
describe: string;
|
|
111
|
+
type: "boolean";
|
|
112
|
+
};
|
|
113
|
+
changed: {
|
|
114
|
+
target: "cli";
|
|
115
|
+
alias: string;
|
|
116
|
+
describe: string;
|
|
117
|
+
type: "boolean";
|
|
118
|
+
};
|
|
119
|
+
changedSince: {
|
|
120
|
+
target: "cli";
|
|
121
|
+
cliName: string;
|
|
122
|
+
describe: string;
|
|
123
|
+
type: "string";
|
|
124
|
+
conflicts: string;
|
|
125
|
+
};
|
|
126
|
+
fromRoot: {
|
|
127
|
+
target: "cli";
|
|
128
|
+
cliName: string;
|
|
129
|
+
alias: string;
|
|
130
|
+
describe: string;
|
|
131
|
+
type: "boolean";
|
|
132
|
+
};
|
|
133
|
+
allowBranch: {
|
|
134
|
+
target: "cli";
|
|
135
|
+
cliName: string;
|
|
136
|
+
describe: string;
|
|
137
|
+
type: "string";
|
|
138
|
+
};
|
|
139
|
+
ignoreBranch: {
|
|
140
|
+
target: "cli";
|
|
141
|
+
cliName: string;
|
|
142
|
+
describe: string;
|
|
143
|
+
type: "string";
|
|
144
|
+
};
|
|
145
|
+
scope: {
|
|
146
|
+
target: "cli";
|
|
147
|
+
describe: string;
|
|
148
|
+
type: "string";
|
|
149
|
+
};
|
|
150
|
+
ignore: {
|
|
151
|
+
target: "cli";
|
|
152
|
+
describe: string;
|
|
153
|
+
type: "string";
|
|
154
|
+
};
|
|
155
|
+
platform: {
|
|
156
|
+
target: "cli";
|
|
157
|
+
describe: string;
|
|
158
|
+
type: "string";
|
|
159
|
+
};
|
|
160
|
+
deps: {
|
|
161
|
+
target: "cli";
|
|
162
|
+
describe: string;
|
|
163
|
+
type: "boolean";
|
|
164
|
+
};
|
|
165
|
+
dependents: {
|
|
166
|
+
target: "cli";
|
|
167
|
+
describe: string;
|
|
168
|
+
type: "boolean";
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
positionals: {
|
|
172
|
+
script: {
|
|
173
|
+
describe: string;
|
|
174
|
+
type: "string";
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
examples: ({
|
|
178
|
+
command: string;
|
|
179
|
+
description?: undefined;
|
|
180
|
+
} | {
|
|
181
|
+
command: string;
|
|
182
|
+
description: string;
|
|
183
|
+
})[];
|
|
184
|
+
handler: (args: Args) => Promise<void>;
|
|
185
|
+
};
|
|
186
|
+
export default runCommand;
|
package/commands/run.command.js
CHANGED
|
@@ -1,77 +1,31 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
'a number for that many, false to run serially. Packages always build in dependency order.',
|
|
9
|
-
coerce: (v) => {
|
|
10
|
-
if (v === undefined)
|
|
11
|
-
return undefined;
|
|
12
|
-
if (v === 'false' || v === false)
|
|
13
|
-
return false;
|
|
14
|
-
if (v === 'true' || v === true)
|
|
15
|
-
return true;
|
|
16
|
-
const n = Number(v);
|
|
17
|
-
return Number.isFinite(n) ? n : true;
|
|
18
|
-
},
|
|
19
|
-
})
|
|
20
|
-
.option('bail', {
|
|
21
|
-
describe: 'Stop on first failure (default: true, overridable per-package via .rmanrc run.<script>.bail)',
|
|
22
|
-
type: 'boolean',
|
|
23
|
-
})
|
|
24
|
-
.option('topo', {
|
|
25
|
-
describe: 'Respect package dependency order: a package waits for its dependencies and is skipped if one ' +
|
|
26
|
-
'fails. Set false for independent scripts (e.g. lint/test) - order becomes alphabetical and ' +
|
|
27
|
-
'failures never skip other packages. Default: true, overridable per-package via .rmanrc run.<script>.topo.',
|
|
28
|
-
type: 'boolean',
|
|
29
|
-
})
|
|
30
|
-
.option('progress', {
|
|
31
|
-
describe: 'Show a live progress panel (default: true; auto-disabled when not a TTY; .rmanrc run.<script>.progress)',
|
|
32
|
-
type: 'boolean',
|
|
33
|
-
})
|
|
34
|
-
.option('changed', {
|
|
35
|
-
alias: 'c',
|
|
36
|
-
describe: 'Only run in packages that have changed since the last publish',
|
|
37
|
-
type: 'boolean',
|
|
38
|
-
})
|
|
39
|
-
.option('changed-since', {
|
|
40
|
-
describe: 'Only run in packages that have changed since the given git commit/hash',
|
|
41
|
-
type: 'string',
|
|
42
|
-
})
|
|
43
|
-
.conflicts('changed', 'changed-since');
|
|
44
|
-
}
|
|
45
|
-
export function readRunOptions(args) {
|
|
1
|
+
import { registerCommand } from '../interfaces/rman-config.interface.js';
|
|
2
|
+
import { assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
|
|
3
|
+
import { readRunOptions, runOptions } from '../utils/run-options.js';
|
|
4
|
+
const COMMAND = 'run <script>';
|
|
5
|
+
const config = runOptions;
|
|
6
|
+
const runCommand = registerCommand(app => {
|
|
7
|
+
const repository = app.repository;
|
|
46
8
|
return {
|
|
47
|
-
|
|
48
|
-
parallel: args.parallel,
|
|
49
|
-
topo: args.topo,
|
|
50
|
-
bail: args.bail,
|
|
51
|
-
progress: args.progress,
|
|
52
|
-
changed: args.changed,
|
|
53
|
-
changedSince: args.changedSince,
|
|
54
|
-
logLevel: args.logLevel,
|
|
55
|
-
root: args.root,
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
export function initCli(repository, program) {
|
|
59
|
-
program.command({
|
|
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],
|
|
9
|
+
command: COMMAND,
|
|
64
10
|
describe: 'Run an npm script in each package',
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The one command whose `--config` keys depend on argv: the script's own block, whichever script
|
|
13
|
+
* was asked for. Read, not owned - `run.<script>.*` is keyed by script name, so it is the one
|
|
14
|
+
* config shape a flat option map cannot describe and it stays hand-written in `RmanConfig`.
|
|
15
|
+
*/
|
|
16
|
+
configKeys: (args) => ['run.' + args.script],
|
|
17
|
+
config,
|
|
18
|
+
positionals: {
|
|
19
|
+
script: { describe: 'The script to run', type: 'string' },
|
|
20
|
+
},
|
|
21
|
+
examples: [
|
|
22
|
+
{ command: '$0 run build' },
|
|
23
|
+
{ command: '$0 run build --changed', description: '# Only in packages changed since the last publish' },
|
|
24
|
+
],
|
|
72
25
|
handler: async (args) => {
|
|
73
26
|
await assertAllowedBranch(repository, readBranchGuardOptions(args));
|
|
74
|
-
await
|
|
27
|
+
await app.getService('run').runScript(args.script, { ...readRunOptions(args), commandName: 'run' });
|
|
75
28
|
},
|
|
76
|
-
}
|
|
77
|
-
}
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
export default runCommand;
|