@continuous-excellence/ze-great-dashboard-aws 0.31.56 → 0.31.57
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/cli.js +336 -211
- package/dist/index.js +336 -211
- package/dist/lambda.mjs +250 -104
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1259,6 +1259,12 @@ var testCountSchema = z4.discriminatedUnion("status", [
|
|
|
1259
1259
|
type: z4.literal("test-count"),
|
|
1260
1260
|
status: z4.literal("reported"),
|
|
1261
1261
|
total: z4.number().int().nonnegative(),
|
|
1262
|
+
/** Public identity for browser-local comparisons, never observation time. */
|
|
1263
|
+
run: z4.object({
|
|
1264
|
+
id: z4.string().min(1),
|
|
1265
|
+
attempt: z4.number().int().positive(),
|
|
1266
|
+
updatedAt: z4.iso.datetime()
|
|
1267
|
+
}).optional(),
|
|
1262
1268
|
passed: z4.number().int().nonnegative().optional(),
|
|
1263
1269
|
failed: z4.number().int().nonnegative().optional(),
|
|
1264
1270
|
skipped: z4.number().int().nonnegative().optional()
|
|
@@ -1351,8 +1357,29 @@ var securityDetailsResponseSchema = z5.strictObject({
|
|
|
1351
1357
|
])
|
|
1352
1358
|
});
|
|
1353
1359
|
|
|
1360
|
+
// packages/shared/src/test-history.ts
|
|
1361
|
+
import { z as z6 } from "zod";
|
|
1362
|
+
var testHistorySampleSchema = z6.object({
|
|
1363
|
+
id: z6.string().min(1),
|
|
1364
|
+
attempt: z6.number().int().positive(),
|
|
1365
|
+
updatedAt: z6.iso.datetime(),
|
|
1366
|
+
total: z6.number().int().nonnegative()
|
|
1367
|
+
});
|
|
1368
|
+
var testHistorySchema = z6.object({
|
|
1369
|
+
inspectedAt: z6.iso.datetime(),
|
|
1370
|
+
inspectedRuns: z6.number().int().min(0).max(8),
|
|
1371
|
+
complete: z6.boolean(),
|
|
1372
|
+
samples: z6.array(testHistorySampleSchema).max(8),
|
|
1373
|
+
retryAt: z6.iso.datetime().optional()
|
|
1374
|
+
});
|
|
1375
|
+
function retryAfterTime(value2, now) {
|
|
1376
|
+
if (!value2) return void 0;
|
|
1377
|
+
const at = /^\d+$/.test(value2) ? now + Number(value2) * 1e3 : Date.parse(value2);
|
|
1378
|
+
return Number.isFinite(at) && at > now ? at : void 0;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1354
1381
|
// packages/server/src/adapters/github-actions.ts
|
|
1355
|
-
import { z as
|
|
1382
|
+
import { z as z9 } from "zod";
|
|
1356
1383
|
|
|
1357
1384
|
// packages/server/src/credentials.ts
|
|
1358
1385
|
function environmentCredentials(env = process.env) {
|
|
@@ -1533,6 +1560,9 @@ function base64url(value2) {
|
|
|
1533
1560
|
return Buffer.from(value2).toString("base64url");
|
|
1534
1561
|
}
|
|
1535
1562
|
|
|
1563
|
+
// packages/server/src/adapters/github-test-evidence.ts
|
|
1564
|
+
import { z as z8 } from "zod";
|
|
1565
|
+
|
|
1536
1566
|
// node_modules/fflate/esm/browser.js
|
|
1537
1567
|
var u82 = Uint8Array;
|
|
1538
1568
|
var u162 = Uint16Array;
|
|
@@ -1972,10 +2002,10 @@ function strFromU8(dat, latin1) {
|
|
|
1972
2002
|
return s;
|
|
1973
2003
|
}
|
|
1974
2004
|
}
|
|
1975
|
-
var z64hs = function(d, b, l,
|
|
2005
|
+
var z64hs = function(d, b, l, z13, sc, su, off) {
|
|
1976
2006
|
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
1977
2007
|
var nf = nsc + nsu + noff;
|
|
1978
|
-
if (
|
|
2008
|
+
if (z13 && nf) {
|
|
1979
2009
|
for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
1980
2010
|
if (b2(d, b) == 1) {
|
|
1981
2011
|
return [
|
|
@@ -1986,7 +2016,7 @@ var z64hs = function(d, b, l, z11, sc, su, off) {
|
|
|
1986
2016
|
];
|
|
1987
2017
|
}
|
|
1988
2018
|
}
|
|
1989
|
-
if (
|
|
2019
|
+
if (z13 < 2)
|
|
1990
2020
|
err2(13);
|
|
1991
2021
|
}
|
|
1992
2022
|
return [sc, su, off, 0];
|
|
@@ -2150,18 +2180,18 @@ var Unzip = /* @__PURE__ */ (function() {
|
|
|
2150
2180
|
})();
|
|
2151
2181
|
|
|
2152
2182
|
// packages/server/src/workflow-artifact-summary.ts
|
|
2153
|
-
import { z as
|
|
2183
|
+
import { z as z7 } from "zod";
|
|
2154
2184
|
var maxArtifactBytes = 64 * 1024;
|
|
2155
|
-
var testResultsSummarySchema =
|
|
2156
|
-
schemaVersion:
|
|
2157
|
-
runId:
|
|
2158
|
-
runAttempt:
|
|
2159
|
-
headSha:
|
|
2160
|
-
total:
|
|
2161
|
-
passed:
|
|
2162
|
-
failed:
|
|
2163
|
-
skipped:
|
|
2164
|
-
metadata:
|
|
2185
|
+
var testResultsSummarySchema = z7.object({
|
|
2186
|
+
schemaVersion: z7.literal(1),
|
|
2187
|
+
runId: z7.number().int().positive(),
|
|
2188
|
+
runAttempt: z7.number().int().positive(),
|
|
2189
|
+
headSha: z7.string().min(1),
|
|
2190
|
+
total: z7.number().int().nonnegative(),
|
|
2191
|
+
passed: z7.number().int().nonnegative().optional(),
|
|
2192
|
+
failed: z7.number().int().nonnegative().optional(),
|
|
2193
|
+
skipped: z7.number().int().nonnegative().optional(),
|
|
2194
|
+
metadata: z7.record(z7.string(), z7.unknown()).optional()
|
|
2165
2195
|
}).superRefine((summary, ctx) => {
|
|
2166
2196
|
const outcomeTotal = (summary.passed ?? 0) + (summary.failed ?? 0) + (summary.skipped ?? 0);
|
|
2167
2197
|
for (const key of ["passed", "failed", "skipped"]) {
|
|
@@ -2237,71 +2267,165 @@ function concat(chunks, length) {
|
|
|
2237
2267
|
return result;
|
|
2238
2268
|
}
|
|
2239
2269
|
|
|
2270
|
+
// packages/server/src/adapters/github-test-evidence.ts
|
|
2271
|
+
var artifactsSchema = z8.object({
|
|
2272
|
+
artifacts: z8.array(
|
|
2273
|
+
z8.object({ id: z8.number().int().positive(), name: z8.string().min(1), expired: z8.boolean() })
|
|
2274
|
+
)
|
|
2275
|
+
});
|
|
2276
|
+
function testArtifactHttpFailure(response) {
|
|
2277
|
+
const retry = retryAfterTime(response.headers.get("retry-after"), Date.now());
|
|
2278
|
+
return {
|
|
2279
|
+
kind: "failed",
|
|
2280
|
+
observedAt: observedAt(response.headers.get("date")),
|
|
2281
|
+
errorKind: upstreamErrorKind(response.status),
|
|
2282
|
+
httpStatus: response.status,
|
|
2283
|
+
...retry === void 0 ? {} : { retryAt: new Date(retry).toISOString() }
|
|
2284
|
+
};
|
|
2285
|
+
}
|
|
2286
|
+
async function inspectGithubTestArtifact(args, selected, config) {
|
|
2287
|
+
const { run } = selected;
|
|
2288
|
+
let at = selected.observedAt;
|
|
2289
|
+
const failed = (errorKind3) => ({
|
|
2290
|
+
kind: "failed",
|
|
2291
|
+
observedAt: at,
|
|
2292
|
+
errorKind: errorKind3
|
|
2293
|
+
});
|
|
2294
|
+
const get = (url) => args.githubClient.get({
|
|
2295
|
+
source: args.source,
|
|
2296
|
+
fetcher: args.fetcher,
|
|
2297
|
+
url,
|
|
2298
|
+
requestHeaders: new Headers()
|
|
2299
|
+
});
|
|
2300
|
+
const observe = (response) => {
|
|
2301
|
+
const value2 = observedAt(response.headers.get("date"));
|
|
2302
|
+
if (Date.parse(value2) < Date.parse(at)) at = value2;
|
|
2303
|
+
};
|
|
2304
|
+
try {
|
|
2305
|
+
if (!run.id) return failed("upstream-error");
|
|
2306
|
+
if (run.status !== "completed") return { kind: "pending", observedAt: at };
|
|
2307
|
+
const url = new URL(
|
|
2308
|
+
`https://api.github.com/repos/${args.source.repo}/actions/runs/${run.id}/artifacts`
|
|
2309
|
+
);
|
|
2310
|
+
url.searchParams.set("name", config.artifact);
|
|
2311
|
+
url.searchParams.set("per_page", "100");
|
|
2312
|
+
const artifacts = await get(url.toString());
|
|
2313
|
+
if (!artifacts.ok) return testArtifactHttpFailure(artifacts);
|
|
2314
|
+
observe(artifacts);
|
|
2315
|
+
const matches = artifactsSchema.parse(await artifacts.json()).artifacts.filter((item) => item.name === config.artifact);
|
|
2316
|
+
if (!matches.length) return { kind: "absent", observedAt: at };
|
|
2317
|
+
const [artifact] = matches;
|
|
2318
|
+
if (matches.length !== 1 || !artifact) return failed("upstream-error");
|
|
2319
|
+
if (artifact.expired) return { kind: "expired", observedAt: at };
|
|
2320
|
+
const archive = await get(
|
|
2321
|
+
`https://api.github.com/repos/${args.source.repo}/actions/artifacts/${artifact.id}/zip`
|
|
2322
|
+
);
|
|
2323
|
+
if (!archive.ok) return testArtifactHttpFailure(archive);
|
|
2324
|
+
observe(archive);
|
|
2325
|
+
const summary = testResultsSummarySchema.parse(
|
|
2326
|
+
JSON.parse(await readTestResultsArtifact(archive, config.entry))
|
|
2327
|
+
);
|
|
2328
|
+
if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
|
|
2329
|
+
return failed("upstream-error");
|
|
2330
|
+
const updatedAt = z8.iso.datetime().safeParse(run.updated_at);
|
|
2331
|
+
const tests = {
|
|
2332
|
+
type: "test-count",
|
|
2333
|
+
status: "reported",
|
|
2334
|
+
total: summary.total,
|
|
2335
|
+
...updatedAt.success ? { run: { id: String(run.id), attempt: summary.runAttempt, updatedAt: updatedAt.data } } : {},
|
|
2336
|
+
...summary.passed === void 0 ? {} : { passed: summary.passed },
|
|
2337
|
+
...summary.failed === void 0 ? {} : { failed: summary.failed },
|
|
2338
|
+
...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
|
|
2339
|
+
};
|
|
2340
|
+
return { kind: "reported", observedAt: at, tests };
|
|
2341
|
+
} catch (error) {
|
|
2342
|
+
return failed(error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error");
|
|
2343
|
+
}
|
|
2344
|
+
}
|
|
2345
|
+
function currentTestEvidence(inspection) {
|
|
2346
|
+
const { observedAt: at } = inspection;
|
|
2347
|
+
switch (inspection.kind) {
|
|
2348
|
+
case "reported":
|
|
2349
|
+
return { state: "ok", observedAt: at, signal: inspection.tests };
|
|
2350
|
+
case "pending":
|
|
2351
|
+
return { state: "ok", observedAt: at, signal: { type: "test-count", status: "pending" } };
|
|
2352
|
+
case "absent":
|
|
2353
|
+
return { state: "ok", observedAt: at, signal: { type: "test-count", status: "not-reported" } };
|
|
2354
|
+
case "expired":
|
|
2355
|
+
return {
|
|
2356
|
+
state: "error",
|
|
2357
|
+
observedAt: at,
|
|
2358
|
+
error: { kind: "upstream-error", message: publicErrorMessage("upstream-error") }
|
|
2359
|
+
};
|
|
2360
|
+
case "failed":
|
|
2361
|
+
return {
|
|
2362
|
+
state: "error",
|
|
2363
|
+
observedAt: at,
|
|
2364
|
+
error: { kind: inspection.errorKind, message: publicErrorMessage(inspection.errorKind) }
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2240
2369
|
// packages/server/src/adapters/github-actions.ts
|
|
2241
|
-
var pipelinePanelSchema =
|
|
2370
|
+
var pipelinePanelSchema = z9.object({
|
|
2242
2371
|
test_results: testResultsArtifactSchema.optional(),
|
|
2243
|
-
id:
|
|
2244
|
-
type:
|
|
2245
|
-
source:
|
|
2372
|
+
id: z9.string().min(1),
|
|
2373
|
+
type: z9.literal("pipeline-status"),
|
|
2374
|
+
source: z9.string().min(1),
|
|
2246
2375
|
/** GitHub accepts a workflow filename or numeric workflow id in this URL segment. */
|
|
2247
|
-
pipeline:
|
|
2376
|
+
pipeline: z9.string().min(1)
|
|
2248
2377
|
});
|
|
2249
|
-
var pullRequestHealthPanelSchema =
|
|
2250
|
-
id:
|
|
2251
|
-
type:
|
|
2252
|
-
source:
|
|
2253
|
-
base_branch:
|
|
2254
|
-
update_workflows:
|
|
2255
|
-
|
|
2256
|
-
workflow:
|
|
2257
|
-
branch_prefixes:
|
|
2378
|
+
var pullRequestHealthPanelSchema = z9.object({
|
|
2379
|
+
id: z9.string().min(1),
|
|
2380
|
+
type: z9.literal("pull-request-health"),
|
|
2381
|
+
source: z9.string().min(1),
|
|
2382
|
+
base_branch: z9.string().min(1),
|
|
2383
|
+
update_workflows: z9.array(
|
|
2384
|
+
z9.object({
|
|
2385
|
+
workflow: z9.string().min(1),
|
|
2386
|
+
branch_prefixes: z9.array(z9.string().min(1)).min(1)
|
|
2258
2387
|
})
|
|
2259
2388
|
).min(1),
|
|
2260
|
-
build_workflow:
|
|
2389
|
+
build_workflow: z9.string().min(1),
|
|
2261
2390
|
build_events: githubActionsBuildEventsSchema.optional()
|
|
2262
2391
|
});
|
|
2263
|
-
var runSchema =
|
|
2264
|
-
id:
|
|
2265
|
-
run_attempt:
|
|
2266
|
-
head_sha:
|
|
2267
|
-
status:
|
|
2268
|
-
conclusion:
|
|
2269
|
-
name:
|
|
2270
|
-
html_url:
|
|
2392
|
+
var runSchema = z9.object({
|
|
2393
|
+
id: z9.number().int().positive().optional(),
|
|
2394
|
+
run_attempt: z9.number().int().positive().optional(),
|
|
2395
|
+
head_sha: z9.string().min(1).optional(),
|
|
2396
|
+
status: z9.string(),
|
|
2397
|
+
conclusion: z9.string().nullable(),
|
|
2398
|
+
name: z9.string().min(1),
|
|
2399
|
+
html_url: z9.url(),
|
|
2271
2400
|
/** The GitHub Actions trigger that started this run. */
|
|
2272
|
-
event:
|
|
2401
|
+
event: z9.string().min(1).optional(),
|
|
2273
2402
|
/** The branch that produced this run; absent for some event types. */
|
|
2274
|
-
head_branch:
|
|
2403
|
+
head_branch: z9.string().min(1).nullable().optional(),
|
|
2275
2404
|
// Timestamp quality should only remove timing advice, never make an otherwise useful run unreadable.
|
|
2276
|
-
run_started_at:
|
|
2277
|
-
updated_at:
|
|
2278
|
-
created_at:
|
|
2405
|
+
run_started_at: z9.string().nullable().optional(),
|
|
2406
|
+
updated_at: z9.string().optional(),
|
|
2407
|
+
created_at: z9.string().optional()
|
|
2279
2408
|
});
|
|
2280
|
-
var
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
jobs: z7.array(
|
|
2288
|
-
z7.object({
|
|
2289
|
-
name: z7.string().min(1),
|
|
2290
|
-
status: z7.string(),
|
|
2291
|
-
steps: z7.array(z7.object({ name: z7.string().min(1), status: z7.string() })).optional()
|
|
2409
|
+
var runsSchema = z9.object({ workflow_runs: z9.array(runSchema) });
|
|
2410
|
+
var jobsSchema = z9.object({
|
|
2411
|
+
jobs: z9.array(
|
|
2412
|
+
z9.object({
|
|
2413
|
+
name: z9.string().min(1),
|
|
2414
|
+
status: z9.string(),
|
|
2415
|
+
steps: z9.array(z9.object({ name: z9.string().min(1), status: z9.string() })).optional()
|
|
2292
2416
|
})
|
|
2293
2417
|
)
|
|
2294
2418
|
});
|
|
2295
|
-
var pullRequestsSchema =
|
|
2296
|
-
|
|
2297
|
-
number:
|
|
2298
|
-
html_url:
|
|
2299
|
-
head:
|
|
2300
|
-
base:
|
|
2419
|
+
var pullRequestsSchema = z9.array(
|
|
2420
|
+
z9.object({
|
|
2421
|
+
number: z9.number().int().positive(),
|
|
2422
|
+
html_url: z9.url(),
|
|
2423
|
+
head: z9.object({ ref: z9.string().min(1) }),
|
|
2424
|
+
base: z9.object({ ref: z9.string().min(1) })
|
|
2301
2425
|
})
|
|
2302
2426
|
);
|
|
2303
2427
|
function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
2304
|
-
const { panel: parsedPanel, source: parsedSource } =
|
|
2428
|
+
const { panel: parsedPanel, source: parsedSource } = z9.object({ panel: pipelinePanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
|
|
2305
2429
|
const url = new URL(
|
|
2306
2430
|
`https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
|
|
2307
2431
|
);
|
|
@@ -2310,7 +2434,7 @@ function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
|
2310
2434
|
return [{ url: url.toString(), headers: new Headers() }];
|
|
2311
2435
|
}
|
|
2312
2436
|
function testCountCapabilities(panel, source) {
|
|
2313
|
-
return
|
|
2437
|
+
return z9.object({ panel: testCountPanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
|
|
2314
2438
|
}
|
|
2315
2439
|
async function fetchGithubActionsTestCount(args) {
|
|
2316
2440
|
const { panel, source } = testCountCapabilities(args.panel, args.source);
|
|
@@ -2328,13 +2452,15 @@ async function fetchGithubActionsTestCount(args) {
|
|
|
2328
2452
|
return testCountEnvelope(
|
|
2329
2453
|
noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
|
|
2330
2454
|
);
|
|
2331
|
-
const evidence =
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2455
|
+
const evidence = currentTestEvidence(
|
|
2456
|
+
await inspectGithubTestArtifact(
|
|
2457
|
+
{ ...args, source, githubClient },
|
|
2458
|
+
{
|
|
2459
|
+
run: selected.run,
|
|
2460
|
+
observedAt: selected.observedAt
|
|
2461
|
+
},
|
|
2462
|
+
panel.test_results
|
|
2463
|
+
)
|
|
2338
2464
|
);
|
|
2339
2465
|
return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
|
|
2340
2466
|
} catch (error) {
|
|
@@ -2348,82 +2474,8 @@ async function fetchGithubActionsTestCount(args) {
|
|
|
2348
2474
|
);
|
|
2349
2475
|
}
|
|
2350
2476
|
}
|
|
2351
|
-
async function readGithubRunTestEvidence(args, selected, artifactConfig) {
|
|
2352
|
-
const { run, observedAt: runObservedAt } = selected;
|
|
2353
|
-
const { source, githubClient } = args;
|
|
2354
|
-
const noValidators = new Headers();
|
|
2355
|
-
let failureObservedAt = runObservedAt;
|
|
2356
|
-
const evidenceError = (kind, at = failureObservedAt) => ({
|
|
2357
|
-
state: "error",
|
|
2358
|
-
observedAt: at,
|
|
2359
|
-
error: { kind, message: publicErrorMessage(kind) }
|
|
2360
|
-
});
|
|
2361
|
-
const failedResponse = (response) => evidenceError(errorKind(response.status), observedAt2(response.headers.get("date")));
|
|
2362
|
-
try {
|
|
2363
|
-
if (!run.id) return evidenceError("upstream-error");
|
|
2364
|
-
if (run.status !== "completed")
|
|
2365
|
-
return {
|
|
2366
|
-
state: "ok",
|
|
2367
|
-
observedAt: runObservedAt,
|
|
2368
|
-
signal: { type: "test-count", status: "pending" }
|
|
2369
|
-
};
|
|
2370
|
-
const artifactsResponse = await githubFetch(
|
|
2371
|
-
githubArtifactsCall(source, run.id, artifactConfig),
|
|
2372
|
-
{
|
|
2373
|
-
...args,
|
|
2374
|
-
source,
|
|
2375
|
-
requestHeaders: noValidators,
|
|
2376
|
-
githubClient
|
|
2377
|
-
}
|
|
2378
|
-
);
|
|
2379
|
-
if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
|
|
2380
|
-
const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
|
|
2381
|
-
failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
|
|
2382
|
-
const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
|
|
2383
|
-
const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
|
|
2384
|
-
if (matches.length === 0)
|
|
2385
|
-
return {
|
|
2386
|
-
state: "ok",
|
|
2387
|
-
observedAt: oldestObservation(runObservedAt, artifactObservedAt),
|
|
2388
|
-
signal: { type: "test-count", status: "not-reported" }
|
|
2389
|
-
};
|
|
2390
|
-
const [artifact] = matches;
|
|
2391
|
-
if (matches.length !== 1 || !artifact || artifact.expired)
|
|
2392
|
-
return evidenceError("upstream-error");
|
|
2393
|
-
const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
|
|
2394
|
-
...args,
|
|
2395
|
-
source,
|
|
2396
|
-
requestHeaders: noValidators,
|
|
2397
|
-
githubClient
|
|
2398
|
-
});
|
|
2399
|
-
if (!archiveResponse.ok) return failedResponse(archiveResponse);
|
|
2400
|
-
const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
|
|
2401
|
-
failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
|
|
2402
|
-
const summary = testResultsSummarySchema.parse(
|
|
2403
|
-
JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
|
|
2404
|
-
);
|
|
2405
|
-
if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
|
|
2406
|
-
throw new Error("Test-results manifest does not belong to the selected workflow run.");
|
|
2407
|
-
return {
|
|
2408
|
-
state: "ok",
|
|
2409
|
-
observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
|
|
2410
|
-
signal: {
|
|
2411
|
-
type: "test-count",
|
|
2412
|
-
status: "reported",
|
|
2413
|
-
total: summary.total,
|
|
2414
|
-
...summary.passed === void 0 ? {} : { passed: summary.passed },
|
|
2415
|
-
...summary.failed === void 0 ? {} : { failed: summary.failed },
|
|
2416
|
-
...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
|
|
2417
|
-
}
|
|
2418
|
-
};
|
|
2419
|
-
} catch (error) {
|
|
2420
|
-
return evidenceError(
|
|
2421
|
-
error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
|
|
2422
|
-
);
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
2477
|
function pullRequestHealthCapabilities(panel) {
|
|
2426
|
-
const { panel: parsed } =
|
|
2478
|
+
const { panel: parsed } = z9.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
|
|
2427
2479
|
return {
|
|
2428
2480
|
panel: parsed,
|
|
2429
2481
|
configuredUpdateWorkflow(workflow) {
|
|
@@ -2525,10 +2577,12 @@ async function fetchGithubActionsPipeline(args) {
|
|
|
2525
2577
|
if (activity) signal.activity = activity;
|
|
2526
2578
|
}
|
|
2527
2579
|
if (parsedPanel.test_results) {
|
|
2528
|
-
signal.testResults =
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2580
|
+
signal.testResults = currentTestEvidence(
|
|
2581
|
+
await inspectGithubTestArtifact(
|
|
2582
|
+
{ ...args, source: parsedSource, githubClient },
|
|
2583
|
+
{ run, observedAt: selected.observedAt },
|
|
2584
|
+
parsedPanel.test_results
|
|
2585
|
+
)
|
|
2532
2586
|
);
|
|
2533
2587
|
}
|
|
2534
2588
|
const envelope = {
|
|
@@ -2647,18 +2701,6 @@ function githubJobsCall(source, runId) {
|
|
|
2647
2701
|
url.searchParams.set("per_page", "100");
|
|
2648
2702
|
return { url: url.toString(), headers: new Headers() };
|
|
2649
2703
|
}
|
|
2650
|
-
function githubArtifactsCall(source, runId, testResults) {
|
|
2651
|
-
const url = new URL(`https://api.github.com/repos/${source.repo}/actions/runs/${runId}/artifacts`);
|
|
2652
|
-
url.searchParams.set("name", testResults.artifact);
|
|
2653
|
-
url.searchParams.set("per_page", "100");
|
|
2654
|
-
return { url: url.toString(), headers: new Headers() };
|
|
2655
|
-
}
|
|
2656
|
-
function githubArtifactDownloadCall(source, artifactId) {
|
|
2657
|
-
return {
|
|
2658
|
-
url: `https://api.github.com/repos/${source.repo}/actions/artifacts/${artifactId}/zip`,
|
|
2659
|
-
headers: new Headers()
|
|
2660
|
-
};
|
|
2661
|
-
}
|
|
2662
2704
|
function noRunEnvelope(panelId, source, pipeline, date) {
|
|
2663
2705
|
return {
|
|
2664
2706
|
panelId,
|
|
@@ -2697,7 +2739,7 @@ function completedRunDuration(run) {
|
|
|
2697
2739
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
2698
2740
|
}
|
|
2699
2741
|
function timestamp(value2) {
|
|
2700
|
-
if (!value2 || !
|
|
2742
|
+
if (!value2 || !z9.iso.datetime().safeParse(value2).success) return void 0;
|
|
2701
2743
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
2702
2744
|
}
|
|
2703
2745
|
function normalizeStatus(status, conclusion) {
|
|
@@ -2714,7 +2756,7 @@ function errorEnvelope(panelId, kind, error, link, observedAt4 = (/* @__PURE__ *
|
|
|
2714
2756
|
return upstreamErrorEnvelope({ panelId, kind, error, link, upstreamDate: observedAt4 });
|
|
2715
2757
|
}
|
|
2716
2758
|
function sourceLink(panel, source) {
|
|
2717
|
-
const parsedPanel =
|
|
2759
|
+
const parsedPanel = z9.object({ pipeline: z9.string().min(1) }).parse(panel);
|
|
2718
2760
|
const parsedSource = githubActionsSourceSchema.parse(source);
|
|
2719
2761
|
return sourceLinkForWorkflow(parsedSource, parsedPanel.pipeline);
|
|
2720
2762
|
}
|
|
@@ -2724,6 +2766,81 @@ function sourceLinkForWorkflow(source, pipeline) {
|
|
|
2724
2766
|
function observedAt2(value2) {
|
|
2725
2767
|
return observedAt(value2);
|
|
2726
2768
|
}
|
|
2769
|
+
async function fetchGithubTestHistory(args) {
|
|
2770
|
+
const source = githubActionsSourceSchema.parse(args.source);
|
|
2771
|
+
const fetcher = (input, init) => args.fetcher(input, { ...init, ...args.signal ? { signal: args.signal } : {} });
|
|
2772
|
+
const artifact = testResultsArtifactSchema.parse(args.panel.test_results);
|
|
2773
|
+
const workflow = z9.string().min(1).parse(args.panel.pipeline);
|
|
2774
|
+
const now = Date.now();
|
|
2775
|
+
const cutoff = now - 14 * 864e5;
|
|
2776
|
+
const history = {
|
|
2777
|
+
inspectedAt: new Date(now).toISOString(),
|
|
2778
|
+
inspectedRuns: 0,
|
|
2779
|
+
complete: true,
|
|
2780
|
+
samples: []
|
|
2781
|
+
};
|
|
2782
|
+
let stop = false;
|
|
2783
|
+
const recordFailure = (failure2) => {
|
|
2784
|
+
history.complete = false;
|
|
2785
|
+
if (failure2.errorKind === "unauthorized" || failure2.httpStatus === 429) stop = true;
|
|
2786
|
+
if (failure2.retryAt && (!history.retryAt || Date.parse(failure2.retryAt) > Date.parse(history.retryAt)))
|
|
2787
|
+
history.retryAt = failure2.retryAt;
|
|
2788
|
+
};
|
|
2789
|
+
try {
|
|
2790
|
+
const call = githubRunsCall(
|
|
2791
|
+
source,
|
|
2792
|
+
workflow,
|
|
2793
|
+
source.branch,
|
|
2794
|
+
void 0,
|
|
2795
|
+
8,
|
|
2796
|
+
new Date(cutoff).toISOString()
|
|
2797
|
+
);
|
|
2798
|
+
const url = new URL(call.url);
|
|
2799
|
+
url.searchParams.set("status", "completed");
|
|
2800
|
+
const response = await githubFetch(
|
|
2801
|
+
{ ...call, url: url.toString() },
|
|
2802
|
+
{ ...args, fetcher, source, requestHeaders: new Headers() }
|
|
2803
|
+
);
|
|
2804
|
+
if (!response.ok) recordFailure(testArtifactHttpFailure(response));
|
|
2805
|
+
else {
|
|
2806
|
+
const runs = runsSchema.parse(await response.json()).workflow_runs.slice(0, 8);
|
|
2807
|
+
for (const run of runs) {
|
|
2808
|
+
if (stop || args.signal?.aborted) {
|
|
2809
|
+
history.complete = false;
|
|
2810
|
+
break;
|
|
2811
|
+
}
|
|
2812
|
+
if (run.status !== "completed") continue;
|
|
2813
|
+
if (run.updated_at && Date.parse(run.updated_at) < cutoff) continue;
|
|
2814
|
+
history.inspectedRuns++;
|
|
2815
|
+
const inspection = await inspectGithubTestArtifact(
|
|
2816
|
+
{ ...args, fetcher, source },
|
|
2817
|
+
{ run, observedAt: observedAt2(response.headers.get("date")) },
|
|
2818
|
+
artifact
|
|
2819
|
+
);
|
|
2820
|
+
switch (inspection.kind) {
|
|
2821
|
+
case "failed":
|
|
2822
|
+
recordFailure(inspection);
|
|
2823
|
+
break;
|
|
2824
|
+
case "reported": {
|
|
2825
|
+
const { run: identity, total } = inspection.tests;
|
|
2826
|
+
if (identity) history.samples.push({ ...identity, total });
|
|
2827
|
+
else history.complete = false;
|
|
2828
|
+
break;
|
|
2829
|
+
}
|
|
2830
|
+
case "absent":
|
|
2831
|
+
case "expired":
|
|
2832
|
+
break;
|
|
2833
|
+
case "pending":
|
|
2834
|
+
history.complete = false;
|
|
2835
|
+
break;
|
|
2836
|
+
}
|
|
2837
|
+
}
|
|
2838
|
+
}
|
|
2839
|
+
} catch {
|
|
2840
|
+
history.complete = false;
|
|
2841
|
+
}
|
|
2842
|
+
return Response.json(history, { headers: { "cache-control": "no-store" } });
|
|
2843
|
+
}
|
|
2727
2844
|
|
|
2728
2845
|
// packages/server/src/configuration-error.ts
|
|
2729
2846
|
var ConfigurationError = class extends Error {
|
|
@@ -2777,37 +2894,37 @@ function correctiveConstraint(issue) {
|
|
|
2777
2894
|
|
|
2778
2895
|
// packages/server/src/adapters/azure-devops.ts
|
|
2779
2896
|
import { readFile } from "node:fs/promises";
|
|
2780
|
-
import { z as
|
|
2781
|
-
var pipelinePanelSchema2 =
|
|
2782
|
-
id:
|
|
2783
|
-
type:
|
|
2784
|
-
source:
|
|
2785
|
-
pipeline:
|
|
2897
|
+
import { z as z10 } from "zod";
|
|
2898
|
+
var pipelinePanelSchema2 = z10.object({
|
|
2899
|
+
id: z10.string().min(1),
|
|
2900
|
+
type: z10.literal("pipeline-status"),
|
|
2901
|
+
source: z10.string().min(1),
|
|
2902
|
+
pipeline: z10.number().int().positive()
|
|
2786
2903
|
});
|
|
2787
|
-
var buildSchema =
|
|
2788
|
-
id:
|
|
2789
|
-
buildNumber:
|
|
2790
|
-
status:
|
|
2791
|
-
result:
|
|
2792
|
-
sourceBranch:
|
|
2793
|
-
startTime:
|
|
2794
|
-
finishTime:
|
|
2795
|
-
lastChangedDate:
|
|
2904
|
+
var buildSchema = z10.object({
|
|
2905
|
+
id: z10.number().int().positive(),
|
|
2906
|
+
buildNumber: z10.string().min(1),
|
|
2907
|
+
status: z10.string().nullable().optional(),
|
|
2908
|
+
result: z10.string().nullable().optional(),
|
|
2909
|
+
sourceBranch: z10.string().min(1).nullable().optional(),
|
|
2910
|
+
startTime: z10.string().nullable().optional(),
|
|
2911
|
+
finishTime: z10.string().nullable().optional(),
|
|
2912
|
+
lastChangedDate: z10.string().nullable().optional()
|
|
2796
2913
|
});
|
|
2797
|
-
var buildsSchema =
|
|
2798
|
-
var timelineSchema =
|
|
2799
|
-
records:
|
|
2800
|
-
|
|
2801
|
-
id:
|
|
2802
|
-
parentId:
|
|
2803
|
-
type:
|
|
2804
|
-
name:
|
|
2805
|
-
state:
|
|
2914
|
+
var buildsSchema = z10.object({ value: z10.array(buildSchema) });
|
|
2915
|
+
var timelineSchema = z10.object({
|
|
2916
|
+
records: z10.array(
|
|
2917
|
+
z10.object({
|
|
2918
|
+
id: z10.string().min(1),
|
|
2919
|
+
parentId: z10.string().min(1).nullable().optional(),
|
|
2920
|
+
type: z10.string().min(1),
|
|
2921
|
+
name: z10.string().min(1),
|
|
2922
|
+
state: z10.string().nullable().optional()
|
|
2806
2923
|
})
|
|
2807
2924
|
)
|
|
2808
2925
|
});
|
|
2809
2926
|
function permittedAzureDevOpsCalls(panel, source) {
|
|
2810
|
-
const { panel: parsedPanel, source: parsedSource } =
|
|
2927
|
+
const { panel: parsedPanel, source: parsedSource } = z10.object({ panel: pipelinePanelSchema2, source: azureDevOpsSourceSchema }).parse({ panel, source });
|
|
2811
2928
|
return [buildsCall(parsedPanel.pipeline, parsedSource)];
|
|
2812
2929
|
}
|
|
2813
2930
|
async function fetchAzureDevOpsPipeline(args) {
|
|
@@ -2920,9 +3037,9 @@ async function fetchAzureDevOpsPipeline(args) {
|
|
|
2920
3037
|
};
|
|
2921
3038
|
}
|
|
2922
3039
|
}
|
|
2923
|
-
var delegatedTokenFileSchema =
|
|
2924
|
-
accessToken:
|
|
2925
|
-
expiresAt:
|
|
3040
|
+
var delegatedTokenFileSchema = z10.object({
|
|
3041
|
+
accessToken: z10.string().min(1),
|
|
3042
|
+
expiresAt: z10.string().min(1)
|
|
2926
3043
|
});
|
|
2927
3044
|
async function azureDevOpsAuthorization(source, credentials) {
|
|
2928
3045
|
if (source.token_env) {
|
|
@@ -3003,7 +3120,7 @@ function completedBuildDuration(build) {
|
|
|
3003
3120
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
3004
3121
|
}
|
|
3005
3122
|
function timestamp2(value2) {
|
|
3006
|
-
if (!value2 || !
|
|
3123
|
+
if (!value2 || !z10.iso.datetime().safeParse(value2).success) return void 0;
|
|
3007
3124
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
3008
3125
|
}
|
|
3009
3126
|
function copyValidators(requestHeaders, upstreamHeaders) {
|
|
@@ -3029,23 +3146,23 @@ function observedAt3(value2) {
|
|
|
3029
3146
|
}
|
|
3030
3147
|
|
|
3031
3148
|
// packages/server/src/adapters/gitlab-ci.ts
|
|
3032
|
-
import { z as
|
|
3033
|
-
var pipelinePanelSchema3 =
|
|
3034
|
-
id:
|
|
3035
|
-
type:
|
|
3036
|
-
source:
|
|
3149
|
+
import { z as z11 } from "zod";
|
|
3150
|
+
var pipelinePanelSchema3 = z11.object({
|
|
3151
|
+
id: z11.string().min(1),
|
|
3152
|
+
type: z11.literal("pipeline-status"),
|
|
3153
|
+
source: z11.string().min(1)
|
|
3037
3154
|
});
|
|
3038
|
-
var pipelineSchema =
|
|
3039
|
-
id:
|
|
3040
|
-
name:
|
|
3041
|
-
status:
|
|
3042
|
-
ref:
|
|
3043
|
-
created_at:
|
|
3044
|
-
updated_at:
|
|
3045
|
-
web_url:
|
|
3155
|
+
var pipelineSchema = z11.object({
|
|
3156
|
+
id: z11.number().int().positive(),
|
|
3157
|
+
name: z11.string().min(1).nullable().optional(),
|
|
3158
|
+
status: z11.string(),
|
|
3159
|
+
ref: z11.string().min(1).nullable().optional(),
|
|
3160
|
+
created_at: z11.string().nullable().optional(),
|
|
3161
|
+
updated_at: z11.string().nullable().optional(),
|
|
3162
|
+
web_url: z11.url()
|
|
3046
3163
|
});
|
|
3047
3164
|
function permittedGitlabCiCalls(panel, source) {
|
|
3048
|
-
const { source: parsedSource } =
|
|
3165
|
+
const { source: parsedSource } = z11.object({ panel: pipelinePanelSchema3, source: gitlabCiSourceSchema }).parse({ panel, source });
|
|
3049
3166
|
return [pipelinesCall(parsedSource)];
|
|
3050
3167
|
}
|
|
3051
3168
|
async function fetchGitlabCiPipeline(args) {
|
|
@@ -3084,7 +3201,7 @@ async function fetchGitlabCiPipeline(args) {
|
|
|
3084
3201
|
);
|
|
3085
3202
|
}
|
|
3086
3203
|
try {
|
|
3087
|
-
const pipeline =
|
|
3204
|
+
const pipeline = z11.array(pipelineSchema).parse(await upstream.json())[0];
|
|
3088
3205
|
if (!pipeline) {
|
|
3089
3206
|
const detail = source.branch ? `No pipelines found for ref "${source.branch}". Check the source's branch setting.` : "No pipelines found.";
|
|
3090
3207
|
return failure(
|
|
@@ -3150,7 +3267,7 @@ function normalizeStatus3(status) {
|
|
|
3150
3267
|
return "unknown";
|
|
3151
3268
|
}
|
|
3152
3269
|
function timestamp3(value2) {
|
|
3153
|
-
if (!value2 || !
|
|
3270
|
+
if (!value2 || !z11.iso.datetime().safeParse(value2).success) return void 0;
|
|
3154
3271
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
3155
3272
|
}
|
|
3156
3273
|
function failure(panelId, kind, error, link, date, failure2) {
|
|
@@ -3163,10 +3280,10 @@ function failure(panelId, kind, error, link, date, failure2) {
|
|
|
3163
3280
|
}
|
|
3164
3281
|
|
|
3165
3282
|
// packages/server/src/adapters/http-value.ts
|
|
3166
|
-
import { z as
|
|
3283
|
+
import { z as z12 } from "zod";
|
|
3167
3284
|
function permittedHttpValueCalls(panel) {
|
|
3168
3285
|
const grouped = httpValueGroupedPanelSchema.safeParse(panel);
|
|
3169
|
-
const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [
|
|
3286
|
+
const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [z12.object({ panel: httpValueScalarPanelSchema }).parse({ panel }).panel.url];
|
|
3170
3287
|
return urls.map(permittedCall);
|
|
3171
3288
|
}
|
|
3172
3289
|
async function fetchHttpValue(args) {
|
|
@@ -3265,6 +3382,9 @@ function readPanelAdapter(panel, source) {
|
|
|
3265
3382
|
if (panel.type === "pipeline-status" && source?.type === "github-actions") {
|
|
3266
3383
|
permittedGithubActionsCalls(panel, source);
|
|
3267
3384
|
return {
|
|
3385
|
+
...panel.test_results ? {
|
|
3386
|
+
testHistory: ({ source: _source, ...args }) => fetchGithubTestHistory({ ...args, source })
|
|
3387
|
+
} : {},
|
|
3268
3388
|
destination: () => "https://api.github.com",
|
|
3269
3389
|
fetch: ({ source: _configuredSource, ...args }) => fetchGithubActionsPipeline({ ...args, source })
|
|
3270
3390
|
};
|
|
@@ -3272,6 +3392,9 @@ function readPanelAdapter(panel, source) {
|
|
|
3272
3392
|
if (panel.type === "test-count" && source?.type === "github-actions") {
|
|
3273
3393
|
testCountCapabilities(panel, source);
|
|
3274
3394
|
return {
|
|
3395
|
+
...panel.test_results ? {
|
|
3396
|
+
testHistory: ({ source: _source, ...args }) => fetchGithubTestHistory({ ...args, source })
|
|
3397
|
+
} : {},
|
|
3275
3398
|
destination: () => "https://api.github.com",
|
|
3276
3399
|
fetch: ({ source: _configuredSource, ...args }) => fetchGithubActionsTestCount({ ...args, source })
|
|
3277
3400
|
};
|
|
@@ -3350,7 +3473,9 @@ function derive(config, rejectUnsupported) {
|
|
|
3350
3473
|
return allowed;
|
|
3351
3474
|
}
|
|
3352
3475
|
function panelCapability(panel, source) {
|
|
3353
|
-
|
|
3476
|
+
const adapter = readPanelAdapter(panel, source);
|
|
3477
|
+
if (adapter)
|
|
3478
|
+
return { kind: "server", operations: adapter.testHistory ? ["read", "test-history"] : ["read"] };
|
|
3354
3479
|
if (panel.type === "pull-request-health" && source?.type === "github-actions") {
|
|
3355
3480
|
pullRequestHealthCapabilities(panel);
|
|
3356
3481
|
return {
|