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,6 +1,7 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
3
|
-
import {
|
|
1
|
+
import { RmanApplication } from '../core/application.js';
|
|
2
|
+
import type { Package } from '../core/classes/package.js';
|
|
3
|
+
import type { Repository } from '../core/classes/repository.js';
|
|
4
|
+
import { VersionScheme } from '../core/classes/version-scheme.js';
|
|
4
5
|
import { type CommitInfo, GitHelper } from '../utils/git.js';
|
|
5
6
|
import { type PackageFilterOptions } from '../utils/package-filter.js';
|
|
6
7
|
/**
|
|
@@ -97,6 +98,31 @@ export declare abstract class VersionPlanService {
|
|
|
97
98
|
* wrong one here is invisible - it produces a plan that simply releases too little.
|
|
98
99
|
*/
|
|
99
100
|
protected abstract cascade(bump: string): VersionPlanService.Cascade;
|
|
101
|
+
/**
|
|
102
|
+
* **Which planner answers for one package: its own technology's.**
|
|
103
|
+
*
|
|
104
|
+
* The two abstract members above are the ecosystem's, and a repository can hold more than one.
|
|
105
|
+
* `app.versionPlanner` is a single slot - last registration wins - so in a polyglot repository
|
|
106
|
+
* both of them used to be answered by whichever plugin happened to register last: a Cargo
|
|
107
|
+
* package's boundary fell back to `npm view`, and its cascade assumed npm's caret ranges. That is
|
|
108
|
+
* the same shape of bug the hardcoded `['npm']` publish default was, and the same fix - ask the
|
|
109
|
+
* technology that read the manifest.
|
|
110
|
+
*
|
|
111
|
+
* Falls back to `this`, which is what a single-technology repository always gets and what a
|
|
112
|
+
* `Plugin` contributing no planner of its own means.
|
|
113
|
+
*/
|
|
114
|
+
protected plannerFor(pkg: Package): VersionPlanService;
|
|
115
|
+
/**
|
|
116
|
+
* `cascade` for a whole group, which is the unit it is asked about - one answer applies to every
|
|
117
|
+
* member, because the group releases as one version line.
|
|
118
|
+
*
|
|
119
|
+
* **Members disagreeing take the widest answer**, and the direction is deliberate: a cascade that
|
|
120
|
+
* is too narrow produces a plan that silently *releases too little* (the failure `cascade`'s own
|
|
121
|
+
* doc calls invisible), while one that is too wide releases a package that did not strictly need
|
|
122
|
+
* it - visible, and harmless. A mixed-technology group is unusual; a mixed group quietly skipping
|
|
123
|
+
* a dependent that pins exact versions is a broken install.
|
|
124
|
+
*/
|
|
125
|
+
protected cascadeFor(members: Package[], bump: string): VersionPlanService.Cascade;
|
|
100
126
|
/**
|
|
101
127
|
* The largest bump `commits` ask for, in `scheme`'s own names.
|
|
102
128
|
*
|
|
@@ -215,7 +241,11 @@ export declare namespace VersionPlanService {
|
|
|
215
241
|
group: string;
|
|
216
242
|
status: 'bump' | 'skip' | 'error' | 'no-change';
|
|
217
243
|
from: string;
|
|
218
|
-
/**
|
|
244
|
+
/** The version this package would receive. Set for `'bump'`, and for an `'error'` entry that
|
|
245
|
+
* earned one - a package with uncommitted changes aborts the run, and `--show` exists to say
|
|
246
|
+
* what it would get. **Never** set for `'skip'`: `--ignore-dirty` proceeds to write, and a
|
|
247
|
+
* version beside an excluded package would name one it is not getting. So `status`, not `to`,
|
|
248
|
+
* is what decides whether something is applied. */
|
|
219
249
|
to?: string;
|
|
220
250
|
/** Human-readable explanation - e.g. why a package was skipped, or why it's being bumped
|
|
221
251
|
* despite having no commits of its own (a dependency of it changed elsewhere). */
|
|
@@ -230,9 +260,6 @@ export declare namespace VersionPlanService {
|
|
|
230
260
|
* repository layering its own policy plugin after `rman-node` could never take effect - which is
|
|
231
261
|
* the only reason to name two in the first place.
|
|
232
262
|
*/
|
|
233
|
-
function setPlanner(planner: VersionPlanService): void;
|
|
234
|
-
/** For tests, which would otherwise leak a planner into every later case in the process. */
|
|
235
|
-
function clearPlanner(): void;
|
|
236
263
|
/**
|
|
237
264
|
* The registered planner. **Throws** when there is none, rather than falling back to some
|
|
238
265
|
* built-in default: `Manifest` and `Workspace` can degrade honestly (a package named after its
|
|
@@ -240,5 +267,5 @@ export declare namespace VersionPlanService {
|
|
|
240
267
|
* merely a diminished one - a wrong cascade or a wrong boundary reports a release that is
|
|
241
268
|
* plausible and untrue.
|
|
242
269
|
*/
|
|
243
|
-
function getPlanner(): VersionPlanService;
|
|
270
|
+
function getPlanner(app: RmanApplication): VersionPlanService;
|
|
244
271
|
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import {
|
|
2
|
+
import { RmanApplication } from '../core/application.js';
|
|
3
|
+
import { assertOneScheme, semverScheme, VersionScheme } from '../core/classes/version-scheme.js';
|
|
3
4
|
import { GitHelper } from '../utils/git.js';
|
|
4
5
|
import { filterPackages } from '../utils/package-filter.js';
|
|
5
6
|
import { findLastReleaseVersion, formatCalendarVersion, usesCalendarVersion } from '../utils/release-version.js';
|
|
7
|
+
import { groupKeyOf } from '../utils/version-group.js';
|
|
6
8
|
import { ConventionalCommitsService } from './conventional-commits.service.js';
|
|
7
9
|
/**
|
|
8
10
|
* Question A, computed and nothing else: **which packages have changed since their last release,
|
|
@@ -95,21 +97,39 @@ export class VersionPlanService {
|
|
|
95
97
|
const packages = filterPackages(repository.getPackages(), options);
|
|
96
98
|
const dirtyFiles = await git.listDirtyFiles({ absolute: true });
|
|
97
99
|
const isDirty = (pkg) => dirtyFiles.some(f => !path.relative(pkg.dirname, f).startsWith('..'));
|
|
100
|
+
const dirty = packages.filter(isDirty);
|
|
98
101
|
const entries = new Map();
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
/**
|
|
103
|
+
* **A dirty package is removed from the plan only when the run is going to proceed without it.**
|
|
104
|
+
* The two answers are not symmetric, and treating them as one is what left the `To` column
|
|
105
|
+
* blank on the command that exists to show it.
|
|
106
|
+
*
|
|
107
|
+
* - `--ignore-dirty` **writes**. The package is deliberately excluded, so it must not reach a
|
|
108
|
+
* group either: a number its clean siblings receive cannot be derived from commits nobody is
|
|
109
|
+
* releasing, and a `to` printed beside `skip` would name a version that package is not
|
|
110
|
+
* getting. Diverted here, before `eligible`.
|
|
111
|
+
* - Aborting writes **nothing** - `getPlan` is pure and the command throws after printing - so
|
|
112
|
+
* there is no number to keep safe, and the one thing the reader wants is what each package
|
|
113
|
+
* would have got once it is committed. The plan is computed in full and the dirty entries are
|
|
114
|
+
* marked at the very end, below.
|
|
115
|
+
*
|
|
116
|
+
* Excluding them from the abort case cost more than the column. `buildRootEntry` reads
|
|
117
|
+
* `e.to ?? e.from`, and its `groupCount` comes from the groups that were actually built - so a
|
|
118
|
+
* dirty tree quietly moved the repository's own release identity: measured on a four-package
|
|
119
|
+
* repo with `group: false`, three dirty packages left one group standing, which is
|
|
120
|
+
* `usesCalendarVersion`'s "one line" case, and the root reported `0.0.5 -> 2.1.6` on the
|
|
121
|
+
* *semver* path instead of the calendar version it takes with four.
|
|
122
|
+
*/
|
|
123
|
+
const eligible = options.ignoreDirty ? packages.filter(pkg => !dirty.includes(pkg)) : packages;
|
|
124
|
+
for (const pkg of options.ignoreDirty ? dirty : []) {
|
|
125
|
+
entries.set(pkg.name, {
|
|
126
|
+
package: pkg,
|
|
127
|
+
groupKey: this.resolveGroupKey(pkg),
|
|
128
|
+
group: this.groupLabel(this.resolveGroupKey(pkg)),
|
|
129
|
+
status: 'skip',
|
|
130
|
+
from: pkg.version,
|
|
131
|
+
reason: 'uncommitted local changes',
|
|
132
|
+
});
|
|
113
133
|
}
|
|
114
134
|
const commitMessage = repository.rootPackage.config?.version?.commitMessage;
|
|
115
135
|
const changeByPackage = new Map();
|
|
@@ -118,7 +138,7 @@ export class VersionPlanService {
|
|
|
118
138
|
changeByPackage.set(pkg.name, { bump: undefined, reason: `explicit version ${explicitVersion}` });
|
|
119
139
|
return;
|
|
120
140
|
}
|
|
121
|
-
const since = await this.detectBoundary(git, pkg, options);
|
|
141
|
+
const since = await this.plannerFor(pkg).detectBoundary(git, pkg, options);
|
|
122
142
|
const commits = since ? await git.listCommits({ hash: since }) : await git.listAllCommits();
|
|
123
143
|
const belongsToPkg = (c) => c.files.some(f => !path.relative(pkg.dirname, f).startsWith('..'));
|
|
124
144
|
const real = commits.filter(c => belongsToPkg(c) && !ConventionalCommitsService.isReleaseCommit(c.subject, commitMessage));
|
|
@@ -150,8 +170,60 @@ export class VersionPlanService {
|
|
|
150
170
|
now: options.now ?? (() => new Date()),
|
|
151
171
|
}));
|
|
152
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* The abort case, marked **after** the root entry so the whole table reads as one coherent
|
|
175
|
+
* "if this were committed" preview rather than a mixture of two.
|
|
176
|
+
*
|
|
177
|
+
* `to` survives the overwrite; `status` is what every writer filters on (`VersionService`,
|
|
178
|
+
* `changed`), so an `'error'` entry carrying a version cannot be applied by any of them - and
|
|
179
|
+
* `version` throws on the first error before it would reach `applyPlan` anyway. The reason
|
|
180
|
+
* keeps the boundary it was computed from, because the status column already says `error` and
|
|
181
|
+
* a reader losing `changed since <tag>` loses the only thing that explains the number.
|
|
182
|
+
*/
|
|
183
|
+
if (!options.ignoreDirty) {
|
|
184
|
+
for (const pkg of dirty) {
|
|
185
|
+
const entry = entries.get(pkg.name);
|
|
186
|
+
if (!entry)
|
|
187
|
+
continue;
|
|
188
|
+
entry.status = 'error';
|
|
189
|
+
entry.reason = entry.reason ? `uncommitted local changes (${entry.reason})` : 'uncommitted local changes';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
153
192
|
return result;
|
|
154
193
|
}
|
|
194
|
+
/**
|
|
195
|
+
* **Which planner answers for one package: its own technology's.**
|
|
196
|
+
*
|
|
197
|
+
* The two abstract members above are the ecosystem's, and a repository can hold more than one.
|
|
198
|
+
* `app.versionPlanner` is a single slot - last registration wins - so in a polyglot repository
|
|
199
|
+
* both of them used to be answered by whichever plugin happened to register last: a Cargo
|
|
200
|
+
* package's boundary fell back to `npm view`, and its cascade assumed npm's caret ranges. That is
|
|
201
|
+
* the same shape of bug the hardcoded `['npm']` publish default was, and the same fix - ask the
|
|
202
|
+
* technology that read the manifest.
|
|
203
|
+
*
|
|
204
|
+
* Falls back to `this`, which is what a single-technology repository always gets and what a
|
|
205
|
+
* `Plugin` contributing no planner of its own means.
|
|
206
|
+
*/
|
|
207
|
+
plannerFor(pkg) {
|
|
208
|
+
return pkg.platform.versionPlanner ?? this;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* `cascade` for a whole group, which is the unit it is asked about - one answer applies to every
|
|
212
|
+
* member, because the group releases as one version line.
|
|
213
|
+
*
|
|
214
|
+
* **Members disagreeing take the widest answer**, and the direction is deliberate: a cascade that
|
|
215
|
+
* is too narrow produces a plan that silently *releases too little* (the failure `cascade`'s own
|
|
216
|
+
* doc calls invisible), while one that is too wide releases a package that did not strictly need
|
|
217
|
+
* it - visible, and harmless. A mixed-technology group is unusual; a mixed group quietly skipping
|
|
218
|
+
* a dependent that pins exact versions is a broken install.
|
|
219
|
+
*/
|
|
220
|
+
cascadeFor(members, bump) {
|
|
221
|
+
const answers = new Set(members.map(m => this.plannerFor(m).cascade(bump)));
|
|
222
|
+
for (const widest of CASCADE_WIDEST_FIRST)
|
|
223
|
+
if (answers.has(widest))
|
|
224
|
+
return widest;
|
|
225
|
+
return 'changed';
|
|
226
|
+
}
|
|
155
227
|
/**
|
|
156
228
|
* The largest bump `commits` ask for, in `scheme`'s own names.
|
|
157
229
|
*
|
|
@@ -196,12 +268,7 @@ export class VersionPlanService {
|
|
|
196
268
|
* group; a non-empty string joins exactly the other packages sharing that string, regardless of
|
|
197
269
|
* the repo's own default; `false` makes it a solo group of one. */
|
|
198
270
|
resolveGroupKey(pkg) {
|
|
199
|
-
|
|
200
|
-
if (g === false)
|
|
201
|
-
return `solo:${pkg.name}`;
|
|
202
|
-
if (typeof g === 'string' && g)
|
|
203
|
-
return `named:${g}`;
|
|
204
|
-
return 'default';
|
|
271
|
+
return groupKeyOf(pkg);
|
|
205
272
|
}
|
|
206
273
|
/** The human-readable name behind a `groupKey` - what a plan's `group` column shows. */
|
|
207
274
|
groupLabel(key) {
|
|
@@ -246,7 +313,7 @@ export class VersionPlanService {
|
|
|
246
313
|
to = scheme.next(current, bump, { preid });
|
|
247
314
|
}
|
|
248
315
|
const bumping = new Set(changed);
|
|
249
|
-
const cascade = bump ? this.
|
|
316
|
+
const cascade = bump ? this.cascadeFor(members, bump) : 'changed';
|
|
250
317
|
if (cascade === 'group') {
|
|
251
318
|
for (const m of members)
|
|
252
319
|
bumping.add(m);
|
|
@@ -377,15 +444,6 @@ export class VersionPlanService {
|
|
|
377
444
|
* repository layering its own policy plugin after `rman-node` could never take effect - which is
|
|
378
445
|
* the only reason to name two in the first place.
|
|
379
446
|
*/
|
|
380
|
-
function setPlanner(planner) {
|
|
381
|
-
current = planner;
|
|
382
|
-
}
|
|
383
|
-
VersionPlanService.setPlanner = setPlanner;
|
|
384
|
-
/** For tests, which would otherwise leak a planner into every later case in the process. */
|
|
385
|
-
function clearPlanner() {
|
|
386
|
-
current = undefined;
|
|
387
|
-
}
|
|
388
|
-
VersionPlanService.clearPlanner = clearPlanner;
|
|
389
447
|
/**
|
|
390
448
|
* The registered planner. **Throws** when there is none, rather than falling back to some
|
|
391
449
|
* built-in default: `Manifest` and `Workspace` can degrade honestly (a package named after its
|
|
@@ -393,16 +451,18 @@ export class VersionPlanService {
|
|
|
393
451
|
* merely a diminished one - a wrong cascade or a wrong boundary reports a release that is
|
|
394
452
|
* plausible and untrue.
|
|
395
453
|
*/
|
|
396
|
-
function getPlanner() {
|
|
397
|
-
|
|
454
|
+
function getPlanner(app) {
|
|
455
|
+
const planner = app.versionPlanner;
|
|
456
|
+
if (!planner) {
|
|
398
457
|
throw new Error('No version planner is registered, so no version plan can be computed. Name a plugin that ' +
|
|
399
458
|
'contributes one in .rmanrc "plugins" - "rman-node" for a Node repository.');
|
|
400
459
|
}
|
|
401
|
-
return
|
|
460
|
+
return planner;
|
|
402
461
|
}
|
|
403
462
|
VersionPlanService.getPlanner = getPlanner;
|
|
404
|
-
let current;
|
|
405
463
|
})(VersionPlanService || (VersionPlanService = {}));
|
|
464
|
+
/** Widest reach first - what `cascadeFor` walks when a group's members answer differently. */
|
|
465
|
+
const CASCADE_WIDEST_FIRST = ['group', 'dependents', 'changed'];
|
|
406
466
|
/** What one commit says happened, with no reference to any version format - `VersionScheme.bumpFor`
|
|
407
467
|
* turns it into a number's movement. Everything unrecognized is a `'fix'`: something changed, so
|
|
408
468
|
* the smallest release is still warranted. */
|
|
@@ -1,17 +1,41 @@
|
|
|
1
|
-
import type { Package } from '../core/package.js';
|
|
2
|
-
import type { Repository } from '../core/repository.js';
|
|
3
|
-
import
|
|
1
|
+
import type { Package } from '../core/classes/package.js';
|
|
2
|
+
import type { Repository } from '../core/classes/repository.js';
|
|
3
|
+
import { Service } from '../core/classes/service.js';
|
|
4
|
+
import type { RunStepValue } from '../core/interfaces/run-step.js';
|
|
4
5
|
import { VersionPlanService } from './version-plan.service.js';
|
|
5
6
|
/**
|
|
6
7
|
* Applying a version plan: the writes. Every manifest edit, dependency-range refresh, stamp,
|
|
7
8
|
* commit and tag lives here; **what** to write is `VersionPlanService`'s answer.
|
|
8
9
|
*
|
|
9
10
|
* Nothing here knows what a `package.json` is, names an npm script, or runs a command: the version
|
|
10
|
-
* goes through `Manifest`/`
|
|
11
|
+
* goes through `Manifest`/`Plugin`'s manifest members, refreshing a sibling's dependency range goes through
|
|
11
12
|
* the same provider, and the lifecycle hooks around the write go through
|
|
12
13
|
* `RunService.runLifecycleSlot` - this module only supplies the `.rmanrc version.<slot>` fallback,
|
|
13
14
|
* which is its own config. What is left is git, that config, and the version stamps.
|
|
14
15
|
*/
|
|
16
|
+
/**
|
|
17
|
+
* A service class - see `ListService` for the shape and `Service` for the three measured
|
|
18
|
+
* consequences a namespace had.
|
|
19
|
+
*
|
|
20
|
+
* **Only `applyPlan` became a method**, because only it takes a repository. `buildCommitMessage`,
|
|
21
|
+
* `stampDockerfile`, `stampSourceFiles` and `normalizeScriptValue` take a `Package` or nothing and
|
|
22
|
+
* stay functions on the namespace below - the same rule that leaves `ChangeHashService` a namespace
|
|
23
|
+
* entirely.
|
|
24
|
+
*
|
|
25
|
+
* **Declared before the namespace**, which TypeScript requires: the other order is
|
|
26
|
+
* `A namespace declaration cannot be located prior to a class with which it is merged`.
|
|
27
|
+
*/
|
|
28
|
+
export declare class VersionService extends Service {
|
|
29
|
+
/**
|
|
30
|
+
* Writes every `'bump'` entry's new version into its own manifest (and refreshes any other bumped
|
|
31
|
+
* package's dependency range on it), runs that package's own version-lifecycle hooks or its
|
|
32
|
+
* `.rmanrc version.before`/`.exec`/`.after` around the write - see the `hook` closure below -
|
|
33
|
+
* then commits and tags **once per group** - so independently-versioned groups each get their own clean commit/tag rather than one entangled
|
|
34
|
+
* commit spanning unrelated version lines. Pushes only when `options.push` is set - same as a
|
|
35
|
+
* plain `npm version`, this never reaches the network on its own otherwise.
|
|
36
|
+
*/
|
|
37
|
+
applyPlan(plan: VersionPlanService.Entry[], options?: VersionService.ApplyOptions): Promise<VersionService.ApplyResult>;
|
|
38
|
+
}
|
|
15
39
|
export declare namespace VersionService {
|
|
16
40
|
interface ApplyOptions {
|
|
17
41
|
/** Push the resulting commit(s) and tag(s) to the remote once applied. Default false - same
|
|
@@ -61,15 +85,6 @@ export declare namespace VersionService {
|
|
|
61
85
|
/** True for the repository's own release tag, which belongs to no single package. */
|
|
62
86
|
release?: boolean;
|
|
63
87
|
}
|
|
64
|
-
/**
|
|
65
|
-
* Writes every `'bump'` entry's new version into its own manifest (and refreshes any other bumped
|
|
66
|
-
* package's dependency range on it), runs that package's own version-lifecycle hooks or its
|
|
67
|
-
* `.rmanrc version.before`/`.exec`/`.after` around the write - see the `hook` closure below -
|
|
68
|
-
* then commits and tags **once per group** - so independently-versioned groups each get their own clean commit/tag rather than one entangled
|
|
69
|
-
* commit spanning unrelated version lines. Pushes only when `options.push` is set - same as a
|
|
70
|
-
* plain `npm version`, this never reaches the network on its own otherwise.
|
|
71
|
-
*/
|
|
72
|
-
function applyPlan(repository: Repository, plan: VersionPlanService.Entry[], options?: ApplyOptions): Promise<ApplyResult>;
|
|
73
88
|
/** `.rmanrc version.commitMessage` (root-level; `{version}` is replaced when every bumped package
|
|
74
89
|
* in this commit shares one version) - defaults to `"chore(release): v{version}"`, or a plain
|
|
75
90
|
* listing of `name@version` pairs when this particular commit spans different versions (a
|
|
@@ -119,8 +134,13 @@ export declare namespace VersionService {
|
|
|
119
134
|
* pattern missed it) released a tagged commit with a stale constant and said nothing. The error
|
|
120
135
|
* names the file and, when the package's ecosystem declared none, says so.
|
|
121
136
|
*
|
|
122
|
-
* *How* a version is declared is the provider's (`
|
|
137
|
+
* *How* a version is declared is the provider's (`Plugin.stampVersion`); *which* files
|
|
123
138
|
* hold one is the repository's, which is why the list is config and the rewrite is a seam.
|
|
124
139
|
*/
|
|
125
140
|
function stampSourceFiles(pkg: Package, version: string): string[];
|
|
126
141
|
}
|
|
142
|
+
declare module '../core/classes/service.js' {
|
|
143
|
+
interface ServiceMap {
|
|
144
|
+
version: VersionService;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Service } from '../core/classes/service.js';
|
|
4
|
+
import { ConfigInterpolator } from '../core/config/config-interpolator.js';
|
|
5
|
+
import { Manifest } from '../core/interfaces/manifest.js';
|
|
5
6
|
import { GitHelper } from '../utils/git.js';
|
|
6
7
|
import { expandReleaseTag, isCalendarVersion } from '../utils/release-version.js';
|
|
7
8
|
import { stampVersionLabel } from '../utils/version-stamp.js';
|
|
8
9
|
import { ChangeHashService } from './change-hash.service.js';
|
|
9
|
-
import { ChangelogService } from './changelog.service.js';
|
|
10
10
|
import { RunService } from './run.service.js';
|
|
11
11
|
import { VersionPlanService } from './version-plan.service.js';
|
|
12
12
|
/**
|
|
@@ -14,13 +14,24 @@ import { VersionPlanService } from './version-plan.service.js';
|
|
|
14
14
|
* commit and tag lives here; **what** to write is `VersionPlanService`'s answer.
|
|
15
15
|
*
|
|
16
16
|
* Nothing here knows what a `package.json` is, names an npm script, or runs a command: the version
|
|
17
|
-
* goes through `Manifest`/`
|
|
17
|
+
* goes through `Manifest`/`Plugin`'s manifest members, refreshing a sibling's dependency range goes through
|
|
18
18
|
* the same provider, and the lifecycle hooks around the write go through
|
|
19
19
|
* `RunService.runLifecycleSlot` - this module only supplies the `.rmanrc version.<slot>` fallback,
|
|
20
20
|
* which is its own config. What is left is git, that config, and the version stamps.
|
|
21
21
|
*/
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
/**
|
|
23
|
+
* A service class - see `ListService` for the shape and `Service` for the three measured
|
|
24
|
+
* consequences a namespace had.
|
|
25
|
+
*
|
|
26
|
+
* **Only `applyPlan` became a method**, because only it takes a repository. `buildCommitMessage`,
|
|
27
|
+
* `stampDockerfile`, `stampSourceFiles` and `normalizeScriptValue` take a `Package` or nothing and
|
|
28
|
+
* stay functions on the namespace below - the same rule that leaves `ChangeHashService` a namespace
|
|
29
|
+
* entirely.
|
|
30
|
+
*
|
|
31
|
+
* **Declared before the namespace**, which TypeScript requires: the other order is
|
|
32
|
+
* `A namespace declaration cannot be located prior to a class with which it is merged`.
|
|
33
|
+
*/
|
|
34
|
+
export class VersionService extends Service {
|
|
24
35
|
/**
|
|
25
36
|
* Writes every `'bump'` entry's new version into its own manifest (and refreshes any other bumped
|
|
26
37
|
* package's dependency range on it), runs that package's own version-lifecycle hooks or its
|
|
@@ -29,7 +40,8 @@ export var VersionService;
|
|
|
29
40
|
* commit spanning unrelated version lines. Pushes only when `options.push` is set - same as a
|
|
30
41
|
* plain `npm version`, this never reaches the network on its own otherwise.
|
|
31
42
|
*/
|
|
32
|
-
async
|
|
43
|
+
async applyPlan(plan, options = {}) {
|
|
44
|
+
const repository = this.repository;
|
|
33
45
|
const git = new GitHelper({ cwd: repository.dirname });
|
|
34
46
|
// The root's own entry is only ever a real package to write/commit like any other when this
|
|
35
47
|
// *isn't* a monorepo (see `getPlan`) - in a monorepo it's the separate, purely informational
|
|
@@ -53,6 +65,9 @@ export var VersionService;
|
|
|
53
65
|
*/
|
|
54
66
|
for (const entry of bumped)
|
|
55
67
|
assertStampable(entry.package, entry.to);
|
|
68
|
+
/** One for the whole run: it carries no per-package state, and `defer(...)`'s bookkeeping is
|
|
69
|
+
* per call. */
|
|
70
|
+
const interpolator = new ConfigInterpolator();
|
|
56
71
|
for (const entry of bumped) {
|
|
57
72
|
const pkg = entry.package;
|
|
58
73
|
/** The scope these hooks are evaluated against - the only place `${{ pkg.targetVersion }}`
|
|
@@ -68,20 +83,23 @@ export var VersionService;
|
|
|
68
83
|
const hook = (slot) => RunService.runLifecycleSlot(pkg, VERSION_LIFECYCLE, slot, RunService.normalizeScriptValue(
|
|
69
84
|
/** `at`: the path is what tells a step function from a value one, and this is a fragment -
|
|
70
85
|
* without it a function here was called while the hook was being prepared. */
|
|
71
|
-
|
|
86
|
+
interpolator.interpolate({ config: pkg.config?.version?.[slot], scope, at: ['version', slot] }), `version.${slot}`));
|
|
72
87
|
await hook('before');
|
|
73
88
|
/** Through the manifest, not through a `package.json` field: where a version is written is
|
|
74
|
-
* the provider's business (see `
|
|
89
|
+
* the provider's business (see `Plugin`'s manifest members), and this is the one place rman changes
|
|
75
90
|
* it. */
|
|
76
91
|
pkg.manifest.version = entry.to;
|
|
77
92
|
/** Which fields hold a sibling reference, and what a reference even looks like, is the
|
|
78
93
|
* ecosystem's - npm's four fields and its `"workspace:"` protocol used to be spelled out
|
|
79
|
-
* here. See `
|
|
94
|
+
* here. See `Plugin.updateDependencyVersions`. */
|
|
80
95
|
Manifest.updateDependencyVersions(pkg, bumpedVersions);
|
|
81
96
|
await hook('exec');
|
|
82
97
|
pkg.writeManifest();
|
|
83
98
|
// Before the `after` hook, so a script reacting to the bump sees the whole new state.
|
|
84
|
-
const stamped = [
|
|
99
|
+
const stamped = [
|
|
100
|
+
VersionService.stampDockerfile(pkg, entry.to),
|
|
101
|
+
...VersionService.stampSourceFiles(pkg, entry.to),
|
|
102
|
+
].filter((f) => !!f);
|
|
85
103
|
if (stamped.length) {
|
|
86
104
|
stampedByPackage.set(pkg.name, stamped.map(f => path.relative(repository.dirname, f)));
|
|
87
105
|
}
|
|
@@ -105,9 +123,9 @@ export var VersionService;
|
|
|
105
123
|
for (const entry of bumped) {
|
|
106
124
|
const fromTag = ChangeHashService.expandTag(entry.package, entry.from);
|
|
107
125
|
const from = (await git.tagExists(fromTag)) ? fromTag : undefined;
|
|
108
|
-
const changelogEntries = await
|
|
126
|
+
const changelogEntries = await this.app.getService('changelog').generateToFile({
|
|
109
127
|
scope: entry.package.name,
|
|
110
|
-
|
|
128
|
+
fromRoot: true,
|
|
111
129
|
from,
|
|
112
130
|
// The tag for this release doesn't exist yet (it's created below), so changelog's own
|
|
113
131
|
// tag-derived version would resolve to the *previous* release and label the entry with it.
|
|
@@ -152,7 +170,7 @@ export var VersionService;
|
|
|
152
170
|
files.push(changelogFile);
|
|
153
171
|
files.push(...(stampedByPackage.get(e.package.name) ?? []));
|
|
154
172
|
}
|
|
155
|
-
const message = buildCommitMessage(repository, groupEntries, options.message);
|
|
173
|
+
const message = VersionService.buildCommitMessage(repository, groupEntries, options.message);
|
|
156
174
|
const sha = await git.commit(files, message);
|
|
157
175
|
commits.push({ sha, message, packages: groupEntries.map(e => e.package.name) });
|
|
158
176
|
const tags = new Set(groupEntries.map(e => ChangeHashService.expandTag(e.package, e.to)));
|
|
@@ -182,7 +200,8 @@ export var VersionService;
|
|
|
182
200
|
await git.push();
|
|
183
201
|
return { entries: plan, updated: bumped, commits, tags: tagged, pushed };
|
|
184
202
|
}
|
|
185
|
-
|
|
203
|
+
}
|
|
204
|
+
(function (VersionService) {
|
|
186
205
|
/** `.rmanrc version.commitMessage` (root-level; `{version}` is replaced when every bumped package
|
|
187
206
|
* in this commit shares one version) - defaults to `"chore(release): v{version}"`, or a plain
|
|
188
207
|
* listing of `name@version` pairs when this particular commit spans different versions (a
|
|
@@ -260,7 +279,7 @@ export var VersionService;
|
|
|
260
279
|
* pattern missed it) released a tagged commit with a stale constant and said nothing. The error
|
|
261
280
|
* names the file and, when the package's ecosystem declared none, says so.
|
|
262
281
|
*
|
|
263
|
-
* *How* a version is declared is the provider's (`
|
|
282
|
+
* *How* a version is declared is the provider's (`Plugin.stampVersion`); *which* files
|
|
264
283
|
* hold one is the repository's, which is why the list is config and the rewrite is a seam.
|
|
265
284
|
*/
|
|
266
285
|
function stampSourceFiles(pkg, version) {
|
package/services.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export { DockerPublishService } from './builtins/publish-targets/docker/docker-publish.service.js';
|
|
1
2
|
export { ChangelogService } from './services/changelog.service.js';
|
|
2
|
-
export { DockerPublishService } from './services/docker-publish.service.js';
|
|
3
3
|
export { ExecService } from './services/exec.service.js';
|
|
4
4
|
export { GithubReleaseService } from './services/github-release.service.js';
|
|
5
5
|
export { ImportService } from './services/import.service.js';
|
package/services.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
export { DockerPublishService } from './builtins/publish-targets/docker/docker-publish.service.js';
|
|
1
2
|
export { ChangelogService } from './services/changelog.service.js';
|
|
2
|
-
export { DockerPublishService } from './services/docker-publish.service.js';
|
|
3
3
|
export { ExecService } from './services/exec.service.js';
|
|
4
4
|
export { GithubReleaseService } from './services/github-release.service.js';
|
|
5
5
|
export { ImportService } from './services/import.service.js';
|
package/utils/bin-path.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RmanApplication } from '../core/application.js';
|
|
1
2
|
/**
|
|
2
3
|
* Where a repository's **locally installed executables** live, so a command an author wrote
|
|
3
4
|
* (`eslint .`, `cargo build`) is found the way it would be in their own shell.
|
|
@@ -6,7 +7,7 @@
|
|
|
6
7
|
*
|
|
7
8
|
* - **Which directories** is the *ecosystem's* answer, and the core has none - `node_modules/.bin`
|
|
8
9
|
* walked up the directory chain is npm's layout and nothing else's (a Python venv says
|
|
9
|
-
* `.venv/bin`, a Ruby project `bin`). `rman-node` contributes it; see `
|
|
10
|
+
* `.venv/bin`, a Ruby project `bin`). `rman-node` contributes it; see `Plugin.getBinPaths`.
|
|
10
11
|
* - **How a PATH is spelled** is the *operating system's*, and that stays here: the variable is
|
|
11
12
|
* `PATH` everywhere except Windows, where its case is whatever the environment happens to use.
|
|
12
13
|
* That has nothing to do with any ecosystem, and every provider would otherwise get it wrong
|
|
@@ -22,20 +23,18 @@ export declare namespace BinPath {
|
|
|
22
23
|
* Return them most-specific-first; the core concatenates providers without reordering. */
|
|
23
24
|
type Provider = (cwd: string) => string[];
|
|
24
25
|
interface EnvOptions {
|
|
26
|
+
/** The application whose technologies contribute directories. Omitted where a caller genuinely
|
|
27
|
+
* has none - `exec` outside a repository - which leaves the inherited PATH untouched. */
|
|
28
|
+
readonly app?: RmanApplication;
|
|
25
29
|
/** The directory the command will run in. Default `process.cwd()`. */
|
|
26
30
|
readonly cwd?: string;
|
|
27
31
|
/** The environment to derive from, like `process.env`. Default `process.env`. */
|
|
28
32
|
readonly env?: ProcessEnv;
|
|
29
33
|
}
|
|
30
|
-
/** Registers a provider. Called by `loadPlugins` for each plugin's `binPaths`, in `plugins`
|
|
31
|
-
* declaration order - so what is on PATH is a function of the repository's own config. */
|
|
32
|
-
function addProvider(provider: Provider): void;
|
|
33
|
-
/** For tests, which would otherwise leak a provider into every later case in the process. */
|
|
34
|
-
function clearProviders(): void;
|
|
35
34
|
/** Every provider's directories for `cwd`, concatenated in declaration order. Empty for a
|
|
36
35
|
* repository that names no plugin - the inherited PATH then stands on its own, which is the
|
|
37
36
|
* honest answer rather than a guess at some ecosystem's layout. */
|
|
38
|
-
function resolve(cwd: string): string[];
|
|
37
|
+
function resolve(app: RmanApplication, cwd: string): string[];
|
|
39
38
|
/**
|
|
40
39
|
* `env` with the contributed directories prepended to its PATH - what `exec` and `runBin` hand to
|
|
41
40
|
* a child process.
|
package/utils/bin-path.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import process from 'node:process';
|
|
3
|
+
import { RmanApplication } from '../core/application.js';
|
|
3
4
|
/**
|
|
4
5
|
* Where a repository's **locally installed executables** live, so a command an author wrote
|
|
5
6
|
* (`eslint .`, `cargo build`) is found the way it would be in their own shell.
|
|
@@ -8,7 +9,7 @@ import process from 'node:process';
|
|
|
8
9
|
*
|
|
9
10
|
* - **Which directories** is the *ecosystem's* answer, and the core has none - `node_modules/.bin`
|
|
10
11
|
* walked up the directory chain is npm's layout and nothing else's (a Python venv says
|
|
11
|
-
* `.venv/bin`, a Ruby project `bin`). `rman-node` contributes it; see `
|
|
12
|
+
* `.venv/bin`, a Ruby project `bin`). `rman-node` contributes it; see `Plugin.getBinPaths`.
|
|
12
13
|
* - **How a PATH is spelled** is the *operating system's*, and that stays here: the variable is
|
|
13
14
|
* `PATH` everywhere except Windows, where its case is whatever the environment happens to use.
|
|
14
15
|
* That has nothing to do with any ecosystem, and every provider would otherwise get it wrong
|
|
@@ -20,25 +21,12 @@ import process from 'node:process';
|
|
|
20
21
|
*/
|
|
21
22
|
export var BinPath;
|
|
22
23
|
(function (BinPath) {
|
|
23
|
-
/** Registers a provider. Called by `loadPlugins` for each plugin's `binPaths`, in `plugins`
|
|
24
|
-
* declaration order - so what is on PATH is a function of the repository's own config. */
|
|
25
|
-
function addProvider(provider) {
|
|
26
|
-
if (providers.includes(provider))
|
|
27
|
-
return;
|
|
28
|
-
providers.push(provider);
|
|
29
|
-
}
|
|
30
|
-
BinPath.addProvider = addProvider;
|
|
31
|
-
/** For tests, which would otherwise leak a provider into every later case in the process. */
|
|
32
|
-
function clearProviders() {
|
|
33
|
-
providers.length = 0;
|
|
34
|
-
}
|
|
35
|
-
BinPath.clearProviders = clearProviders;
|
|
36
24
|
/** Every provider's directories for `cwd`, concatenated in declaration order. Empty for a
|
|
37
25
|
* repository that names no plugin - the inherited PATH then stands on its own, which is the
|
|
38
26
|
* honest answer rather than a guess at some ecosystem's layout. */
|
|
39
|
-
function resolve(cwd) {
|
|
27
|
+
function resolve(app, cwd) {
|
|
40
28
|
const dir = path.resolve(cwd);
|
|
41
|
-
return
|
|
29
|
+
return [...app.platforms].flatMap(stack => stack.getBinPaths?.(dir) ?? []);
|
|
42
30
|
}
|
|
43
31
|
BinPath.resolve = resolve;
|
|
44
32
|
/**
|
|
@@ -52,7 +40,9 @@ export var BinPath;
|
|
|
52
40
|
const cwd = options.cwd || process.cwd();
|
|
53
41
|
const result = { ...(options.env || process.env) };
|
|
54
42
|
const key = pathKey({ env: result });
|
|
55
|
-
|
|
43
|
+
/** No application means no technologies, so nothing is prepended and the inherited PATH stands
|
|
44
|
+
* on its own - the same answer a repository naming no plugin has always got. */
|
|
45
|
+
const entries = options.app ? resolve(options.app, cwd) : [];
|
|
56
46
|
if (!entries.length)
|
|
57
47
|
return result;
|
|
58
48
|
const inherited = result[key];
|
|
@@ -78,5 +68,4 @@ export var BinPath;
|
|
|
78
68
|
.find(key => key.toUpperCase() === 'PATH') || 'Path');
|
|
79
69
|
}
|
|
80
70
|
BinPath.pathKey = pathKey;
|
|
81
|
-
const providers = [];
|
|
82
71
|
})(BinPath || (BinPath = {}));
|
package/utils/branch-guard.d.ts
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
import type { Argv } from 'yargs';
|
|
2
|
-
import type { Repository } from '../core/repository.js';
|
|
2
|
+
import type { Repository } from '../core/classes/repository.js';
|
|
3
3
|
/** Same idea as GitHub Actions' own `branches`/`branches-ignore` workflow filters - restricts a
|
|
4
4
|
* command to running only from certain branches (or refuses certain ones), instead of any. */
|
|
5
5
|
export interface BranchGuardOptions {
|
|
6
6
|
allowBranch?: string | string[];
|
|
7
7
|
ignoreBranch?: string | string[];
|
|
8
8
|
}
|
|
9
|
+
/**
|
|
10
|
+
* `--allow-branch`/`--ignore-branch` as a declaration, to spread into a command's `config` block.
|
|
11
|
+
* See `packageFilterOptions` for why this is `satisfies` rather than an annotation.
|
|
12
|
+
*
|
|
13
|
+
* **The key is the camelCase one and `cliName` carries the flag's spelling.** `allowBranch` is what
|
|
14
|
+
* a `.rmanrc` writes and what `assertAllowedBranch` reads off the config; `--allow-branch` is what
|
|
15
|
+
* the shell sees. The `Argv` version relied on yargs converting one into the other silently, which
|
|
16
|
+
* is why `applyBranchGuardOptions` declares `'allow-branch'` and `readBranchGuardOptions` reads
|
|
17
|
+
* `args.allowBranch`.
|
|
18
|
+
*
|
|
19
|
+
* **`target: 'cli'`, even though `allowBranch` *is* a config key.** It is a repo-wide core key read
|
|
20
|
+
* off the root, not any command's - so it belongs on `RmanConfig` directly, and a command that
|
|
21
|
+
* reads it names it in `configKeys`. Declaring it `'both'` here would contribute `version.allowBranch`,
|
|
22
|
+
* which nothing reads.
|
|
23
|
+
*/
|
|
24
|
+
export declare const branchGuardOptions: {
|
|
25
|
+
allowBranch: {
|
|
26
|
+
target: "cli";
|
|
27
|
+
cliName: string;
|
|
28
|
+
describe: string;
|
|
29
|
+
type: "string";
|
|
30
|
+
};
|
|
31
|
+
ignoreBranch: {
|
|
32
|
+
target: "cli";
|
|
33
|
+
cliName: string;
|
|
34
|
+
describe: string;
|
|
35
|
+
type: "string";
|
|
36
|
+
};
|
|
37
|
+
};
|
|
9
38
|
/** `--allow-branch`/`--ignore-branch`, the same shape and describe text in every command that
|
|
10
39
|
* supports them - mirrors `package-filter.ts`'s own `applyPackageFilterOptions`. */
|
|
11
40
|
export declare function applyBranchGuardOptions<T>(cmd: Argv<T>): Argv<T>;
|