@rainy-updates/cli 0.6.0 → 0.6.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 +53 -0
- package/dist/bin/cli.js +12 -127
- package/dist/bin/dispatch.js +6 -0
- package/dist/bin/help.js +47 -0
- package/dist/bin/main.d.ts +1 -0
- package/dist/bin/main.js +126 -0
- package/dist/commands/audit/parser.js +36 -0
- package/dist/commands/audit/runner.js +17 -18
- package/dist/commands/bisect/oracle.js +18 -15
- package/dist/commands/bisect/runner.js +4 -3
- package/dist/commands/dashboard/parser.js +41 -0
- package/dist/commands/doctor/parser.js +44 -0
- package/dist/commands/ga/parser.js +39 -0
- package/dist/commands/ga/runner.js +10 -7
- package/dist/commands/health/parser.js +36 -0
- package/dist/commands/health/runner.js +5 -1
- package/dist/commands/hook/parser.d.ts +2 -0
- package/dist/commands/hook/parser.js +40 -0
- package/dist/commands/hook/runner.d.ts +2 -0
- package/dist/commands/hook/runner.js +174 -0
- package/dist/commands/licenses/parser.js +39 -0
- package/dist/commands/licenses/runner.js +5 -1
- package/dist/commands/resolve/graph/builder.js +5 -1
- package/dist/commands/resolve/parser.js +39 -0
- package/dist/commands/resolve/runner.js +5 -0
- package/dist/commands/review/parser.js +44 -0
- package/dist/commands/snapshot/parser.js +39 -0
- package/dist/commands/snapshot/runner.js +4 -1
- package/dist/commands/unused/parser.js +39 -0
- package/dist/commands/unused/runner.js +4 -1
- package/dist/commands/unused/scanner.d.ts +2 -1
- package/dist/commands/unused/scanner.js +60 -44
- package/dist/core/check.js +5 -1
- package/dist/core/init-ci.js +28 -26
- package/dist/core/options.d.ts +4 -1
- package/dist/core/options.js +57 -0
- package/dist/core/verification.js +8 -6
- package/dist/core/warm-cache.js +5 -1
- package/dist/generated/version.d.ts +1 -0
- package/dist/generated/version.js +2 -0
- package/dist/git/scope.d.ts +19 -0
- package/dist/git/scope.js +167 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/output/sarif.js +2 -8
- package/dist/pm/detect.d.ts +37 -0
- package/dist/pm/detect.js +133 -2
- package/dist/pm/install.d.ts +2 -1
- package/dist/pm/install.js +7 -5
- package/dist/rup +0 -0
- package/dist/types/index.d.ts +58 -0
- package/dist/ui/tui.js +152 -64
- package/dist/workspace/discover.d.ts +7 -1
- package/dist/workspace/discover.js +12 -3
- package/package.json +10 -5
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project are documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.6.1] - 2026-03-03
|
|
6
|
+
|
|
7
|
+
Compatibility, git-aware workspace scoping, and release-readiness stabilization for the `v0.6` line.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **First-class package-manager profile layer**:
|
|
12
|
+
- detection now prefers `package.json.packageManager` before falling back to lockfiles,
|
|
13
|
+
- additive package-manager metadata for lockfile source and Yarn flavor detection,
|
|
14
|
+
- centralized install, add, and test command construction for npm, pnpm, Bun, and Yarn.
|
|
15
|
+
- **Git-aware workspace scoping**:
|
|
16
|
+
- `--affected`,
|
|
17
|
+
- `--staged`,
|
|
18
|
+
- `--base <ref>`,
|
|
19
|
+
- `--head <ref>`,
|
|
20
|
+
- `--since <ref>`.
|
|
21
|
+
- **Workspace dependent expansion for affected scans**:
|
|
22
|
+
- changed packages can now expand to dependent workspace packages instead of stopping at direct file matches.
|
|
23
|
+
- **New `hook` command**:
|
|
24
|
+
- `rup hook install`,
|
|
25
|
+
- `rup hook uninstall`,
|
|
26
|
+
- `rup hook doctor`.
|
|
27
|
+
- **Rainy-managed git hooks**:
|
|
28
|
+
- `pre-commit` runs `rup unused --workspace --staged` and `rup resolve --workspace --staged`,
|
|
29
|
+
- `pre-push` runs `rup audit --workspace --affected --report summary`.
|
|
30
|
+
- **New test coverage** for:
|
|
31
|
+
- package-manager field precedence and Yarn Berry behavior,
|
|
32
|
+
- git-scoped workspace discovery,
|
|
33
|
+
- hook install/doctor/uninstall lifecycle,
|
|
34
|
+
- scoped standalone parser support.
|
|
35
|
+
|
|
36
|
+
### Changed
|
|
37
|
+
|
|
38
|
+
- `init-ci` workflow generation now uses the centralized package-manager profile layer instead of special-casing npm/pnpm/Bun only.
|
|
39
|
+
- Yarn support is now explicit in generated workflows:
|
|
40
|
+
- Corepack enablement for Yarn/pnpm repos,
|
|
41
|
+
- Yarn Berry uses immutable installs,
|
|
42
|
+
- Yarn package adds no longer fall back to npm command construction.
|
|
43
|
+
- `verification`, `audit --fix`, and `bisect` now reuse the same package-manager command model as `upgrade`.
|
|
44
|
+
- `ga` package-manager reporting now includes detection source details and respects the git-scoped workspace discovery flow.
|
|
45
|
+
- `check`, `warm-cache`, `audit`, `unused`, `resolve`, `health`, `licenses`, `snapshot`, and `ga` now share the same git-aware workspace scoping path.
|
|
46
|
+
- Command help and parser support were aligned so git-scoping flags are consistently accepted across the primary and standalone command surfaces.
|
|
47
|
+
|
|
48
|
+
### Tests
|
|
49
|
+
|
|
50
|
+
- Full release validation passed:
|
|
51
|
+
- `pnpm -s exec tsc --noEmit`
|
|
52
|
+
- `bun test`
|
|
53
|
+
- `pnpm run build`
|
|
54
|
+
- `bun run build:exe`
|
|
55
|
+
- `bun run test:prod`
|
|
56
|
+
- `bun ./dist/bin/cli.js ga --workspace`
|
|
57
|
+
|
|
5
58
|
## [0.6.0] - 2026-03-01
|
|
6
59
|
|
|
7
60
|
Dashboard-first release candidate for the `v0.6` series, focused on unifying the interactive surface, introducing replayable decision plans, tightening CI/apply verification flows, and undergoing a complete native Bun performance optimization.
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,134 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { applyFixPrBatches } from "../core/fix-pr-batch.js";
|
|
6
|
-
import { createRunId, writeArtifactManifest } from "../core/artifacts.js";
|
|
7
|
-
import { renderResult } from "../output/format.js";
|
|
8
|
-
import { writeGitHubOutput } from "../output/github.js";
|
|
9
|
-
import { createSarifReport } from "../output/sarif.js";
|
|
10
|
-
import { renderPrReport } from "../output/pr-report.js";
|
|
11
|
-
import { writeFileAtomic } from "../utils/io.js";
|
|
12
|
-
import { resolveFailReason } from "../core/summary.js";
|
|
13
|
-
import { stableStringify } from "../utils/stable-json.js";
|
|
14
|
-
import { getRuntimeArgv, setRuntimeExitCode, writeStderr, writeStdout, } from "../utils/runtime.js";
|
|
15
|
-
import { handleDirectCommand, runPrimaryCommand } from "./dispatch.js";
|
|
16
|
-
import { renderHelp } from "./help.js";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
import { runCli } from "./main.js";
|
|
17
5
|
async function main() {
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (argv.includes("--help") || argv.includes("-h")) {
|
|
25
|
-
writeStdout(renderHelp(argv[0]) + "\n");
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
const parsed = await parseCliArgs(argv);
|
|
29
|
-
if (await handleDirectCommand(parsed))
|
|
30
|
-
return;
|
|
31
|
-
if (parsed.command !== "check" &&
|
|
32
|
-
parsed.command !== "upgrade" &&
|
|
33
|
-
parsed.command !== "warm-cache" &&
|
|
34
|
-
parsed.command !== "ci") {
|
|
35
|
-
throw new Error(`Unhandled command: ${parsed.command}`);
|
|
36
|
-
}
|
|
37
|
-
const result = await runPrimaryCommand(parsed);
|
|
38
|
-
result.summary.runId = createRunId(parsed.command, parsed.options, result);
|
|
39
|
-
if (parsed.options.fixPr &&
|
|
40
|
-
(parsed.command === "check" ||
|
|
41
|
-
parsed.command === "upgrade" ||
|
|
42
|
-
parsed.command === "ci")) {
|
|
43
|
-
result.summary.fixPrApplied = false;
|
|
44
|
-
result.summary.fixBranchName =
|
|
45
|
-
parsed.options.fixBranch ?? "chore/rainy-updates";
|
|
46
|
-
result.summary.fixCommitSha = "";
|
|
47
|
-
result.summary.fixPrBranchesCreated = 0;
|
|
48
|
-
if (parsed.command === "ci") {
|
|
49
|
-
const batched = await applyFixPrBatches(parsed.options, result);
|
|
50
|
-
result.summary.fixPrApplied = batched.applied;
|
|
51
|
-
result.summary.fixBranchName =
|
|
52
|
-
batched.branches[0] ??
|
|
53
|
-
parsed.options.fixBranch ??
|
|
54
|
-
"chore/rainy-updates";
|
|
55
|
-
result.summary.fixCommitSha = batched.commits[0] ?? "";
|
|
56
|
-
result.summary.fixPrBranchesCreated = batched.branches.length;
|
|
57
|
-
if (batched.branches.length > 1) {
|
|
58
|
-
result.warnings.push(`Created ${batched.branches.length} fix-pr batch branches.`);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
const fixResult = await applyFixPr(parsed.options, result, []);
|
|
63
|
-
result.summary.fixPrApplied = fixResult.applied;
|
|
64
|
-
result.summary.fixBranchName = fixResult.branchName ?? "";
|
|
65
|
-
result.summary.fixCommitSha = fixResult.commitSha ?? "";
|
|
66
|
-
result.summary.fixPrBranchesCreated = fixResult.applied ? 1 : 0;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (parsed.options.prReportFile) {
|
|
70
|
-
const markdown = renderPrReport(result);
|
|
71
|
-
await writeFileAtomic(parsed.options.prReportFile, markdown + "\n");
|
|
72
|
-
}
|
|
73
|
-
const artifactManifest = await writeArtifactManifest(parsed.command, parsed.options, result);
|
|
74
|
-
if (artifactManifest) {
|
|
75
|
-
result.summary.artifactManifest = artifactManifest.artifactManifestPath;
|
|
76
|
-
}
|
|
77
|
-
result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
|
|
78
|
-
const renderStartedAt = Date.now();
|
|
79
|
-
let rendered = renderResult(result, parsed.options.format, {
|
|
80
|
-
showImpact: parsed.options.showImpact,
|
|
81
|
-
showHomepage: parsed.options.showHomepage,
|
|
6
|
+
if (typeof Bun === "undefined") {
|
|
7
|
+
const currentFile = fileURLToPath(import.meta.url);
|
|
8
|
+
const result = spawnSync("bun", [currentFile, ...process.argv.slice(2)], {
|
|
9
|
+
stdio: "inherit",
|
|
82
10
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
rendered = renderResult(result, parsed.options.format, {
|
|
87
|
-
showImpact: parsed.options.showImpact,
|
|
88
|
-
showHomepage: parsed.options.showHomepage,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
if (parsed.options.onlyChanged &&
|
|
92
|
-
result.updates.length === 0 &&
|
|
93
|
-
result.errors.length === 0 &&
|
|
94
|
-
result.warnings.length === 0 &&
|
|
95
|
-
(parsed.options.format === "table" ||
|
|
96
|
-
parsed.options.format === "minimal" ||
|
|
97
|
-
parsed.options.format === "github")) {
|
|
98
|
-
rendered = "";
|
|
99
|
-
}
|
|
100
|
-
if (parsed.options.jsonFile) {
|
|
101
|
-
await writeFileAtomic(parsed.options.jsonFile, stableStringify(result, 2) + "\n");
|
|
11
|
+
if (result.error) {
|
|
12
|
+
process.stderr.write("rainy-updates (rup): Bun is required to run the published JavaScript entrypoint. Install Bun or use the compiled binary release.\n");
|
|
13
|
+
process.exit(1);
|
|
102
14
|
}
|
|
103
|
-
|
|
104
|
-
await writeGitHubOutput(parsed.options.githubOutputFile, result);
|
|
105
|
-
}
|
|
106
|
-
if (parsed.options.sarifFile) {
|
|
107
|
-
const sarif = createSarifReport(result);
|
|
108
|
-
await writeFileAtomic(parsed.options.sarifFile, stableStringify(sarif, 2) + "\n");
|
|
109
|
-
}
|
|
110
|
-
writeStdout(rendered + "\n");
|
|
111
|
-
setRuntimeExitCode(resolveExitCode(result, result.summary.failReason));
|
|
112
|
-
}
|
|
113
|
-
catch (error) {
|
|
114
|
-
writeStderr(`rainy-updates (rup): ${String(error)}\n`);
|
|
115
|
-
setRuntimeExitCode(2);
|
|
15
|
+
process.exit(result.status ?? 1);
|
|
116
16
|
}
|
|
17
|
+
await runCli();
|
|
117
18
|
}
|
|
118
19
|
void main();
|
|
119
|
-
async function readPackageVersion() {
|
|
120
|
-
try {
|
|
121
|
-
const packageJson = JSON.parse(readFileSync(new URL("../../package.json", import.meta.url), "utf8"));
|
|
122
|
-
return packageJson.version ?? "0.0.0";
|
|
123
|
-
}
|
|
124
|
-
catch {
|
|
125
|
-
return "0.0.0";
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
function resolveExitCode(result, failReason) {
|
|
129
|
-
if (result.errors.length > 0)
|
|
130
|
-
return 2;
|
|
131
|
-
if (failReason !== "none")
|
|
132
|
-
return 1;
|
|
133
|
-
return 0;
|
|
134
|
-
}
|
package/dist/bin/dispatch.js
CHANGED
|
@@ -108,6 +108,12 @@ export async function handleDirectCommand(parsed) {
|
|
|
108
108
|
setRuntimeExitCode(result.ready ? 0 : 1);
|
|
109
109
|
return true;
|
|
110
110
|
}
|
|
111
|
+
if (parsed.command === "hook") {
|
|
112
|
+
const { runHook } = await import("../commands/hook/runner.js");
|
|
113
|
+
const result = await runHook(parsed.options);
|
|
114
|
+
setRuntimeExitCode(result.errors.length > 0 ? 1 : 0);
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
111
117
|
if (parsed.options.interactive &&
|
|
112
118
|
(parsed.command === "check" ||
|
|
113
119
|
parsed.command === "upgrade" ||
|
package/dist/bin/help.js
CHANGED
|
@@ -40,6 +40,11 @@ Options:
|
|
|
40
40
|
--cooldown-days <n>
|
|
41
41
|
--pr-limit <n>
|
|
42
42
|
--only-changed
|
|
43
|
+
--affected
|
|
44
|
+
--staged
|
|
45
|
+
--base <ref>
|
|
46
|
+
--head <ref>
|
|
47
|
+
--since <ref>
|
|
43
48
|
--interactive
|
|
44
49
|
--plan-file <path>
|
|
45
50
|
--verify none|install|test|install,test
|
|
@@ -123,6 +128,11 @@ Options:
|
|
|
123
128
|
--cooldown-days <n>
|
|
124
129
|
--pr-limit <n>
|
|
125
130
|
--only-changed
|
|
131
|
+
--affected
|
|
132
|
+
--staged
|
|
133
|
+
--base <ref>
|
|
134
|
+
--head <ref>
|
|
135
|
+
--since <ref>
|
|
126
136
|
--offline
|
|
127
137
|
--concurrency <n>
|
|
128
138
|
--registry-timeout-ms <n>
|
|
@@ -180,6 +190,11 @@ Scan dependencies for CVEs using OSV.dev and GitHub Advisory Database.
|
|
|
180
190
|
|
|
181
191
|
Options:
|
|
182
192
|
--workspace
|
|
193
|
+
--affected
|
|
194
|
+
--staged
|
|
195
|
+
--base <ref>
|
|
196
|
+
--head <ref>
|
|
197
|
+
--since <ref>
|
|
183
198
|
--severity critical|high|medium|low
|
|
184
199
|
--summary
|
|
185
200
|
--report table|summary|json
|
|
@@ -200,6 +215,12 @@ Use it to inspect risk, security, peer, license, and policy context before apply
|
|
|
200
215
|
|
|
201
216
|
Options:
|
|
202
217
|
--workspace
|
|
218
|
+
--only-changed
|
|
219
|
+
--affected
|
|
220
|
+
--staged
|
|
221
|
+
--base <ref>
|
|
222
|
+
--head <ref>
|
|
223
|
+
--since <ref>
|
|
203
224
|
--interactive
|
|
204
225
|
--security-only
|
|
205
226
|
--risk critical|high|medium|low
|
|
@@ -220,6 +241,12 @@ Produce a fast summary verdict and point the operator to review when action is n
|
|
|
220
241
|
|
|
221
242
|
Options:
|
|
222
243
|
--workspace
|
|
244
|
+
--only-changed
|
|
245
|
+
--affected
|
|
246
|
+
--staged
|
|
247
|
+
--base <ref>
|
|
248
|
+
--head <ref>
|
|
249
|
+
--since <ref>
|
|
223
250
|
--verdict-only
|
|
224
251
|
--include-changelog
|
|
225
252
|
--json-file <path>`;
|
|
@@ -231,6 +258,12 @@ Open the primary interactive dependency operations console.
|
|
|
231
258
|
|
|
232
259
|
Options:
|
|
233
260
|
--workspace
|
|
261
|
+
--only-changed
|
|
262
|
+
--affected
|
|
263
|
+
--staged
|
|
264
|
+
--base <ref>
|
|
265
|
+
--head <ref>
|
|
266
|
+
--since <ref>
|
|
234
267
|
--mode check|review|upgrade
|
|
235
268
|
--focus all|security|risk|major|blocked|workspace
|
|
236
269
|
--apply-selected
|
|
@@ -248,6 +281,14 @@ Audit release and CI readiness for Rainy Updates.
|
|
|
248
281
|
Options:
|
|
249
282
|
--workspace
|
|
250
283
|
--json-file <path>
|
|
284
|
+
--cwd <path>`;
|
|
285
|
+
}
|
|
286
|
+
if (isCommand && command === "hook") {
|
|
287
|
+
return `rainy-updates hook <install|uninstall|doctor> [options]
|
|
288
|
+
|
|
289
|
+
Install, remove, or inspect Rainy-managed git hooks.
|
|
290
|
+
|
|
291
|
+
Options:
|
|
251
292
|
--cwd <path>`;
|
|
252
293
|
}
|
|
253
294
|
return `rainy-updates (rup / rainy-up) <command> [options]
|
|
@@ -270,6 +311,7 @@ Commands:
|
|
|
270
311
|
licenses Scan dependency licenses and generate SPDX SBOM
|
|
271
312
|
snapshot Save, list, restore, and diff dependency state snapshots
|
|
272
313
|
ga Audit GA and CI readiness for this checkout
|
|
314
|
+
hook Install or inspect Rainy-managed git hooks
|
|
273
315
|
|
|
274
316
|
Global options:
|
|
275
317
|
--cwd <path>
|
|
@@ -288,6 +330,11 @@ Global options:
|
|
|
288
330
|
--cooldown-days <n>
|
|
289
331
|
--pr-limit <n>
|
|
290
332
|
--only-changed
|
|
333
|
+
--affected
|
|
334
|
+
--staged
|
|
335
|
+
--base <ref>
|
|
336
|
+
--head <ref>
|
|
337
|
+
--since <ref>
|
|
291
338
|
--interactive
|
|
292
339
|
--show-impact
|
|
293
340
|
--show-links
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runCli(): Promise<void>;
|
package/dist/bin/main.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { parseCliArgs } from "../core/options.js";
|
|
2
|
+
import { createRunId, writeArtifactManifest } from "../core/artifacts.js";
|
|
3
|
+
import { renderResult } from "../output/format.js";
|
|
4
|
+
import { writeGitHubOutput } from "../output/github.js";
|
|
5
|
+
import { createSarifReport } from "../output/sarif.js";
|
|
6
|
+
import { renderPrReport } from "../output/pr-report.js";
|
|
7
|
+
import { writeFileAtomic } from "../utils/io.js";
|
|
8
|
+
import { resolveFailReason } from "../core/summary.js";
|
|
9
|
+
import { stableStringify } from "../utils/stable-json.js";
|
|
10
|
+
import { getRuntimeArgv, setRuntimeExitCode, writeStderr, writeStdout, } from "../utils/runtime.js";
|
|
11
|
+
import { CLI_VERSION } from "../generated/version.js";
|
|
12
|
+
import { handleDirectCommand, runPrimaryCommand } from "./dispatch.js";
|
|
13
|
+
import { renderHelp } from "./help.js";
|
|
14
|
+
export async function runCli() {
|
|
15
|
+
try {
|
|
16
|
+
const argv = getRuntimeArgv();
|
|
17
|
+
if (argv.includes("--version") || argv.includes("-v")) {
|
|
18
|
+
writeStdout((await readPackageVersion()) + "\n");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
22
|
+
writeStdout(renderHelp(argv[0]) + "\n");
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const parsed = await parseCliArgs(argv);
|
|
26
|
+
if (await handleDirectCommand(parsed))
|
|
27
|
+
return;
|
|
28
|
+
if (parsed.command !== "check" &&
|
|
29
|
+
parsed.command !== "upgrade" &&
|
|
30
|
+
parsed.command !== "warm-cache" &&
|
|
31
|
+
parsed.command !== "ci") {
|
|
32
|
+
throw new Error(`Unhandled command: ${parsed.command}`);
|
|
33
|
+
}
|
|
34
|
+
const result = await runPrimaryCommand(parsed);
|
|
35
|
+
result.summary.runId = createRunId(parsed.command, parsed.options, result);
|
|
36
|
+
if (parsed.options.fixPr &&
|
|
37
|
+
(parsed.command === "check" ||
|
|
38
|
+
parsed.command === "upgrade" ||
|
|
39
|
+
parsed.command === "ci")) {
|
|
40
|
+
result.summary.fixPrApplied = false;
|
|
41
|
+
result.summary.fixBranchName =
|
|
42
|
+
parsed.options.fixBranch ?? "chore/rainy-updates";
|
|
43
|
+
result.summary.fixCommitSha = "";
|
|
44
|
+
result.summary.fixPrBranchesCreated = 0;
|
|
45
|
+
if (parsed.command === "ci") {
|
|
46
|
+
const { applyFixPrBatches } = await import("../core/fix-pr-batch.js");
|
|
47
|
+
const batched = await applyFixPrBatches(parsed.options, result);
|
|
48
|
+
result.summary.fixPrApplied = batched.applied;
|
|
49
|
+
result.summary.fixBranchName =
|
|
50
|
+
batched.branches[0] ??
|
|
51
|
+
parsed.options.fixBranch ??
|
|
52
|
+
"chore/rainy-updates";
|
|
53
|
+
result.summary.fixCommitSha = batched.commits[0] ?? "";
|
|
54
|
+
result.summary.fixPrBranchesCreated = batched.branches.length;
|
|
55
|
+
if (batched.branches.length > 1) {
|
|
56
|
+
result.warnings.push(`Created ${batched.branches.length} fix-pr batch branches.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const { applyFixPr } = await import("../core/fix-pr.js");
|
|
61
|
+
const fixResult = await applyFixPr(parsed.options, result, []);
|
|
62
|
+
result.summary.fixPrApplied = fixResult.applied;
|
|
63
|
+
result.summary.fixBranchName = fixResult.branchName ?? "";
|
|
64
|
+
result.summary.fixCommitSha = fixResult.commitSha ?? "";
|
|
65
|
+
result.summary.fixPrBranchesCreated = fixResult.applied ? 1 : 0;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (parsed.options.prReportFile) {
|
|
69
|
+
const markdown = renderPrReport(result);
|
|
70
|
+
await writeFileAtomic(parsed.options.prReportFile, markdown + "\n");
|
|
71
|
+
}
|
|
72
|
+
const artifactManifest = await writeArtifactManifest(parsed.command, parsed.options, result);
|
|
73
|
+
if (artifactManifest) {
|
|
74
|
+
result.summary.artifactManifest = artifactManifest.artifactManifestPath;
|
|
75
|
+
}
|
|
76
|
+
result.summary.failReason = resolveFailReason(result.updates, result.errors, parsed.options.failOn, parsed.options.maxUpdates, parsed.options.ci);
|
|
77
|
+
const renderStartedAt = Date.now();
|
|
78
|
+
let rendered = renderResult(result, parsed.options.format, {
|
|
79
|
+
showImpact: parsed.options.showImpact,
|
|
80
|
+
showHomepage: parsed.options.showHomepage,
|
|
81
|
+
});
|
|
82
|
+
result.summary.durationMs.render = Math.max(0, Date.now() - renderStartedAt);
|
|
83
|
+
if (parsed.options.format === "json" ||
|
|
84
|
+
parsed.options.format === "metrics") {
|
|
85
|
+
rendered = renderResult(result, parsed.options.format, {
|
|
86
|
+
showImpact: parsed.options.showImpact,
|
|
87
|
+
showHomepage: parsed.options.showHomepage,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (parsed.options.onlyChanged &&
|
|
91
|
+
result.updates.length === 0 &&
|
|
92
|
+
result.errors.length === 0 &&
|
|
93
|
+
result.warnings.length === 0 &&
|
|
94
|
+
(parsed.options.format === "table" ||
|
|
95
|
+
parsed.options.format === "minimal" ||
|
|
96
|
+
parsed.options.format === "github")) {
|
|
97
|
+
rendered = "";
|
|
98
|
+
}
|
|
99
|
+
if (parsed.options.jsonFile) {
|
|
100
|
+
await writeFileAtomic(parsed.options.jsonFile, stableStringify(result, 2) + "\n");
|
|
101
|
+
}
|
|
102
|
+
if (parsed.options.githubOutputFile) {
|
|
103
|
+
await writeGitHubOutput(parsed.options.githubOutputFile, result);
|
|
104
|
+
}
|
|
105
|
+
if (parsed.options.sarifFile) {
|
|
106
|
+
const sarif = createSarifReport(result);
|
|
107
|
+
await writeFileAtomic(parsed.options.sarifFile, stableStringify(sarif, 2) + "\n");
|
|
108
|
+
}
|
|
109
|
+
writeStdout(rendered + "\n");
|
|
110
|
+
setRuntimeExitCode(resolveExitCode(result, result.summary.failReason));
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
writeStderr(`rainy-updates (rup): ${String(error)}\n`);
|
|
114
|
+
setRuntimeExitCode(2);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
async function readPackageVersion() {
|
|
118
|
+
return CLI_VERSION;
|
|
119
|
+
}
|
|
120
|
+
function resolveExitCode(result, failReason) {
|
|
121
|
+
if (result.errors.length > 0)
|
|
122
|
+
return 2;
|
|
123
|
+
if (failReason !== "none")
|
|
124
|
+
return 1;
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
@@ -12,6 +12,11 @@ export function parseAuditArgs(args) {
|
|
|
12
12
|
const options = {
|
|
13
13
|
cwd: getRuntimeCwd(),
|
|
14
14
|
workspace: false,
|
|
15
|
+
affected: false,
|
|
16
|
+
staged: false,
|
|
17
|
+
baseRef: undefined,
|
|
18
|
+
headRef: undefined,
|
|
19
|
+
sinceRef: undefined,
|
|
15
20
|
severity: undefined,
|
|
16
21
|
fix: false,
|
|
17
22
|
dryRun: false,
|
|
@@ -39,6 +44,37 @@ export function parseAuditArgs(args) {
|
|
|
39
44
|
index += 1;
|
|
40
45
|
continue;
|
|
41
46
|
}
|
|
47
|
+
if (current === "--affected") {
|
|
48
|
+
options.affected = true;
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (current === "--staged") {
|
|
53
|
+
options.staged = true;
|
|
54
|
+
index += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (current === "--base" && next) {
|
|
58
|
+
options.baseRef = next;
|
|
59
|
+
index += 2;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (current === "--base")
|
|
63
|
+
throw new Error("Missing value for --base");
|
|
64
|
+
if (current === "--head" && next) {
|
|
65
|
+
options.headRef = next;
|
|
66
|
+
index += 2;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (current === "--head")
|
|
70
|
+
throw new Error("Missing value for --head");
|
|
71
|
+
if (current === "--since" && next) {
|
|
72
|
+
options.sinceRef = next;
|
|
73
|
+
index += 2;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (current === "--since")
|
|
77
|
+
throw new Error("Missing value for --since");
|
|
42
78
|
if (current === "--severity" && next) {
|
|
43
79
|
options.severity = parseSeverity(next);
|
|
44
80
|
index += 2;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { collectDependencies, readManifest, } from "../../parsers/package-json.js";
|
|
2
|
-
import {
|
|
2
|
+
import { buildAddInvocation, createPackageManagerProfile, detectPackageManagerDetails, } from "../../pm/detect.js";
|
|
3
3
|
import { discoverPackageDirs } from "../../workspace/discover.js";
|
|
4
4
|
import { writeFileAtomic } from "../../utils/io.js";
|
|
5
5
|
import { stableStringify } from "../../utils/stable-json.js";
|
|
@@ -28,7 +28,15 @@ export async function runAudit(options) {
|
|
|
28
28
|
unresolved: 0,
|
|
29
29
|
},
|
|
30
30
|
};
|
|
31
|
-
const packageDirs = await discoverPackageDirs(options.cwd, options.workspace
|
|
31
|
+
const packageDirs = await discoverPackageDirs(options.cwd, options.workspace, {
|
|
32
|
+
git: options,
|
|
33
|
+
includeKinds: [
|
|
34
|
+
"dependencies",
|
|
35
|
+
"devDependencies",
|
|
36
|
+
"optionalDependencies",
|
|
37
|
+
],
|
|
38
|
+
includeDependents: options.affected === true,
|
|
39
|
+
});
|
|
32
40
|
const depsByDir = new Map();
|
|
33
41
|
for (const dir of packageDirs) {
|
|
34
42
|
let manifest;
|
|
@@ -121,10 +129,10 @@ async function applyFix(advisories, options) {
|
|
|
121
129
|
const patchMap = buildPatchMap(advisories);
|
|
122
130
|
if (patchMap.size === 0)
|
|
123
131
|
return;
|
|
124
|
-
const detected = await
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
const installCmd =
|
|
132
|
+
const detected = await detectPackageManagerDetails(options.cwd);
|
|
133
|
+
const profile = createPackageManagerProfile(options.packageManager, detected);
|
|
134
|
+
const install = buildInstallArgs(profile, patchMap);
|
|
135
|
+
const installCmd = install.display;
|
|
128
136
|
if (options.dryRun) {
|
|
129
137
|
if (!options.silent) {
|
|
130
138
|
writeStderr(`[audit] --dry-run: would execute:\n ${installCmd}\n`);
|
|
@@ -140,7 +148,7 @@ async function applyFix(advisories, options) {
|
|
|
140
148
|
writeStderr(` → ${installCmd}\n`);
|
|
141
149
|
}
|
|
142
150
|
try {
|
|
143
|
-
await runCommand(
|
|
151
|
+
await runCommand(install.command, install.args, options.cwd);
|
|
144
152
|
}
|
|
145
153
|
catch (err) {
|
|
146
154
|
if (!options.silent) {
|
|
@@ -158,18 +166,9 @@ async function applyFix(advisories, options) {
|
|
|
158
166
|
writeStderr(`[audit] Tip: run with --commit to automatically commit the changes.\n`);
|
|
159
167
|
}
|
|
160
168
|
}
|
|
161
|
-
function buildInstallArgs(
|
|
169
|
+
function buildInstallArgs(profile, patchMap) {
|
|
162
170
|
const packages = [...patchMap.entries()].map(([n, v]) => `${n}@${v}`);
|
|
163
|
-
|
|
164
|
-
case "pnpm":
|
|
165
|
-
return ["add", ...packages];
|
|
166
|
-
case "bun":
|
|
167
|
-
return ["add", ...packages];
|
|
168
|
-
case "yarn":
|
|
169
|
-
return ["add", ...packages];
|
|
170
|
-
default:
|
|
171
|
-
return ["install", ...packages]; // npm
|
|
172
|
-
}
|
|
171
|
+
return buildAddInvocation(profile, packages);
|
|
173
172
|
}
|
|
174
173
|
async function commitFix(patchMap, cwd, silent) {
|
|
175
174
|
const msg = buildCommitMessage(patchMap);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { buildAddInvocation, createPackageManagerProfile, detectPackageManagerDetails, } from "../../pm/detect.js";
|
|
3
3
|
/**
|
|
4
4
|
* The "oracle" for bisect: installs a specific version of a package
|
|
5
5
|
* into the project's node_modules (via the shell), then runs --cmd.
|
|
@@ -11,9 +11,12 @@ export async function bisectOracle(packageName, version, options) {
|
|
|
11
11
|
process.stderr.write(`[bisect:dry-run] Would test ${packageName}@${version}\n`);
|
|
12
12
|
return "skip";
|
|
13
13
|
}
|
|
14
|
-
const detected = await
|
|
15
|
-
const
|
|
16
|
-
const installResult = await
|
|
14
|
+
const detected = await detectPackageManagerDetails(options.cwd);
|
|
15
|
+
const profile = createPackageManagerProfile("auto", detected, "bun");
|
|
16
|
+
const installResult = await runCommand(buildAddInvocation(profile, [`${packageName}@${version}`], {
|
|
17
|
+
exact: true,
|
|
18
|
+
noSave: true,
|
|
19
|
+
}), options.cwd);
|
|
17
20
|
if (installResult !== 0) {
|
|
18
21
|
process.stderr.write(`[bisect] Failed to install ${packageName}@${version}, skipping.\n`);
|
|
19
22
|
return "skip";
|
|
@@ -38,16 +41,16 @@ async function runShell(command, cwd) {
|
|
|
38
41
|
return 1;
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
44
|
+
async function runCommand(command, cwd) {
|
|
45
|
+
try {
|
|
46
|
+
const proc = Bun.spawn([command.command, ...command.args], {
|
|
47
|
+
cwd: path.resolve(cwd),
|
|
48
|
+
stdout: "pipe",
|
|
49
|
+
stderr: "pipe",
|
|
50
|
+
});
|
|
51
|
+
return await proc.exited;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return 1;
|
|
52
55
|
}
|
|
53
56
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildTestCommand, createPackageManagerProfile, detectPackageManagerDetails, } from "../../pm/detect.js";
|
|
2
2
|
import { fetchBisectVersions, bisectVersions } from "./engine.js";
|
|
3
3
|
/**
|
|
4
4
|
* Entry point for the `bisect` command. Lazy-loaded by cli.ts.
|
|
5
5
|
* Fully isolated: does NOT import anything from core/options.ts.
|
|
6
6
|
*/
|
|
7
7
|
export async function runBisect(options) {
|
|
8
|
-
const detected = await
|
|
8
|
+
const detected = await detectPackageManagerDetails(options.cwd);
|
|
9
|
+
const profile = createPackageManagerProfile("auto", detected, "bun");
|
|
9
10
|
const runtimeOptions = {
|
|
10
11
|
...options,
|
|
11
12
|
testCommand: options.testCommand ||
|
|
12
|
-
|
|
13
|
+
buildTestCommand(profile),
|
|
13
14
|
};
|
|
14
15
|
process.stderr.write(`\n[bisect] Fetching available versions for ${runtimeOptions.packageName}...\n`);
|
|
15
16
|
const versions = await fetchBisectVersions(runtimeOptions);
|