@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/cli.js
CHANGED
|
@@ -577,6 +577,12 @@ var testCountSchema = z4.discriminatedUnion("status", [
|
|
|
577
577
|
type: z4.literal("test-count"),
|
|
578
578
|
status: z4.literal("reported"),
|
|
579
579
|
total: z4.number().int().nonnegative(),
|
|
580
|
+
/** Public identity for browser-local comparisons, never observation time. */
|
|
581
|
+
run: z4.object({
|
|
582
|
+
id: z4.string().min(1),
|
|
583
|
+
attempt: z4.number().int().positive(),
|
|
584
|
+
updatedAt: z4.iso.datetime()
|
|
585
|
+
}).optional(),
|
|
580
586
|
passed: z4.number().int().nonnegative().optional(),
|
|
581
587
|
failed: z4.number().int().nonnegative().optional(),
|
|
582
588
|
skipped: z4.number().int().nonnegative().optional()
|
|
@@ -669,8 +675,29 @@ var securityDetailsResponseSchema = z5.strictObject({
|
|
|
669
675
|
])
|
|
670
676
|
});
|
|
671
677
|
|
|
678
|
+
// packages/shared/src/test-history.ts
|
|
679
|
+
import { z as z6 } from "zod";
|
|
680
|
+
var testHistorySampleSchema = z6.object({
|
|
681
|
+
id: z6.string().min(1),
|
|
682
|
+
attempt: z6.number().int().positive(),
|
|
683
|
+
updatedAt: z6.iso.datetime(),
|
|
684
|
+
total: z6.number().int().nonnegative()
|
|
685
|
+
});
|
|
686
|
+
var testHistorySchema = z6.object({
|
|
687
|
+
inspectedAt: z6.iso.datetime(),
|
|
688
|
+
inspectedRuns: z6.number().int().min(0).max(8),
|
|
689
|
+
complete: z6.boolean(),
|
|
690
|
+
samples: z6.array(testHistorySampleSchema).max(8),
|
|
691
|
+
retryAt: z6.iso.datetime().optional()
|
|
692
|
+
});
|
|
693
|
+
function retryAfterTime(value2, now) {
|
|
694
|
+
if (!value2) return void 0;
|
|
695
|
+
const at = /^\d+$/.test(value2) ? now + Number(value2) * 1e3 : Date.parse(value2);
|
|
696
|
+
return Number.isFinite(at) && at > now ? at : void 0;
|
|
697
|
+
}
|
|
698
|
+
|
|
672
699
|
// packages/server/src/adapters/github-actions.ts
|
|
673
|
-
import { z as
|
|
700
|
+
import { z as z9 } from "zod";
|
|
674
701
|
|
|
675
702
|
// packages/server/src/credentials.ts
|
|
676
703
|
function environmentCredentials(env = process.env) {
|
|
@@ -851,6 +878,9 @@ function base64url(value2) {
|
|
|
851
878
|
return Buffer.from(value2).toString("base64url");
|
|
852
879
|
}
|
|
853
880
|
|
|
881
|
+
// packages/server/src/adapters/github-test-evidence.ts
|
|
882
|
+
import { z as z8 } from "zod";
|
|
883
|
+
|
|
854
884
|
// node_modules/fflate/esm/browser.js
|
|
855
885
|
var u8 = Uint8Array;
|
|
856
886
|
var u16 = Uint16Array;
|
|
@@ -1290,10 +1320,10 @@ function strFromU8(dat, latin1) {
|
|
|
1290
1320
|
return s;
|
|
1291
1321
|
}
|
|
1292
1322
|
}
|
|
1293
|
-
var z64hs = function(d, b, l,
|
|
1323
|
+
var z64hs = function(d, b, l, z13, sc, su, off) {
|
|
1294
1324
|
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
1295
1325
|
var nf = nsc + nsu + noff;
|
|
1296
|
-
if (
|
|
1326
|
+
if (z13 && nf) {
|
|
1297
1327
|
for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
1298
1328
|
if (b2(d, b) == 1) {
|
|
1299
1329
|
return [
|
|
@@ -1304,7 +1334,7 @@ var z64hs = function(d, b, l, z11, sc, su, off) {
|
|
|
1304
1334
|
];
|
|
1305
1335
|
}
|
|
1306
1336
|
}
|
|
1307
|
-
if (
|
|
1337
|
+
if (z13 < 2)
|
|
1308
1338
|
err(13);
|
|
1309
1339
|
}
|
|
1310
1340
|
return [sc, su, off, 0];
|
|
@@ -1468,18 +1498,18 @@ var Unzip = /* @__PURE__ */ (function() {
|
|
|
1468
1498
|
})();
|
|
1469
1499
|
|
|
1470
1500
|
// packages/server/src/workflow-artifact-summary.ts
|
|
1471
|
-
import { z as
|
|
1501
|
+
import { z as z7 } from "zod";
|
|
1472
1502
|
var maxArtifactBytes = 64 * 1024;
|
|
1473
|
-
var testResultsSummarySchema =
|
|
1474
|
-
schemaVersion:
|
|
1475
|
-
runId:
|
|
1476
|
-
runAttempt:
|
|
1477
|
-
headSha:
|
|
1478
|
-
total:
|
|
1479
|
-
passed:
|
|
1480
|
-
failed:
|
|
1481
|
-
skipped:
|
|
1482
|
-
metadata:
|
|
1503
|
+
var testResultsSummarySchema = z7.object({
|
|
1504
|
+
schemaVersion: z7.literal(1),
|
|
1505
|
+
runId: z7.number().int().positive(),
|
|
1506
|
+
runAttempt: z7.number().int().positive(),
|
|
1507
|
+
headSha: z7.string().min(1),
|
|
1508
|
+
total: z7.number().int().nonnegative(),
|
|
1509
|
+
passed: z7.number().int().nonnegative().optional(),
|
|
1510
|
+
failed: z7.number().int().nonnegative().optional(),
|
|
1511
|
+
skipped: z7.number().int().nonnegative().optional(),
|
|
1512
|
+
metadata: z7.record(z7.string(), z7.unknown()).optional()
|
|
1483
1513
|
}).superRefine((summary, ctx) => {
|
|
1484
1514
|
const outcomeTotal = (summary.passed ?? 0) + (summary.failed ?? 0) + (summary.skipped ?? 0);
|
|
1485
1515
|
for (const key of ["passed", "failed", "skipped"]) {
|
|
@@ -1555,71 +1585,165 @@ function concat(chunks, length) {
|
|
|
1555
1585
|
return result;
|
|
1556
1586
|
}
|
|
1557
1587
|
|
|
1588
|
+
// packages/server/src/adapters/github-test-evidence.ts
|
|
1589
|
+
var artifactsSchema = z8.object({
|
|
1590
|
+
artifacts: z8.array(
|
|
1591
|
+
z8.object({ id: z8.number().int().positive(), name: z8.string().min(1), expired: z8.boolean() })
|
|
1592
|
+
)
|
|
1593
|
+
});
|
|
1594
|
+
function testArtifactHttpFailure(response) {
|
|
1595
|
+
const retry = retryAfterTime(response.headers.get("retry-after"), Date.now());
|
|
1596
|
+
return {
|
|
1597
|
+
kind: "failed",
|
|
1598
|
+
observedAt: observedAt(response.headers.get("date")),
|
|
1599
|
+
errorKind: upstreamErrorKind(response.status),
|
|
1600
|
+
httpStatus: response.status,
|
|
1601
|
+
...retry === void 0 ? {} : { retryAt: new Date(retry).toISOString() }
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
async function inspectGithubTestArtifact(args2, selected, config) {
|
|
1605
|
+
const { run: run2 } = selected;
|
|
1606
|
+
let at = selected.observedAt;
|
|
1607
|
+
const failed = (errorKind3) => ({
|
|
1608
|
+
kind: "failed",
|
|
1609
|
+
observedAt: at,
|
|
1610
|
+
errorKind: errorKind3
|
|
1611
|
+
});
|
|
1612
|
+
const get = (url) => args2.githubClient.get({
|
|
1613
|
+
source: args2.source,
|
|
1614
|
+
fetcher: args2.fetcher,
|
|
1615
|
+
url,
|
|
1616
|
+
requestHeaders: new Headers()
|
|
1617
|
+
});
|
|
1618
|
+
const observe = (response) => {
|
|
1619
|
+
const value2 = observedAt(response.headers.get("date"));
|
|
1620
|
+
if (Date.parse(value2) < Date.parse(at)) at = value2;
|
|
1621
|
+
};
|
|
1622
|
+
try {
|
|
1623
|
+
if (!run2.id) return failed("upstream-error");
|
|
1624
|
+
if (run2.status !== "completed") return { kind: "pending", observedAt: at };
|
|
1625
|
+
const url = new URL(
|
|
1626
|
+
`https://api.github.com/repos/${args2.source.repo}/actions/runs/${run2.id}/artifacts`
|
|
1627
|
+
);
|
|
1628
|
+
url.searchParams.set("name", config.artifact);
|
|
1629
|
+
url.searchParams.set("per_page", "100");
|
|
1630
|
+
const artifacts = await get(url.toString());
|
|
1631
|
+
if (!artifacts.ok) return testArtifactHttpFailure(artifacts);
|
|
1632
|
+
observe(artifacts);
|
|
1633
|
+
const matches = artifactsSchema.parse(await artifacts.json()).artifacts.filter((item) => item.name === config.artifact);
|
|
1634
|
+
if (!matches.length) return { kind: "absent", observedAt: at };
|
|
1635
|
+
const [artifact] = matches;
|
|
1636
|
+
if (matches.length !== 1 || !artifact) return failed("upstream-error");
|
|
1637
|
+
if (artifact.expired) return { kind: "expired", observedAt: at };
|
|
1638
|
+
const archive = await get(
|
|
1639
|
+
`https://api.github.com/repos/${args2.source.repo}/actions/artifacts/${artifact.id}/zip`
|
|
1640
|
+
);
|
|
1641
|
+
if (!archive.ok) return testArtifactHttpFailure(archive);
|
|
1642
|
+
observe(archive);
|
|
1643
|
+
const summary = testResultsSummarySchema.parse(
|
|
1644
|
+
JSON.parse(await readTestResultsArtifact(archive, config.entry))
|
|
1645
|
+
);
|
|
1646
|
+
if (summary.runId !== run2.id || summary.runAttempt !== run2.run_attempt || summary.headSha !== run2.head_sha)
|
|
1647
|
+
return failed("upstream-error");
|
|
1648
|
+
const updatedAt = z8.iso.datetime().safeParse(run2.updated_at);
|
|
1649
|
+
const tests = {
|
|
1650
|
+
type: "test-count",
|
|
1651
|
+
status: "reported",
|
|
1652
|
+
total: summary.total,
|
|
1653
|
+
...updatedAt.success ? { run: { id: String(run2.id), attempt: summary.runAttempt, updatedAt: updatedAt.data } } : {},
|
|
1654
|
+
...summary.passed === void 0 ? {} : { passed: summary.passed },
|
|
1655
|
+
...summary.failed === void 0 ? {} : { failed: summary.failed },
|
|
1656
|
+
...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
|
|
1657
|
+
};
|
|
1658
|
+
return { kind: "reported", observedAt: at, tests };
|
|
1659
|
+
} catch (error) {
|
|
1660
|
+
return failed(error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error");
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
function currentTestEvidence(inspection) {
|
|
1664
|
+
const { observedAt: at } = inspection;
|
|
1665
|
+
switch (inspection.kind) {
|
|
1666
|
+
case "reported":
|
|
1667
|
+
return { state: "ok", observedAt: at, signal: inspection.tests };
|
|
1668
|
+
case "pending":
|
|
1669
|
+
return { state: "ok", observedAt: at, signal: { type: "test-count", status: "pending" } };
|
|
1670
|
+
case "absent":
|
|
1671
|
+
return { state: "ok", observedAt: at, signal: { type: "test-count", status: "not-reported" } };
|
|
1672
|
+
case "expired":
|
|
1673
|
+
return {
|
|
1674
|
+
state: "error",
|
|
1675
|
+
observedAt: at,
|
|
1676
|
+
error: { kind: "upstream-error", message: publicErrorMessage("upstream-error") }
|
|
1677
|
+
};
|
|
1678
|
+
case "failed":
|
|
1679
|
+
return {
|
|
1680
|
+
state: "error",
|
|
1681
|
+
observedAt: at,
|
|
1682
|
+
error: { kind: inspection.errorKind, message: publicErrorMessage(inspection.errorKind) }
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1558
1687
|
// packages/server/src/adapters/github-actions.ts
|
|
1559
|
-
var pipelinePanelSchema =
|
|
1688
|
+
var pipelinePanelSchema = z9.object({
|
|
1560
1689
|
test_results: testResultsArtifactSchema.optional(),
|
|
1561
|
-
id:
|
|
1562
|
-
type:
|
|
1563
|
-
source:
|
|
1690
|
+
id: z9.string().min(1),
|
|
1691
|
+
type: z9.literal("pipeline-status"),
|
|
1692
|
+
source: z9.string().min(1),
|
|
1564
1693
|
/** GitHub accepts a workflow filename or numeric workflow id in this URL segment. */
|
|
1565
|
-
pipeline:
|
|
1694
|
+
pipeline: z9.string().min(1)
|
|
1566
1695
|
});
|
|
1567
|
-
var pullRequestHealthPanelSchema =
|
|
1568
|
-
id:
|
|
1569
|
-
type:
|
|
1570
|
-
source:
|
|
1571
|
-
base_branch:
|
|
1572
|
-
update_workflows:
|
|
1573
|
-
|
|
1574
|
-
workflow:
|
|
1575
|
-
branch_prefixes:
|
|
1696
|
+
var pullRequestHealthPanelSchema = z9.object({
|
|
1697
|
+
id: z9.string().min(1),
|
|
1698
|
+
type: z9.literal("pull-request-health"),
|
|
1699
|
+
source: z9.string().min(1),
|
|
1700
|
+
base_branch: z9.string().min(1),
|
|
1701
|
+
update_workflows: z9.array(
|
|
1702
|
+
z9.object({
|
|
1703
|
+
workflow: z9.string().min(1),
|
|
1704
|
+
branch_prefixes: z9.array(z9.string().min(1)).min(1)
|
|
1576
1705
|
})
|
|
1577
1706
|
).min(1),
|
|
1578
|
-
build_workflow:
|
|
1707
|
+
build_workflow: z9.string().min(1),
|
|
1579
1708
|
build_events: githubActionsBuildEventsSchema.optional()
|
|
1580
1709
|
});
|
|
1581
|
-
var runSchema =
|
|
1582
|
-
id:
|
|
1583
|
-
run_attempt:
|
|
1584
|
-
head_sha:
|
|
1585
|
-
status:
|
|
1586
|
-
conclusion:
|
|
1587
|
-
name:
|
|
1588
|
-
html_url:
|
|
1710
|
+
var runSchema = z9.object({
|
|
1711
|
+
id: z9.number().int().positive().optional(),
|
|
1712
|
+
run_attempt: z9.number().int().positive().optional(),
|
|
1713
|
+
head_sha: z9.string().min(1).optional(),
|
|
1714
|
+
status: z9.string(),
|
|
1715
|
+
conclusion: z9.string().nullable(),
|
|
1716
|
+
name: z9.string().min(1),
|
|
1717
|
+
html_url: z9.url(),
|
|
1589
1718
|
/** The GitHub Actions trigger that started this run. */
|
|
1590
|
-
event:
|
|
1719
|
+
event: z9.string().min(1).optional(),
|
|
1591
1720
|
/** The branch that produced this run; absent for some event types. */
|
|
1592
|
-
head_branch:
|
|
1721
|
+
head_branch: z9.string().min(1).nullable().optional(),
|
|
1593
1722
|
// Timestamp quality should only remove timing advice, never make an otherwise useful run unreadable.
|
|
1594
|
-
run_started_at:
|
|
1595
|
-
updated_at:
|
|
1596
|
-
created_at:
|
|
1723
|
+
run_started_at: z9.string().nullable().optional(),
|
|
1724
|
+
updated_at: z9.string().optional(),
|
|
1725
|
+
created_at: z9.string().optional()
|
|
1597
1726
|
});
|
|
1598
|
-
var
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
jobs: z7.array(
|
|
1606
|
-
z7.object({
|
|
1607
|
-
name: z7.string().min(1),
|
|
1608
|
-
status: z7.string(),
|
|
1609
|
-
steps: z7.array(z7.object({ name: z7.string().min(1), status: z7.string() })).optional()
|
|
1727
|
+
var runsSchema = z9.object({ workflow_runs: z9.array(runSchema) });
|
|
1728
|
+
var jobsSchema = z9.object({
|
|
1729
|
+
jobs: z9.array(
|
|
1730
|
+
z9.object({
|
|
1731
|
+
name: z9.string().min(1),
|
|
1732
|
+
status: z9.string(),
|
|
1733
|
+
steps: z9.array(z9.object({ name: z9.string().min(1), status: z9.string() })).optional()
|
|
1610
1734
|
})
|
|
1611
1735
|
)
|
|
1612
1736
|
});
|
|
1613
|
-
var pullRequestsSchema =
|
|
1614
|
-
|
|
1615
|
-
number:
|
|
1616
|
-
html_url:
|
|
1617
|
-
head:
|
|
1618
|
-
base:
|
|
1737
|
+
var pullRequestsSchema = z9.array(
|
|
1738
|
+
z9.object({
|
|
1739
|
+
number: z9.number().int().positive(),
|
|
1740
|
+
html_url: z9.url(),
|
|
1741
|
+
head: z9.object({ ref: z9.string().min(1) }),
|
|
1742
|
+
base: z9.object({ ref: z9.string().min(1) })
|
|
1619
1743
|
})
|
|
1620
1744
|
);
|
|
1621
1745
|
function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
1622
|
-
const { panel: parsedPanel, source: parsedSource } =
|
|
1746
|
+
const { panel: parsedPanel, source: parsedSource } = z9.object({ panel: pipelinePanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
|
|
1623
1747
|
const url = new URL(
|
|
1624
1748
|
`https://api.github.com/repos/${parsedSource.repo}/actions/workflows/${encodeURIComponent(parsedPanel.pipeline)}/runs`
|
|
1625
1749
|
);
|
|
@@ -1628,7 +1752,7 @@ function permittedGithubActionsCalls(panel, source, _credentials) {
|
|
|
1628
1752
|
return [{ url: url.toString(), headers: new Headers() }];
|
|
1629
1753
|
}
|
|
1630
1754
|
function testCountCapabilities(panel, source) {
|
|
1631
|
-
return
|
|
1755
|
+
return z9.object({ panel: testCountPanelSchema, source: githubActionsSourceSchema }).parse({ panel, source });
|
|
1632
1756
|
}
|
|
1633
1757
|
async function fetchGithubActionsTestCount(args2) {
|
|
1634
1758
|
const { panel, source } = testCountCapabilities(args2.panel, args2.source);
|
|
@@ -1646,13 +1770,15 @@ async function fetchGithubActionsTestCount(args2) {
|
|
|
1646
1770
|
return testCountEnvelope(
|
|
1647
1771
|
noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
|
|
1648
1772
|
);
|
|
1649
|
-
const evidence =
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1773
|
+
const evidence = currentTestEvidence(
|
|
1774
|
+
await inspectGithubTestArtifact(
|
|
1775
|
+
{ ...args2, source, githubClient },
|
|
1776
|
+
{
|
|
1777
|
+
run: selected.run,
|
|
1778
|
+
observedAt: selected.observedAt
|
|
1779
|
+
},
|
|
1780
|
+
panel.test_results
|
|
1781
|
+
)
|
|
1656
1782
|
);
|
|
1657
1783
|
return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
|
|
1658
1784
|
} catch (error) {
|
|
@@ -1666,82 +1792,8 @@ async function fetchGithubActionsTestCount(args2) {
|
|
|
1666
1792
|
);
|
|
1667
1793
|
}
|
|
1668
1794
|
}
|
|
1669
|
-
async function readGithubRunTestEvidence(args2, selected, artifactConfig) {
|
|
1670
|
-
const { run: run2, observedAt: runObservedAt } = selected;
|
|
1671
|
-
const { source, githubClient } = args2;
|
|
1672
|
-
const noValidators = new Headers();
|
|
1673
|
-
let failureObservedAt = runObservedAt;
|
|
1674
|
-
const evidenceError = (kind, at = failureObservedAt) => ({
|
|
1675
|
-
state: "error",
|
|
1676
|
-
observedAt: at,
|
|
1677
|
-
error: { kind, message: publicErrorMessage(kind) }
|
|
1678
|
-
});
|
|
1679
|
-
const failedResponse = (response) => evidenceError(errorKind(response.status), observedAt2(response.headers.get("date")));
|
|
1680
|
-
try {
|
|
1681
|
-
if (!run2.id) return evidenceError("upstream-error");
|
|
1682
|
-
if (run2.status !== "completed")
|
|
1683
|
-
return {
|
|
1684
|
-
state: "ok",
|
|
1685
|
-
observedAt: runObservedAt,
|
|
1686
|
-
signal: { type: "test-count", status: "pending" }
|
|
1687
|
-
};
|
|
1688
|
-
const artifactsResponse = await githubFetch(
|
|
1689
|
-
githubArtifactsCall(source, run2.id, artifactConfig),
|
|
1690
|
-
{
|
|
1691
|
-
...args2,
|
|
1692
|
-
source,
|
|
1693
|
-
requestHeaders: noValidators,
|
|
1694
|
-
githubClient
|
|
1695
|
-
}
|
|
1696
|
-
);
|
|
1697
|
-
if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
|
|
1698
|
-
const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
|
|
1699
|
-
failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
|
|
1700
|
-
const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
|
|
1701
|
-
const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
|
|
1702
|
-
if (matches.length === 0)
|
|
1703
|
-
return {
|
|
1704
|
-
state: "ok",
|
|
1705
|
-
observedAt: oldestObservation(runObservedAt, artifactObservedAt),
|
|
1706
|
-
signal: { type: "test-count", status: "not-reported" }
|
|
1707
|
-
};
|
|
1708
|
-
const [artifact] = matches;
|
|
1709
|
-
if (matches.length !== 1 || !artifact || artifact.expired)
|
|
1710
|
-
return evidenceError("upstream-error");
|
|
1711
|
-
const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
|
|
1712
|
-
...args2,
|
|
1713
|
-
source,
|
|
1714
|
-
requestHeaders: noValidators,
|
|
1715
|
-
githubClient
|
|
1716
|
-
});
|
|
1717
|
-
if (!archiveResponse.ok) return failedResponse(archiveResponse);
|
|
1718
|
-
const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
|
|
1719
|
-
failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
|
|
1720
|
-
const summary = testResultsSummarySchema.parse(
|
|
1721
|
-
JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
|
|
1722
|
-
);
|
|
1723
|
-
if (summary.runId !== run2.id || summary.runAttempt !== run2.run_attempt || summary.headSha !== run2.head_sha)
|
|
1724
|
-
throw new Error("Test-results manifest does not belong to the selected workflow run.");
|
|
1725
|
-
return {
|
|
1726
|
-
state: "ok",
|
|
1727
|
-
observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
|
|
1728
|
-
signal: {
|
|
1729
|
-
type: "test-count",
|
|
1730
|
-
status: "reported",
|
|
1731
|
-
total: summary.total,
|
|
1732
|
-
...summary.passed === void 0 ? {} : { passed: summary.passed },
|
|
1733
|
-
...summary.failed === void 0 ? {} : { failed: summary.failed },
|
|
1734
|
-
...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
|
|
1735
|
-
}
|
|
1736
|
-
};
|
|
1737
|
-
} catch (error) {
|
|
1738
|
-
return evidenceError(
|
|
1739
|
-
error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
|
|
1740
|
-
);
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
1795
|
function pullRequestHealthCapabilities(panel) {
|
|
1744
|
-
const { panel: parsed } =
|
|
1796
|
+
const { panel: parsed } = z9.object({ panel: pullRequestHealthPanelSchema }).parse({ panel });
|
|
1745
1797
|
return {
|
|
1746
1798
|
panel: parsed,
|
|
1747
1799
|
configuredUpdateWorkflow(workflow) {
|
|
@@ -1843,10 +1895,12 @@ async function fetchGithubActionsPipeline(args2) {
|
|
|
1843
1895
|
if (activity) signal.activity = activity;
|
|
1844
1896
|
}
|
|
1845
1897
|
if (parsedPanel.test_results) {
|
|
1846
|
-
signal.testResults =
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1898
|
+
signal.testResults = currentTestEvidence(
|
|
1899
|
+
await inspectGithubTestArtifact(
|
|
1900
|
+
{ ...args2, source: parsedSource, githubClient },
|
|
1901
|
+
{ run: run2, observedAt: selected.observedAt },
|
|
1902
|
+
parsedPanel.test_results
|
|
1903
|
+
)
|
|
1850
1904
|
);
|
|
1851
1905
|
}
|
|
1852
1906
|
const envelope = {
|
|
@@ -1965,18 +2019,6 @@ function githubJobsCall(source, runId) {
|
|
|
1965
2019
|
url.searchParams.set("per_page", "100");
|
|
1966
2020
|
return { url: url.toString(), headers: new Headers() };
|
|
1967
2021
|
}
|
|
1968
|
-
function githubArtifactsCall(source, runId, testResults) {
|
|
1969
|
-
const url = new URL(`https://api.github.com/repos/${source.repo}/actions/runs/${runId}/artifacts`);
|
|
1970
|
-
url.searchParams.set("name", testResults.artifact);
|
|
1971
|
-
url.searchParams.set("per_page", "100");
|
|
1972
|
-
return { url: url.toString(), headers: new Headers() };
|
|
1973
|
-
}
|
|
1974
|
-
function githubArtifactDownloadCall(source, artifactId) {
|
|
1975
|
-
return {
|
|
1976
|
-
url: `https://api.github.com/repos/${source.repo}/actions/artifacts/${artifactId}/zip`,
|
|
1977
|
-
headers: new Headers()
|
|
1978
|
-
};
|
|
1979
|
-
}
|
|
1980
2022
|
function noRunEnvelope(panelId, source, pipeline, date) {
|
|
1981
2023
|
return {
|
|
1982
2024
|
panelId,
|
|
@@ -2015,7 +2057,7 @@ function completedRunDuration(run2) {
|
|
|
2015
2057
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
2016
2058
|
}
|
|
2017
2059
|
function timestamp(value2) {
|
|
2018
|
-
if (!value2 || !
|
|
2060
|
+
if (!value2 || !z9.iso.datetime().safeParse(value2).success) return void 0;
|
|
2019
2061
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
2020
2062
|
}
|
|
2021
2063
|
function normalizeStatus(status, conclusion) {
|
|
@@ -2032,7 +2074,7 @@ function errorEnvelope(panelId, kind, error, link, observedAt4 = (/* @__PURE__ *
|
|
|
2032
2074
|
return upstreamErrorEnvelope({ panelId, kind, error, link, upstreamDate: observedAt4 });
|
|
2033
2075
|
}
|
|
2034
2076
|
function sourceLink(panel, source) {
|
|
2035
|
-
const parsedPanel =
|
|
2077
|
+
const parsedPanel = z9.object({ pipeline: z9.string().min(1) }).parse(panel);
|
|
2036
2078
|
const parsedSource = githubActionsSourceSchema.parse(source);
|
|
2037
2079
|
return sourceLinkForWorkflow(parsedSource, parsedPanel.pipeline);
|
|
2038
2080
|
}
|
|
@@ -2042,6 +2084,81 @@ function sourceLinkForWorkflow(source, pipeline) {
|
|
|
2042
2084
|
function observedAt2(value2) {
|
|
2043
2085
|
return observedAt(value2);
|
|
2044
2086
|
}
|
|
2087
|
+
async function fetchGithubTestHistory(args2) {
|
|
2088
|
+
const source = githubActionsSourceSchema.parse(args2.source);
|
|
2089
|
+
const fetcher = (input, init) => args2.fetcher(input, { ...init, ...args2.signal ? { signal: args2.signal } : {} });
|
|
2090
|
+
const artifact = testResultsArtifactSchema.parse(args2.panel.test_results);
|
|
2091
|
+
const workflow = z9.string().min(1).parse(args2.panel.pipeline);
|
|
2092
|
+
const now = Date.now();
|
|
2093
|
+
const cutoff = now - 14 * 864e5;
|
|
2094
|
+
const history = {
|
|
2095
|
+
inspectedAt: new Date(now).toISOString(),
|
|
2096
|
+
inspectedRuns: 0,
|
|
2097
|
+
complete: true,
|
|
2098
|
+
samples: []
|
|
2099
|
+
};
|
|
2100
|
+
let stop = false;
|
|
2101
|
+
const recordFailure = (failure2) => {
|
|
2102
|
+
history.complete = false;
|
|
2103
|
+
if (failure2.errorKind === "unauthorized" || failure2.httpStatus === 429) stop = true;
|
|
2104
|
+
if (failure2.retryAt && (!history.retryAt || Date.parse(failure2.retryAt) > Date.parse(history.retryAt)))
|
|
2105
|
+
history.retryAt = failure2.retryAt;
|
|
2106
|
+
};
|
|
2107
|
+
try {
|
|
2108
|
+
const call = githubRunsCall(
|
|
2109
|
+
source,
|
|
2110
|
+
workflow,
|
|
2111
|
+
source.branch,
|
|
2112
|
+
void 0,
|
|
2113
|
+
8,
|
|
2114
|
+
new Date(cutoff).toISOString()
|
|
2115
|
+
);
|
|
2116
|
+
const url = new URL(call.url);
|
|
2117
|
+
url.searchParams.set("status", "completed");
|
|
2118
|
+
const response = await githubFetch(
|
|
2119
|
+
{ ...call, url: url.toString() },
|
|
2120
|
+
{ ...args2, fetcher, source, requestHeaders: new Headers() }
|
|
2121
|
+
);
|
|
2122
|
+
if (!response.ok) recordFailure(testArtifactHttpFailure(response));
|
|
2123
|
+
else {
|
|
2124
|
+
const runs = runsSchema.parse(await response.json()).workflow_runs.slice(0, 8);
|
|
2125
|
+
for (const run2 of runs) {
|
|
2126
|
+
if (stop || args2.signal?.aborted) {
|
|
2127
|
+
history.complete = false;
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
if (run2.status !== "completed") continue;
|
|
2131
|
+
if (run2.updated_at && Date.parse(run2.updated_at) < cutoff) continue;
|
|
2132
|
+
history.inspectedRuns++;
|
|
2133
|
+
const inspection = await inspectGithubTestArtifact(
|
|
2134
|
+
{ ...args2, fetcher, source },
|
|
2135
|
+
{ run: run2, observedAt: observedAt2(response.headers.get("date")) },
|
|
2136
|
+
artifact
|
|
2137
|
+
);
|
|
2138
|
+
switch (inspection.kind) {
|
|
2139
|
+
case "failed":
|
|
2140
|
+
recordFailure(inspection);
|
|
2141
|
+
break;
|
|
2142
|
+
case "reported": {
|
|
2143
|
+
const { run: identity, total } = inspection.tests;
|
|
2144
|
+
if (identity) history.samples.push({ ...identity, total });
|
|
2145
|
+
else history.complete = false;
|
|
2146
|
+
break;
|
|
2147
|
+
}
|
|
2148
|
+
case "absent":
|
|
2149
|
+
case "expired":
|
|
2150
|
+
break;
|
|
2151
|
+
case "pending":
|
|
2152
|
+
history.complete = false;
|
|
2153
|
+
break;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
} catch {
|
|
2158
|
+
history.complete = false;
|
|
2159
|
+
}
|
|
2160
|
+
return Response.json(history, { headers: { "cache-control": "no-store" } });
|
|
2161
|
+
}
|
|
2045
2162
|
|
|
2046
2163
|
// packages/server/src/configuration-error.ts
|
|
2047
2164
|
var ConfigurationError = class extends Error {
|
|
@@ -2095,37 +2212,37 @@ function correctiveConstraint(issue) {
|
|
|
2095
2212
|
|
|
2096
2213
|
// packages/server/src/adapters/azure-devops.ts
|
|
2097
2214
|
import { readFile } from "node:fs/promises";
|
|
2098
|
-
import { z as
|
|
2099
|
-
var pipelinePanelSchema2 =
|
|
2100
|
-
id:
|
|
2101
|
-
type:
|
|
2102
|
-
source:
|
|
2103
|
-
pipeline:
|
|
2215
|
+
import { z as z10 } from "zod";
|
|
2216
|
+
var pipelinePanelSchema2 = z10.object({
|
|
2217
|
+
id: z10.string().min(1),
|
|
2218
|
+
type: z10.literal("pipeline-status"),
|
|
2219
|
+
source: z10.string().min(1),
|
|
2220
|
+
pipeline: z10.number().int().positive()
|
|
2104
2221
|
});
|
|
2105
|
-
var buildSchema =
|
|
2106
|
-
id:
|
|
2107
|
-
buildNumber:
|
|
2108
|
-
status:
|
|
2109
|
-
result:
|
|
2110
|
-
sourceBranch:
|
|
2111
|
-
startTime:
|
|
2112
|
-
finishTime:
|
|
2113
|
-
lastChangedDate:
|
|
2222
|
+
var buildSchema = z10.object({
|
|
2223
|
+
id: z10.number().int().positive(),
|
|
2224
|
+
buildNumber: z10.string().min(1),
|
|
2225
|
+
status: z10.string().nullable().optional(),
|
|
2226
|
+
result: z10.string().nullable().optional(),
|
|
2227
|
+
sourceBranch: z10.string().min(1).nullable().optional(),
|
|
2228
|
+
startTime: z10.string().nullable().optional(),
|
|
2229
|
+
finishTime: z10.string().nullable().optional(),
|
|
2230
|
+
lastChangedDate: z10.string().nullable().optional()
|
|
2114
2231
|
});
|
|
2115
|
-
var buildsSchema =
|
|
2116
|
-
var timelineSchema =
|
|
2117
|
-
records:
|
|
2118
|
-
|
|
2119
|
-
id:
|
|
2120
|
-
parentId:
|
|
2121
|
-
type:
|
|
2122
|
-
name:
|
|
2123
|
-
state:
|
|
2232
|
+
var buildsSchema = z10.object({ value: z10.array(buildSchema) });
|
|
2233
|
+
var timelineSchema = z10.object({
|
|
2234
|
+
records: z10.array(
|
|
2235
|
+
z10.object({
|
|
2236
|
+
id: z10.string().min(1),
|
|
2237
|
+
parentId: z10.string().min(1).nullable().optional(),
|
|
2238
|
+
type: z10.string().min(1),
|
|
2239
|
+
name: z10.string().min(1),
|
|
2240
|
+
state: z10.string().nullable().optional()
|
|
2124
2241
|
})
|
|
2125
2242
|
)
|
|
2126
2243
|
});
|
|
2127
2244
|
function permittedAzureDevOpsCalls(panel, source) {
|
|
2128
|
-
const { panel: parsedPanel, source: parsedSource } =
|
|
2245
|
+
const { panel: parsedPanel, source: parsedSource } = z10.object({ panel: pipelinePanelSchema2, source: azureDevOpsSourceSchema }).parse({ panel, source });
|
|
2129
2246
|
return [buildsCall(parsedPanel.pipeline, parsedSource)];
|
|
2130
2247
|
}
|
|
2131
2248
|
async function fetchAzureDevOpsPipeline(args2) {
|
|
@@ -2238,9 +2355,9 @@ async function fetchAzureDevOpsPipeline(args2) {
|
|
|
2238
2355
|
};
|
|
2239
2356
|
}
|
|
2240
2357
|
}
|
|
2241
|
-
var delegatedTokenFileSchema =
|
|
2242
|
-
accessToken:
|
|
2243
|
-
expiresAt:
|
|
2358
|
+
var delegatedTokenFileSchema = z10.object({
|
|
2359
|
+
accessToken: z10.string().min(1),
|
|
2360
|
+
expiresAt: z10.string().min(1)
|
|
2244
2361
|
});
|
|
2245
2362
|
async function azureDevOpsAuthorization(source, credentials) {
|
|
2246
2363
|
if (source.token_env) {
|
|
@@ -2321,7 +2438,7 @@ function completedBuildDuration(build) {
|
|
|
2321
2438
|
return Number.isFinite(durationMs) && durationMs >= 0 ? { durationMs } : {};
|
|
2322
2439
|
}
|
|
2323
2440
|
function timestamp2(value2) {
|
|
2324
|
-
if (!value2 || !
|
|
2441
|
+
if (!value2 || !z10.iso.datetime().safeParse(value2).success) return void 0;
|
|
2325
2442
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
2326
2443
|
}
|
|
2327
2444
|
function copyValidators(requestHeaders, upstreamHeaders) {
|
|
@@ -2347,23 +2464,23 @@ function observedAt3(value2) {
|
|
|
2347
2464
|
}
|
|
2348
2465
|
|
|
2349
2466
|
// packages/server/src/adapters/gitlab-ci.ts
|
|
2350
|
-
import { z as
|
|
2351
|
-
var pipelinePanelSchema3 =
|
|
2352
|
-
id:
|
|
2353
|
-
type:
|
|
2354
|
-
source:
|
|
2467
|
+
import { z as z11 } from "zod";
|
|
2468
|
+
var pipelinePanelSchema3 = z11.object({
|
|
2469
|
+
id: z11.string().min(1),
|
|
2470
|
+
type: z11.literal("pipeline-status"),
|
|
2471
|
+
source: z11.string().min(1)
|
|
2355
2472
|
});
|
|
2356
|
-
var pipelineSchema =
|
|
2357
|
-
id:
|
|
2358
|
-
name:
|
|
2359
|
-
status:
|
|
2360
|
-
ref:
|
|
2361
|
-
created_at:
|
|
2362
|
-
updated_at:
|
|
2363
|
-
web_url:
|
|
2473
|
+
var pipelineSchema = z11.object({
|
|
2474
|
+
id: z11.number().int().positive(),
|
|
2475
|
+
name: z11.string().min(1).nullable().optional(),
|
|
2476
|
+
status: z11.string(),
|
|
2477
|
+
ref: z11.string().min(1).nullable().optional(),
|
|
2478
|
+
created_at: z11.string().nullable().optional(),
|
|
2479
|
+
updated_at: z11.string().nullable().optional(),
|
|
2480
|
+
web_url: z11.url()
|
|
2364
2481
|
});
|
|
2365
2482
|
function permittedGitlabCiCalls(panel, source) {
|
|
2366
|
-
const { source: parsedSource } =
|
|
2483
|
+
const { source: parsedSource } = z11.object({ panel: pipelinePanelSchema3, source: gitlabCiSourceSchema }).parse({ panel, source });
|
|
2367
2484
|
return [pipelinesCall(parsedSource)];
|
|
2368
2485
|
}
|
|
2369
2486
|
async function fetchGitlabCiPipeline(args2) {
|
|
@@ -2402,7 +2519,7 @@ async function fetchGitlabCiPipeline(args2) {
|
|
|
2402
2519
|
);
|
|
2403
2520
|
}
|
|
2404
2521
|
try {
|
|
2405
|
-
const pipeline =
|
|
2522
|
+
const pipeline = z11.array(pipelineSchema).parse(await upstream.json())[0];
|
|
2406
2523
|
if (!pipeline) {
|
|
2407
2524
|
const detail = source.branch ? `No pipelines found for ref "${source.branch}". Check the source's branch setting.` : "No pipelines found.";
|
|
2408
2525
|
return failure(
|
|
@@ -2468,7 +2585,7 @@ function normalizeStatus3(status) {
|
|
|
2468
2585
|
return "unknown";
|
|
2469
2586
|
}
|
|
2470
2587
|
function timestamp3(value2) {
|
|
2471
|
-
if (!value2 || !
|
|
2588
|
+
if (!value2 || !z11.iso.datetime().safeParse(value2).success) return void 0;
|
|
2472
2589
|
return Number.isFinite(new Date(value2).valueOf()) ? value2 : void 0;
|
|
2473
2590
|
}
|
|
2474
2591
|
function failure(panelId, kind, error, link, date, failure2) {
|
|
@@ -2481,10 +2598,10 @@ function failure(panelId, kind, error, link, date, failure2) {
|
|
|
2481
2598
|
}
|
|
2482
2599
|
|
|
2483
2600
|
// packages/server/src/adapters/http-value.ts
|
|
2484
|
-
import { z as
|
|
2601
|
+
import { z as z12 } from "zod";
|
|
2485
2602
|
function permittedHttpValueCalls(panel) {
|
|
2486
2603
|
const grouped = httpValueGroupedPanelSchema.safeParse(panel);
|
|
2487
|
-
const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [
|
|
2604
|
+
const urls = grouped.success ? grouped.data.facts.map((fact) => fact.url) : [z12.object({ panel: httpValueScalarPanelSchema }).parse({ panel }).panel.url];
|
|
2488
2605
|
return urls.map(permittedCall);
|
|
2489
2606
|
}
|
|
2490
2607
|
async function fetchHttpValue(args2) {
|
|
@@ -2583,6 +2700,9 @@ function readPanelAdapter(panel, source) {
|
|
|
2583
2700
|
if (panel.type === "pipeline-status" && source?.type === "github-actions") {
|
|
2584
2701
|
permittedGithubActionsCalls(panel, source);
|
|
2585
2702
|
return {
|
|
2703
|
+
...panel.test_results ? {
|
|
2704
|
+
testHistory: ({ source: _source, ...args2 }) => fetchGithubTestHistory({ ...args2, source })
|
|
2705
|
+
} : {},
|
|
2586
2706
|
destination: () => "https://api.github.com",
|
|
2587
2707
|
fetch: ({ source: _configuredSource, ...args2 }) => fetchGithubActionsPipeline({ ...args2, source })
|
|
2588
2708
|
};
|
|
@@ -2590,6 +2710,9 @@ function readPanelAdapter(panel, source) {
|
|
|
2590
2710
|
if (panel.type === "test-count" && source?.type === "github-actions") {
|
|
2591
2711
|
testCountCapabilities(panel, source);
|
|
2592
2712
|
return {
|
|
2713
|
+
...panel.test_results ? {
|
|
2714
|
+
testHistory: ({ source: _source, ...args2 }) => fetchGithubTestHistory({ ...args2, source })
|
|
2715
|
+
} : {},
|
|
2593
2716
|
destination: () => "https://api.github.com",
|
|
2594
2717
|
fetch: ({ source: _configuredSource, ...args2 }) => fetchGithubActionsTestCount({ ...args2, source })
|
|
2595
2718
|
};
|
|
@@ -2668,7 +2791,9 @@ function derive(config, rejectUnsupported) {
|
|
|
2668
2791
|
return allowed;
|
|
2669
2792
|
}
|
|
2670
2793
|
function panelCapability(panel, source) {
|
|
2671
|
-
|
|
2794
|
+
const adapter = readPanelAdapter(panel, source);
|
|
2795
|
+
if (adapter)
|
|
2796
|
+
return { kind: "server", operations: adapter.testHistory ? ["read", "test-history"] : ["read"] };
|
|
2672
2797
|
if (panel.type === "pull-request-health" && source?.type === "github-actions") {
|
|
2673
2798
|
pullRequestHealthCapabilities(panel);
|
|
2674
2799
|
return {
|