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 +20 -4
- package/cli.js +2 -0
- package/commands/changelog.command.js +16 -6
- package/commands/github-release.command.d.ts +3 -0
- package/commands/github-release.command.js +119 -0
- package/commands/publish.command.js +29 -5
- package/commands/version.command.js +4 -2
- package/constants.js +1 -1
- package/core/config.d.ts +1 -99
- package/core/package.d.ts +1 -1
- package/index.d.ts +1 -1
- package/index.js +11 -0
- package/interfaces/rman-config.interface.d.ts +135 -0
- package/interfaces/rman-config.interface.js +1 -0
- package/package.json +1 -1
- package/rmanrc.schema.json +123 -20
- package/services/changelog.service.d.ts +21 -12
- package/services/changelog.service.js +17 -16
- package/services/github-release.service.d.ts +69 -0
- package/services/github-release.service.js +258 -0
- package/services/list.service.d.ts +1 -1
- package/services/version.service.d.ts +15 -4
- package/services/version.service.js +70 -32
- package/services.d.ts +1 -0
- package/services.js +1 -0
- package/utils/change-hash.d.ts +21 -12
- package/utils/change-hash.js +38 -26
- package/utils/conventional-commits.d.ts +13 -0
- package/utils/conventional-commits.js +47 -0
- package/utils/git.d.ts +8 -1
- package/utils/git.js +26 -2
- package/utils/release-version.d.ts +50 -0
- package/utils/release-version.js +66 -0
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
15
|
-
"falling back to
|
|
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
|
-
//
|
|
43
|
-
//
|
|
44
|
-
|
|
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,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
|
|
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
|
-
|
|
91
|
-
|
|
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
|
|
112
|
-
|
|
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
|
|
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.
|
|
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
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 {};
|