rman 2.14.0 → 2.15.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.
- package/README.md +52 -19
- package/builtins/platforms/node/services/version-plan.service.d.ts +1 -1
- package/builtins/platforms/node/services/version-plan.service.js +1 -1
- package/commands/changelog.command.js +4 -3
- package/commands/info.command.js +11 -5
- package/commands/version.command.js +4 -1
- package/constants.js +1 -1
- package/core/interfaces/manifest.js +1 -1
- package/core/interfaces/plugin.d.ts +1 -1
- package/core/interfaces/plugin.js +1 -1
- package/package.json +1 -1
- package/services/change-hash.service.d.ts +2 -2
- package/services/change-hash.service.js +2 -2
- package/services/system-info.d.ts +3 -0
- package/services/system-info.js +1 -0
- package/services/version-plan.service.d.ts +2 -1
- package/services/version-plan.service.js +7 -5
- package/services/version.service.js +19 -6
- package/utils/git.d.ts +5 -3
- package/utils/git.js +15 -5
- package/utils/package-filter.d.ts +1 -1
- package/utils/package-filter.js +1 -1
package/README.md
CHANGED
|
@@ -88,6 +88,7 @@ worked examples of every single command, see **[docs/cli-rman.md](https://github
|
|
|
88
88
|
| [`config`](#rman-config) | Prints the effective `.rmanrc` config for the current directory's package. |
|
|
89
89
|
| [`diff [package]`](#rman-diff-package) | Shows the git diff since a package's (or the repo's) last release tag. |
|
|
90
90
|
| [`changelog`](#rman-changelog) | Generates a changelog per package from unreleased commits. |
|
|
91
|
+
| [`deps [names..]`](#rman-deps-names) | Lists dependencies with a newer version; `-u` upgrades them. |
|
|
91
92
|
| [`version [bump]`](#rman-version-bump) | Bumps versions of changed packages (and their dependents). |
|
|
92
93
|
| [`publish`](#rman-publish) | Publishes every package whose version isn't on its registry yet. |
|
|
93
94
|
| [`github-release`](#rman-github-release) | Creates the repository's GitHub Release for its release tag. |
|
|
@@ -129,16 +130,17 @@ Options shared across several commands:
|
|
|
129
130
|
|
|
130
131
|
- **`skip`** (`.rmanrc`, per package): leave this package alone - honoured by every command that
|
|
131
132
|
*acts* on packages, ignored by `list`, which reports on them.
|
|
132
|
-
- **Package filtering** (`list`, `run`/`build`/`test`, `exec`, `version`, `changelog`,
|
|
133
|
-
plugin's own commands): `--scope <glob>`, `--ignore <glob>`, `--deps`, `--dependents` - see
|
|
134
|
-
[Package filtering](https://github.com/panates/rman/blob/main/docs/rman.md#package-filtering-
|
|
133
|
+
- **Package filtering** (`list`, `run`/`build`/`test`, `exec`, `version`, `changelog`, `publish`,
|
|
134
|
+
`deps`, `clean`, `ci`, and a plugin's own commands): `--scope <glob>`, `--ignore <glob>`, `--deps`, `--dependents` - see
|
|
135
|
+
[Package filtering](https://github.com/panates/rman/blob/main/docs/rman.md#package-filtering-scopeignoreplatformdepsdependents)
|
|
135
136
|
for the full semantics. **`--scope /` is the repository's own root package** - the same `/`
|
|
136
137
|
`.rmanrc`'s `"[/]"` block uses, and not a glob, so `--scope '*'` means the members and a glob
|
|
137
138
|
never picks up the root by name.
|
|
138
139
|
- **`--from-root`/`-r`** (every command that narrows to the package you are standing in -
|
|
139
|
-
`run`/`build`/`test`, `exec`, `changelog`, `diff`): run against the whole
|
|
140
|
+
`run`/`build`/`test`, `exec`, `clean`, `changelog`, `diff`, `config`): run against the whole
|
|
141
|
+
repository instead.
|
|
140
142
|
- **Branch guard** (every command that mutates state or runs scripts - `run`/`build`/`test`,
|
|
141
|
-
`exec`, `version`): `--allow-branch <glob>`, `--ignore-branch <glob>` -
|
|
143
|
+
`exec`, `version`, `publish`, `github-release`, `clean`, `ci`): `--allow-branch <glob>`, `--ignore-branch <glob>` -
|
|
142
144
|
refuses to run unless (or if) the current git branch matches, the same idea as GitHub Actions'
|
|
143
145
|
own `branches`/`branches-ignore` workflow filters.
|
|
144
146
|
|
|
@@ -147,7 +149,7 @@ Options shared across several commands:
|
|
|
147
149
|
Lists packages in the repository (alias: `ls`).
|
|
148
150
|
|
|
149
151
|
```bash
|
|
150
|
-
rman list # table: Package / Version / Private / Changed / Path
|
|
152
|
+
rman list # table: Package / Version / Group / Platform / Private / Publish / Changed / Path
|
|
151
153
|
rman ls --short # just the bare package names
|
|
152
154
|
rman list --json # full detail as JSON
|
|
153
155
|
rman list --parseable # location::name::version::PRIVATE::STATUS lines, for scripting
|
|
@@ -158,12 +160,16 @@ rman list --changed-since HEAD~5
|
|
|
158
160
|
rman list --scope '@myorg/*' --ignore '*-internal'
|
|
159
161
|
```
|
|
160
162
|
|
|
163
|
+
The table keeps each release group together, in `version`'s plan order (root, then groups, then
|
|
164
|
+
packages in no group), and indents a package by how deep it sits. `Group` appears only when it says
|
|
165
|
+
something; `Publish` names the targets a package ships to, or `-` when none is left. `--toposort`
|
|
166
|
+
orders by dependencies instead, and `--json` keeps the inventory's own order.
|
|
167
|
+
|
|
161
168
|
### `rman info`
|
|
162
169
|
|
|
163
170
|
Prints local environment (OS/CPU/memory, Node, git) and repository information. A platform adds its
|
|
164
171
|
own ecosystem's part - the `node` built-in reports whichever package manager
|
|
165
|
-
`.rmanrc "packageManager"` names, plus the installed `rman`
|
|
166
|
-
asked for it.
|
|
172
|
+
`.rmanrc "packageManager"` names (`npm` by default), plus the installed `rman` and `typescript`.
|
|
167
173
|
|
|
168
174
|
```bash
|
|
169
175
|
rman info
|
|
@@ -239,16 +245,38 @@ rman diff pkg-a # since pkg-a's own last tag, scoped to its directory
|
|
|
239
245
|
|
|
240
246
|
### `rman changelog`
|
|
241
247
|
|
|
242
|
-
Generates a changelog per package from unreleased commits,
|
|
243
|
-
|
|
248
|
+
Generates a changelog per package from unreleased commits, with a section per Conventional Commits
|
|
249
|
+
type (✨ Features, 🐛 Bug Fixes, ⚡ Performance, ...; anything else under 💬 General Changes) -
|
|
250
|
+
renamed or extended with `.rmanrc "changelog.titles"`. With `changelog.groupBy: group`, one file per
|
|
251
|
+
release group instead of per package.
|
|
244
252
|
|
|
245
253
|
```bash
|
|
246
254
|
rman changelog # auto-detects each package's own last release
|
|
247
255
|
rman changelog --from a1b2c3d # since a specific commit, for every package
|
|
248
256
|
rman changelog --write # prepend into each package's own CHANGELOG.md
|
|
249
257
|
rman changelog --write --file-path docs/CHANGELOG.md
|
|
258
|
+
rman changelog --rebuild # regenerate the files from scratch instead of appending
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### `rman deps [names..]`
|
|
262
|
+
|
|
263
|
+
Lists the dependencies that have a newer version on their registry - every package, the monorepo
|
|
264
|
+
root's own tooling included - and with `-u` writes the new ranges to the manifests, then checks that
|
|
265
|
+
they still install.
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
rman deps # what could move, and what holds it back
|
|
269
|
+
rman deps -u # write the new ranges, then check that they install
|
|
270
|
+
rman deps --target major # across a major too
|
|
271
|
+
rman deps '@types/*' # only the dependencies matching this glob
|
|
250
272
|
```
|
|
251
273
|
|
|
274
|
+
**A dependency stays inside its major by default** (`deps.target: minor`). Taking a major is a
|
|
275
|
+
decision a person makes: `--target major` for one run, `.rmanrc "deps.target"` for a standing
|
|
276
|
+
answer, or `deps.targets` for one dependency. Only a caret or tilde range is rewritten; a version is
|
|
277
|
+
offered only when every rule rman can see allows it. See
|
|
278
|
+
[docs/cli/deps.md](https://github.com/panates/rman/blob/main/docs/cli/deps.md).
|
|
279
|
+
|
|
252
280
|
### `rman version [bump]`
|
|
253
281
|
|
|
254
282
|
Bumps versions of changed packages (and their in-group dependents), grouped via `.rmanrc "group"`.
|
|
@@ -394,10 +422,11 @@ precedence: `package.json`'s own `"rman"` key, `.rmanrc.yml` (YAML), `.rmanrc` (
|
|
|
394
422
|
the dotfile-style name), and `.rmanrc.cjs`/`.rmanrc.mjs`/`.rmanrc.js` for config that needs real
|
|
395
423
|
logic (a JS module's default export).
|
|
396
424
|
|
|
397
|
-
**Who a declaration is about** follows one rule:
|
|
398
|
-
|
|
399
|
-
repository root's own keys are the
|
|
400
|
-
|
|
425
|
+
**Who a declaration is about** follows one rule: what is written above reaches below, and a
|
|
426
|
+
`"[selector]"` block narrows the audience. An unmarked key configures its directory's package and
|
|
427
|
+
every package under it, so the repository root's own keys are the baseline for the whole repository.
|
|
428
|
+
`"[/]"` is the root package alone, `"[platform:node]"` every package of that technology, and a glob
|
|
429
|
+
such as `"[*]"` the packages below.
|
|
401
430
|
|
|
402
431
|
```yaml
|
|
403
432
|
# .rmanrc.yml, at the repository root
|
|
@@ -405,6 +434,11 @@ packageManager: pnpm
|
|
|
405
434
|
logLevel: info
|
|
406
435
|
allowBranch: [main, release/*]
|
|
407
436
|
|
|
437
|
+
'[/]': # the root package alone - run's scheduling keys are read from here
|
|
438
|
+
run:
|
|
439
|
+
build:
|
|
440
|
+
concurrency: 4
|
|
441
|
+
|
|
408
442
|
version:
|
|
409
443
|
commitMessage: 'chore(release): v{version}'
|
|
410
444
|
|
|
@@ -418,7 +452,6 @@ version:
|
|
|
418
452
|
run:
|
|
419
453
|
test: mocha # a bare string is shorthand for { exec: mocha }
|
|
420
454
|
build:
|
|
421
|
-
concurrency: 4
|
|
422
455
|
before: [rman run lint]
|
|
423
456
|
exec: tsc -b tsconfig-build.json
|
|
424
457
|
after: node ../../support/postbuild.cjs
|
|
@@ -462,15 +495,15 @@ used to cover them was removed.
|
|
|
462
495
|
|
|
463
496
|
## Programmatic API
|
|
464
497
|
|
|
465
|
-
Every command above is a thin wrapper around an exported service
|
|
498
|
+
Every command above is a thin wrapper around an exported service - call them directly
|
|
466
499
|
from your own Node.js scripts without shelling out to the `rman` binary:
|
|
467
500
|
|
|
468
501
|
```ts
|
|
469
|
-
import { Repository,
|
|
502
|
+
import { Repository, VersionPlanService } from 'rman';
|
|
470
503
|
|
|
471
504
|
const repository = await Repository.create();
|
|
472
|
-
const plan = await
|
|
473
|
-
await
|
|
505
|
+
const plan = await VersionPlanService.getPlanner(repository.app).getPlan(repository);
|
|
506
|
+
await repository.app.getService('version').applyPlan(plan, { changelog: true, push: true });
|
|
474
507
|
```
|
|
475
508
|
|
|
476
509
|
Full reference, with detailed examples for every service (`VersionService`, `PublishService`,
|
|
@@ -9,7 +9,7 @@ import type { GitHelper } from '../../../../utils/git.js';
|
|
|
9
9
|
* abstract because they are statements about an *ecosystem* rather than about releases. This is
|
|
10
10
|
* npm's pair of answers.
|
|
11
11
|
*
|
|
12
|
-
* Registered through the plugin's `versionPlanner`, so `rman version
|
|
12
|
+
* Registered through the plugin's `versionPlanner`, so `rman version` works in a
|
|
13
13
|
* repository that registered the `node` built-in and say what is missing in one that did not.
|
|
14
14
|
*/
|
|
15
15
|
export declare class NodeVersionPlanService extends VersionPlanService {
|
|
@@ -8,7 +8,7 @@ import { VersionPlanService } from '../../../../services/version-plan.service.js
|
|
|
8
8
|
* abstract because they are statements about an *ecosystem* rather than about releases. This is
|
|
9
9
|
* npm's pair of answers.
|
|
10
10
|
*
|
|
11
|
-
* Registered through the plugin's `versionPlanner`, so `rman version
|
|
11
|
+
* Registered through the plugin's `versionPlanner`, so `rman version` works in a
|
|
12
12
|
* repository that registered the `node` built-in and say what is missing in one that did not.
|
|
13
13
|
*/
|
|
14
14
|
export class NodeVersionPlanService extends VersionPlanService {
|
|
@@ -13,7 +13,7 @@ const config = {
|
|
|
13
13
|
target: 'cli',
|
|
14
14
|
describe: 'Generate the changelog since this commit/hash, applied the same way to every package. ' +
|
|
15
15
|
'Default (also "auto" explicitly): auto-detect per package from its own most recent release ' +
|
|
16
|
-
'tag - same as "version"
|
|
16
|
+
'tag - same as "version" - falling back to the version its own ecosystem\'s ' +
|
|
17
17
|
"registry reports (no tag yet), then to its whole history for a package that's never been " +
|
|
18
18
|
'released at all',
|
|
19
19
|
type: 'string',
|
|
@@ -43,7 +43,7 @@ const config = {
|
|
|
43
43
|
cliName: 'release-version',
|
|
44
44
|
describe: 'The version these notes are for - what the entry heading shows. Default: read back from ' +
|
|
45
45
|
"each package's own latest release tag, which is only right once that release is tagged. " +
|
|
46
|
-
'Pass it when generating notes ahead of the bump (e.g. from "
|
|
46
|
+
'Pass it when generating notes ahead of the bump (e.g. from "version --json" in CI), ' +
|
|
47
47
|
'otherwise the heading shows the previous release.',
|
|
48
48
|
type: 'string',
|
|
49
49
|
},
|
|
@@ -91,7 +91,8 @@ const config = {
|
|
|
91
91
|
target: 'config',
|
|
92
92
|
describe: "The release tag naming scheme each package's changelog boundary is detected from - " +
|
|
93
93
|
'"{name}" is replaced with the package name (e.g. "{name}@*" for independent versioning). ' +
|
|
94
|
-
'Default "v*"
|
|
94
|
+
'Default: "v*" (one repo-wide tag, resolved through git describe) while the repository has one ' +
|
|
95
|
+
'version line, "{name}@*" once it has several.',
|
|
95
96
|
type: 'string',
|
|
96
97
|
},
|
|
97
98
|
/**
|
package/commands/info.command.js
CHANGED
|
@@ -60,13 +60,19 @@ function printSystemInfo(systemInfo) {
|
|
|
60
60
|
}
|
|
61
61
|
function printRepositoryInfo(info) {
|
|
62
62
|
console.log('', colors.whiteBright('Repository') + ':');
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
63
|
+
const rows = [
|
|
64
|
+
['Type', colors.yellowBright(info.type === 'monorepo' ? 'Monorepo' : 'Single package')],
|
|
65
|
+
['Name', colors.yellowBright(info.name || '(none)')],
|
|
66
|
+
['Version', colors.yellowBright(info.version || '(none)')],
|
|
67
|
+
['Root', colors.yellowBright(info.root)],
|
|
68
|
+
['Platforms', colors.yellowBright(info.platforms.join(', ') || '(none)')],
|
|
69
|
+
];
|
|
67
70
|
if (info.type === 'monorepo') {
|
|
68
|
-
|
|
71
|
+
rows.push(['Packages', colors.yellowBright(String(info.packageCount)), colors.gray('(run "list" to see them)')]);
|
|
69
72
|
}
|
|
73
|
+
const width = Math.max(...rows.map(([label]) => label.length));
|
|
74
|
+
for (const [label, ...values] of rows)
|
|
75
|
+
console.log(' ' + colors.reset(label.padEnd(width)) + ' :', ...values);
|
|
70
76
|
}
|
|
71
77
|
/**
|
|
72
78
|
* `rman info` - environment and repository, and back in the core because most of what it reports
|
|
@@ -210,6 +210,8 @@ const versionCommand = registerCommand(app => {
|
|
|
210
210
|
name: e.package.name,
|
|
211
211
|
selector: e.package.selector,
|
|
212
212
|
isRoot: e.package.isRoot,
|
|
213
|
+
/** `rman list --json`'s spelling, so a consumer joins the two on it. */
|
|
214
|
+
groupKey: e.groupKey,
|
|
213
215
|
group: e.group,
|
|
214
216
|
status: e.status,
|
|
215
217
|
from: e.from,
|
|
@@ -284,7 +286,8 @@ function printApplied(result) {
|
|
|
284
286
|
console.log(`${colors.green('tags')} ${release.map(label).join(', ')} ${colors.gray('(repository release)')}`);
|
|
285
287
|
}
|
|
286
288
|
console.log(result.pushed
|
|
287
|
-
? `${colors.green('push')} pushed
|
|
289
|
+
? `${colors.green('push')} pushed the branch` +
|
|
290
|
+
(result.tags.length ? ` and ${result.tags.map(t => t.name).join(', ')}, together` : '')
|
|
288
291
|
: `${colors.gray('push')} ${colors.gray('not pushed - run with --push, or push it yourself')}`);
|
|
289
292
|
}
|
|
290
293
|
function printPlan(entries) {
|
package/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '2.
|
|
1
|
+
export const version = '2.15.1';
|
|
@@ -53,7 +53,7 @@ export var Manifest;
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
throw new Error(`No manifest provider recognizes "${dir}", so there is nowhere to write its version.\n` +
|
|
56
|
-
` A repository's ".rmanrc" names its technologies - see "
|
|
56
|
+
` A repository's ".rmanrc" names its technologies - see "platforms", or "extends" (e.g. "rman:node").`);
|
|
57
57
|
}
|
|
58
58
|
Manifest.write = write;
|
|
59
59
|
/**
|
|
@@ -172,7 +172,7 @@ export declare function isPlugin(value: unknown): value is Plugin;
|
|
|
172
172
|
* - no `getBinPaths` -> nothing is prepended to a child process's PATH, so the inherited one
|
|
173
173
|
* stands on its own rather than being guessed at;
|
|
174
174
|
* - no `getRunSteps` -> a package's steps come from its `.rmanrc` alone, the core's only source;
|
|
175
|
-
* - no `versionPlanner` -> `version
|
|
175
|
+
* - no `versionPlanner` -> `version` fails naming the key, rather than releasing a
|
|
176
176
|
* plausible but untrue set of packages from a default nobody chose.
|
|
177
177
|
*/
|
|
178
178
|
export declare const basePlatform: Platform;
|
|
@@ -73,7 +73,7 @@ export function isPlugin(value) {
|
|
|
73
73
|
* - no `getBinPaths` -> nothing is prepended to a child process's PATH, so the inherited one
|
|
74
74
|
* stands on its own rather than being guessed at;
|
|
75
75
|
* - no `getRunSteps` -> a package's steps come from its `.rmanrc` alone, the core's only source;
|
|
76
|
-
* - no `versionPlanner` -> `version
|
|
76
|
+
* - no `versionPlanner` -> `version` fails naming the key, rather than releasing a
|
|
77
77
|
* plausible but untrue set of packages from a default nobody chose.
|
|
78
78
|
*/
|
|
79
79
|
export const basePlatform = definePlatform({
|
package/package.json
CHANGED
|
@@ -106,8 +106,8 @@ export declare namespace ChangeHashService {
|
|
|
106
106
|
* `changelog --from` uses, but reusable anywhere a command wants to answer "what changed for this
|
|
107
107
|
* package". An explicit `options.from` (anything but `AUTO`) is returned as-is, applying the same
|
|
108
108
|
* way to every package. Otherwise, it's auto-detected in order: (1) this package's own most recent
|
|
109
|
-
* release tag - the same network-free `findLatestTag` lookup `version
|
|
110
|
-
* so
|
|
109
|
+
* release tag - the same network-free `findLatestTag` lookup `version` itself uses,
|
|
110
|
+
* so both commands agree on "since when" for any repo whose tags are the ones `rman version`
|
|
111
111
|
* actually created; (2) failing that (no tag at all yet - e.g. onboarding `rman` onto a repo with
|
|
112
112
|
* real release history but no `rman`-created tags), whatever this package's **own ecosystem**
|
|
113
113
|
* reports as its published version (`Plugin.publishedVersion`), mapped to a git tag via
|
|
@@ -134,8 +134,8 @@ export var ChangeHashService;
|
|
|
134
134
|
* `changelog --from` uses, but reusable anywhere a command wants to answer "what changed for this
|
|
135
135
|
* package". An explicit `options.from` (anything but `AUTO`) is returned as-is, applying the same
|
|
136
136
|
* way to every package. Otherwise, it's auto-detected in order: (1) this package's own most recent
|
|
137
|
-
* release tag - the same network-free `findLatestTag` lookup `version
|
|
138
|
-
* so
|
|
137
|
+
* release tag - the same network-free `findLatestTag` lookup `version` itself uses,
|
|
138
|
+
* so both commands agree on "since when" for any repo whose tags are the ones `rman version`
|
|
139
139
|
* actually created; (2) failing that (no tag at all yet - e.g. onboarding `rman` onto a repo with
|
|
140
140
|
* real release history but no `rman`-created tags), whatever this package's **own ecosystem**
|
|
141
141
|
* reports as its published version (`Plugin.publishedVersion`), mapped to a git tag via
|
|
@@ -7,6 +7,9 @@ export declare namespace SystemInfo {
|
|
|
7
7
|
version: string;
|
|
8
8
|
root: string;
|
|
9
9
|
packageCount: number;
|
|
10
|
+
/** The technologies this run loaded, by `Platform.name`, in the order a directory is offered to
|
|
11
|
+
* them - so `["cargo", "node"]` means a directory both recognize is a Cargo package. */
|
|
12
|
+
platforms: string[];
|
|
10
13
|
}
|
|
11
14
|
/** Whatever `envinfo` reports, grouped by category - shape is `envinfo`'s own, not ours. */
|
|
12
15
|
type SystemInfo = Record<string, Record<string, unknown>>;
|
package/services/system-info.js
CHANGED
|
@@ -23,6 +23,7 @@ export var SystemInfo;
|
|
|
23
23
|
version: repository.rootPackage.version,
|
|
24
24
|
root: repository.dirname,
|
|
25
25
|
packageCount: repository.getPackages().length,
|
|
26
|
+
platforms: [...repository.app.platforms].map(p => p.name),
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
29
|
SystemInfo.getRepositoryInfo = getRepositoryInfo;
|
|
@@ -56,7 +56,8 @@ export declare abstract class VersionPlanService {
|
|
|
56
56
|
* Across groups: a package depending on another group's bumped package always gets its scheme's
|
|
57
57
|
* **smallest** bump of its own (never inheriting the source's) - the dependency reference itself
|
|
58
58
|
* is the only thing that changed for it. Whether that re-triggers its own group's cascade is
|
|
59
|
-
* `cascade`'s answer for that smallest bump (`'
|
|
59
|
+
* `cascade`'s answer for that smallest bump (`'dependents'` under npm, so its own in-group
|
|
60
|
+
* dependents move with it), and it can
|
|
60
61
|
* itself ripple into a third group, and so on, until nothing new is affected - see
|
|
61
62
|
* `rippleCrossGroup`.
|
|
62
63
|
*
|
|
@@ -58,7 +58,8 @@ export class VersionPlanService {
|
|
|
58
58
|
* Across groups: a package depending on another group's bumped package always gets its scheme's
|
|
59
59
|
* **smallest** bump of its own (never inheriting the source's) - the dependency reference itself
|
|
60
60
|
* is the only thing that changed for it. Whether that re-triggers its own group's cascade is
|
|
61
|
-
* `cascade`'s answer for that smallest bump (`'
|
|
61
|
+
* `cascade`'s answer for that smallest bump (`'dependents'` under npm, so its own in-group
|
|
62
|
+
* dependents move with it), and it can
|
|
62
63
|
* itself ripple into a third group, and so on, until nothing new is affected - see
|
|
63
64
|
* `rippleCrossGroup`.
|
|
64
65
|
*
|
|
@@ -174,8 +175,8 @@ export class VersionPlanService {
|
|
|
174
175
|
* The abort case, marked **after** the root entry so the whole table reads as one coherent
|
|
175
176
|
* "if this were committed" preview rather than a mixture of two.
|
|
176
177
|
*
|
|
177
|
-
* `to` survives the overwrite; `status` is what every writer filters on (`VersionService
|
|
178
|
-
*
|
|
178
|
+
* `to` survives the overwrite; `status` is what every writer filters on (`VersionService`),
|
|
179
|
+
* so an `'error'` entry carrying a version cannot be applied by any of them - and
|
|
179
180
|
* `version` throws on the first error before it would reach `applyPlan` anyway. The reason
|
|
180
181
|
* keeps the boundary it was computed from, because the status column already says `error` and
|
|
181
182
|
* a reader losing `changed since <tag>` loses the only thing that explains the number.
|
|
@@ -523,8 +524,9 @@ export class VersionPlanService {
|
|
|
523
524
|
function getPlanner(app) {
|
|
524
525
|
const planner = app.versionPlanner;
|
|
525
526
|
if (!planner) {
|
|
526
|
-
throw new Error('No version planner is registered, so no version plan can be computed. Name a
|
|
527
|
-
'contributes one in .rmanrc "
|
|
527
|
+
throw new Error('No version planner is registered, so no version plan can be computed. Name a technology ' +
|
|
528
|
+
'that contributes one in .rmanrc "platforms", or reach it through "extends" - "rman:node" ' +
|
|
529
|
+
'for a Node repository, which is laid down by default unless presets were turned off.');
|
|
528
530
|
}
|
|
529
531
|
return planner;
|
|
530
532
|
}
|
|
@@ -254,8 +254,21 @@ export class VersionService extends Service {
|
|
|
254
254
|
tagged.push({ name: releaseTag, created: true, release: true });
|
|
255
255
|
}
|
|
256
256
|
const pushed = !!options.push && bumped.length > 0;
|
|
257
|
-
if (pushed)
|
|
258
|
-
|
|
257
|
+
if (pushed) {
|
|
258
|
+
/** Every tag this release names, including one that was already there: it is this release's
|
|
259
|
+
* tag all the same, and a remote that lacks it is missing part of the release. */
|
|
260
|
+
const tags = tagged.map(t => t.name);
|
|
261
|
+
try {
|
|
262
|
+
await git.push({ tags });
|
|
263
|
+
}
|
|
264
|
+
catch (e) {
|
|
265
|
+
throw new Error(`${e.message}\n\n` +
|
|
266
|
+
` Nothing was pushed - the branch and its tags go up together or not at all. Left behind ` +
|
|
267
|
+
`locally: ${commits.map(c => c.sha).join(', ') || 'no commit'}` +
|
|
268
|
+
(tags.length ? `, tagged ${tags.join(', ')}` : '') +
|
|
269
|
+
`.\n Once the cause is fixed, push them with: git push --atomic origin HEAD ${tags.join(' ')}`.trimEnd(), { cause: e });
|
|
270
|
+
}
|
|
271
|
+
}
|
|
259
272
|
return { entries: plan, updated: bumped, commits, tags: tagged, pushed };
|
|
260
273
|
}
|
|
261
274
|
}
|
|
@@ -361,8 +374,8 @@ export class VersionService extends Service {
|
|
|
361
374
|
(pkg.provider
|
|
362
375
|
? ` The "${pkg.provider}" provider looked and found no version to change. Name the ` +
|
|
363
376
|
`identifier with { file, constant } if it is not "version", or drop the entry.`
|
|
364
|
-
: ` This package belongs to no ecosystem (no
|
|
365
|
-
`a version is declared in it. Name
|
|
377
|
+
: ` This package belongs to no ecosystem (no platform claimed it), so nothing knows how ` +
|
|
378
|
+
`a version is declared in it. Name the technology in .rmanrc "platforms", or reach it through "extends" (e.g. "rman:node").`));
|
|
366
379
|
}
|
|
367
380
|
/** Matched, but already reads the target - nothing to write and nothing to report. Distinct
|
|
368
381
|
* from the `undefined` above, which is "nothing here to rewrite at all". */
|
|
@@ -447,8 +460,8 @@ function assertStampable(pkg, version) {
|
|
|
447
460
|
(pkg.provider
|
|
448
461
|
? ` The "${pkg.provider}" provider looked and found no version to change. Name the ` +
|
|
449
462
|
`identifier with { file, constant } if it is not "version", or drop the entry.`
|
|
450
|
-
: ` This package belongs to no ecosystem (no
|
|
451
|
-
`version is declared in it. Name
|
|
463
|
+
: ` This package belongs to no ecosystem (no platform claimed it), so nothing knows how a ` +
|
|
464
|
+
`version is declared in it. Name the technology in .rmanrc "platforms", or reach it through "extends" (e.g. "rman:node").`));
|
|
452
465
|
}
|
|
453
466
|
}
|
|
454
467
|
/**
|
package/utils/git.d.ts
CHANGED
|
@@ -121,11 +121,13 @@ export declare class GitHelper {
|
|
|
121
121
|
* Throws if a tag with that name already exists - callers wanting idempotent tagging should
|
|
122
122
|
* check `tagExists` first. */
|
|
123
123
|
createTag(name: string, message?: string): Promise<void>;
|
|
124
|
-
/**
|
|
125
|
-
*
|
|
124
|
+
/**
|
|
125
|
+
* Pushes the current branch to `remote` (default `"origin"`) together with `options.tags`, by
|
|
126
|
+
* name, in **one atomic push**: the branch and every tag go up, or none of them does.
|
|
127
|
+
*/
|
|
126
128
|
push(options?: {
|
|
127
129
|
remote?: string;
|
|
128
|
-
tags?:
|
|
130
|
+
tags?: readonly string[];
|
|
129
131
|
}): Promise<void>;
|
|
130
132
|
/** `git remote get-url <remote>` (default `"origin"`) - `undefined` when that remote isn't
|
|
131
133
|
* configured at all, which is a perfectly normal state for a local-only repository. */
|
package/utils/git.js
CHANGED
|
@@ -394,14 +394,24 @@ export class GitHelper {
|
|
|
394
394
|
throw new Error(`Unable to create tag "${name}": ${e.message}`, { cause: e });
|
|
395
395
|
}
|
|
396
396
|
}
|
|
397
|
-
/**
|
|
398
|
-
*
|
|
397
|
+
/**
|
|
398
|
+
* Pushes the current branch to `remote` (default `"origin"`) together with `options.tags`, by
|
|
399
|
+
* name, in **one atomic push**: the branch and every tag go up, or none of them does.
|
|
400
|
+
*/
|
|
401
|
+
/* **Named tags, not `--tags`.** `git push <remote> --tags` sends every tag in the clone, so one
|
|
402
|
+
* stale tag from months ago - re-created locally, diverged from the remote's - failed every
|
|
403
|
+
* release from then on, and failed it *after* the new tag had already gone up. Measured on
|
|
404
|
+
* `postgrejs` with 2.15.0: `v3.13.0` pushed, `v3.10.0` rejected, exit 1, and in CI the publish
|
|
405
|
+
* step after it never ran.
|
|
406
|
+
*
|
|
407
|
+
* **One command, `--atomic`.** The branch used to go first and the tags second, so a failure in
|
|
408
|
+
* the second - GitHub's own `fatal error in commit_refs` did it to the same repository an hour
|
|
409
|
+
* earlier - left a pushed version bump with no tag, which a re-run cannot repair because it has
|
|
410
|
+
* nothing left to bump. Atomic, a failure leaves the remote exactly as it was. */
|
|
399
411
|
async push(options) {
|
|
400
412
|
const remote = options?.remote ?? 'origin';
|
|
401
413
|
try {
|
|
402
|
-
await execFileAsync('git', ['push', remote], { cwd: this.cwd });
|
|
403
|
-
if (options?.tags !== false)
|
|
404
|
-
await execFileAsync('git', ['push', remote, '--tags'], { cwd: this.cwd });
|
|
414
|
+
await execFileAsync('git', ['push', '--atomic', remote, 'HEAD', ...(options?.tags ?? [])], { cwd: this.cwd });
|
|
405
415
|
}
|
|
406
416
|
catch (e) {
|
|
407
417
|
throw new Error(`Unable to push to "${remote}": ${e.message}`, { cause: e });
|
|
@@ -176,7 +176,7 @@ applySkip?: boolean): Package[];
|
|
|
176
176
|
* **It only means anything where a command scopes by the current directory** - `run`/`build`/`test`,
|
|
177
177
|
* `exec`, `clean`, `changelog` and `diff` narrow to `Repository.currentPackage` when you stand
|
|
178
178
|
* inside a package, and this is the escape hatch. On a command that already works across the whole
|
|
179
|
-
* repository (`version`, `publish`, `list
|
|
179
|
+
* repository (`version`, `publish`, `list`) it would be a flag that does nothing, which
|
|
180
180
|
* is worse than not offering it: a no-op flag reads as a promise.
|
|
181
181
|
*
|
|
182
182
|
* That same rule is why there is no `--root-only` beside it, however naturally the pair reads: it
|
package/utils/package-filter.js
CHANGED
|
@@ -210,7 +210,7 @@ applySkip = true) {
|
|
|
210
210
|
* **It only means anything where a command scopes by the current directory** - `run`/`build`/`test`,
|
|
211
211
|
* `exec`, `clean`, `changelog` and `diff` narrow to `Repository.currentPackage` when you stand
|
|
212
212
|
* inside a package, and this is the escape hatch. On a command that already works across the whole
|
|
213
|
-
* repository (`version`, `publish`, `list
|
|
213
|
+
* repository (`version`, `publish`, `list`) it would be a flag that does nothing, which
|
|
214
214
|
* is worse than not offering it: a no-op flag reads as a promise.
|
|
215
215
|
*
|
|
216
216
|
* That same rule is why there is no `--root-only` beside it, however naturally the pair reads: it
|