rman 1.0.8 → 1.0.10

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 CHANGED
@@ -91,7 +91,7 @@ worked examples of every single command, see **[docs/cli.md](docs/cli.md)**.
91
91
  | [`diff [package]`](#rman-diff-package) | Shows the git diff since a package's (or the repo's) last release tag. |
92
92
  | [`changelog`](#rman-changelog) | Generates a changelog per package from unreleased commits. |
93
93
  | [`version [bump]`](#rman-version-bump) | Bumps versions of changed packages (and their dependents). |
94
- | [`publish`](#rman-publish) | Publishes every package to its configured target(s) - npm and/or Docker. |
94
+ | [`publish`](#rman-publish) | Publishes every package to its configured target(s) - npm, Docker and/or GitHub Releases. |
95
95
  | [`import <path>`](#rman-import-path) | Imports an external git repository as a new package, with history. |
96
96
 
97
97
  Options shared across several commands:
@@ -222,7 +222,7 @@ Generates a changelog per package from unreleased commits, grouped into ✨ Feat
222
222
  / 🔧 Other Changes.
223
223
 
224
224
  ```bash
225
- rman changelog # auto-detects each package's last published npm version
225
+ rman changelog # auto-detects each package's own last release
226
226
  rman changelog --from a1b2c3d # since a specific commit, for every package
227
227
  rman changelog --write # prepend into each package's own CHANGELOG.md
228
228
  rman changelog --write --file-path docs/CHANGELOG.md
@@ -265,8 +265,10 @@ algorithm, prerelease semantics, and `"workspace:"` dependency-range handling.
265
265
 
266
266
  ### `rman publish`
267
267
 
268
- Publishes every package to its configured target(s) - `npm` by default, or whatever each package's
269
- own `.rmanrc "publish.target"` says (`"npm"`, `"docker"`, or both).
268
+ Publishes every package to its configured registry - `npm` by default, or whatever each package's
269
+ own `.rmanrc "publish.target"` says (`"npm"`, `"docker"`, or both). Each target decides for itself
270
+ whether the current version is already out there: `npm view` on the npm side, `docker manifest
271
+ inspect` on the docker side.
270
272
 
271
273
  ```bash
272
274
  rman publish # show the plan, then ask for confirmation
@@ -288,6 +290,20 @@ A package opts into building/pushing a Docker image via `.rmanrc "publish.target
288
290
  a `"publish.docker"` block (`image`, `platforms`, `buildContexts`, `buildArgs`, ...) - see
289
291
  [docs/cli/publish.md#docker-publishing-publishdocker](docs/cli/publish.md#docker-publishing-publishdocker).
290
292
 
293
+ ### `rman github-release`
294
+
295
+ Creates the repository's GitHub Release for the version that just shipped - one per run, named after
296
+ the repository's own release tag, with notes covering every package that shipped under it.
297
+
298
+ ```bash
299
+ rman github-release --yes
300
+ ```
301
+
302
+ It is deliberately neither a `publish.target` nor opt-in: a release isn't a registry a package ships
303
+ to, it's the repository's own record that a version shipped, and every repository wants that record.
304
+ It needs no configuration at all - see
305
+ [docs/cli/github-release.md](docs/cli/github-release.md).
306
+
291
307
  ### `rman import <path>`
292
308
 
293
309
  Imports an external git repository as a new package, preserving its **entire commit history**
package/cli.js CHANGED
@@ -11,6 +11,7 @@ import * as ciCommand from './commands/ci.command.js';
11
11
  import * as cleanCommand from './commands/clean.command.js';
12
12
  import * as diffCommand from './commands/diff.command.js';
13
13
  import * as execCommand from './commands/exec.command.js';
14
+ import * as githubReleaseCommand from './commands/github-release.command.js';
14
15
  import * as importCommand from './commands/import.command.js';
15
16
  import * as infoCommand from './commands/info.command.js';
16
17
  import * as listCommand from './commands/list.command.js';
@@ -61,6 +62,7 @@ export async function runCli(options) {
61
62
  testCommand.initCli(repository, program);
62
63
  versionCommand.initCli(repository, program);
63
64
  publishCommand.initCli(repository, program);
65
+ githubReleaseCommand.initCli(repository, program);
64
66
  execCommand.initCli(repository, program);
65
67
  changedCommand.initCli(repository, program);
66
68
  diffCommand.initCli(repository, program);
@@ -7,12 +7,13 @@ export function initCli(repository, program) {
7
7
  command: 'changelog',
8
8
  describe: 'Generates a changelog per package from unreleased commits',
9
9
  builder: cmd => applyPackageFilterOptions(cmd)
10
- .example('$0 changelog', "# Auto-detects each package's last published version on npm")
10
+ .example('$0 changelog', "# Auto-detects each package's own last release tag (or npm version)")
11
11
  .example('$0 changelog --from <hash> --write', '# Since a specific commit, written to file')
12
12
  .option('from', {
13
13
  describe: 'Generate the changelog since this commit/hash, applied the same way to every package. ' +
14
- 'Default (also "npm" explicitly): auto-detect per package from its published npm version, ' +
15
- "falling back to not-yet-pushed commits for a package that can't be resolved this way",
14
+ 'Default (also "npm" explicitly): auto-detect per package from its own most recent release ' +
15
+ 'tag - same as "version"/"changed" - falling back to its published npm version (no tag yet), ' +
16
+ "then to its whole history for a package that's never been released at all",
16
17
  type: 'string',
17
18
  })
18
19
  .option('write', {
@@ -33,15 +34,23 @@ export function initCli(repository, program) {
33
34
  .option('include-skipped', {
34
35
  describe: 'Also generate for a package with .rmanrc "publish.skip" - excluded by default',
35
36
  type: 'boolean',
37
+ })
38
+ .option('release-version', {
39
+ describe: 'The version these notes are for - what the entry heading shows. Default: read back from ' +
40
+ "each package's own latest release tag, which is only right once that release is tagged. " +
41
+ 'Pass it when generating notes ahead of the bump (e.g. from "changed --json" in CI), ' +
42
+ 'otherwise the heading shows the previous release.',
43
+ type: 'string',
36
44
  }),
37
45
  handler: async (args) => {
38
46
  const from = args.from;
39
47
  const write = args.write;
40
48
  const logger = new Logger(args.logLevel ?? resolveRootLogLevel(repository));
41
49
  if (!from || from === 'npm') {
42
- // A network round trip per package, even run concurrently, can still take a visible
43
- // moment - without this, the command looks hung for that stretch instead of just busy.
44
- logger.info(colors.gray('Checking published npm versions...'));
50
+ // Auto-detection is mostly local git work, but the npm fallback it can reach for (only
51
+ // when a package has no tag at all) is a network round trip per package - without this,
52
+ // the command looks hung for that stretch instead of just busy.
53
+ logger.info(colors.gray("Detecting each package's last release..."));
45
54
  }
46
55
  const options = {
47
56
  ...readPackageFilterOptions(args),
@@ -49,6 +58,7 @@ export function initCli(repository, program) {
49
58
  filePath: args.filePath,
50
59
  root: args.root,
51
60
  includeSkipped: args.includeSkipped,
61
+ version: args.releaseVersion,
52
62
  };
53
63
  const entries = args.write
54
64
  ? await ChangelogService.generateToFile(repository, options)
@@ -0,0 +1,3 @@
1
+ import type { Argv } from 'yargs';
2
+ import type { Repository } from '../core/repository.js';
3
+ export declare function initCli(repository: Repository, program: Argv): void;
@@ -0,0 +1,119 @@
1
+ import readline from 'node:readline/promises';
2
+ import colors from 'ansi-colors';
3
+ import { GithubReleaseService } from '../services/github-release.service.js';
4
+ import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
5
+ export function initCli(repository, program) {
6
+ program.command({
7
+ command: 'github-release',
8
+ describe: "Creates the repository's GitHub Release for the version that just shipped",
9
+ builder: cmd => applyBranchGuardOptions(cmd)
10
+ .example('$0 github-release', '# Show what would be released, then ask for confirmation')
11
+ .example('$0 github-release --yes', '# Create it immediately, no confirmation (CI)')
12
+ .example('$0 github-release --dry-run', '# Only show the plan')
13
+ .option('yes', {
14
+ alias: 'y',
15
+ describe: 'Skip the confirmation prompt and create the release immediately',
16
+ type: 'boolean',
17
+ })
18
+ .option('dry-run', {
19
+ describe: 'Only show the plan - never creates anything, regardless of --yes',
20
+ type: 'boolean',
21
+ })
22
+ .option('json', {
23
+ alias: 'j',
24
+ describe: 'Print the plan as JSON instead of text',
25
+ type: 'boolean',
26
+ })
27
+ .option('repository', {
28
+ describe: 'The "owner/repo" the release is created in - default: .rmanrc "githubRelease.repository", ' +
29
+ 'falling back to the "origin" remote.',
30
+ type: 'string',
31
+ })
32
+ .option('ignore-dirty', {
33
+ describe: 'Release anyway when the working tree has uncommitted changes, instead of aborting',
34
+ type: 'boolean',
35
+ }),
36
+ handler: async (args) => {
37
+ await assertAllowedBranch(repository, readBranchGuardOptions(args));
38
+ // No package filtering: a release belongs to the repository, not to a package, so there is
39
+ // nothing for --scope/--ignore to narrow down.
40
+ const plan = await GithubReleaseService.getPlan(repository, {
41
+ ignoreDirty: args.ignoreDirty,
42
+ repository: args.repository,
43
+ });
44
+ if (args.json) {
45
+ console.log(JSON.stringify(plan.map(e => ({
46
+ tag: e.tag,
47
+ repository: e.repository,
48
+ status: e.status,
49
+ version: e.version,
50
+ reason: e.reason,
51
+ })), undefined, 2));
52
+ }
53
+ else {
54
+ for (const e of plan) {
55
+ const name = colors.cyan(e.tag ?? e.version);
56
+ switch (e.status) {
57
+ case 'publish':
58
+ console.log(colors.green('release'), name, colors.gray(`${e.repository} - ${e.reason ?? ''}`));
59
+ break;
60
+ case 'up-to-date':
61
+ console.log(colors.gray('up-to-date'), name, colors.gray(e.reason ?? ''));
62
+ break;
63
+ case 'skip':
64
+ console.log(colors.cyan('skip'), name, colors.gray(e.reason ?? ''));
65
+ break;
66
+ case 'error':
67
+ console.log(colors.red('error'), name, colors.red(e.reason ?? ''));
68
+ break;
69
+ }
70
+ }
71
+ }
72
+ const error = plan.find(e => e.status === 'error');
73
+ if (error) {
74
+ const err = new Error(error.reason ?? 'Unable to prepare the GitHub Release');
75
+ err.logged = true;
76
+ throw err;
77
+ }
78
+ if (!plan.some(e => e.status === 'publish')) {
79
+ if (!args.json)
80
+ console.log(colors.gray('Nothing to release.'));
81
+ return;
82
+ }
83
+ if (args.dryRun)
84
+ return;
85
+ let proceed = !!args.yes;
86
+ if (!proceed) {
87
+ if (!process.stdout.isTTY) {
88
+ console.log(colors.gray('Not a TTY - refusing to prompt. Pass --yes to release non-interactively.'));
89
+ return;
90
+ }
91
+ proceed = await confirm('Create this release?');
92
+ }
93
+ if (!proceed)
94
+ return;
95
+ const applied = await GithubReleaseService.applyPlan(repository, plan);
96
+ const failed = applied.find(e => e.status === 'error');
97
+ if (failed) {
98
+ console.log(colors.red('failed'), colors.cyan(failed.tag ?? ''), colors.red(failed.reason ?? ''));
99
+ const err = new Error('"github-release" failed');
100
+ err.logged = true;
101
+ throw err;
102
+ }
103
+ for (const e of applied) {
104
+ if (e.status === 'publish')
105
+ console.log(colors.green('released'), colors.cyan(e.tag ?? ''));
106
+ }
107
+ },
108
+ });
109
+ }
110
+ async function confirm(question) {
111
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
112
+ try {
113
+ const answer = await rl.question(`${question} (y/N) `);
114
+ return /^y(es)?$/i.test(answer.trim());
115
+ }
116
+ finally {
117
+ rl.close();
118
+ }
119
+ }
@@ -22,6 +22,12 @@ export function initCli(repository, program) {
22
22
  .option('dry-run', {
23
23
  describe: 'Only show the plan - never publishes, regardless of --yes',
24
24
  type: 'boolean',
25
+ })
26
+ .option('json', {
27
+ alias: 'j',
28
+ describe: 'Print the plan as JSON instead of text - one entry per package and target. Combine with ' +
29
+ '--dry-run to ask "is there anything to publish?" without publishing (e.g. a CI release gate).',
30
+ type: 'boolean',
25
31
  })
26
32
  .option('target', {
27
33
  describe: 'Restrict this run to just these publish target(s) ("npm"/"docker", repeatable) - default: ' +
@@ -72,7 +78,8 @@ export function initCli(repository, program) {
72
78
  handler: async (args) => {
73
79
  await assertAllowedBranch(repository, readBranchGuardOptions(args));
74
80
  const targets = resolveTargets(args.target);
75
- const explicitDockerTarget = !!args.target?.length && targets.has('docker');
81
+ const explicitTargets = !!args.target?.length;
82
+ const explicitDockerTarget = explicitTargets && targets.has('docker');
76
83
  const ignoreDirty = args.ignoreDirty;
77
84
  const npmOptions = {
78
85
  ...readPackageFilterOptions(args),
@@ -87,8 +94,13 @@ export function initCli(repository, program) {
87
94
  };
88
95
  const npmPlan = targets.has('npm') ? await PublishService.getPlan(repository, npmOptions) : [];
89
96
  const dockerPlan = targets.has('docker') ? await DockerPublishService.getPlan(repository, dockerOptions) : [];
90
- printPlan(npmPlan);
91
- printPlan(dockerPlan, 'docker');
97
+ if (args.json) {
98
+ console.log(JSON.stringify([...npmPlan.map(e => jsonEntry(e, 'npm')), ...dockerPlan.map(e => jsonEntry(e, 'docker'))], undefined, 2));
99
+ }
100
+ else {
101
+ printPlan(npmPlan);
102
+ printPlan(dockerPlan, 'docker');
103
+ }
92
104
  if (explicitDockerTarget && !dockerPlan.length) {
93
105
  const message = '--target docker was given, but no package\'s .rmanrc configures "publish.docker".';
94
106
  console.log(colors.red(message));
@@ -108,8 +120,9 @@ export function initCli(repository, program) {
108
120
  err.logged = true;
109
121
  throw err;
110
122
  }
111
- if (!npmPlan.some(e => e.status === 'publish') && !dockerPlan.some(e => e.status === 'publish')) {
112
- console.log(colors.gray('Nothing to publish.'));
123
+ if (![...npmPlan, ...dockerPlan].some(e => e.status === 'publish')) {
124
+ if (!args.json)
125
+ console.log(colors.gray('Nothing to publish.'));
113
126
  return;
114
127
  }
115
128
  if (args.dryRun)
@@ -168,6 +181,17 @@ function resolveTargets(input) {
168
181
  return new Set(['npm', 'docker']);
169
182
  return new Set(input);
170
183
  }
184
+ /** One `--json` row. `target` is what distinguishes otherwise-identical rows for a package that
185
+ * ships to several targets at once, so a consumer can tell which one still needs publishing. */
186
+ function jsonEntry(entry, target) {
187
+ return {
188
+ name: entry.package.name,
189
+ target,
190
+ status: entry.status,
191
+ version: entry.version,
192
+ reason: entry.reason,
193
+ };
194
+ }
171
195
  function printPlan(entries, label) {
172
196
  const prefix = label ? colors.gray(`[${label}] `) : '';
173
197
  for (const e of entries) {
@@ -54,7 +54,8 @@ export function initCli(repository, program) {
54
54
  })
55
55
  .option('changelog', {
56
56
  describe: "Also write each bumped package's CHANGELOG.md (same as running changelog --write " +
57
- 'separately) and fold it into the same commit as its version bump',
57
+ 'separately) and fold it into the same commit as its version bump. Default: .rmanrc ' +
58
+ '"version.changelog", or false - --no-changelog forces it off even when that\'s true.',
58
59
  type: 'boolean',
59
60
  })
60
61
  .option('preid', {
@@ -100,10 +101,11 @@ export function initCli(repository, program) {
100
101
  }
101
102
  if (!apply)
102
103
  return;
104
+ const changelog = args.changelog ?? repository.config?.version?.changelog ?? false;
103
105
  const applied = await VersionService.applyPlan(repository, plan, {
104
106
  push: args.push,
105
107
  message: args.message,
106
- changelog: args.changelog,
108
+ changelog,
107
109
  });
108
110
  for (const entry of applied) {
109
111
  if (entry.status === 'bump') {
package/constants.js CHANGED
@@ -1 +1 @@
1
- export const version = '1.0.8';
1
+ export const version = '1.0.10';
package/core/config.d.ts CHANGED
@@ -1,102 +1,4 @@
1
- /**
2
- * The shape of `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` (and `package.json`'s own
3
- * `"rman"` key) - see docs/api.md#configuration-rmanrc-rmanrcyml for the full reference. Every
4
- * field is optional and cascades from the repository root down to each package's own directory.
5
- * Purely a typing aid (used by `defineConfig` below, and importable on its own for a `.rmanrc.ts`/
6
- * `.mts` authored config, or a plain `: RmanConfig` annotation) - never read by rman itself, which
7
- * only ever sees the plain JS object a JS config file exports.
8
- */
9
- export interface RmanConfig {
10
- packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
11
- logLevel?: 'silent' | 'error' | 'info' | 'verbose';
12
- allowBranch?: string | string[];
13
- ignoreBranch?: string | string[];
14
- group?: boolean | string;
15
- version?: RmanConfig.VersionOptions;
16
- changelog?: RmanConfig.ChangelogOptions;
17
- clean?: RmanConfig.CleanOptions;
18
- publish?: RmanConfig.PublishOptions;
19
- /** Keyed by npm script name (e.g. `"build"`, `"lint"`, `"test"`). */
20
- run?: Record<string, RmanConfig.RunScriptOptions>;
21
- /** Keyed by the in-repo package's own name. */
22
- packages?: Record<string, RmanConfig.PackageOptions>;
23
- }
24
- export declare namespace RmanConfig {
25
- interface VersionOptions {
26
- commitMessage?: string;
27
- script?: string | string[];
28
- preScript?: string | string[];
29
- postScript?: string | string[];
30
- }
31
- interface ChangelogOptions {
32
- ignoreTypes?: string[];
33
- template?: string;
34
- filePath?: string;
35
- tagPattern?: string;
36
- }
37
- interface CleanOptions {
38
- include?: string | string[];
39
- exclude?: string | string[];
40
- skip?: boolean;
41
- }
42
- interface RunScriptOptions {
43
- concurrency?: number;
44
- topo?: boolean;
45
- bail?: boolean;
46
- progress?: boolean;
47
- logLevel?: 'silent' | 'error' | 'info' | 'verbose';
48
- changedSince?: string;
49
- skip?: boolean;
50
- if?: string;
51
- script?: string | string[];
52
- preScript?: string | string[];
53
- postScript?: string | string[];
54
- override?: boolean;
55
- }
56
- interface PackageOptions {
57
- dependencies?: string[] | Record<string, string>;
58
- }
59
- interface PublishOptions {
60
- /** Which registries `publish` should target for this package - default `['npm']` (every
61
- * existing repo keeps working unchanged). A package that only ever wants Docker images
62
- * (typically also `"private": true`, since it's not meant for npm at all) sets `['docker']`;
63
- * one that publishes both sets `['npm', 'docker']`. */
64
- target?: PublishTarget | PublishTarget[];
65
- docker?: DockerPublishOptions;
66
- /** Excludes this package from `publish` entirely (npm and docker both), regardless of
67
- * `target`/`"private"` - a single, explicit "never published" statement, e.g. for a package
68
- * released through some separate, unrelated process. `changelog` also skips it by default
69
- * (see its own `--include-skipped`) - there's little point changelogging something that's
70
- * never actually released. Independent of `version`, which never consults this at all - a
71
- * package can still be meaningfully versioned without ever being published. */
72
- skip?: boolean;
73
- }
74
- type PublishTarget = 'npm' | 'docker';
75
- /** Required once `"docker"` is one of this package's `publish.target`s - `publish --target
76
- * docker` errors clearly on a package that opts in here but leaves this out. */
77
- interface DockerPublishOptions {
78
- /** DockerHub image name/repository - bare (e.g. `"my-app"`) to be prefixed with
79
- * `--docker-namespace`/`DOCKERHUB_NAMESPACE`, or already-namespaced (contains a `/`) to use
80
- * verbatim. */
81
- image: string;
82
- /** Relative to the package's own directory. Default `"Dockerfile"`. */
83
- dockerfile?: string;
84
- /** Default `["linux/amd64"]`. */
85
- platforms?: string[];
86
- /** Build `cwd` override, relative to the repository root - only needed when the Dockerfile's
87
- * own `COPY`/`ADD` paths expect something other than the package's own directory (rare). */
88
- cwd?: string;
89
- /** Named `docker buildx build --build-context <name>=<path>` entries, keyed by name - each
90
- * path is relative to the package's own directory (or absolute). */
91
- buildContexts?: Record<string, string>;
92
- /** `docker buildx build --build-arg <name>=<value>` entries - a value of exactly `"$NAME"`
93
- * expands to `process.env.NAME` at build time (e.g. to pass a CI secret through). */
94
- buildArgs?: Record<string, string>;
95
- /** A file (relative to the package's own directory) whose contents become the DockerHub repo's
96
- * full description, if present. Default `"DOCKER_README.md"`. */
97
- readme?: string;
98
- }
99
- }
1
+ import type { RmanConfig } from '../interfaces/rman-config.interface.js';
100
2
  /**
101
3
  * Identity helper for authoring a `.rmanrc.cjs`/`.mjs`/`.js` config with full type-checking and
102
4
  * autocomplete - the same `defineConfig` pattern Vite/Vitest use. Returns `config` completely
package/core/package.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RmanConfig } from './config.js';
1
+ import type { RmanConfig } from '../interfaces/rman-config.interface.js';
2
2
  export declare class Package {
3
3
  readonly dirname: string;
4
4
  private _json;
package/index.d.ts CHANGED
@@ -8,10 +8,10 @@
8
8
  * CLI-only concerns (argv parsing, `--help` text, and all console/file presentation) stay in
9
9
  * `cli.ts` and the individual `commands/*.command.ts` modules, which are not exported here.
10
10
  */
11
- export type { RmanConfig } from './core/config.js';
12
11
  export { defineConfig } from './core/config.js';
13
12
  export { Package } from './core/package.js';
14
13
  export { Repository } from './core/repository.js';
14
+ export * from './interfaces/rman-config.interface.js';
15
15
  export * from './services.js';
16
16
  export type { DetectChangeHashOptions } from './utils/change-hash.js';
17
17
  export { detectChangeHash } from './utils/change-hash.js';
package/index.js CHANGED
@@ -1,6 +1,17 @@
1
+ /**
2
+ * Programmatic API - the same logic the CLI commands run, importable directly without going
3
+ * through yargs/argv. Each domain's logic lives in a `<Name>` namespace under `./services/*.ts`
4
+ * (e.g. `ChangelogService`, `CiService`, `CleanService`, `ListService`, `RunService`,
5
+ * `SystemInfo`, `VersionService`), re-exported here via `./services.js`. Purpose-specific functions, not one
6
+ * generic `run`/`get` per domain (see e.g. `SystemInfo.getSystemInfo`/`getRepositoryInfo`, kept
7
+ * separate since they're genuinely independent capabilities, not just steps of one operation) -
8
+ * CLI-only concerns (argv parsing, `--help` text, and all console/file presentation) stay in
9
+ * `cli.ts` and the individual `commands/*.command.ts` modules, which are not exported here.
10
+ */
1
11
  export { defineConfig } from './core/config.js';
2
12
  export { Package } from './core/package.js';
3
13
  export { Repository } from './core/repository.js';
14
+ export * from './interfaces/rman-config.interface.js';
4
15
  export * from './services.js';
5
16
  export { detectChangeHash } from './utils/change-hash.js';
6
17
  export { LOG_LEVELS, Logger, resolveRootLogLevel } from './utils/logger.js';
@@ -0,0 +1,135 @@
1
+ /**
2
+ * The shape of `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` (and `package.json`'s own
3
+ * `"rman"` key) - see docs/api.md#configuration-rmanrc-rmanrcyml for the full reference. Every
4
+ * field is optional and cascades from the repository root down to each package's own directory.
5
+ * Purely a typing aid (used by `defineConfig` below, and importable on its own for a `.rmanrc.ts`/
6
+ * `.mts` authored config, or a plain `: RmanConfig` annotation) - never read by rman itself, which
7
+ * only ever sees the plain JS object a JS config file exports.
8
+ */
9
+ export interface RmanConfig {
10
+ packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
11
+ logLevel?: 'silent' | 'error' | 'info' | 'verbose';
12
+ allowBranch?: string | string[];
13
+ ignoreBranch?: string | string[];
14
+ group?: boolean | string;
15
+ version?: RmanConfig.VersionOptions;
16
+ changelog?: RmanConfig.ChangelogOptions;
17
+ clean?: RmanConfig.CleanOptions;
18
+ publish?: RmanConfig.PublishOptions;
19
+ githubRelease?: RmanConfig.GithubReleaseOptions;
20
+ /** Keyed by npm script name (e.g. `"build"`, `"lint"`, `"test"`). */
21
+ run?: Record<string, RmanConfig.RunScriptOptions>;
22
+ /** Keyed by the in-repo package's own name. */
23
+ packages?: Record<string, RmanConfig.PackageOptions>;
24
+ }
25
+ export declare namespace RmanConfig {
26
+ interface VersionOptions {
27
+ commitMessage?: string;
28
+ /** Default for `version --changelog` when the CLI flag isn't given - a standing "always fold
29
+ * the changelog into the version-bump commit" policy, rather than something that behaves
30
+ * differently on the one run someone forgets to pass `--changelog`. An explicit `--changelog`/
31
+ * `--no-changelog` on the command line still wins either way. Root-level only. Default `false`. */
32
+ changelog?: boolean;
33
+ /** Tag naming the repository's own release, as opposed to the per-package/group tags
34
+ * `changelog.tagPattern` names - only created when the root is on a calendar version (a repo
35
+ * with more than one version line). Root-level only. Default `"release-*"`. Must **not** match
36
+ * any package's own `changelog.tagPattern`, or that package's changelog boundary will resolve
37
+ * to the repository release instead of its own last release. */
38
+ releaseTagPattern?: string;
39
+ script?: string | string[];
40
+ preScript?: string | string[];
41
+ postScript?: string | string[];
42
+ }
43
+ interface ChangelogOptions {
44
+ ignoreTypes?: string[];
45
+ template?: string;
46
+ filePath?: string;
47
+ tagPattern?: string;
48
+ }
49
+ interface CleanOptions {
50
+ include?: string | string[];
51
+ exclude?: string | string[];
52
+ skip?: boolean;
53
+ }
54
+ interface RunScriptOptions {
55
+ concurrency?: number;
56
+ topo?: boolean;
57
+ bail?: boolean;
58
+ progress?: boolean;
59
+ logLevel?: 'silent' | 'error' | 'info' | 'verbose';
60
+ changedSince?: string;
61
+ skip?: boolean;
62
+ if?: string;
63
+ script?: string | string[];
64
+ preScript?: string | string[];
65
+ postScript?: string | string[];
66
+ override?: boolean;
67
+ }
68
+ interface PackageOptions {
69
+ dependencies?: string[] | Record<string, string>;
70
+ }
71
+ interface PublishOptions {
72
+ /** Which **registry** `publish` ships this package to - default `['npm']` (every existing repo
73
+ * keeps working unchanged). A package that only ever wants Docker images (typically also
74
+ * `"private": true`, since it's not meant for npm at all) sets `['docker']`; both works too.
75
+ * Each target answers "is this version already out there?" against its own registry, so a
76
+ * package is never left without one: npm via `npm view`, docker via `docker manifest inspect`.
77
+ *
78
+ * Note this is strictly about *package distribution*. The repository's GitHub Release is not
79
+ * a target here - it isn't a place a package ships to, it's the repository's own record that
80
+ * a release happened, and it is never opted into: see `githubRelease` and the
81
+ * `github-release` command. */
82
+ target?: PublishTarget | PublishTarget[];
83
+ docker?: DockerPublishOptions;
84
+ /** Excludes this package from `publish` entirely (every target), regardless of
85
+ * `target`/`"private"` - a single, explicit "never published" statement, e.g. for a package
86
+ * released through some separate, unrelated process. `changelog` also skips it by default
87
+ * (see its own `--include-skipped`) - there's little point changelogging something that's
88
+ * never actually released. Independent of `version`, which never consults this at all - a
89
+ * package can still be meaningfully versioned without ever being published. */
90
+ skip?: boolean;
91
+ }
92
+ type PublishTarget = 'npm' | 'docker';
93
+ /** Required once `"docker"` is one of this package's `publish.target`s - `publish --target
94
+ * docker` errors clearly on a package that opts in here but leaves this out. */
95
+ interface DockerPublishOptions {
96
+ /** DockerHub image name/repository - bare (e.g. `"my-app"`) to be prefixed with
97
+ * `--docker-namespace`/`DOCKERHUB_NAMESPACE`, or already-namespaced (contains a `/`) to use
98
+ * verbatim. */
99
+ image: string;
100
+ /** Relative to the package's own directory. Default `"Dockerfile"`. */
101
+ dockerfile?: string;
102
+ /** Default `["linux/amd64"]`. */
103
+ platforms?: string[];
104
+ /** Build `cwd` override, relative to the repository root - only needed when the Dockerfile's
105
+ * own `COPY`/`ADD` paths expect something other than the package's own directory (rare). */
106
+ cwd?: string;
107
+ /** Named `docker buildx build --build-context <name>=<path>` entries, keyed by name - each
108
+ * path is relative to the package's own directory (or absolute). */
109
+ buildContexts?: Record<string, string>;
110
+ /** `docker buildx build --build-arg <name>=<value>` entries - a value of exactly `"$NAME"`
111
+ * expands to `process.env.NAME` at build time (e.g. to pass a CI secret through). */
112
+ buildArgs?: Record<string, string>;
113
+ /** A file (relative to the package's own directory) whose contents become the DockerHub repo's
114
+ * full description, if present. Default `"DOCKER_README.md"`. */
115
+ readme?: string;
116
+ }
117
+ /** Entirely optional - `github-release` needs no configuration at all, since every required fact
118
+ * (which tag, which repository, what the notes say) already has a sensible source. Nothing here
119
+ * decides *whether* a release is cut: a release records that the repository shipped, so it is
120
+ * always cut, and these are only details about how. */
121
+ interface GithubReleaseOptions {
122
+ /** Files to attach to the release, as glob patterns relative to the package's own directory
123
+ * (e.g. `["dist/*.tar.gz"]`). Read from **every** package, since one release covers the whole
124
+ * source tree. A release with no assets at all is still perfectly valid - it records that the
125
+ * version shipped, which is all a deploy-elsewhere package needs. */
126
+ assets?: string[];
127
+ /** `owner/repo`. Default: parsed from the `origin` remote's URL. Root-level only. */
128
+ repository?: string;
129
+ /** Create the release as an unpublished draft. Default `false`. Root-level only. */
130
+ draft?: boolean;
131
+ /** Default: whether the version being released is itself a semver prerelease (`1.3.0-beta.0`).
132
+ * Root-level only. */
133
+ prerelease?: boolean;
134
+ }
135
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "rman",
3
3
  "description": "Repository manager",
4
- "version": "1.0.8",
4
+ "version": "1.0.10",
5
5
  "author": "Panates",
6
6
  "license": "MIT",
7
7
  "dependencies": {