rman 1.0.2 → 1.0.5
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 +21 -10
- package/cli.js +1 -1
- package/commands/version.command.js +35 -16
- package/constants.js +1 -1
- package/core/config.d.ts +77 -3
- package/core/config.js +61 -5
- package/core/package.d.ts +2 -1
- package/core/repository.d.ts +6 -2
- package/core/repository.js +17 -8
- package/index.d.ts +2 -0
- package/index.js +1 -10
- package/package.json +1 -1
- package/rmanrc.schema.json +1 -1
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
Changesets, and a handful of shell scripts glued together. One tool for running scripts across
|
|
10
10
|
packages, computing semantic version bumps from your commit history, publishing, changelogs,
|
|
11
11
|
importing external repos with history intact, and more - all driven by a single, cascading
|
|
12
|
-
`.rmanrc`/`.
|
|
12
|
+
`.rmanrc`/`.rmanrc.yml` config.
|
|
13
13
|
|
|
14
14
|
Every command is also available as a **programmatic API** - see [docs/api.md](docs/api.md) if you
|
|
15
15
|
want to call `rman`'s logic directly from a Node.js script instead of shelling out to the CLI.
|
|
@@ -243,6 +243,7 @@ rman version --changelog # also write/fold in each bumped package's CHAN
|
|
|
243
243
|
rman version patch --push # commit, tag, and push in one go
|
|
244
244
|
rman version patch --message "chore(release): {version}"
|
|
245
245
|
rman version --ignore-dirty # exclude dirty packages instead of aborting the whole run
|
|
246
|
+
rman version patch --show # preview what an explicit patch bump would do, without applying it
|
|
246
247
|
```
|
|
247
248
|
|
|
248
249
|
Severity, when not given explicitly, is auto-detected per package/group from
|
|
@@ -298,12 +299,13 @@ covered, then run `rman ci` to install it.
|
|
|
298
299
|
|
|
299
300
|
`rman` reads config cascaded from the repository root down to each package's own directory (the
|
|
300
301
|
same way a `tsconfig.json` `extends` chain works) - a value set closer to a package overrides the
|
|
301
|
-
same key set further up.
|
|
302
|
-
precedence: `package.json`'s own `"rman"` key, `.
|
|
303
|
-
the dotfile-style name).
|
|
302
|
+
same key set further up. Several file forms are supported per directory, merged in increasing
|
|
303
|
+
precedence: `package.json`'s own `"rman"` key, `.rmanrc.yml` (YAML), `.rmanrc` (**JSON**, despite
|
|
304
|
+
the dotfile-style name), and `.rmanrc.cjs`/`.rmanrc.mjs`/`.rmanrc.js` for config that needs real
|
|
305
|
+
logic (a JS module's default export).
|
|
304
306
|
|
|
305
307
|
```yaml
|
|
306
|
-
# .
|
|
308
|
+
# .rmanrc.yml, at the repository root
|
|
307
309
|
packageManager: pnpm
|
|
308
310
|
logLevel: info
|
|
309
311
|
allowBranch: [main, release/*]
|
|
@@ -337,14 +339,23 @@ run:
|
|
|
337
339
|
{ "group": "plugins" }
|
|
338
340
|
```
|
|
339
341
|
|
|
340
|
-
See [docs/api.md#configuration-rmanrc-
|
|
342
|
+
See [docs/api.md#configuration-rmanrc-rmanrcyml](docs/api.md#configuration-rmanrc-rmanrcyml) for the
|
|
341
343
|
full key reference (every `run.<script>.*` sub-key, `clean.*`, `changelog.*`, precedence rules,
|
|
342
344
|
and which keys are root-level-only today).
|
|
343
345
|
|
|
344
|
-
**Editor autocomplete:** `rman` ships a JSON Schema for `.rmanrc`/`.
|
|
346
|
+
**Editor autocomplete:** `rman` ships a JSON Schema for `.rmanrc`/`.rmanrc.yml` at
|
|
345
347
|
`rman/rmanrc.schema.json` - add `"$schema": "./node_modules/rman/rmanrc.schema.json"` to your
|
|
346
|
-
`.rmanrc` (or the equivalent `# yaml-language-server: $schema=...` comment in `.
|
|
347
|
-
autocomplete and validation in VS Code/WebStorm.
|
|
348
|
+
`.rmanrc` (or the equivalent `# yaml-language-server: $schema=...` comment in `.rmanrc.yml`) to get
|
|
349
|
+
autocomplete and validation in VS Code/WebStorm. For a `.rmanrc.cjs`/`.mjs`/`.js` config, wrap it in
|
|
350
|
+
the exported `defineConfig()` helper instead for the same autocomplete via the `RmanConfig` type:
|
|
351
|
+
|
|
352
|
+
```js
|
|
353
|
+
// .rmanrc.mjs
|
|
354
|
+
import { defineConfig } from 'rman';
|
|
355
|
+
export default defineConfig({ packageManager: 'pnpm' });
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
See
|
|
348
359
|
[docs/api.md#editor-support-json-schema](docs/api.md#editor-support-json-schema) for details,
|
|
349
360
|
including a WebStorm setup that needs no changes to the config file itself.
|
|
350
361
|
|
|
@@ -356,7 +367,7 @@ from your own Node.js scripts without shelling out to the `rman` binary:
|
|
|
356
367
|
```ts
|
|
357
368
|
import { Repository, VersionService } from 'rman';
|
|
358
369
|
|
|
359
|
-
const repository = Repository.create();
|
|
370
|
+
const repository = await Repository.create();
|
|
360
371
|
const plan = await VersionService.getPlan(repository);
|
|
361
372
|
await VersionService.applyPlan(repository, plan, { changelog: true, push: true });
|
|
362
373
|
```
|
package/cli.js
CHANGED
|
@@ -23,7 +23,7 @@ import { Repository } from './core/repository.js';
|
|
|
23
23
|
import { LOG_LEVELS } from './utils/logger.js';
|
|
24
24
|
export async function runCli(options) {
|
|
25
25
|
try {
|
|
26
|
-
const repository = Repository.create(options?.cwd);
|
|
26
|
+
const repository = await Repository.create(options?.cwd);
|
|
27
27
|
const _argv = options?.argv || hideBin(process.argv);
|
|
28
28
|
const program = yargs(_argv)
|
|
29
29
|
.scriptName('rman')
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import readline from 'node:readline/promises';
|
|
2
2
|
import colors from 'ansi-colors';
|
|
3
|
+
import EasyTable from 'easy-table';
|
|
3
4
|
import { VersionService } from '../services/version.service.js';
|
|
4
5
|
import { applyBranchGuardOptions, assertAllowedBranch, readBranchGuardOptions } from '../utils/branch-guard.js';
|
|
5
6
|
import { applyPackageFilterOptions, readPackageFilterOptions } from '../utils/package-filter.js';
|
|
@@ -11,6 +12,7 @@ export function initCli(repository, program) {
|
|
|
11
12
|
.example('$0 version patch', '# Bump patch severity directly, applied immediately')
|
|
12
13
|
.example('$0 version', "# Auto-detect severity from commits, show the plan, don't write anything")
|
|
13
14
|
.example('$0 version --interactive', '# Show the plan either way, then ask for confirmation')
|
|
15
|
+
.example('$0 version patch --show', '# Preview what an explicit patch bump would do, without applying it')
|
|
14
16
|
.positional('bump', {
|
|
15
17
|
describe: 'A release-type keyword ("patch"/"minor"/"major") or an explicit semver version. ' +
|
|
16
18
|
'Omit to auto-detect from commits and only preview the plan.',
|
|
@@ -21,6 +23,13 @@ export function initCli(repository, program) {
|
|
|
21
23
|
describe: 'Show the plan and ask for confirmation before applying (with or without an explicit bump)',
|
|
22
24
|
type: 'boolean',
|
|
23
25
|
})
|
|
26
|
+
.option('show', {
|
|
27
|
+
describe: 'Show the resulting plan for the given bump without applying it - unlike omitting bump ' +
|
|
28
|
+
'entirely, this still uses the given release-type keyword/version to compute the plan, ' +
|
|
29
|
+
'just never writes it.',
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
})
|
|
32
|
+
.conflicts('show', 'interactive')
|
|
24
33
|
.option('ignore-dirty', {
|
|
25
34
|
describe: 'Exclude a package with uncommitted local changes instead of aborting the whole run',
|
|
26
35
|
type: 'boolean',
|
|
@@ -70,6 +79,10 @@ export function initCli(repository, program) {
|
|
|
70
79
|
console.log(colors.gray('Nothing to version.'));
|
|
71
80
|
return;
|
|
72
81
|
}
|
|
82
|
+
if (args.show) {
|
|
83
|
+
console.log(colors.gray('Preview only (--show) - nothing was written.'));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
73
86
|
let apply = !!bump;
|
|
74
87
|
if (args.interactive) {
|
|
75
88
|
apply = await confirm('Apply these changes?');
|
|
@@ -94,23 +107,29 @@ export function initCli(repository, program) {
|
|
|
94
107
|
});
|
|
95
108
|
}
|
|
96
109
|
function printPlan(entries) {
|
|
110
|
+
const table = new EasyTable();
|
|
97
111
|
for (const e of entries) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
112
|
+
table.cell('Status', statusLabel(e.status));
|
|
113
|
+
table.cell('Package', colors.cyan(e.package.name));
|
|
114
|
+
table.cell('Group', colors.gray(`(${e.group})`));
|
|
115
|
+
table.cell('From', e.from);
|
|
116
|
+
table.cell('', e.status === 'bump' ? '->' : '');
|
|
117
|
+
table.cell('To', e.status === 'bump' ? colors.yellow(e.to) : '');
|
|
118
|
+
table.cell('Reason', e.status === 'error' ? colors.red(e.reason ?? '') : colors.gray(e.reason ?? ''));
|
|
119
|
+
table.newRow();
|
|
120
|
+
}
|
|
121
|
+
console.log(table.toString().trim());
|
|
122
|
+
}
|
|
123
|
+
function statusLabel(status) {
|
|
124
|
+
switch (status) {
|
|
125
|
+
case 'bump':
|
|
126
|
+
return colors.green('bump');
|
|
127
|
+
case 'no-change':
|
|
128
|
+
return colors.gray('no-change');
|
|
129
|
+
case 'skip':
|
|
130
|
+
return colors.cyan('skip');
|
|
131
|
+
case 'error':
|
|
132
|
+
return colors.red('error');
|
|
114
133
|
}
|
|
115
134
|
}
|
|
116
135
|
async function confirm(question) {
|
package/constants.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '1.0.
|
|
1
|
+
export const version = '1.0.5';
|
package/core/config.d.ts
CHANGED
|
@@ -1,8 +1,82 @@
|
|
|
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
|
+
/** Keyed by npm script name (e.g. `"build"`, `"lint"`, `"test"`). */
|
|
19
|
+
run?: Record<string, RmanConfig.RunScriptOptions>;
|
|
20
|
+
/** Keyed by the in-repo package's own name. */
|
|
21
|
+
packages?: Record<string, RmanConfig.PackageOptions>;
|
|
22
|
+
}
|
|
23
|
+
export declare namespace RmanConfig {
|
|
24
|
+
interface VersionOptions {
|
|
25
|
+
commitMessage?: string;
|
|
26
|
+
script?: string | string[];
|
|
27
|
+
preScript?: string | string[];
|
|
28
|
+
postScript?: string | string[];
|
|
29
|
+
}
|
|
30
|
+
interface ChangelogOptions {
|
|
31
|
+
ignoreTypes?: string[];
|
|
32
|
+
template?: string;
|
|
33
|
+
filePath?: string;
|
|
34
|
+
tagPattern?: string;
|
|
35
|
+
}
|
|
36
|
+
interface CleanOptions {
|
|
37
|
+
include?: string | string[];
|
|
38
|
+
exclude?: string | string[];
|
|
39
|
+
skip?: boolean;
|
|
40
|
+
}
|
|
41
|
+
interface RunScriptOptions {
|
|
42
|
+
concurrency?: number;
|
|
43
|
+
topo?: boolean;
|
|
44
|
+
bail?: boolean;
|
|
45
|
+
progress?: boolean;
|
|
46
|
+
logLevel?: 'silent' | 'error' | 'info' | 'verbose';
|
|
47
|
+
changedSince?: string;
|
|
48
|
+
skip?: boolean;
|
|
49
|
+
if?: string;
|
|
50
|
+
script?: string | string[];
|
|
51
|
+
preScript?: string | string[];
|
|
52
|
+
postScript?: string | string[];
|
|
53
|
+
override?: boolean;
|
|
54
|
+
}
|
|
55
|
+
interface PackageOptions {
|
|
56
|
+
dependencies?: string[] | Record<string, string>;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Identity helper for authoring a `.rmanrc.cjs`/`.mjs`/`.js` config with full type-checking and
|
|
61
|
+
* autocomplete - the same `defineConfig` pattern Vite/Vitest use. Returns `config` completely
|
|
62
|
+
* unchanged; this exists purely so TypeScript can infer/check against `RmanConfig`, not for any
|
|
63
|
+
* runtime behavior:
|
|
64
|
+
*
|
|
65
|
+
* // .rmanrc.mjs
|
|
66
|
+
* import { defineConfig } from 'rman';
|
|
67
|
+
* export default defineConfig({ packageManager: 'pnpm' });
|
|
68
|
+
*
|
|
69
|
+
* // .rmanrc.cjs
|
|
70
|
+
* const { defineConfig } = require('rman');
|
|
71
|
+
* module.exports = defineConfig({ packageManager: 'pnpm' });
|
|
72
|
+
*/
|
|
73
|
+
export declare function defineConfig(config: RmanConfig): RmanConfig;
|
|
1
74
|
/**
|
|
2
75
|
* Reads the rman configuration defined at a single directory level, merging
|
|
3
|
-
* (in increasing precedence): `package.json#rman`, `.
|
|
76
|
+
* (in increasing precedence): `package.json#rman`, `.rmanrc.yml`, `.rmanrc`,
|
|
77
|
+
* then `.rmanrc.cjs`/`.rmanrc.mjs`/`.rmanrc.js` (whichever exist, in that order).
|
|
4
78
|
*/
|
|
5
|
-
export declare function readDirConfig(dirname: string):
|
|
79
|
+
export declare function readDirConfig(dirname: string): Promise<RmanConfig>;
|
|
6
80
|
/**
|
|
7
81
|
* Resolves the effective config for `targetDir` by cascading from `rootDir`
|
|
8
82
|
* down to `targetDir` (inclusive), the same way tsconfig's `extends` chain
|
|
@@ -10,4 +84,4 @@ export declare function readDirConfig(dirname: string): any;
|
|
|
10
84
|
* package (or any intermediate directory) narrow or override the repository's
|
|
11
85
|
* root configuration for itself and everything below it.
|
|
12
86
|
*/
|
|
13
|
-
export declare function resolveConfig(rootDir: string, targetDir: string, cache?: Map<string,
|
|
87
|
+
export declare function resolveConfig(rootDir: string, targetDir: string, cache?: Map<string, RmanConfig>): Promise<RmanConfig>;
|
package/core/config.js
CHANGED
|
@@ -1,12 +1,60 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import * as yaml from 'js-yaml';
|
|
3
|
+
import { createRequire } from 'module';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import merge from 'putil-merge';
|
|
6
|
+
import { pathToFileURL } from 'url';
|
|
7
|
+
/**
|
|
8
|
+
* Identity helper for authoring a `.rmanrc.cjs`/`.mjs`/`.js` config with full type-checking and
|
|
9
|
+
* autocomplete - the same `defineConfig` pattern Vite/Vitest use. Returns `config` completely
|
|
10
|
+
* unchanged; this exists purely so TypeScript can infer/check against `RmanConfig`, not for any
|
|
11
|
+
* runtime behavior:
|
|
12
|
+
*
|
|
13
|
+
* // .rmanrc.mjs
|
|
14
|
+
* import { defineConfig } from 'rman';
|
|
15
|
+
* export default defineConfig({ packageManager: 'pnpm' });
|
|
16
|
+
*
|
|
17
|
+
* // .rmanrc.cjs
|
|
18
|
+
* const { defineConfig } = require('rman');
|
|
19
|
+
* module.exports = defineConfig({ packageManager: 'pnpm' });
|
|
20
|
+
*/
|
|
21
|
+
export function defineConfig(config) {
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
/** `.rmanrc.cjs`/`.rmanrc.mjs`/`.rmanrc.js`, checked in this order - a JS module whose default
|
|
25
|
+
* export (or, lacking one, the module's own exports object) is the config. Both CommonJS (`.cjs`,
|
|
26
|
+
* or a `.js` under a `"type": "commonjs"` package.json) and native ESM (`.mjs`, or a `.js` under
|
|
27
|
+
* `"type": "module"`) are supported - the reason `readDirConfig`/`resolveConfig` are async at all. */
|
|
28
|
+
const JS_CONFIG_FILES = ['.rmanrc.cjs', '.rmanrc.mjs', '.rmanrc.js'];
|
|
29
|
+
const requireJsConfig = createRequire(import.meta.url);
|
|
30
|
+
/**
|
|
31
|
+
* Loads `file`'s config object. Tries `require()` first - not just an optimization: a CommonJS
|
|
32
|
+
* module's `module.exports` is more reliably observed this way than through dynamic `import()`'s
|
|
33
|
+
* CJS-interop synthesis, which some ESM loader hooks (e.g. ts-node/swc-node-style transpilers
|
|
34
|
+
* registered via `--import`) can end up short-circuiting into an empty object. `require()` throws
|
|
35
|
+
* `ERR_REQUIRE_ESM` for a genuinely-ESM file (`.mjs`, or `.js` under `"type": "module"`) - only
|
|
36
|
+
* then does this fall back to `import()`, the one case that actually needs it. Either path can
|
|
37
|
+
* hand back an ES module namespace instead of a plain object (Node's `require(esm)` support does
|
|
38
|
+
* this too, not just `import()`), so `.default` is preferred whenever present.
|
|
39
|
+
*/
|
|
40
|
+
async function loadJsConfig(file) {
|
|
41
|
+
let mod;
|
|
42
|
+
try {
|
|
43
|
+
mod = requireJsConfig(file);
|
|
44
|
+
}
|
|
45
|
+
catch (e) {
|
|
46
|
+
if (e?.code !== 'ERR_REQUIRE_ESM')
|
|
47
|
+
throw e;
|
|
48
|
+
mod = await import(pathToFileURL(file).href);
|
|
49
|
+
}
|
|
50
|
+
return mod?.default ?? mod;
|
|
51
|
+
}
|
|
5
52
|
/**
|
|
6
53
|
* Reads the rman configuration defined at a single directory level, merging
|
|
7
|
-
* (in increasing precedence): `package.json#rman`, `.
|
|
54
|
+
* (in increasing precedence): `package.json#rman`, `.rmanrc.yml`, `.rmanrc`,
|
|
55
|
+
* then `.rmanrc.cjs`/`.rmanrc.mjs`/`.rmanrc.js` (whichever exist, in that order).
|
|
8
56
|
*/
|
|
9
|
-
export function readDirConfig(dirname) {
|
|
57
|
+
export async function readDirConfig(dirname) {
|
|
10
58
|
const result = {};
|
|
11
59
|
const pkgJsonFile = path.join(dirname, 'package.json');
|
|
12
60
|
if (fs.existsSync(pkgJsonFile)) {
|
|
@@ -14,7 +62,7 @@ export function readDirConfig(dirname) {
|
|
|
14
62
|
if (pkgJson && typeof pkgJson.rman === 'object')
|
|
15
63
|
merge(result, pkgJson.rman, { deep: true });
|
|
16
64
|
}
|
|
17
|
-
const ymlFile = path.join(dirname, '.
|
|
65
|
+
const ymlFile = path.join(dirname, '.rmanrc.yml');
|
|
18
66
|
if (fs.existsSync(ymlFile)) {
|
|
19
67
|
const obj = yaml.load(fs.readFileSync(ymlFile, 'utf-8'));
|
|
20
68
|
if (obj && typeof obj === 'object')
|
|
@@ -26,6 +74,14 @@ export function readDirConfig(dirname) {
|
|
|
26
74
|
if (obj && typeof obj === 'object')
|
|
27
75
|
merge(result, obj, { deep: true });
|
|
28
76
|
}
|
|
77
|
+
for (const jsFileName of JS_CONFIG_FILES) {
|
|
78
|
+
const jsFile = path.join(dirname, jsFileName);
|
|
79
|
+
if (fs.existsSync(jsFile)) {
|
|
80
|
+
const obj = await loadJsConfig(jsFile);
|
|
81
|
+
if (obj && typeof obj === 'object')
|
|
82
|
+
merge(result, obj, { deep: true });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
29
85
|
return result;
|
|
30
86
|
}
|
|
31
87
|
/**
|
|
@@ -35,12 +91,12 @@ export function readDirConfig(dirname) {
|
|
|
35
91
|
* package (or any intermediate directory) narrow or override the repository's
|
|
36
92
|
* root configuration for itself and everything below it.
|
|
37
93
|
*/
|
|
38
|
-
export function resolveConfig(rootDir, targetDir, cache = new Map()) {
|
|
94
|
+
export async function resolveConfig(rootDir, targetDir, cache = new Map()) {
|
|
39
95
|
const result = {};
|
|
40
96
|
for (const dir of dirChain(rootDir, targetDir)) {
|
|
41
97
|
let local = cache.get(dir);
|
|
42
98
|
if (!local) {
|
|
43
|
-
local = readDirConfig(dir);
|
|
99
|
+
local = await readDirConfig(dir);
|
|
44
100
|
cache.set(dir, local);
|
|
45
101
|
}
|
|
46
102
|
merge(result, local, { deep: true });
|
package/core/package.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import type { RmanConfig } from './config.js';
|
|
1
2
|
export declare class Package {
|
|
2
3
|
readonly dirname: string;
|
|
3
4
|
private _json;
|
|
4
5
|
dependencies: string[];
|
|
5
6
|
/** Effective rman config for this package, cascaded from the repository root. */
|
|
6
|
-
config:
|
|
7
|
+
config: RmanConfig;
|
|
7
8
|
constructor(dirname: string);
|
|
8
9
|
get basename(): string;
|
|
9
10
|
get name(): string;
|
package/core/repository.d.ts
CHANGED
|
@@ -41,11 +41,15 @@ export declare class Repository extends Package {
|
|
|
41
41
|
* package, cascading root -> intermediate directories -> package directory,
|
|
42
42
|
* so a `.rmanrc` placed anywhere along that path overrides the levels above it.
|
|
43
43
|
*/
|
|
44
|
-
protected _resolveConfigs(): void
|
|
44
|
+
protected _resolveConfigs(): Promise<void>;
|
|
45
45
|
protected _updateDependencies(): void;
|
|
46
46
|
static create(root?: string, options?: {
|
|
47
47
|
deep?: number;
|
|
48
|
-
}): Repository
|
|
48
|
+
}): Promise<Repository>;
|
|
49
|
+
/** Finishes constructing `repo` with the async work a constructor can't do itself - resolving
|
|
50
|
+
* `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` config (which may need a dynamic `import()`)
|
|
51
|
+
* before the dependency graph is built from it. */
|
|
52
|
+
private static _init;
|
|
49
53
|
protected static _resolvePackages(dirname: string, patterns: string[]): Package[];
|
|
50
54
|
}
|
|
51
55
|
export declare namespace Repository {
|
package/core/repository.js
CHANGED
|
@@ -23,8 +23,9 @@ export class Repository extends Package {
|
|
|
23
23
|
this.rootPackage = new Package(dirname);
|
|
24
24
|
if (!monorepo)
|
|
25
25
|
this.packages = [this.rootPackage];
|
|
26
|
-
|
|
27
|
-
this
|
|
26
|
+
// Config resolution can load a `.rmanrc.cjs`/`.mjs`/`.js` module (dynamic `import()`, always
|
|
27
|
+
// async) - a constructor can't `await`, so `create()` finishes this instance off via `_init()`
|
|
28
|
+
// once construction itself (synchronous) completes.
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
31
|
* The package whose own directory contains `cwd` (the deepest match, so a package nested
|
|
@@ -90,15 +91,15 @@ export class Repository extends Package {
|
|
|
90
91
|
* package, cascading root -> intermediate directories -> package directory,
|
|
91
92
|
* so a `.rmanrc` placed anywhere along that path overrides the levels above it.
|
|
92
93
|
*/
|
|
93
|
-
_resolveConfigs() {
|
|
94
|
+
async _resolveConfigs() {
|
|
94
95
|
const cache = new Map();
|
|
95
|
-
const rootConfig = resolveConfig(this.dirname, this.dirname, cache);
|
|
96
|
+
const rootConfig = await resolveConfig(this.dirname, this.dirname, cache);
|
|
96
97
|
this.config = rootConfig;
|
|
97
98
|
this.rootPackage.config = rootConfig;
|
|
98
99
|
for (const pkg of this.packages) {
|
|
99
100
|
if (pkg === this.rootPackage)
|
|
100
101
|
continue;
|
|
101
|
-
pkg.config = resolveConfig(this.dirname, pkg.dirname, cache);
|
|
102
|
+
pkg.config = await resolveConfig(this.dirname, pkg.dirname, cache);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
_updateDependencies() {
|
|
@@ -149,7 +150,7 @@ export class Repository extends Package {
|
|
|
149
150
|
deepFindDependencies(pkg, pkg.dependencies);
|
|
150
151
|
}
|
|
151
152
|
}
|
|
152
|
-
static create(root, options) {
|
|
153
|
+
static async create(root, options) {
|
|
153
154
|
const dirname = root || process.cwd();
|
|
154
155
|
let deep = options?.deep ?? 10;
|
|
155
156
|
let pkgDirname = dirname;
|
|
@@ -159,7 +160,7 @@ export class Repository extends Package {
|
|
|
159
160
|
const pkgJson = JSON.parse(fs.readFileSync(f, 'utf-8'));
|
|
160
161
|
if (Array.isArray(pkgJson.workspaces)) {
|
|
161
162
|
const packages = this._resolvePackages(pkgDirname, pkgJson.workspaces);
|
|
162
|
-
return new Repository(pkgDirname, true, packages, dirname);
|
|
163
|
+
return Repository._init(new Repository(pkgDirname, true, packages, dirname));
|
|
163
164
|
}
|
|
164
165
|
/** If we reach to the root of the project */
|
|
165
166
|
if (fs.existsSync(path.join(pkgDirname, '.git')))
|
|
@@ -167,7 +168,15 @@ export class Repository extends Package {
|
|
|
167
168
|
}
|
|
168
169
|
pkgDirname = path.resolve(pkgDirname, '..');
|
|
169
170
|
}
|
|
170
|
-
return new Repository(dirname, false, [], dirname);
|
|
171
|
+
return Repository._init(new Repository(dirname, false, [], dirname));
|
|
172
|
+
}
|
|
173
|
+
/** Finishes constructing `repo` with the async work a constructor can't do itself - resolving
|
|
174
|
+
* `.rmanrc`/`.rmanrc.yml`/`.rmanrc.cjs`/`.mjs`/`.js` config (which may need a dynamic `import()`)
|
|
175
|
+
* before the dependency graph is built from it. */
|
|
176
|
+
static async _init(repo) {
|
|
177
|
+
await repo._resolveConfigs();
|
|
178
|
+
repo._updateDependencies();
|
|
179
|
+
return repo;
|
|
171
180
|
}
|
|
172
181
|
static _resolvePackages(dirname, patterns) {
|
|
173
182
|
const packages = [];
|
package/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
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
|
+
export { defineConfig } from './core/config.js';
|
|
11
13
|
export { Package } from './core/package.js';
|
|
12
14
|
export { Repository } from './core/repository.js';
|
|
13
15
|
export * from './services.js';
|
package/index.js
CHANGED
|
@@ -1,13 +1,4 @@
|
|
|
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
|
+
export { defineConfig } from './core/config.js';
|
|
11
2
|
export { Package } from './core/package.js';
|
|
12
3
|
export { Repository } from './core/repository.js';
|
|
13
4
|
export * from './services.js';
|
package/package.json
CHANGED
package/rmanrc.schema.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
3
|
"$id": "https://raw.githubusercontent.com/panates/rman/main/schemas/rmanrc.schema.json",
|
|
4
4
|
"title": "rman configuration",
|
|
5
|
-
"description": "Schema for rman's .rmanrc (JSON) and .
|
|
5
|
+
"description": "Schema for rman's .rmanrc (JSON) and .rmanrc.yml (YAML) config files, and the \"rman\" key in package.json. See docs/api.md#configuration-rmanrc-rmanrcyml for the full reference.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"$schema": {
|