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.
Files changed (187) hide show
  1. package/README.md +65 -31
  2. package/builtins/platforms/node/augmentation/rmanrc.augmentation.d.ts +83 -0
  3. package/builtins/platforms/node/augmentation/system-info.augmentation.d.ts +26 -0
  4. package/builtins/platforms/node/augmentation/system-info.augmentation.js +79 -0
  5. package/builtins/platforms/node/commands/ci.command.d.ts +133 -0
  6. package/builtins/platforms/node/commands/ci.command.js +60 -0
  7. package/builtins/platforms/node/commands/clean.command.d.ts +185 -0
  8. package/builtins/platforms/node/commands/clean.command.js +74 -0
  9. package/builtins/platforms/node/index.d.ts +8 -0
  10. package/builtins/platforms/node/index.js +8 -0
  11. package/builtins/platforms/node/node-config.interface.d.ts +76 -0
  12. package/builtins/platforms/node/node-config.interface.js +7 -0
  13. package/builtins/platforms/node/node-manifest.provider.d.ts +68 -0
  14. package/builtins/platforms/node/node-manifest.provider.js +125 -0
  15. package/builtins/platforms/node/node.platform.d.ts +53 -0
  16. package/builtins/platforms/node/node.platform.js +134 -0
  17. package/builtins/platforms/node/services/ci.service.d.ts +47 -0
  18. package/builtins/platforms/node/services/ci.service.js +213 -0
  19. package/builtins/platforms/node/services/clean.service.d.ts +53 -0
  20. package/builtins/platforms/node/services/clean.service.js +237 -0
  21. package/builtins/platforms/node/services/publish.service.d.ts +114 -0
  22. package/builtins/platforms/node/services/publish.service.js +371 -0
  23. package/builtins/platforms/node/services/version-plan.service.d.ts +44 -0
  24. package/builtins/platforms/node/services/version-plan.service.js +58 -0
  25. package/builtins/platforms/node/utils/workspace-range.d.ts +26 -0
  26. package/builtins/platforms/node/utils/workspace-range.js +28 -0
  27. package/builtins/presets/index.d.ts +15 -0
  28. package/builtins/presets/index.js +57 -0
  29. package/builtins/presets/node.d.ts +16 -0
  30. package/builtins/presets/node.js +57 -0
  31. package/{services → builtins/publish-targets/docker}/docker-publish.service.d.ts +52 -31
  32. package/{services → builtins/publish-targets/docker}/docker-publish.service.js +49 -26
  33. package/builtins/publish-targets/docker/docker.target.d.ts +54 -0
  34. package/builtins/publish-targets/docker/docker.target.js +40 -0
  35. package/builtins/publish-targets/docker/index.d.ts +2 -0
  36. package/builtins/publish-targets/docker/index.js +2 -0
  37. package/builtins/publish-targets/npm/index.d.ts +2 -0
  38. package/builtins/publish-targets/npm/index.js +2 -0
  39. package/builtins/publish-targets/npm/npm-publish-target.d.ts +73 -0
  40. package/builtins/publish-targets/npm/npm-publish-target.js +95 -0
  41. package/builtins/publish-targets/npm/npm-view.d.ts +48 -0
  42. package/builtins/publish-targets/npm/npm-view.js +71 -0
  43. package/cli.d.ts +8 -0
  44. package/cli.js +228 -93
  45. package/commands/build.command.d.ts +177 -3
  46. package/commands/build.command.js +20 -10
  47. package/commands/changelog.command.d.ts +296 -3
  48. package/commands/changelog.command.js +127 -43
  49. package/commands/config.command.d.ts +44 -3
  50. package/commands/config.command.js +53 -24
  51. package/commands/diff.command.d.ts +37 -3
  52. package/commands/diff.command.js +25 -16
  53. package/commands/exec.command.d.ts +193 -3
  54. package/commands/exec.command.js +60 -58
  55. package/commands/github-release.command.d.ts +154 -3
  56. package/commands/github-release.command.js +67 -37
  57. package/commands/import.command.d.ts +36 -3
  58. package/commands/import.command.js +28 -20
  59. package/commands/info.command.d.ts +35 -7
  60. package/commands/info.command.js +36 -30
  61. package/commands/lint.command.d.ts +176 -0
  62. package/commands/lint.command.js +34 -0
  63. package/commands/list.command.d.ts +163 -3
  64. package/commands/list.command.js +109 -71
  65. package/commands/publish.command.d.ts +231 -0
  66. package/commands/publish.command.js +304 -0
  67. package/commands/run.command.d.ts +186 -6
  68. package/commands/run.command.js +26 -72
  69. package/commands/test.command.d.ts +173 -3
  70. package/commands/test.command.js +16 -10
  71. package/commands/version.command.d.ts +330 -3
  72. package/commands/version.command.js +292 -78
  73. package/commands.d.ts +32 -0
  74. package/commands.js +28 -0
  75. package/constants.js +1 -1
  76. package/core/application.d.ts +116 -0
  77. package/core/application.js +160 -0
  78. package/core/classes/package.d.ts +219 -0
  79. package/core/classes/package.js +214 -0
  80. package/core/classes/registry.d.ts +30 -0
  81. package/core/classes/registry.js +47 -0
  82. package/core/{repository.d.ts → classes/repository.d.ts} +69 -20
  83. package/core/{repository.js → classes/repository.js} +195 -75
  84. package/core/classes/service.d.ts +49 -0
  85. package/core/classes/service.js +40 -0
  86. package/core/{version-scheme.d.ts → classes/version-scheme.d.ts} +23 -1
  87. package/core/{version-scheme.js → classes/version-scheme.js} +29 -1
  88. package/core/classes/workspace.d.ts +275 -0
  89. package/core/classes/workspace.js +537 -0
  90. package/core/command-builder.d.ts +14 -0
  91. package/core/command-builder.js +94 -0
  92. package/core/config/config-file-scope.d.ts +107 -0
  93. package/core/config/config-file-scope.js +226 -0
  94. package/core/config/config-interpolator.d.ts +164 -0
  95. package/core/config/config-interpolator.js +577 -0
  96. package/core/config/config-paths.d.ts +65 -0
  97. package/core/config/config-paths.js +78 -0
  98. package/core/config/config-reader.d.ts +192 -0
  99. package/core/config/config-reader.js +727 -0
  100. package/core/{merge-config.d.ts → config/merge-config.d.ts} +33 -34
  101. package/core/config/merge-config.js +260 -0
  102. package/core/{resolve-target.d.ts → config/resolve-config-target.d.ts} +1 -1
  103. package/core/{resolve-target.js → config/resolve-config-target.js} +1 -1
  104. package/core/{custom-command.d.ts → interfaces/custom-command.d.ts} +46 -10
  105. package/core/{custom-command.js → interfaces/custom-command.js} +44 -17
  106. package/core/{manifest.d.ts → interfaces/manifest.d.ts} +49 -27
  107. package/core/interfaces/manifest.js +132 -0
  108. package/core/interfaces/plugin.d.ts +174 -0
  109. package/core/interfaces/plugin.js +124 -0
  110. package/core/interfaces/publish-target.d.ts +136 -0
  111. package/core/interfaces/publish-target.js +43 -0
  112. package/core/{run-step.d.ts → interfaces/run-step.d.ts} +4 -4
  113. package/core/interfaces/run-step.js +1 -0
  114. package/core/plugin-loader.d.ts +25 -0
  115. package/core/plugin-loader.js +53 -0
  116. package/index.d.ts +122 -24
  117. package/index.js +66 -16
  118. package/interfaces/config-scope.interface.d.ts +223 -0
  119. package/interfaces/config-scope.interface.js +1 -0
  120. package/interfaces/rman-config.interface.d.ts +821 -203
  121. package/interfaces/rman-config.interface.js +78 -1
  122. package/package.json +3 -1
  123. package/services/change-hash.service.d.ts +42 -8
  124. package/services/change-hash.service.js +92 -13
  125. package/services/changelog.service.d.ts +91 -52
  126. package/services/changelog.service.js +460 -74
  127. package/services/config-service.d.ts +8 -0
  128. package/services/config-service.js +3 -0
  129. package/services/exec.service.d.ts +23 -12
  130. package/services/exec.service.js +14 -9
  131. package/services/github-release.service.d.ts +45 -34
  132. package/services/github-release.service.js +15 -12
  133. package/services/import.service.d.ts +25 -14
  134. package/services/import.service.js +9 -5
  135. package/services/list.service.d.ts +67 -13
  136. package/services/list.service.js +62 -15
  137. package/services/run.service.d.ts +35 -22
  138. package/services/run.service.js +316 -233
  139. package/services/system-info.d.ts +1 -1
  140. package/services/version-plan.service.d.ts +35 -8
  141. package/services/version-plan.service.js +96 -36
  142. package/services/version.service.d.ts +34 -14
  143. package/services/version.service.js +35 -16
  144. package/services.d.ts +1 -1
  145. package/services.js +1 -1
  146. package/utils/bin-path.d.ts +6 -7
  147. package/utils/bin-path.js +7 -18
  148. package/utils/branch-guard.d.ts +30 -1
  149. package/utils/branch-guard.js +31 -0
  150. package/utils/color-yaml.d.ts +8 -0
  151. package/utils/color-yaml.js +86 -0
  152. package/utils/exec.d.ts +10 -0
  153. package/utils/exec.js +1 -1
  154. package/utils/git.d.ts +26 -0
  155. package/utils/git.js +65 -0
  156. package/utils/logger.d.ts +2 -2
  157. package/utils/logger.js +1 -1
  158. package/utils/package-filter.d.ts +135 -8
  159. package/utils/package-filter.js +204 -16
  160. package/utils/printable-config.d.ts +9 -1
  161. package/utils/printable-config.js +46 -1
  162. package/utils/progress-panel.d.ts +9 -0
  163. package/utils/progress-panel.js +23 -1
  164. package/utils/release-version.d.ts +1 -1
  165. package/utils/run-bin.d.ts +10 -0
  166. package/utils/run-bin.js +1 -1
  167. package/utils/run-options.d.ts +97 -0
  168. package/utils/run-options.js +81 -0
  169. package/utils/version-group.d.ts +31 -0
  170. package/utils/version-group.js +43 -0
  171. package/utils/version-stamp.d.ts +1 -1
  172. package/utils/version-stamp.js +1 -1
  173. package/commands/changed.command.d.ts +0 -3
  174. package/commands/changed.command.js +0 -29
  175. package/core/config.d.ts +0 -409
  176. package/core/config.js +0 -939
  177. package/core/extends-config.d.ts +0 -27
  178. package/core/extends-config.js +0 -89
  179. package/core/manifest.js +0 -150
  180. package/core/merge-config.js +0 -219
  181. package/core/package.d.ts +0 -83
  182. package/core/package.js +0 -106
  183. package/core/plugin.d.ts +0 -112
  184. package/core/plugin.js +0 -189
  185. package/core/workspace.d.ts +0 -68
  186. package/core/workspace.js +0 -83
  187. /package/{core/run-step.js → builtins/platforms/node/augmentation/rmanrc.augmentation.js} +0 -0
package/README.md CHANGED
@@ -66,7 +66,7 @@ rman version
66
66
  # Apply it: bump versions, write CHANGELOG.md, commit, tag
67
67
  rman version --changelog
68
68
 
69
- # Publish everything that isn't already on the registry (needs rman-node)
69
+ # Publish everything that isn't already on the registry
70
70
  rman publish
71
71
  ```
72
72
 
@@ -86,21 +86,32 @@ worked examples of every single command, see **[docs/cli-rman.md](https://github
86
86
  | [`test`](#rman-test) | Alias for `run test`. |
87
87
  | [`exec <command..>`](#rman-exec-command) | Runs an arbitrary shell command in each package. |
88
88
  | [`config`](#rman-config) | Prints the effective `.rmanrc` config for the current directory's package. |
89
- | [`changed`](#rman-changed) | Shows which packages the next `version` run would bump. |
90
89
  | [`diff [package]`](#rman-diff-package) | Shows the git diff since a package's (or the repo's) last release tag. |
91
90
  | [`changelog`](#rman-changelog) | Generates a changelog per package from unreleased commits. |
92
91
  | [`version [bump]`](#rman-version-bump) | Bumps versions of changed packages (and their dependents). |
92
+ | [`publish`](#rman-publish) | Publishes every package whose version isn't on its registry yet. |
93
93
  | [`github-release`](#rman-github-release) | Creates the repository's GitHub Release for its release tag. |
94
94
  | [`import <path>`](#rman-import-path) | Imports an external git repository as a new package, with history. |
95
95
 
96
- **`publish`, `ci` and `clean` come from [`rman-node`](https://www.npmjs.com/package/rman-node)**,
97
- not from this package - each is about npm or TypeScript rather than about repositories. Name the
98
- plugin in `.rmanrc` to get them:
96
+ **`ci` and `clean` come from the `node` built-in**, which ships inside this package - each is about
97
+ npm or TypeScript rather than about repositories, so nothing it contributes exists until a
98
+ repository asks for it:
99
99
 
100
100
  ```yaml
101
- plugins: ['rman-node']
101
+ plugins: ['node'] # by name
102
+ platform: node # the same statement at a repository root, plus which technology its packages are
102
103
  ```
103
104
 
105
+ Or say nothing: a repository that declares no technology gets the one its own files imply, announced
106
+ on stderr rather than guessed silently. It used to take a second package (`rman-node`) and a
107
+ `.rmanrc` before anything worked at all.
108
+
109
+ **`publish` is here, but *where* a package ships is a plugin's to say.** A **publish target** is
110
+ one answer to "is this version on the registry, and how do I push it" - rman ships `docker`
111
+ (any language's project can push an image), and the `node` built-in contributes `npm` with the flags
112
+ that only mean something there (`--access`, `--tag`, `--otp`, `--registry`, ...). So
113
+ `rman publish --help` lists what this repository's targets actually understand.
114
+
104
115
  Options shared across several commands:
105
116
 
106
117
  - **`skip`** (`.rmanrc`, per package): leave this package alone - honoured by every command that
@@ -108,8 +119,10 @@ Options shared across several commands:
108
119
  - **Package filtering** (`list`, `run`/`build`/`test`, `exec`, `version`, `changelog`, and a
109
120
  plugin's own commands): `--scope <glob>`, `--ignore <glob>`, `--deps`, `--dependents` - see
110
121
  [Package filtering](https://github.com/panates/rman/blob/main/docs/rman.md#package-filtering-scopeignoredepsdependents)
111
- for the full semantics.
112
- - **`--root`/`-r`** (every command that narrows to the package you are standing in -
122
+ for the full semantics. **`--scope /` is the repository's own root package** - the same `/`
123
+ `.rmanrc`'s `"[/]"` block uses, and not a glob, so `--scope '*'` means the members and a glob
124
+ never picks up the root by name.
125
+ - **`--from-root`/`-r`** (every command that narrows to the package you are standing in -
113
126
  `run`/`build`/`test`, `exec`, `changelog`, `diff`): run against the whole repository instead.
114
127
  - **Branch guard** (every command that mutates state or runs scripts - `run`/`build`/`test`,
115
128
  `exec`, `version`): `--allow-branch <glob>`, `--ignore-branch <glob>` -
@@ -127,16 +140,17 @@ rman list --json # full detail as JSON
127
140
  rman list --parseable # location::name::version::PRIVATE::STATUS lines, for scripting
128
141
  rman list --toposort # dependencies before dependents, instead of directory order
129
142
  rman list --graph # dependency graph as a JSON adjacency list
130
- rman list --changed # only packages changed since the last publish
143
+ rman list --changed # only packages you have touched but not pushed
131
144
  rman list --changed-since HEAD~5
132
145
  rman list --scope '@myorg/*' --ignore '*-internal'
133
146
  ```
134
147
 
135
148
  ### `rman info`
136
149
 
137
- Prints local environment (OS/CPU/memory, Node, git) and repository information. A plugin adds its
138
- own ecosystem's part - `rman-node` reports whichever package manager `.rmanrc "packageManager"`
139
- names, plus the installed `rman` packages.
150
+ Prints local environment (OS/CPU/memory, Node, git) and repository information. A platform adds its
151
+ own ecosystem's part - the `node` built-in reports whichever package manager
152
+ `.rmanrc "packageManager"` names, plus the installed `rman` packages, and only in a repository that
153
+ asked for it.
140
154
 
141
155
  ```bash
142
156
  rman info
@@ -150,7 +164,7 @@ Runs an npm script in each package, in dependency order by default.
150
164
  ```bash
151
165
  rman run build
152
166
  rman run lint --topo=false # independent packages, alphabetical order, no dependency waiting
153
- rman run test --changed # only in packages changed since the last publish
167
+ rman run test --changed # only in packages you have touched but not pushed
154
168
  rman run build --changed-since v1.2.0
155
169
  rman run build --parallel 4 # at most 4 packages at once
156
170
  rman run build --parallel false # serially, one at a time
@@ -192,24 +206,15 @@ rman exec --topo=false pwd # every package independently, alphabetical o
192
206
  ### `rman config`
193
207
 
194
208
  Prints the **effective** config for the package of the current directory - after the directory
195
- cascade, `"[selector]"` blocks, `extends`, `+key` appends and `${{ ... }}` expressions have all been
209
+ cascade, `"[selector]"` blocks, `extends` and `${{ ... }}` expressions have all been
196
210
  applied. What rman actually sees there, which no single file shows.
197
211
 
198
212
  ```bash
199
213
  rman config # the package you are standing in
200
- rman config --root # the repository root's own config instead
214
+ rman config --from-root # the repository root's own config instead
201
215
  rman config --json | jq .run
202
216
  ```
203
217
 
204
- ### `rman changed`
205
-
206
- Shows which packages the next `rman version` run would bump, without changing anything.
207
-
208
- ```bash
209
- rman changed
210
- rman changed --json
211
- ```
212
-
213
218
  ### `rman diff [package]`
214
219
 
215
220
  Shows the git diff since a package's (or the whole repository's) last release tag.
@@ -266,6 +271,29 @@ Release-As: patch
266
271
  See [docs/rman.md#versionservice](https://github.com/panates/rman/blob/main/docs/rman.md#versionservice) for the full grouping/propagation
267
272
  algorithm, prerelease semantics, and `"workspace:"` dependency-range handling.
268
273
 
274
+ ### `rman publish`
275
+
276
+ Publishes every package whose current version isn't on its registry yet. Shows the plan first, then
277
+ asks for confirmation (unless `--yes` or `--dry-run`), then publishes in topological order,
278
+ dependencies before dependents.
279
+
280
+ ```bash
281
+ rman publish # show the plan, then ask for confirmation
282
+ rman publish --yes # publish immediately, no confirmation
283
+ rman publish --dry-run --json # "is there anything to release?", for a CI gate
284
+ rman publish --target docker # only the packages configured for that target
285
+ ```
286
+
287
+ **Where a package ships is a publish target, and a target is a contribution.** rman ships `docker`;
288
+ the `node` built-in contributes `npm`. A package says where it goes with `.rmanrc "publish.target"`, or says
289
+ nothing and goes wherever the installed targets claim it - so a Cargo package is never assumed to be
290
+ an npm one. Each target adds its own flags, so `rman publish --help` is worth reading in your own
291
+ repository. See
292
+ [docs/cli/publish.md](https://github.com/panates/rman/blob/main/docs/cli/publish.md).
293
+
294
+ It never looks at whether `version` ran: it inspects what is on disk and on each registry, so it
295
+ behaves the same right after a bump or days later, and re-running is safe.
296
+
269
297
  ### `rman github-release`
270
298
 
271
299
  Creates the repository's GitHub Release for the version that just shipped - one per run, named after
@@ -294,7 +322,7 @@ rman import ../my-old-standalone-repo --dest libs # under libs/ instead of pac
294
322
  already. After importing, add the new directory to your `workspaces` glob if it isn't already
295
323
  covered, then run `rman ci` to install it.
296
324
 
297
- ## Shared config (`extends`) and appending (`+key`)
325
+ ## Shared config (`extends`) and adding to it (`value`)
298
326
 
299
327
  House rules live in one package, and a repository names it:
300
328
 
@@ -305,13 +333,18 @@ extends: '@panates/rman-monorepo'
305
333
  '[*]':
306
334
  run:
307
335
  build:
308
- +before: 'rm -rf ./cache' # adds to the base's step, rather than replacing it
336
+ # adds to the base's step, rather than replacing it
337
+ before: "${{ [...value, 'rm -rf ./cache'] }}"
309
338
  ```
310
339
 
311
340
  `extends` merges underneath the file naming it (a package, a path, or a list), and may itself be
312
- chained. `+key` appends to whatever the key already resolved to - from the base, a parent directory,
313
- or a selector - which is what lets a repository add one step without restating a list it doesn't
314
- own. See [docs/rman.md](https://github.com/panates/rman/blob/main/docs/rman.md#inheriting-a-shared-config-extends).
341
+ chained. `value` is what the key already resolved to - from the base, a parent directory, or a
342
+ selector - which is what lets a repository add one step without restating a list it doesn't own. It
343
+ is the list form of whatever is underneath, so the spread needs no guard even when nothing is.
344
+ See [docs/rman.md](https://github.com/panates/rman/blob/main/docs/rman.md#inheriting-a-shared-config-extends).
345
+
346
+ There was a `+key` prefix for this and it is gone; one still in a config is refused, naming what to
347
+ write instead.
315
348
 
316
349
  ## Your own commands
317
350
 
@@ -408,8 +441,9 @@ import { defineConfig } from 'rman';
408
441
  export default defineConfig({ allowBranch: ['main'] });
409
442
  ```
410
443
 
411
- With a plugin, import `defineConfig` from the plugin instead (`rman-node`'s carries its own keys
412
- into the type). The `.rmanrc`/`.rmanrc.yml` forms get no checking - see
444
+ A plugin's keys arrive by declaration merging, so annotating with `RmanConfig` types them too;
445
+ `RmanNodeConfig` is the alias that says out loud which set a config is using. The
446
+ `.rmanrc`/`.rmanrc.yml` forms get no checking - see
413
447
  [docs/rman.md#editor-support-types](https://github.com/panates/rman/blob/main/docs/rman.md#editor-support-types) for why the JSON Schema that
414
448
  used to cover them was removed.
415
449
 
@@ -0,0 +1,83 @@
1
+ import type { cleanCommand, CleanExtraKeys } from '../commands/clean.command.js';
2
+ import type { NodeConfigKeys, RmanNodeConfig } from '../node-config.interface.js';
3
+ import type { CiService } from '../services/ci.service.js';
4
+ /**
5
+ * **Every type this plugin adds to rman, in one `declare module` block.**
6
+ *
7
+ * **One block was once forced and is now only convenient.** While this shipped as its own package
8
+ * it augmented the *package name* `'rman'`, and a second such block anywhere silently disabled the
9
+ * first - measured, `SystemInfo.PackageManager` went unresolved at four call sites with nothing
10
+ * pointing at the cause. Bundled into rman, these augment a **module path** like every built-in
11
+ * command's own contribution does, and that limit is gone; they stay together because the plugin's
12
+ * types read better in one place, not because they have to.
13
+ *
14
+ * Type-only. The runtime half of each augmentation lives with its own subject
15
+ * (`augmentSystemInfo()`, `augmentManifest()`, ...); this file is imported by the plugin's entry
16
+ * point purely so a consumer's compiler loads it.
17
+ */
18
+ declare module '../../../../interfaces/rman-config.interface.js' {
19
+ /**
20
+ * The `.rmanrc` keys that only mean something in a Node repository - merged into the core's own
21
+ * key list, so `pkg.config.clean` is typed wherever it is read (`CleanService` included) without
22
+ * a cast, and without the core declaring a key it knows nothing about.
23
+ *
24
+ * The augmentation is evaluated where it is used, so `clean` is typed at the place it is read.
25
+ */
26
+ interface RmanConfigKeys extends NodeConfigKeys {
27
+ }
28
+ /**
29
+ * **`clean.*`, contributed by the command that reads it**, the way every built-in contributes its
30
+ * own key - `skip` derived from the command's `config` block, `include`/`exclude` hand-written in
31
+ * `CleanExtraKeys` because a `CommandOption` cannot say "a glob *or* a list of them".
32
+ *
33
+ * It is declared here rather than beside the command only because of the one-block rule above.
34
+ * rman's own commands put theirs next to themselves, augmenting a module path instead of a
35
+ * package name, which has no such limit.
36
+ */
37
+ namespace RmanConfig {
38
+ interface CommandConfigs extends RmanConfig.CommandContribution<ReturnType<typeof cleanCommand>, CleanExtraKeys> {
39
+ }
40
+ }
41
+ }
42
+ /**
43
+ * **The `npm` target's own `publish.*` block** - declared into the slot `publish` exports, exactly
44
+ * where the core's own `docker` target declares `publish.docker`.
45
+ *
46
+ * A *different* module from the block above, and that is the shape the fold made possible: while
47
+ * this shipped as `rman-node` everything had to augment the one package name `'rman'`, so a slot
48
+ * declared in `publish.command.ts` was reachable only by re-declaring it - which now reads as two
49
+ * interfaces of one name and is refused. Each interface is augmented where it lives.
50
+ */
51
+ declare module '../../../../commands/publish.command.js' {
52
+ /**
53
+ * The `npm` publish target's own `publish.*` block, declared the way the core's `docker` target
54
+ * declares `publish.docker` - through the slot `publish` contributes, rather than into a central
55
+ * `PublishOptionsKeys` that the core owned.
56
+ *
57
+ * That is the config half of a target being a contribution: this package brings the flags, the
58
+ * registry check, *and* the keys, and none of it is written down in rman.
59
+ */
60
+ interface PublishTargetConfigs {
61
+ /** The `npm` target's block, named after the target exactly as the core's `docker` one is. */
62
+ npm?: RmanNodeConfig.NpmPublishOptions;
63
+ }
64
+ }
65
+ /**
66
+ * **The npm half of `SystemInfo`** - what `rman info` reports once a repository is a Node one. The
67
+ * runtime half is `augmentSystemInfo()` in the file beside this one, called when the built-in is
68
+ * registered rather than at import, so a repository that never named it reports no npm.
69
+ */
70
+ declare module '../../../../services/system-info.js' {
71
+ namespace SystemInfo {
72
+ type PackageManager = CiService.PackageManager;
73
+ interface Options {
74
+ /**
75
+ * Report this package manager's version under `Binaries`, plus the `npmPackages` sections.
76
+ *
77
+ * Defaults to `.rmanrc "packageManager"` (read off `Options.repository`), then to `npm` -
78
+ * this package being installed is itself the statement that the repository is a Node one.
79
+ */
80
+ packageManager?: PackageManager;
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Adds the npm half of `SystemInfo` to rman's own types.
3
+ *
4
+ * The core's `Options` carries nothing language-specific on purpose, so `packageManager` is not a
5
+ * setting it hid behind a flag - it is a setting it does not have. Declaration merging is what lets
6
+ * this package add it as if it had always been there, `SystemInfo.PackageManager` included, without
7
+ * the core naming npm anywhere.
8
+ *
9
+ * The union itself is `CiService.PackageManager`, not a second copy: `ci` and `publish` already
10
+ * shell out to one of these, and two lists of the same four names drift the moment a fifth appears.
11
+ */
12
+ /** The import above is aliased precisely so this block can use the real name: declaration merging
13
+ * keys off the module specifier, not off any local binding, so `namespace SystemInfo` here *is*
14
+ * rman's - and nothing shadows anything. */
15
+ /** The `SystemInfo` types this file's wrapper relies on are declared in
16
+ * [`rman.augmentation.ts`](rman.augmentation.ts), with the rest of this plugin's - one
17
+ * `declare module` block per package, or the others stop applying. */
18
+ /**
19
+ * Turns the npm half on at runtime.
20
+ *
21
+ * Applied by wrapping rather than by a flag on the core service: "is this a Node repository" is not
22
+ * a question rman's core should be able to ask, and a `nodejs: true` option there would be exactly
23
+ * that question wearing a different hat. The wrapper translates `packageManager` into the `envinfo`
24
+ * categories the core knows nothing about.
25
+ */
26
+ export declare function augmentSystemInfo(): void;
@@ -0,0 +1,79 @@
1
+ import { SystemInfo as OrgSystemInfo } from '../../../../services/system-info.js';
2
+ /**
3
+ * Adds the npm half of `SystemInfo` to rman's own types.
4
+ *
5
+ * The core's `Options` carries nothing language-specific on purpose, so `packageManager` is not a
6
+ * setting it hid behind a flag - it is a setting it does not have. Declaration merging is what lets
7
+ * this package add it as if it had always been there, `SystemInfo.PackageManager` included, without
8
+ * the core naming npm anywhere.
9
+ *
10
+ * The union itself is `CiService.PackageManager`, not a second copy: `ci` and `publish` already
11
+ * shell out to one of these, and two lists of the same four names drift the moment a fifth appears.
12
+ */
13
+ /** The import above is aliased precisely so this block can use the real name: declaration merging
14
+ * keys off the module specifier, not off any local binding, so `namespace SystemInfo` here *is*
15
+ * rman's - and nothing shadows anything. */
16
+ /** The `SystemInfo` types this file's wrapper relies on are declared in
17
+ * [`rman.augmentation.ts`](rman.augmentation.ts), with the rest of this plugin's - one
18
+ * `declare module` block per package, or the others stop applying. */
19
+ /**
20
+ * Turns the npm half on at runtime.
21
+ *
22
+ * Applied by wrapping rather than by a flag on the core service: "is this a Node repository" is not
23
+ * a question rman's core should be able to ask, and a `nodejs: true` option there would be exactly
24
+ * that question wearing a different hat. The wrapper translates `packageManager` into the `envinfo`
25
+ * categories the core knows nothing about.
26
+ */
27
+ export function augmentSystemInfo() {
28
+ const base = OrgSystemInfo.getSystemInfo;
29
+ /**
30
+ * Idempotent, and marked on **the function** rather than in a module-level flag: the flag made
31
+ * re-application impossible once anything had replaced `getSystemInfo` - a test substituting a
32
+ * stub, or a second augmentation layering on - so whether the wrapper was actually installed came
33
+ * down to import order. Asking the current implementation whether it is already wrapped cannot go
34
+ * stale that way.
35
+ */
36
+ if (base[AUGMENTED])
37
+ return;
38
+ /** A namespace's exported function is a property of a plain object at runtime, so this is an
39
+ * ordinary assignment - the ESM *binding* is immutable, the object it points at is not. */
40
+ const wrapped = options => {
41
+ /** An explicit argument first, then the repository's own config, then npm. The config step is
42
+ * why the core declares `Options.repository`: `rman info` passes only that, so without it a
43
+ * pnpm repository would silently be reported as an npm one. */
44
+ const packageManager = options?.packageManager ?? asPackageManager(options?.repository?.config?.packageManager) ?? 'npm';
45
+ return base({
46
+ ...options,
47
+ envinfo: {
48
+ /** Replaces the core's `Binaries: ['Node']` - `envinfo` categories merge by key, not by
49
+ * concatenation, so the whole list has to be restated. */
50
+ Binaries: ['Node', PACKAGE_MANAGER_BINARY[packageManager]],
51
+ /** This package's own version alongside rman's - when `info` is being read to work out why
52
+ * a command behaved oddly, which plugin version is installed is half the answer. */
53
+ npmPackages: ['rman', 'typescript'],
54
+ npmGlobalPackages: ['typescript'],
55
+ ...options?.envinfo,
56
+ },
57
+ });
58
+ };
59
+ wrapped[AUGMENTED] = true;
60
+ OrgSystemInfo.getSystemInfo = wrapped;
61
+ }
62
+ /** `.rmanrc "packageManager"` value -> the `Binaries` key `envinfo` recognizes for it (`npm`/
63
+ * `pnpm`/`bun` are lowercase, `Yarn` isn't - envinfo's own naming, not ours). */
64
+ const PACKAGE_MANAGER_BINARY = {
65
+ npm: 'npm',
66
+ yarn: 'Yarn',
67
+ pnpm: 'pnpm',
68
+ bun: 'bun',
69
+ };
70
+ /** A config value is whatever the file said, so an unrecognized one is ignored rather than used to
71
+ * index `PACKAGE_MANAGER_BINARY` and produce `Binaries: ['Node', undefined]`. */
72
+ function asPackageManager(value) {
73
+ return typeof value === 'string' && value in PACKAGE_MANAGER_BINARY
74
+ ? value
75
+ : undefined;
76
+ }
77
+ /** Marks an implementation as already wrapped. A symbol rather than a property name so it cannot
78
+ * collide with anything `envinfo` or a future core option carries. */
79
+ const AUGMENTED = Symbol.for('rman.node.systemInfo.augmented');
@@ -0,0 +1,133 @@
1
+ import type { ArgsOf } from '../../../../index.js';
2
+ /** Hoisted out of the metadata literal so the handler can be annotated against them - see
3
+ * `RmanConfig.ArgsOf` for why an inferred `argv` and the metadata's own typo checking cannot both
4
+ * work in one signature. */
5
+ declare const COMMAND: "ci";
6
+ declare const config: {
7
+ packageManager: {
8
+ target: "cli";
9
+ cliName: string;
10
+ describe: string;
11
+ choices: readonly ["npm", "yarn", "pnpm", "bun"];
12
+ };
13
+ progress: {
14
+ target: "cli";
15
+ describe: string;
16
+ type: "boolean";
17
+ };
18
+ allowBranch: {
19
+ target: "cli";
20
+ cliName: string;
21
+ describe: string;
22
+ type: "string";
23
+ };
24
+ ignoreBranch: {
25
+ target: "cli";
26
+ cliName: string;
27
+ describe: string;
28
+ type: "string";
29
+ };
30
+ scope: {
31
+ target: "cli";
32
+ describe: string;
33
+ type: "string";
34
+ };
35
+ ignore: {
36
+ target: "cli";
37
+ describe: string;
38
+ type: "string";
39
+ };
40
+ platform: {
41
+ target: "cli";
42
+ describe: string;
43
+ type: "string";
44
+ };
45
+ deps: {
46
+ target: "cli";
47
+ describe: string;
48
+ type: "boolean";
49
+ };
50
+ dependents: {
51
+ target: "cli";
52
+ describe: string;
53
+ type: "boolean";
54
+ };
55
+ };
56
+ type Args = ArgsOf<typeof config, typeof COMMAND>;
57
+ /**
58
+ * `rman ci` - contributed by the `node` built-in rather than always present.
59
+ *
60
+ * **Declared, not built.** This was a `CustomCommand` with a hand-written `builder` chaining
61
+ * `applyBranchGuardOptions(applyPackageFilterOptions(cmd))`, which is the shape every built-in had
62
+ * before the options became data. A plugin's command uses the identical declaration now -
63
+ * `declareCommand` rather than `registerCommand`, which is the one difference and the reason for
64
+ * it: `registerCommand` pushes onto a module-level registry that `runCli` always walks, so a plugin
65
+ * using it would hand `ci` to repositories that are not Node ones.
66
+ *
67
+ * The repository arrives through `app` when the factory runs (in `cli.ts`, after `Repository.create`
68
+ * has attached one), rather than through a `CommandContext` per invocation.
69
+ */
70
+ export declare const ciCommand: (app: import("../../../../index.js").RmanApplication) => {
71
+ command: "ci";
72
+ /** npm's alone: it installs through a Node package manager, from a Node lockfile. */
73
+ platforms: string[];
74
+ describe: string;
75
+ /** Read, not owned: `packageManager` is a root-level key this package declares in
76
+ * `NodeConfigKeys`, and the `npm` publish target reads it too. */
77
+ configKeys: string[];
78
+ config: {
79
+ packageManager: {
80
+ target: "cli";
81
+ cliName: string;
82
+ describe: string;
83
+ choices: readonly ["npm", "yarn", "pnpm", "bun"];
84
+ };
85
+ progress: {
86
+ target: "cli";
87
+ describe: string;
88
+ type: "boolean";
89
+ };
90
+ allowBranch: {
91
+ target: "cli";
92
+ cliName: string;
93
+ describe: string;
94
+ type: "string";
95
+ };
96
+ ignoreBranch: {
97
+ target: "cli";
98
+ cliName: string;
99
+ describe: string;
100
+ type: "string";
101
+ };
102
+ scope: {
103
+ target: "cli";
104
+ describe: string;
105
+ type: "string";
106
+ };
107
+ ignore: {
108
+ target: "cli";
109
+ describe: string;
110
+ type: "string";
111
+ };
112
+ platform: {
113
+ target: "cli";
114
+ describe: string;
115
+ type: "string";
116
+ };
117
+ deps: {
118
+ target: "cli";
119
+ describe: string;
120
+ type: "boolean";
121
+ };
122
+ dependents: {
123
+ target: "cli";
124
+ describe: string;
125
+ type: "boolean";
126
+ };
127
+ };
128
+ examples: {
129
+ command: string;
130
+ }[];
131
+ handler: (args: Args) => Promise<void>;
132
+ };
133
+ export {};
@@ -0,0 +1,60 @@
1
+ import { declareCommand } from '../../../../interfaces/rman-config.interface.js';
2
+ import { assertAllowedBranch, branchGuardOptions, readBranchGuardOptions } from '../../../../utils/branch-guard.js';
3
+ import { packageFilterOptions, readPackageFilterOptions } from '../../../../utils/package-filter.js';
4
+ import { CiService } from '../services/ci.service.js';
5
+ /** Hoisted out of the metadata literal so the handler can be annotated against them - see
6
+ * `RmanConfig.ArgsOf` for why an inferred `argv` and the metadata's own typo checking cannot both
7
+ * work in one signature. */
8
+ const COMMAND = 'ci';
9
+ const config = {
10
+ ...packageFilterOptions,
11
+ ...branchGuardOptions,
12
+ packageManager: {
13
+ target: 'cli',
14
+ cliName: 'package-manager',
15
+ describe: 'Package manager to install with (default: npm, or .rmanrc "packageManager")',
16
+ choices: CiService.PACKAGE_MANAGERS,
17
+ },
18
+ progress: {
19
+ target: 'cli',
20
+ describe: 'Show a live progress panel while running (default: true; auto-disabled when not a TTY). ' +
21
+ 'Unlike run/build, completion is not reported as a per-package tally - only failures are called out.',
22
+ type: 'boolean',
23
+ },
24
+ };
25
+ /**
26
+ * `rman ci` - contributed by the `node` built-in rather than always present.
27
+ *
28
+ * **Declared, not built.** This was a `CustomCommand` with a hand-written `builder` chaining
29
+ * `applyBranchGuardOptions(applyPackageFilterOptions(cmd))`, which is the shape every built-in had
30
+ * before the options became data. A plugin's command uses the identical declaration now -
31
+ * `declareCommand` rather than `registerCommand`, which is the one difference and the reason for
32
+ * it: `registerCommand` pushes onto a module-level registry that `runCli` always walks, so a plugin
33
+ * using it would hand `ci` to repositories that are not Node ones.
34
+ *
35
+ * The repository arrives through `app` when the factory runs (in `cli.ts`, after `Repository.create`
36
+ * has attached one), rather than through a `CommandContext` per invocation.
37
+ */
38
+ export const ciCommand = declareCommand(app => {
39
+ const repository = app.repository;
40
+ return {
41
+ command: COMMAND,
42
+ /** npm's alone: it installs through a Node package manager, from a Node lockfile. */
43
+ platforms: ['node'],
44
+ describe: 'Deletes node_modules and lockfiles in every package, then reinstalls from scratch',
45
+ /** Read, not owned: `packageManager` is a root-level key this package declares in
46
+ * `NodeConfigKeys`, and the `npm` publish target reads it too. */
47
+ configKeys: ['packageManager'],
48
+ config,
49
+ examples: [{ command: '$0 ci' }],
50
+ handler: async (args) => {
51
+ await assertAllowedBranch(repository, readBranchGuardOptions(args));
52
+ await CiService.reinstall(repository, {
53
+ ...readPackageFilterOptions(args),
54
+ packageManager: args.packageManager,
55
+ progress: args.progress,
56
+ logLevel: args.logLevel,
57
+ });
58
+ },
59
+ };
60
+ });