rman 2.13.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/README.md +52 -19
  2. package/builtins/platforms/node/node-dependency-updater.d.ts +116 -0
  3. package/builtins/platforms/node/node-dependency-updater.js +452 -0
  4. package/builtins/platforms/node/node.platform.d.ts +2 -0
  5. package/builtins/platforms/node/node.platform.js +2 -0
  6. package/builtins/platforms/node/services/version-plan.service.d.ts +1 -1
  7. package/builtins/platforms/node/services/version-plan.service.js +1 -1
  8. package/builtins/publish-targets/npm/npm-view.d.ts +31 -0
  9. package/builtins/publish-targets/npm/npm-view.js +47 -0
  10. package/commands/changelog.command.js +4 -3
  11. package/commands/deps.command.d.ts +175 -0
  12. package/commands/deps.command.js +252 -0
  13. package/commands/info.command.js +11 -5
  14. package/commands/version.command.js +2 -0
  15. package/commands.d.ts +2 -0
  16. package/commands.js +1 -0
  17. package/constants.js +1 -1
  18. package/core/interfaces/dependency-updater.d.ts +114 -0
  19. package/core/interfaces/dependency-updater.js +61 -0
  20. package/core/interfaces/manifest.js +1 -1
  21. package/core/interfaces/plugin.d.ts +5 -1
  22. package/core/interfaces/plugin.js +1 -1
  23. package/index.d.ts +2 -0
  24. package/index.js +2 -0
  25. package/package.json +1 -1
  26. package/services/change-hash.service.d.ts +2 -2
  27. package/services/change-hash.service.js +2 -2
  28. package/services/system-info.d.ts +3 -0
  29. package/services/system-info.js +1 -0
  30. package/services/version-plan.service.d.ts +2 -1
  31. package/services/version-plan.service.js +7 -5
  32. package/services/version.service.js +4 -4
  33. package/utils/package-filter.d.ts +1 -1
  34. 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`, and a
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-scopeignoredepsdependents)
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 repository instead.
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` packages, and only in a repository that
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, grouped into ✨ Features / 🐛 Bug Fixes
243
- / 🔧 Other Changes.
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: unmarked keys configure the package of the
398
- directory declaring them, and a `"[selector]"` block configures the packages it names. So the
399
- repository root's own keys are the *root package's* - which is where repo-wide settings are read
400
- from anyway - and they reach the other packages only through a selector.
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 function - call them directly
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, VersionService } from 'rman';
502
+ import { Repository, VersionPlanService } from 'rman';
470
503
 
471
504
  const repository = await Repository.create();
472
- const plan = await VersionService.getPlan(repository);
473
- await VersionService.applyPlan(repository, plan, { changelog: true, push: true });
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`,
@@ -0,0 +1,116 @@
1
+ import type { Package } from '../../../core/classes/package.js';
2
+ import { DependencyUpdater } from '../../../core/interfaces/dependency-updater.js';
3
+ import { type NpmRelease, type NpmReleases } from '../../publish-targets/npm/npm-view.js';
4
+ /**
5
+ * npm's answer to `rman deps`: which of a `package.json`'s dependencies have a newer version on the
6
+ * registry, and which of those can be taken without breaking a rule another dependency states.
7
+ *
8
+ * Only a caret or tilde range on a plain version moves (`^1.2.3`, `~1.2.3`), keeping its prefix. An
9
+ * exact version, a compound range (`>=1 <2`, `a || b`), a dist-tag, a URL, an alias and an in-repo
10
+ * package are left as they are - but every one of them still counts as a rule the others must keep.
11
+ */
12
+ export declare class NodeDependencyUpdater implements DependencyUpdater {
13
+ /** `.rmanrc "deps.types"`'s short spellings, as `npm-check-updates` named them. The field names
14
+ * themselves are accepted too. */
15
+ protected readonly kindAliases: Readonly<Record<string, string>>;
16
+ /** The ranges that move: `^` or `~`, then a plain version. The prefix is kept on the rewrite. */
17
+ protected readonly movablePattern: RegExp;
18
+ /** The plan each `'update'` entry was made from, for `applyPlan`. */
19
+ protected readonly planned: WeakMap<DependencyUpdater.Entry, NodeDependencyUpdater.Decision>;
20
+ getPlan(ctx: DependencyUpdater.Context, packages: readonly Package[]): Promise<DependencyUpdater.Entry[]>;
21
+ applyPlan(ctx: DependencyUpdater.Context, plan: readonly DependencyUpdater.Entry[]): Promise<DependencyUpdater.Applied>;
22
+ /**
23
+ * `npm install --dry-run` at the repository root: npm's own resolver, which refuses a peer
24
+ * conflict anywhere in the tree with `ERESOLVE`, and writes nothing.
25
+ *
26
+ * Another package manager is not asked - its dry run is not the same question - and a note says so.
27
+ */
28
+ verify(ctx: DependencyUpdater.Context): Promise<string | undefined>;
29
+ /** One decision per dependency name `pkg` declares, whether or not it may move - one that may not
30
+ * still states rules the others have to keep. */
31
+ protected collect(pkg: Package, settings: DependencyUpdater.Settings, options: DependencyUpdater.Options, inRepo: ReadonlySet<string>): NodeDependencyUpdater.Decision[];
32
+ /** Every name's releases, from the lowest version any declaration of it can mean - once per name,
33
+ * however many packages declare it, `concurrency` at a time. */
34
+ protected fetchAll(ctx: DependencyUpdater.Context, decisions: readonly NodeDependencyUpdater.Decision[], withTime: boolean): Promise<Map<string, NpmReleases | undefined>>;
35
+ /** The registry's answer about one name - the seam a spec replaces. */
36
+ protected fetchReleases(name: string, range: string, cwd: string, withTime: boolean): Promise<NpmReleases | undefined>;
37
+ /** Fills in what `d` may move to, from its own settings and the rules that do not depend on what
38
+ * else moves (steps 1-3). */
39
+ protected prepare(d: NodeDependencyUpdater.Decision, info: NpmReleases | undefined): void;
40
+ /** Whether the registry offers `release` as a move at all: newer than what is declared, not
41
+ * deprecated, not above the `latest` tag, and not a prerelease unless the range is on one. */
42
+ protected offerable(d: NodeDependencyUpdater.Decision, release: NpmRelease): boolean;
43
+ /** Step 1: why the package's own settings leave `release` out - `deps.target` or `deps.minAge` -
44
+ * or `undefined` when they do not. */
45
+ protected settingRefusal(d: NodeDependencyUpdater.Decision, release: NpmRelease, time?: Record<string, string>): string | undefined;
46
+ /**
47
+ * How big a move from `from` to `to` is, **as npm's caret reads it**: anything a `^from` range
48
+ * would not accept is a `major`, so `0.1.0 -> 0.2.0` is one.
49
+ */
50
+ protected sizeOf(from: string, to: string): string;
51
+ /** Steps 2 and 3: the package's own other declarations of this name, and the runtime it supports.
52
+ * The rule `release` breaks, or `undefined`. */
53
+ protected staticRefusal(d: NodeDependencyUpdater.Decision, release: NpmRelease): string | undefined;
54
+ /**
55
+ * The Node versions a newer release has to keep covering: those the package supports **and** the
56
+ * lowest release its declaration allows now (`current`) already runs on.
57
+ */
58
+ protected nodeCoverage(pkg: Package, current: NpmRelease | undefined): string | undefined;
59
+ /** The Node versions `pkg` supports - its own `engines.node`, else the repository root's. */
60
+ protected supportedNode(pkg: Package): string | undefined;
61
+ /**
62
+ * Steps 4 and 5: while any peer range is broken by a version that moved, one side steps down.
63
+ *
64
+ * The side that steps down is the one the range is *about* - for "`parser` needs `typescript`
65
+ * below 6", `typescript` - to the newest candidate the range allows; only when none is left does
66
+ * the side stating the range step down instead.
67
+ */
68
+ protected resolve(decisions: readonly NodeDependencyUpdater.Decision[], ctx: DependencyUpdater.Context): void;
69
+ /** One broken rule, mended by one step down. Whether anything moved. */
70
+ protected settle(about: NodeDependencyUpdater.Decision, stating: NodeDependencyUpdater.Decision | undefined, range: string, rule: string): boolean;
71
+ /** Moves `d` down to `index` (`-1` keeps what is declared), remembering why it left its newest. */
72
+ protected stepTo(d: NodeDependencyUpdater.Decision, index: number, rule: string): void;
73
+ /** The version `d` resolves to: the one it moves to, or else the newest release its declarations
74
+ * already allow, which is what an install picks. */
75
+ protected effective(d: NodeDependencyUpdater.Decision): string | undefined;
76
+ /** What `d` declares in `field` once it has moved. */
77
+ protected rangeFor(d: NodeDependencyUpdater.Decision, field: string): string;
78
+ /** The in-repo packages `pkg` declares a dependency on. */
79
+ protected siblingsOf(pkg: Package, repoPackages: ReadonlyMap<string, Package>): Package[];
80
+ protected toEntry(d: NodeDependencyUpdater.Decision): DependencyUpdater.Entry;
81
+ protected manifestFile(pkg: Package): string;
82
+ /** `fn` over `items`, at most `limit` at a time. */
83
+ protected mapConcurrent<T>(items: readonly T[], limit: number, fn: (item: T) => Promise<void>): Promise<void>;
84
+ }
85
+ export declare namespace NodeDependencyUpdater {
86
+ /** One dependency name of one package, and where planning has got to with it. */
87
+ interface Decision {
88
+ pkg: Package;
89
+ name: string;
90
+ settings: DependencyUpdater.Settings;
91
+ /** Every field declaring the name, and its range there. */
92
+ fields: Map<string, string>;
93
+ /** The fields whose range is rewritten. */
94
+ movable: string[];
95
+ /** Whether this name is planned at all - rather than only stating rules for the others. */
96
+ wanted: boolean;
97
+ /** What is declared now, as a version: the highest floor among the movable ranges. */
98
+ floor?: string;
99
+ /** The newest version the registry offers at all, before the package's own settings. */
100
+ available?: string;
101
+ /** Why the settings leave `available` out, when they do. */
102
+ skipReason?: string;
103
+ /** Newer versions the package's own settings allow, newest first. */
104
+ allowed: string[];
105
+ /** `allowed`, less the ones another of the package's own rules refuses. */
106
+ candidates: string[];
107
+ /** Into `candidates`; `-1` keeps what is declared. */
108
+ index: number;
109
+ releases?: Map<string, NpmRelease>;
110
+ latestTag?: string;
111
+ /** The Node versions a newer release has to keep covering - see `nodeCoverage`. */
112
+ baselineNode?: string;
113
+ reason?: string;
114
+ error?: string;
115
+ }
116
+ }