ccqa 1.50.1 → 1.51.0
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/dist/bin/ccqa.mjs +62 -48
- package/dist/hub-client/index.d.mts +6 -3
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/bin/ccqa.mjs
CHANGED
|
@@ -14664,32 +14664,42 @@ function requireReportToHubConnection(conn) {
|
|
|
14664
14664
|
process.exit(2);
|
|
14665
14665
|
}
|
|
14666
14666
|
/**
|
|
14667
|
-
* Open the run a `--report-to-hub` command patches into
|
|
14668
|
-
*
|
|
14669
|
-
*
|
|
14670
|
-
*
|
|
14671
|
-
*
|
|
14672
|
-
|
|
14673
|
-
|
|
14674
|
-
|
|
14667
|
+
* Open the run a `--report-to-hub` command patches into, and name it on stderr
|
|
14668
|
+
* — stdout belongs to the report (`--report-format json`), and a caller that
|
|
14669
|
+
* links to the run needs its id before the command ends (docs/hub.md).
|
|
14670
|
+
*
|
|
14671
|
+
* Failure is fatal: a job that asked to publish and cannot reach the hub has
|
|
14672
|
+
* not done what it was told. Thrown rather than exited, so a caller's
|
|
14673
|
+
* `finally` still runs (the audit releases its spec claims there). Not
|
|
14674
|
+
* retried: a dropped response after the hub committed would leave a second
|
|
14675
|
+
* orphan running run.
|
|
14676
|
+
*/
|
|
14677
|
+
async function openHubRun(kind, conn, cwd, opts = {}) {
|
|
14678
|
+
const [branch, gitHead] = await Promise.all([detectBranch(cwd), opts.gitHead !== void 0 ? opts.gitHead : getGitHead(cwd)]);
|
|
14679
|
+
let opened;
|
|
14675
14680
|
try {
|
|
14676
|
-
|
|
14681
|
+
opened = await conn.hub.openRun({
|
|
14677
14682
|
project: conn.project,
|
|
14678
14683
|
kind,
|
|
14679
14684
|
...branch ? { branch } : {},
|
|
14680
|
-
...profile ? { profile } : {},
|
|
14685
|
+
...opts.profile ? { profile: opts.profile } : {},
|
|
14681
14686
|
...gitHead ? { gitHead } : {},
|
|
14687
|
+
...opts.deployedSha ? { deployedSha: opts.deployedSha } : {},
|
|
14682
14688
|
...ciProvenance()
|
|
14683
14689
|
});
|
|
14684
|
-
return {
|
|
14685
|
-
hub: conn.hub,
|
|
14686
|
-
kind,
|
|
14687
|
-
runId: run.id,
|
|
14688
|
-
gitHead
|
|
14689
|
-
};
|
|
14690
14690
|
} catch (err) {
|
|
14691
14691
|
throw new RunUsageError(`--report-to-hub: could not open a run on the hub (${errMessage(err)})`);
|
|
14692
14692
|
}
|
|
14693
|
+
process.stderr.write(`[hub-run] ${JSON.stringify({
|
|
14694
|
+
id: opened.id,
|
|
14695
|
+
kind
|
|
14696
|
+
})}\n`);
|
|
14697
|
+
return {
|
|
14698
|
+
hub: conn.hub,
|
|
14699
|
+
kind,
|
|
14700
|
+
runId: opened.id,
|
|
14701
|
+
gitHead
|
|
14702
|
+
};
|
|
14693
14703
|
}
|
|
14694
14704
|
/**
|
|
14695
14705
|
* Close an open run with its final rows and envelope, answering whether it
|
|
@@ -15437,25 +15447,17 @@ async function executeRun(targets, opts) {
|
|
|
15437
15447
|
reportDir: null
|
|
15438
15448
|
};
|
|
15439
15449
|
}
|
|
15440
|
-
const det = await runDeterministicSpecs(detSpecs, opts, cwd, reportDir, resources);
|
|
15441
15450
|
let hubRunId = null;
|
|
15442
15451
|
let hubSink;
|
|
15443
15452
|
let hubPublishBroken = false;
|
|
15444
|
-
if (hubCtx != null && opts.reportToHub)
|
|
15445
|
-
const
|
|
15446
|
-
const opened = await hubCtx.hub.openRun({
|
|
15447
|
-
project: hubCtx.project,
|
|
15448
|
-
...branch ? { branch } : {},
|
|
15453
|
+
if (hubCtx != null && opts.reportToHub) {
|
|
15454
|
+
const { runId } = await openHubRun("run", hubCtx, cwd, {
|
|
15449
15455
|
...opts.hubProfile ? { profile: opts.hubProfile } : {},
|
|
15450
|
-
|
|
15451
|
-
|
|
15452
|
-
...ciProvenance(),
|
|
15453
|
-
kind: "run"
|
|
15456
|
+
gitHead: git.head,
|
|
15457
|
+
deployedSha
|
|
15454
15458
|
});
|
|
15455
|
-
hubRunId =
|
|
15456
|
-
|
|
15457
|
-
await coverage?.linkHubRun(opened.id);
|
|
15458
|
-
const runId = opened.id;
|
|
15459
|
+
hubRunId = runId;
|
|
15460
|
+
await coverage?.linkHubRun(runId);
|
|
15459
15461
|
let hubPatchEverSucceeded = false;
|
|
15460
15462
|
hubSink = { onUpsert: async (row) => {
|
|
15461
15463
|
try {
|
|
@@ -15473,8 +15475,6 @@ async function executeRun(targets, opts) {
|
|
|
15473
15475
|
} else warn(`hub: incremental push failed for ${row.feature}/${row.spec}: ${errMessage(err)}`);
|
|
15474
15476
|
}
|
|
15475
15477
|
} };
|
|
15476
|
-
} catch (err) {
|
|
15477
|
-
throw new RunUsageError(`--report-to-hub: could not open a run on the hub (${errMessage(err)})`);
|
|
15478
15478
|
}
|
|
15479
15479
|
const incrementalReport = createIncrementalReport(reportDir, buildReportEnvelope({
|
|
15480
15480
|
git,
|
|
@@ -15499,6 +15499,7 @@ async function executeRun(targets, opts) {
|
|
|
15499
15499
|
warn(`hub: could not finalize interrupted run ${hubRunId}: ${errMessage(err)}`);
|
|
15500
15500
|
}
|
|
15501
15501
|
});
|
|
15502
|
+
const det = await runDeterministicSpecs(detSpecs, opts, cwd, reportDir, resources);
|
|
15502
15503
|
const externalRows = await runExternalSpecs(dispatch, {
|
|
15503
15504
|
cwd,
|
|
15504
15505
|
reportDir,
|
|
@@ -17986,8 +17987,7 @@ async function runRecord(specPath, opts) {
|
|
|
17986
17987
|
}
|
|
17987
17988
|
throw e;
|
|
17988
17989
|
});
|
|
17989
|
-
const push = pushConn ? await openHubRun("record", pushConn, cwdForProfile, opts.hubProfile) : null;
|
|
17990
|
-
if (push) info(`hub: record run opened (${push.runId})`);
|
|
17990
|
+
const push = pushConn ? await openHubRun("record", pushConn, cwdForProfile, { ...opts.hubProfile ? { profile: opts.hubProfile } : {} }) : null;
|
|
17991
17991
|
let recorded = false;
|
|
17992
17992
|
let sealed = true;
|
|
17993
17993
|
let tracingStep;
|
|
@@ -19065,10 +19065,7 @@ async function runAudit(specPath, opts) {
|
|
|
19065
19065
|
let push = null;
|
|
19066
19066
|
try {
|
|
19067
19067
|
promptCtx = await resolveAuditPromptContext(opts, cwd);
|
|
19068
|
-
if (pushConn) {
|
|
19069
|
-
push = await openHubRun("drift", pushConn, cwd, opts.hubProfile);
|
|
19070
|
-
if (format === "text") info(`hub: incremental drift run opened (${push.runId})`);
|
|
19071
|
-
}
|
|
19068
|
+
if (pushConn) push = await openHubRun("drift", pushConn, cwd, { ...opts.hubProfile ? { profile: opts.hubProfile } : {} });
|
|
19072
19069
|
results = await analyzeDrift({
|
|
19073
19070
|
targets,
|
|
19074
19071
|
cwd,
|
|
@@ -20613,7 +20610,7 @@ function createPatchRunHandler(config) {
|
|
|
20613
20610
|
sendJson(ctx.res, 200, updated);
|
|
20614
20611
|
};
|
|
20615
20612
|
}
|
|
20616
|
-
/** GET /api/v1/runs?project&branch&status&kind&since&until&limit */
|
|
20613
|
+
/** GET /api/v1/runs?project&branch&status&kind&ciRunId&since&until&limit */
|
|
20617
20614
|
function createListRunsHandler(storage) {
|
|
20618
20615
|
return async (ctx) => {
|
|
20619
20616
|
const project = ctx.url.searchParams.get("project");
|
|
@@ -20621,11 +20618,13 @@ function createListRunsHandler(storage) {
|
|
|
20621
20618
|
const status = ctx.url.searchParams.get("status");
|
|
20622
20619
|
const limitRaw = ctx.url.searchParams.get("limit");
|
|
20623
20620
|
const kindsRaw = ctx.url.searchParams.get("kind");
|
|
20621
|
+
const ciRunId = boundedParam(ctx.url.searchParams.get("ciRunId"), "ciRunId", 128);
|
|
20624
20622
|
const runs = await storage.runs.list({
|
|
20625
20623
|
...project ? { project } : {},
|
|
20626
20624
|
...branch ? { branch } : {},
|
|
20627
20625
|
...status ? { status } : {},
|
|
20628
20626
|
...kindsRaw ? { kinds: kindsRaw.split(",").map(requireKind) } : {},
|
|
20627
|
+
...ciRunId ? { ciRunId } : {},
|
|
20629
20628
|
...requireWindowParams(ctx.url),
|
|
20630
20629
|
...limitRaw ? { limit: Number(limitRaw) } : {}
|
|
20631
20630
|
});
|
|
@@ -24817,12 +24816,15 @@ const CLIENT_JS = `
|
|
|
24817
24816
|
// Disconnected: the full-screen login gate is the only thing to show.
|
|
24818
24817
|
if (!state.token) { showAuthGate(false); return; }
|
|
24819
24818
|
showAuthGate(true);
|
|
24819
|
+
// A run is addressed by its own id, not through a project, so a link from
|
|
24820
|
+
// outside (a chat message, a CI job) opens it even in a browser that has
|
|
24821
|
+
// never picked one — ahead of the gate below, which would drop the link.
|
|
24822
|
+
var m = parseRunHash(location.hash);
|
|
24823
|
+
if (m) { openRunDetail(m.runId, m.caseKey); return; }
|
|
24820
24824
|
// With no project chosen yet, the Projects picker is the only useful view —
|
|
24821
24825
|
// land there (e.g. right after login) instead of an empty Runs list, and
|
|
24822
|
-
// gate any deep-linked
|
|
24826
|
+
// gate any deep-linked project-scoped view to it too.
|
|
24823
24827
|
if (location.hash === "#/projects" || !state.project) { openProjects(); return; }
|
|
24824
|
-
var m = parseRunHash(location.hash);
|
|
24825
|
-
if (m) { openRunDetail(m.runId, m.caseKey); return; }
|
|
24826
24828
|
if (location.hash === "#/perspectives") { openPerspectives(); return; }
|
|
24827
24829
|
if (location.hash === "#/coverage") { openCoverage(); return; }
|
|
24828
24830
|
if (location.hash === "#/secrets") { openSecrets(); return; }
|
|
@@ -26406,6 +26408,11 @@ const CLIENT_JS = `
|
|
|
26406
26408
|
var runGone = false;
|
|
26407
26409
|
|
|
26408
26410
|
apiFetch("/api/v1/runs/" + encodeURIComponent(runId)).then(function (run) {
|
|
26411
|
+
// Arrived by an outside link: the selected project is whatever the last
|
|
26412
|
+
// visit or the boot auto-select left, which need not be this run's.
|
|
26413
|
+
// Follow the run, so the nav around it answers for the project the page
|
|
26414
|
+
// is actually showing.
|
|
26415
|
+
if (run.project && run.project !== state.project) adoptProject(run.project);
|
|
26409
26416
|
renderRunHead(run);
|
|
26410
26417
|
}).catch(function (err) {
|
|
26411
26418
|
runGone = err.status === 404;
|
|
@@ -28483,14 +28490,20 @@ const CLIENT_JS = `
|
|
|
28483
28490
|
updateNavGate();
|
|
28484
28491
|
}
|
|
28485
28492
|
|
|
28486
|
-
// Scope to a project
|
|
28487
|
-
//
|
|
28488
|
-
//
|
|
28489
|
-
//
|
|
28490
|
-
function
|
|
28493
|
+
// Scope the UI to a project, restoring the profile last chosen for it (or
|
|
28494
|
+
// "default" if none was saved); the Secrets tab reloads the profile list when
|
|
28495
|
+
// opened. Separate from the navigation below because arriving on a run by
|
|
28496
|
+
// link adopts a project without going anywhere.
|
|
28497
|
+
function adoptProject(p) {
|
|
28491
28498
|
setProject(p);
|
|
28492
28499
|
storeProject(p);
|
|
28493
28500
|
setProfile(storedProfileForProject(p) || "default");
|
|
28501
|
+
}
|
|
28502
|
+
|
|
28503
|
+
// Scope to a project and land on its Runs view. Shared by the top menu, the
|
|
28504
|
+
// Projects grid, and the "new project" flow.
|
|
28505
|
+
function chooseProject(p) {
|
|
28506
|
+
adoptProject(p);
|
|
28494
28507
|
location.hash = "#/runs";
|
|
28495
28508
|
route();
|
|
28496
28509
|
}
|
|
@@ -30188,7 +30201,7 @@ function createFileRunStore(root) {
|
|
|
30188
30201
|
async delete(id) {
|
|
30189
30202
|
await serialize(runMetaPath(root, id), () => removePath(runDir(root, id)));
|
|
30190
30203
|
},
|
|
30191
|
-
async list({ project, branch, status, kinds, since, until, limit }) {
|
|
30204
|
+
async list({ project, branch, status, kinds, ciRunId, since, until, limit }) {
|
|
30192
30205
|
const ids = await listSubdirsOrEmpty(runsDir(root));
|
|
30193
30206
|
const inWindow = windowFilter({
|
|
30194
30207
|
since,
|
|
@@ -30202,6 +30215,7 @@ function createFileRunStore(root) {
|
|
|
30202
30215
|
if (branch !== void 0 && run.branch !== branch) continue;
|
|
30203
30216
|
if (status !== void 0 && run.status !== status) continue;
|
|
30204
30217
|
if (kinds !== void 0 && !kinds.includes(run.kind)) continue;
|
|
30218
|
+
if (ciRunId !== void 0 && run.ciRunId !== ciRunId) continue;
|
|
30205
30219
|
if (!inWindow(run.createdAt)) continue;
|
|
30206
30220
|
runs.push(run);
|
|
30207
30221
|
}
|
|
@@ -1147,9 +1147,10 @@ interface HubClient {
|
|
|
1147
1147
|
* `gitHead` stamps the run's commit at open time, so even a run that dies
|
|
1148
1148
|
* before its final reconcile patch is attributable to a commit.
|
|
1149
1149
|
*
|
|
1150
|
-
* `deployedSha` does the same for the environment's commit
|
|
1151
|
-
*
|
|
1152
|
-
* the
|
|
1150
|
+
* `deployedSha` does the same for the environment's commit: the baseline the
|
|
1151
|
+
* caller selected against, which a `--rerun` inherits from an earlier run.
|
|
1152
|
+
* Left unset the hub reads its own deploy-log head, which by the time this
|
|
1153
|
+
* call lands can already name a later deploy.
|
|
1153
1154
|
*/
|
|
1154
1155
|
openRun(meta: {
|
|
1155
1156
|
project: string;
|
|
@@ -1165,11 +1166,13 @@ interface HubClient {
|
|
|
1165
1166
|
}): Promise<Run>;
|
|
1166
1167
|
/** Add finished spec rows (+ evidence) to a running run; `done` closes it. */
|
|
1167
1168
|
patchRun(id: string, body: PatchRunRequest): Promise<Run>;
|
|
1169
|
+
/** `ciRunId` answers "which runs did this CI job create", whatever the window. */
|
|
1168
1170
|
listRuns(q?: {
|
|
1169
1171
|
project?: string;
|
|
1170
1172
|
branch?: string;
|
|
1171
1173
|
status?: RunStatus;
|
|
1172
1174
|
kind?: Run["kind"];
|
|
1175
|
+
ciRunId?: string;
|
|
1173
1176
|
limit?: number;
|
|
1174
1177
|
}): Promise<Run[]>;
|
|
1175
1178
|
getRun(id: string): Promise<Run>;
|
package/dist/package.json
CHANGED