@rainy-updates/cli 0.5.0-rc.2 → 0.5.1-rc.1
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/CHANGELOG.md +62 -0
- package/README.md +11 -0
- package/dist/bin/cli.js +82 -27
- package/dist/cache/cache.d.ts +2 -0
- package/dist/cache/cache.js +8 -3
- package/dist/config/loader.d.ts +9 -1
- package/dist/config/policy.d.ts +21 -4
- package/dist/config/policy.js +39 -7
- package/dist/core/check.js +142 -10
- package/dist/core/ci.d.ts +2 -0
- package/dist/core/ci.js +30 -0
- package/dist/core/fix-pr.js +24 -9
- package/dist/core/init-ci.js +3 -3
- package/dist/core/options.d.ts +3 -0
- package/dist/core/options.js +122 -4
- package/dist/core/summary.d.ts +26 -0
- package/dist/core/summary.js +82 -0
- package/dist/core/warm-cache.js +34 -5
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/output/format.js +25 -1
- package/dist/output/github.js +24 -9
- package/dist/output/pr-report.js +4 -0
- package/dist/output/sarif.js +20 -2
- package/dist/registry/npm.d.ts +2 -0
- package/dist/registry/npm.js +68 -6
- package/dist/types/index.d.ts +40 -4
- package/dist/utils/io.d.ts +1 -0
- package/dist/utils/io.js +10 -0
- package/dist/utils/stable-json.d.ts +1 -0
- package/dist/utils/stable-json.js +20 -0
- package/dist/workspace/discover.js +7 -1
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.5.1-rc.1] - 2026-02-27
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- New `ci` command for CI-first orchestration:
|
|
10
|
+
- profile-driven automation with `--mode minimal|strict|enterprise`,
|
|
11
|
+
- warm-cache + check/upgrade flow with deterministic artifacts.
|
|
12
|
+
- New rollout and orchestration flags:
|
|
13
|
+
- `--group-by none|name|scope|kind|risk`
|
|
14
|
+
- `--group-max <n>`
|
|
15
|
+
- `--cooldown-days <n>`
|
|
16
|
+
- `--pr-limit <n>`
|
|
17
|
+
- `--only-changed`
|
|
18
|
+
- Additive summary/output contract fields:
|
|
19
|
+
- `groupedUpdates`
|
|
20
|
+
- `cooldownSkipped`
|
|
21
|
+
- `ciProfile`
|
|
22
|
+
- `prLimitHit`
|
|
23
|
+
- Policy schema extensions:
|
|
24
|
+
- global `cooldownDays`
|
|
25
|
+
- package rule `group` and `priority`
|
|
26
|
+
|
|
27
|
+
### Changed
|
|
28
|
+
|
|
29
|
+
- `check` now supports cooldown-aware filtering when publish timestamps are available.
|
|
30
|
+
- CI workflow templates generated by `init-ci` now use `rainy-updates ci` with explicit profile mode.
|
|
31
|
+
- GitHub output, metrics output, SARIF properties, and PR report include new CI orchestration metadata.
|
|
32
|
+
|
|
33
|
+
### Tests
|
|
34
|
+
|
|
35
|
+
- Added parser coverage for `ci` command orchestration flags.
|
|
36
|
+
- Extended workflow, policy, summary, and output tests for new metadata and profile behavior.
|
|
37
|
+
|
|
38
|
+
## [0.5.0] - 2026-02-27
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Promoted `0.5.0-rc.4` to General Availability.
|
|
43
|
+
- Stabilized deterministic CI artifact behavior for JSON, SARIF, and GitHub outputs.
|
|
44
|
+
- Finalized fix-PR summary metadata contract defaults for automation pipelines.
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
|
|
48
|
+
- GA release gate includes `perf:smoke` CI check for regression protection.
|
|
49
|
+
|
|
50
|
+
## [0.5.0-rc.4] - 2026-02-27
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
|
|
54
|
+
- Hardened deterministic CI artifacts:
|
|
55
|
+
- stable key ordering for JSON and SARIF files,
|
|
56
|
+
- deterministic sorting for updates, warnings, and errors in output pipelines.
|
|
57
|
+
- Improved fail-reason classification consistency for registry/runtime failures across commands.
|
|
58
|
+
- Fix-PR metadata in summary now has stable defaults (`fixPrApplied`, `fixBranchName`, `fixCommitSha`) to reduce contract drift.
|
|
59
|
+
- Fix-PR staging now includes only updated manifests plus explicit report files, with deterministic file ordering.
|
|
60
|
+
- Added warning when Bun runtime falls back from SQLite cache backend to file cache backend.
|
|
61
|
+
|
|
62
|
+
### Added
|
|
63
|
+
|
|
64
|
+
- Added `perf:smoke` script and CI gate to enforce a basic performance regression threshold.
|
|
65
|
+
- Added deterministic output and summary regression tests.
|
|
66
|
+
|
|
5
67
|
## [0.5.0-rc.2] - 2026-02-27
|
|
6
68
|
|
|
7
69
|
### Added
|
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ pnpm add -D @rainy-updates/cli
|
|
|
24
24
|
|
|
25
25
|
- `check`: analyze dependencies and report available updates.
|
|
26
26
|
- `upgrade`: rewrite dependency ranges in manifests, optionally install lockfile updates.
|
|
27
|
+
- `ci`: run CI-focused dependency automation (warm cache, check/upgrade, policy gates).
|
|
27
28
|
- `warm-cache`: prefetch package metadata for fast and offline checks.
|
|
28
29
|
- `baseline`: save and compare dependency baseline snapshots.
|
|
29
30
|
|
|
@@ -36,6 +37,9 @@ npx @rainy-updates/cli check --format table
|
|
|
36
37
|
# 2) Strict CI mode (non-zero when updates exist)
|
|
37
38
|
npx @rainy-updates/cli check --workspace --ci --format json --json-file .artifacts/updates.json
|
|
38
39
|
|
|
40
|
+
# 2b) CI orchestration mode
|
|
41
|
+
npx @rainy-updates/cli ci --workspace --mode strict --format github --json-file .artifacts/updates.json
|
|
42
|
+
|
|
39
43
|
# 3) Apply upgrades with workspace sync
|
|
40
44
|
npx @rainy-updates/cli upgrade --target latest --workspace --sync --install
|
|
41
45
|
|
|
@@ -151,6 +155,12 @@ Schedule:
|
|
|
151
155
|
- `--offline`
|
|
152
156
|
- `--fail-on none|patch|minor|major|any`
|
|
153
157
|
- `--max-updates <n>`
|
|
158
|
+
- `--group-by none|name|scope|kind|risk`
|
|
159
|
+
- `--group-max <n>`
|
|
160
|
+
- `--cooldown-days <n>`
|
|
161
|
+
- `--pr-limit <n>`
|
|
162
|
+
- `--only-changed`
|
|
163
|
+
- `--mode minimal|strict|enterprise` (for `ci`)
|
|
154
164
|
- `--policy-file <path>`
|
|
155
165
|
- `--format table|json|minimal|github`
|
|
156
166
|
- `--json-file <path>`
|
|
@@ -205,6 +215,7 @@ rainy-updates --version
|
|
|
205
215
|
This package ships with production CI/CD pipelines in the repository:
|
|
206
216
|
|
|
207
217
|
- Continuous integration pipeline for typecheck, tests, build, and production smoke checks.
|
|
218
|
+
- Performance smoke gate (`perf:smoke`) to catch startup/runtime regressions in CI.
|
|
208
219
|
- Tag-driven release pipeline for npm publishing with provenance.
|
|
209
220
|
- Release preflight validation for npm auth/scope checks before publishing.
|
|
210
221
|
|
package/dist/bin/cli.js
CHANGED
|
@@ -7,6 +7,7 @@ import { parseCliArgs } from "../core/options.js";
|
|
|
7
7
|
import { check } from "../core/check.js";
|
|
8
8
|
import { upgrade } from "../core/upgrade.js";
|
|
9
9
|
import { warmCache } from "../core/warm-cache.js";
|
|
10
|
+
import { runCi } from "../core/ci.js";
|
|
10
11
|
import { initCiWorkflow } from "../core/init-ci.js";
|
|
11
12
|
import { diffBaseline, saveBaseline } from "../core/baseline.js";
|
|
12
13
|
import { applyFixPr } from "../core/fix-pr.js";
|
|
@@ -14,6 +15,9 @@ import { renderResult } from "../output/format.js";
|
|
|
14
15
|
import { writeGitHubOutput } from "../output/github.js";
|
|
15
16
|
import { createSarifReport } from "../output/sarif.js";
|
|
16
17
|
import { renderPrReport } from "../output/pr-report.js";
|
|
18
|
+
import { writeFileAtomic } from "../utils/io.js";
|
|
19
|
+
import { resolveFailReason } from "../core/summary.js";
|
|
20
|
+
import { stableStringify } from "../utils/stable-json.js";
|
|
17
21
|
async function main() {
|
|
18
22
|
try {
|
|
19
23
|
const argv = process.argv.slice(2);
|
|
@@ -64,30 +68,43 @@ async function main() {
|
|
|
64
68
|
const result = await runCommand(parsed);
|
|
65
69
|
if (parsed.options.prReportFile) {
|
|
66
70
|
const markdown = renderPrReport(result);
|
|
67
|
-
await
|
|
68
|
-
await fs.writeFile(parsed.options.prReportFile, markdown + "\n", "utf8");
|
|
71
|
+
await writeFileAtomic(parsed.options.prReportFile, markdown + "\n");
|
|
69
72
|
}
|
|
70
|
-
if (parsed.options.fixPr && (parsed.command === "check" || parsed.command === "upgrade")) {
|
|
73
|
+
if (parsed.options.fixPr && (parsed.command === "check" || parsed.command === "upgrade" || parsed.command === "ci")) {
|
|
74
|
+
result.summary.fixPrApplied = false;
|
|
75
|
+
result.summary.fixBranchName = parsed.options.fixBranch ?? "chore/rainy-updates";
|
|
76
|
+
result.summary.fixCommitSha = "";
|
|
71
77
|
const fixResult = await applyFixPr(parsed.options, result, parsed.options.prReportFile ? [parsed.options.prReportFile] : []);
|
|
72
78
|
result.summary.fixPrApplied = fixResult.applied;
|
|
73
|
-
result.summary.fixBranchName = fixResult.branchName;
|
|
74
|
-
result.summary.fixCommitSha = fixResult.commitSha;
|
|
79
|
+
result.summary.fixBranchName = fixResult.branchName ?? "";
|
|
80
|
+
result.summary.fixCommitSha = fixResult.commitSha ?? "";
|
|
81
|
+
}
|
|
82
|
+
result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
|
|
83
|
+
const renderStartedAt = Date.now();
|
|
84
|
+
let rendered = renderResult(result, parsed.options.format);
|
|
85
|
+
result.summary.durationMs.render = Math.max(0, Date.now() - renderStartedAt);
|
|
86
|
+
if (parsed.options.format === "json" || parsed.options.format === "metrics") {
|
|
87
|
+
rendered = renderResult(result, parsed.options.format);
|
|
88
|
+
}
|
|
89
|
+
if (parsed.options.onlyChanged &&
|
|
90
|
+
result.updates.length === 0 &&
|
|
91
|
+
result.errors.length === 0 &&
|
|
92
|
+
result.warnings.length === 0 &&
|
|
93
|
+
(parsed.options.format === "table" || parsed.options.format === "minimal" || parsed.options.format === "github")) {
|
|
94
|
+
rendered = "";
|
|
75
95
|
}
|
|
76
96
|
if (parsed.options.jsonFile) {
|
|
77
|
-
await
|
|
78
|
-
await fs.writeFile(parsed.options.jsonFile, JSON.stringify(result, null, 2) + "\n", "utf8");
|
|
97
|
+
await writeFileAtomic(parsed.options.jsonFile, stableStringify(result, 2) + "\n");
|
|
79
98
|
}
|
|
80
99
|
if (parsed.options.githubOutputFile) {
|
|
81
100
|
await writeGitHubOutput(parsed.options.githubOutputFile, result);
|
|
82
101
|
}
|
|
83
102
|
if (parsed.options.sarifFile) {
|
|
84
103
|
const sarif = createSarifReport(result);
|
|
85
|
-
await
|
|
86
|
-
await fs.writeFile(parsed.options.sarifFile, JSON.stringify(sarif, null, 2) + "\n", "utf8");
|
|
104
|
+
await writeFileAtomic(parsed.options.sarifFile, stableStringify(sarif, 2) + "\n");
|
|
87
105
|
}
|
|
88
|
-
const rendered = renderResult(result, parsed.options.format);
|
|
89
106
|
process.stdout.write(rendered + "\n");
|
|
90
|
-
process.exitCode = resolveExitCode(result,
|
|
107
|
+
process.exitCode = resolveExitCode(result, result.summary.failReason);
|
|
91
108
|
}
|
|
92
109
|
catch (error) {
|
|
93
110
|
process.stderr.write(`rainy-updates: ${String(error)}\n`);
|
|
@@ -116,6 +133,7 @@ Options:
|
|
|
116
133
|
--fix-branch <name>
|
|
117
134
|
--fix-commit-message <text>
|
|
118
135
|
--fix-dry-run
|
|
136
|
+
--fix-pr-no-checkout
|
|
119
137
|
--no-pr-report
|
|
120
138
|
--json-file <path>
|
|
121
139
|
--github-output <path>
|
|
@@ -123,6 +141,12 @@ Options:
|
|
|
123
141
|
--pr-report-file <path>
|
|
124
142
|
--fail-on none|patch|minor|major|any
|
|
125
143
|
--max-updates <n>
|
|
144
|
+
--group-by none|name|scope|kind|risk
|
|
145
|
+
--group-max <n>
|
|
146
|
+
--cooldown-days <n>
|
|
147
|
+
--pr-limit <n>
|
|
148
|
+
--only-changed
|
|
149
|
+
--log-level error|warn|info|debug
|
|
126
150
|
--ci`;
|
|
127
151
|
}
|
|
128
152
|
if (isCommand && command === "warm-cache") {
|
|
@@ -161,9 +185,40 @@ Options:
|
|
|
161
185
|
--fix-branch <name>
|
|
162
186
|
--fix-commit-message <text>
|
|
163
187
|
--fix-dry-run
|
|
188
|
+
--fix-pr-no-checkout
|
|
164
189
|
--no-pr-report
|
|
165
190
|
--json-file <path>
|
|
166
191
|
--pr-report-file <path>`;
|
|
192
|
+
}
|
|
193
|
+
if (isCommand && command === "ci") {
|
|
194
|
+
return `rainy-updates ci [options]
|
|
195
|
+
|
|
196
|
+
Run CI-oriented dependency automation pipeline.
|
|
197
|
+
|
|
198
|
+
Options:
|
|
199
|
+
--workspace
|
|
200
|
+
--mode minimal|strict|enterprise
|
|
201
|
+
--group-by none|name|scope|kind|risk
|
|
202
|
+
--group-max <n>
|
|
203
|
+
--cooldown-days <n>
|
|
204
|
+
--pr-limit <n>
|
|
205
|
+
--only-changed
|
|
206
|
+
--offline
|
|
207
|
+
--concurrency <n>
|
|
208
|
+
--fix-pr
|
|
209
|
+
--fix-branch <name>
|
|
210
|
+
--fix-commit-message <text>
|
|
211
|
+
--fix-dry-run
|
|
212
|
+
--fix-pr-no-checkout
|
|
213
|
+
--no-pr-report
|
|
214
|
+
--json-file <path>
|
|
215
|
+
--github-output <path>
|
|
216
|
+
--sarif-file <path>
|
|
217
|
+
--pr-report-file <path>
|
|
218
|
+
--fail-on none|patch|minor|major|any
|
|
219
|
+
--max-updates <n>
|
|
220
|
+
--log-level error|warn|info|debug
|
|
221
|
+
--ci`;
|
|
167
222
|
}
|
|
168
223
|
if (isCommand && command === "init-ci") {
|
|
169
224
|
return `rainy-updates init-ci [options]
|
|
@@ -194,6 +249,7 @@ Options:
|
|
|
194
249
|
Commands:
|
|
195
250
|
check Detect available updates
|
|
196
251
|
upgrade Apply updates to manifests
|
|
252
|
+
ci Run CI-focused update pipeline
|
|
197
253
|
warm-cache Warm local cache for fast/offline checks
|
|
198
254
|
init-ci Scaffold GitHub Actions workflow
|
|
199
255
|
baseline Save/check dependency baseline snapshots
|
|
@@ -202,7 +258,7 @@ Global options:
|
|
|
202
258
|
--cwd <path>
|
|
203
259
|
--workspace
|
|
204
260
|
--target patch|minor|major|latest
|
|
205
|
-
--format table|json|minimal|github
|
|
261
|
+
--format table|json|minimal|github|metrics
|
|
206
262
|
--json-file <path>
|
|
207
263
|
--github-output <path>
|
|
208
264
|
--sarif-file <path>
|
|
@@ -210,11 +266,19 @@ Global options:
|
|
|
210
266
|
--policy-file <path>
|
|
211
267
|
--fail-on none|patch|minor|major|any
|
|
212
268
|
--max-updates <n>
|
|
269
|
+
--group-by none|name|scope|kind|risk
|
|
270
|
+
--group-max <n>
|
|
271
|
+
--cooldown-days <n>
|
|
272
|
+
--pr-limit <n>
|
|
273
|
+
--only-changed
|
|
274
|
+
--mode minimal|strict|enterprise
|
|
213
275
|
--fix-pr
|
|
214
276
|
--fix-branch <name>
|
|
215
277
|
--fix-commit-message <text>
|
|
216
278
|
--fix-dry-run
|
|
279
|
+
--fix-pr-no-checkout
|
|
217
280
|
--no-pr-report
|
|
281
|
+
--log-level error|warn|info|debug
|
|
218
282
|
--concurrency <n>
|
|
219
283
|
--cache-ttl <seconds>
|
|
220
284
|
--offline
|
|
@@ -229,6 +293,9 @@ async function runCommand(parsed) {
|
|
|
229
293
|
if (parsed.command === "warm-cache") {
|
|
230
294
|
return await warmCache(parsed.options);
|
|
231
295
|
}
|
|
296
|
+
if (parsed.command === "ci") {
|
|
297
|
+
return await runCi(parsed.options);
|
|
298
|
+
}
|
|
232
299
|
if (parsed.options.fixPr) {
|
|
233
300
|
const upgradeOptions = {
|
|
234
301
|
...parsed.options,
|
|
@@ -247,22 +314,10 @@ async function readPackageVersion() {
|
|
|
247
314
|
const parsed = JSON.parse(content);
|
|
248
315
|
return parsed.version ?? "0.0.0";
|
|
249
316
|
}
|
|
250
|
-
function resolveExitCode(result,
|
|
317
|
+
function resolveExitCode(result, failReason) {
|
|
251
318
|
if (result.errors.length > 0)
|
|
252
319
|
return 2;
|
|
253
|
-
if (
|
|
320
|
+
if (failReason !== "none")
|
|
254
321
|
return 1;
|
|
255
|
-
|
|
256
|
-
if (!shouldFailForUpdates(result.updates, effectiveFailOn))
|
|
257
|
-
return 0;
|
|
258
|
-
return 1;
|
|
259
|
-
}
|
|
260
|
-
function shouldFailForUpdates(updates, failOn) {
|
|
261
|
-
if (failOn === "none")
|
|
262
|
-
return false;
|
|
263
|
-
if (failOn === "any" || failOn === "patch")
|
|
264
|
-
return updates.length > 0;
|
|
265
|
-
if (failOn === "minor")
|
|
266
|
-
return updates.some((update) => update.diffType === "minor" || update.diffType === "major");
|
|
267
|
-
return updates.some((update) => update.diffType === "major");
|
|
322
|
+
return 0;
|
|
268
323
|
}
|
package/dist/cache/cache.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { CachedVersion, TargetLevel } from "../types/index.js";
|
|
2
2
|
export declare class VersionCache {
|
|
3
3
|
private readonly store;
|
|
4
|
+
readonly backend: "sqlite" | "file";
|
|
5
|
+
readonly degraded: boolean;
|
|
4
6
|
private constructor();
|
|
5
7
|
static create(customPath?: string): Promise<VersionCache>;
|
|
6
8
|
getValid(packageName: string, target: TargetLevel): Promise<CachedVersion | null>;
|
package/dist/cache/cache.js
CHANGED
|
@@ -106,17 +106,22 @@ class SqliteCacheStore {
|
|
|
106
106
|
}
|
|
107
107
|
export class VersionCache {
|
|
108
108
|
store;
|
|
109
|
-
|
|
109
|
+
backend;
|
|
110
|
+
degraded;
|
|
111
|
+
constructor(store, backend, degraded) {
|
|
110
112
|
this.store = store;
|
|
113
|
+
this.backend = backend;
|
|
114
|
+
this.degraded = degraded;
|
|
111
115
|
}
|
|
112
116
|
static async create(customPath) {
|
|
113
117
|
const basePath = customPath ?? path.join(os.homedir(), ".cache", "rainy-updates");
|
|
114
118
|
const sqlitePath = path.join(basePath, "cache.db");
|
|
115
119
|
const sqliteStore = await tryCreateSqliteStore(sqlitePath);
|
|
116
120
|
if (sqliteStore)
|
|
117
|
-
return new VersionCache(sqliteStore);
|
|
121
|
+
return new VersionCache(sqliteStore, "sqlite", false);
|
|
118
122
|
const jsonPath = path.join(basePath, "cache.json");
|
|
119
|
-
|
|
123
|
+
const degraded = typeof Bun !== "undefined";
|
|
124
|
+
return new VersionCache(new FileCacheStore(jsonPath), "file", degraded);
|
|
120
125
|
}
|
|
121
126
|
async getValid(packageName, target) {
|
|
122
127
|
const entry = await this.store.get(packageName, target);
|
package/dist/config/loader.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DependencyKind, FailOnLevel, OutputFormat, TargetLevel } from "../types/index.js";
|
|
1
|
+
import type { CiProfile, DependencyKind, FailOnLevel, GroupBy, LogLevel, OutputFormat, TargetLevel } from "../types/index.js";
|
|
2
2
|
export interface FileConfig {
|
|
3
3
|
target?: TargetLevel;
|
|
4
4
|
filter?: string;
|
|
@@ -21,7 +21,15 @@ export interface FileConfig {
|
|
|
21
21
|
fixBranch?: string;
|
|
22
22
|
fixCommitMessage?: string;
|
|
23
23
|
fixDryRun?: boolean;
|
|
24
|
+
fixPrNoCheckout?: boolean;
|
|
24
25
|
noPrReport?: boolean;
|
|
26
|
+
logLevel?: LogLevel;
|
|
27
|
+
groupBy?: GroupBy;
|
|
28
|
+
groupMax?: number;
|
|
29
|
+
cooldownDays?: number;
|
|
30
|
+
prLimit?: number;
|
|
31
|
+
onlyChanged?: boolean;
|
|
32
|
+
ciProfile?: CiProfile;
|
|
25
33
|
install?: boolean;
|
|
26
34
|
packageManager?: "auto" | "npm" | "pnpm";
|
|
27
35
|
sync?: boolean;
|
package/dist/config/policy.d.ts
CHANGED
|
@@ -1,16 +1,33 @@
|
|
|
1
1
|
import type { TargetLevel } from "../types/index.js";
|
|
2
2
|
export interface PolicyConfig {
|
|
3
3
|
ignore?: string[];
|
|
4
|
+
cooldownDays?: number;
|
|
4
5
|
packageRules?: Record<string, {
|
|
6
|
+
match?: string;
|
|
5
7
|
maxTarget?: TargetLevel;
|
|
6
8
|
ignore?: boolean;
|
|
9
|
+
maxUpdatesPerRun?: number;
|
|
10
|
+
cooldownDays?: number;
|
|
11
|
+
allowPrerelease?: boolean;
|
|
12
|
+
group?: string;
|
|
13
|
+
priority?: number;
|
|
7
14
|
}>;
|
|
8
15
|
}
|
|
16
|
+
export interface PolicyRule {
|
|
17
|
+
match?: string;
|
|
18
|
+
maxTarget?: TargetLevel;
|
|
19
|
+
ignore: boolean;
|
|
20
|
+
maxUpdatesPerRun?: number;
|
|
21
|
+
cooldownDays?: number;
|
|
22
|
+
allowPrerelease?: boolean;
|
|
23
|
+
group?: string;
|
|
24
|
+
priority?: number;
|
|
25
|
+
}
|
|
9
26
|
export interface ResolvedPolicy {
|
|
10
27
|
ignorePatterns: string[];
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}>;
|
|
28
|
+
cooldownDays?: number;
|
|
29
|
+
packageRules: Map<string, PolicyRule>;
|
|
30
|
+
matchRules: PolicyRule[];
|
|
15
31
|
}
|
|
16
32
|
export declare function loadPolicy(cwd: string, policyFile?: string): Promise<ResolvedPolicy>;
|
|
33
|
+
export declare function resolvePolicyRule(packageName: string, policy: ResolvedPolicy): PolicyRule | undefined;
|
package/dist/config/policy.js
CHANGED
|
@@ -12,13 +12,11 @@ export async function loadPolicy(cwd, policyFile) {
|
|
|
12
12
|
const parsed = JSON.parse(content);
|
|
13
13
|
return {
|
|
14
14
|
ignorePatterns: parsed.ignore ?? [],
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
])),
|
|
15
|
+
cooldownDays: asNonNegativeInt(parsed.cooldownDays),
|
|
16
|
+
packageRules: new Map(Object.entries(parsed.packageRules ?? {}).map(([pkg, rule]) => [pkg, normalizeRule(rule)])),
|
|
17
|
+
matchRules: Object.values(parsed.packageRules ?? {})
|
|
18
|
+
.map((rule) => normalizeRule(rule))
|
|
19
|
+
.filter((rule) => typeof rule.match === "string" && rule.match.length > 0),
|
|
22
20
|
};
|
|
23
21
|
}
|
|
24
22
|
catch {
|
|
@@ -27,6 +25,40 @@ export async function loadPolicy(cwd, policyFile) {
|
|
|
27
25
|
}
|
|
28
26
|
return {
|
|
29
27
|
ignorePatterns: [],
|
|
28
|
+
cooldownDays: undefined,
|
|
30
29
|
packageRules: new Map(),
|
|
30
|
+
matchRules: [],
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
export function resolvePolicyRule(packageName, policy) {
|
|
34
|
+
const exact = policy.packageRules.get(packageName);
|
|
35
|
+
if (exact)
|
|
36
|
+
return exact;
|
|
37
|
+
return policy.matchRules.find((rule) => matchesPattern(packageName, rule.match));
|
|
38
|
+
}
|
|
39
|
+
function normalizeRule(rule) {
|
|
40
|
+
return {
|
|
41
|
+
match: typeof rule.match === "string" ? rule.match : undefined,
|
|
42
|
+
maxTarget: rule.maxTarget,
|
|
43
|
+
ignore: rule.ignore === true,
|
|
44
|
+
maxUpdatesPerRun: asNonNegativeInt(rule.maxUpdatesPerRun),
|
|
45
|
+
cooldownDays: asNonNegativeInt(rule.cooldownDays),
|
|
46
|
+
allowPrerelease: rule.allowPrerelease === true,
|
|
47
|
+
group: typeof rule.group === "string" && rule.group.trim().length > 0 ? rule.group.trim() : undefined,
|
|
48
|
+
priority: asNonNegativeInt(rule.priority),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function asNonNegativeInt(value) {
|
|
52
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0)
|
|
53
|
+
return undefined;
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
function matchesPattern(value, pattern) {
|
|
57
|
+
if (!pattern || pattern.length === 0)
|
|
58
|
+
return false;
|
|
59
|
+
if (pattern === "*")
|
|
60
|
+
return true;
|
|
61
|
+
const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
62
|
+
const regex = new RegExp(`^${escaped}$`);
|
|
63
|
+
return regex.test(value);
|
|
64
|
+
}
|