@continuous-excellence/ze-great-dashboard-aws 0.31.54 → 0.31.55

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 CHANGED
@@ -205,11 +205,11 @@ var panelSchema = z2.looseObject({
205
205
  path: ["test_results"],
206
206
  message: "test-count requires test_results artifact configuration"
207
207
  });
208
- } else if (panel.test_results) {
208
+ } else if (panel.test_results && panel.type !== "pipeline-status") {
209
209
  ctx.addIssue({
210
210
  code: "custom",
211
211
  path: ["test_results"],
212
- message: "test_results is only supported by test-count panels"
212
+ message: "test_results is only supported by test-count and pipeline-status panels"
213
213
  });
214
214
  }
215
215
  if (panel.type !== "http-value") return;
@@ -454,6 +454,12 @@ var boardConfigSchema = z2.object({
454
454
  }
455
455
  });
456
456
  }
457
+ if (panel.type === "pipeline-status" && panel.test_results && source?.type !== "github-actions")
458
+ ctx.addIssue({
459
+ code: "custom",
460
+ path: ["boards", boardName, "panels", panelIndex, "test_results"],
461
+ message: "test_results requires a github-actions source"
462
+ });
457
463
  if (panel.type !== "pipeline-status" || source?.type !== "azure-devops") return;
458
464
  if (typeof panel.pipeline !== "number" || !Number.isInteger(panel.pipeline) || panel.pipeline <= 0) {
459
465
  ctx.addIssue({
@@ -566,11 +572,29 @@ var pipelineActivitySchema = z4.object({
566
572
  name: z4.string().min(1),
567
573
  parent: z4.string().min(1).optional()
568
574
  });
575
+ var testCountSchema = z4.discriminatedUnion("status", [
576
+ z4.object({
577
+ type: z4.literal("test-count"),
578
+ status: z4.literal("reported"),
579
+ total: z4.number().int().nonnegative(),
580
+ passed: z4.number().int().nonnegative().optional(),
581
+ failed: z4.number().int().nonnegative().optional(),
582
+ skipped: z4.number().int().nonnegative().optional()
583
+ }),
584
+ z4.object({ type: z4.literal("test-count"), status: z4.literal("pending") }),
585
+ z4.object({ type: z4.literal("test-count"), status: z4.literal("not-reported") })
586
+ ]);
587
+ var testEvidenceSchema = z4.discriminatedUnion("state", [
588
+ z4.object({ state: z4.literal("ok"), observedAt: z4.iso.datetime(), signal: testCountSchema }),
589
+ z4.object({ state: z4.literal("error"), observedAt: z4.iso.datetime(), error: envelopeErrorSchema })
590
+ ]);
569
591
  var pipelineStatusSchema = z4.object({
570
592
  type: z4.literal("pipeline-status"),
571
593
  status: z4.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
572
594
  /** The source's unmodified status/result vocabulary, for an honest display. */
573
595
  rawStatus: z4.string(),
596
+ /** Test evidence bound to this exact run; failures do not erase build status. */
597
+ testResults: testEvidenceSchema.optional(),
574
598
  name: z4.string().min(1),
575
599
  /** The branch represented by this status, when the upstream supplies or filters by one. */
576
600
  branch: z4.string().min(1).optional(),
@@ -587,18 +611,6 @@ var pipelineStatusSchema = z4.object({
587
611
  /** When this workflow run was last updated by its source, distinct from our observation time. */
588
612
  sourceUpdatedAt: z4.iso.datetime().optional()
589
613
  });
590
- var testCountSchema = z4.discriminatedUnion("status", [
591
- z4.object({
592
- type: z4.literal("test-count"),
593
- status: z4.literal("reported"),
594
- total: z4.number().int().nonnegative(),
595
- passed: z4.number().int().nonnegative().optional(),
596
- failed: z4.number().int().nonnegative().optional(),
597
- skipped: z4.number().int().nonnegative().optional()
598
- }),
599
- z4.object({ type: z4.literal("test-count"), status: z4.literal("pending") }),
600
- z4.object({ type: z4.literal("test-count"), status: z4.literal("not-reported") })
601
- ]);
602
614
  var pullRequestHealthItemSchema = z4.object({
603
615
  label: z4.string().min(1),
604
616
  status: pipelineStatusSchema.shape.status,
@@ -1545,6 +1557,7 @@ function concat(chunks, length) {
1545
1557
 
1546
1558
  // packages/server/src/adapters/github-actions.ts
1547
1559
  var pipelinePanelSchema = z7.object({
1560
+ test_results: testResultsArtifactSchema.optional(),
1548
1561
  id: z7.string().min(1),
1549
1562
  type: z7.literal("pipeline-status"),
1550
1563
  source: z7.string().min(1),
@@ -1620,37 +1633,60 @@ function testCountCapabilities(panel, source) {
1620
1633
  async function fetchGithubActionsTestCount(args2) {
1621
1634
  const { panel, source } = testCountCapabilities(args2.panel, args2.source);
1622
1635
  const githubClient = githubClientFor(args2);
1623
- const noValidators = new Headers();
1624
- let failureLink = sourceLinkForWorkflow(source, panel.pipeline);
1625
- let failureObservedAt;
1626
1636
  try {
1627
1637
  const selected = await selectGithubWorkflowRun({
1628
1638
  ...args2,
1629
1639
  source,
1630
1640
  workflow: panel.pipeline,
1631
- requestHeaders: noValidators,
1641
+ requestHeaders: new Headers(),
1632
1642
  githubClient
1633
1643
  });
1634
1644
  if (!selected.response.ok) return testCountFailure(panel.id, source, selected.response);
1635
- const { run: run2 } = selected;
1636
- if (!run2?.id)
1645
+ if (!selected.run?.id)
1637
1646
  return testCountEnvelope(
1638
1647
  noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
1639
1648
  );
1640
- const link = run2.html_url;
1641
- const runObservedAt = selected.observedAt;
1642
- failureLink = link;
1643
- failureObservedAt = runObservedAt;
1649
+ const evidence = await readGithubRunTestEvidence(
1650
+ { ...args2, source, githubClient },
1651
+ {
1652
+ run: selected.run,
1653
+ observedAt: selected.observedAt
1654
+ },
1655
+ panel.test_results
1656
+ );
1657
+ return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
1658
+ } catch (error) {
1659
+ return testCountEnvelope(
1660
+ errorEnvelope(
1661
+ panel.id,
1662
+ error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
1663
+ error,
1664
+ sourceLinkForWorkflow(source, panel.pipeline)
1665
+ )
1666
+ );
1667
+ }
1668
+ }
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");
1644
1682
  if (run2.status !== "completed")
1645
- return testCountEnvelope({
1646
- panelId: panel.id,
1683
+ return {
1647
1684
  state: "ok",
1648
1685
  observedAt: runObservedAt,
1649
- link,
1650
1686
  signal: { type: "test-count", status: "pending" }
1651
- });
1687
+ };
1652
1688
  const artifactsResponse = await githubFetch(
1653
- githubArtifactsCall(source, run2.id, panel.test_results),
1689
+ githubArtifactsCall(source, run2.id, artifactConfig),
1654
1690
  {
1655
1691
  ...args2,
1656
1692
  source,
@@ -1658,57 +1694,37 @@ async function fetchGithubActionsTestCount(args2) {
1658
1694
  githubClient
1659
1695
  }
1660
1696
  );
1661
- if (!artifactsResponse.ok) return testCountFailure(panel.id, source, artifactsResponse, link);
1697
+ if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
1662
1698
  const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
1663
1699
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
1664
1700
  const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
1665
- const matches = artifacts.filter((artifact2) => artifact2.name === panel.test_results.artifact);
1701
+ const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
1666
1702
  if (matches.length === 0)
1667
- return testCountEnvelope({
1668
- panelId: panel.id,
1703
+ return {
1669
1704
  state: "ok",
1670
1705
  observedAt: oldestObservation(runObservedAt, artifactObservedAt),
1671
- link,
1672
1706
  signal: { type: "test-count", status: "not-reported" }
1673
- });
1674
- if (matches.length !== 1 || matches[0]?.expired)
1675
- return testCountEnvelope(
1676
- errorEnvelope(
1677
- panel.id,
1678
- "upstream-error",
1679
- "The test-results artifact is unavailable.",
1680
- link
1681
- )
1682
- );
1707
+ };
1683
1708
  const [artifact] = matches;
1684
- if (!artifact)
1685
- return testCountEnvelope(
1686
- errorEnvelope(
1687
- panel.id,
1688
- "upstream-error",
1689
- "The test-results artifact is unavailable.",
1690
- link
1691
- )
1692
- );
1709
+ if (matches.length !== 1 || !artifact || artifact.expired)
1710
+ return evidenceError("upstream-error");
1693
1711
  const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
1694
1712
  ...args2,
1695
1713
  source,
1696
1714
  requestHeaders: noValidators,
1697
1715
  githubClient
1698
1716
  });
1699
- if (!archiveResponse.ok) return testCountFailure(panel.id, source, archiveResponse, link);
1717
+ if (!archiveResponse.ok) return failedResponse(archiveResponse);
1700
1718
  const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
1701
1719
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
1702
1720
  const summary = testResultsSummarySchema.parse(
1703
- JSON.parse(await readTestResultsArtifact(archiveResponse, panel.test_results.entry))
1721
+ JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
1704
1722
  );
1705
1723
  if (summary.runId !== run2.id || summary.runAttempt !== run2.run_attempt || summary.headSha !== run2.head_sha)
1706
1724
  throw new Error("Test-results manifest does not belong to the selected workflow run.");
1707
- return testCountEnvelope({
1708
- panelId: panel.id,
1725
+ return {
1709
1726
  state: "ok",
1710
1727
  observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
1711
- link,
1712
1728
  signal: {
1713
1729
  type: "test-count",
1714
1730
  status: "reported",
@@ -1717,16 +1733,10 @@ async function fetchGithubActionsTestCount(args2) {
1717
1733
  ...summary.failed === void 0 ? {} : { failed: summary.failed },
1718
1734
  ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
1719
1735
  }
1720
- });
1736
+ };
1721
1737
  } catch (error) {
1722
- return testCountEnvelope(
1723
- errorEnvelope(
1724
- panel.id,
1725
- error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
1726
- error,
1727
- failureLink,
1728
- failureObservedAt
1729
- )
1738
+ return evidenceError(
1739
+ error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
1730
1740
  );
1731
1741
  }
1732
1742
  }
@@ -1767,6 +1777,7 @@ async function fetchGithubActionsPipeline(args2) {
1767
1777
  ...args2,
1768
1778
  source: parsedSource,
1769
1779
  workflow: parsedPanel.pipeline,
1780
+ requestHeaders: parsedPanel.test_results ? new Headers() : args2.requestHeaders,
1770
1781
  githubClient
1771
1782
  });
1772
1783
  } catch (error) {
@@ -1831,14 +1842,21 @@ async function fetchGithubActionsPipeline(args2) {
1831
1842
  });
1832
1843
  if (activity) signal.activity = activity;
1833
1844
  }
1845
+ if (parsedPanel.test_results) {
1846
+ signal.testResults = await readGithubRunTestEvidence(
1847
+ { ...args2, source: parsedSource, githubClient },
1848
+ { run: run2, observedAt: selected.observedAt },
1849
+ parsedPanel.test_results
1850
+ );
1851
+ }
1834
1852
  const envelope = {
1835
1853
  panelId: args2.panel.id,
1836
1854
  state: "ok",
1837
- observedAt: observedAt2(upstream.headers.get("date")),
1855
+ observedAt: signal.testResults ? oldestObservation(selected.observedAt, signal.testResults.observedAt) : selected.observedAt,
1838
1856
  link: run2.html_url,
1839
1857
  signal
1840
1858
  };
1841
- return { envelope, response: upstream };
1859
+ return { envelope, response: parsedPanel.test_results ? new Response(null) : upstream };
1842
1860
  } catch (error) {
1843
1861
  return {
1844
1862
  response: new Response(
package/dist/index.js CHANGED
@@ -887,11 +887,11 @@ var panelSchema = z2.looseObject({
887
887
  path: ["test_results"],
888
888
  message: "test-count requires test_results artifact configuration"
889
889
  });
890
- } else if (panel.test_results) {
890
+ } else if (panel.test_results && panel.type !== "pipeline-status") {
891
891
  ctx.addIssue({
892
892
  code: "custom",
893
893
  path: ["test_results"],
894
- message: "test_results is only supported by test-count panels"
894
+ message: "test_results is only supported by test-count and pipeline-status panels"
895
895
  });
896
896
  }
897
897
  if (panel.type !== "http-value") return;
@@ -1136,6 +1136,12 @@ var boardConfigSchema = z2.object({
1136
1136
  }
1137
1137
  });
1138
1138
  }
1139
+ if (panel.type === "pipeline-status" && panel.test_results && source?.type !== "github-actions")
1140
+ ctx.addIssue({
1141
+ code: "custom",
1142
+ path: ["boards", boardName, "panels", panelIndex, "test_results"],
1143
+ message: "test_results requires a github-actions source"
1144
+ });
1139
1145
  if (panel.type !== "pipeline-status" || source?.type !== "azure-devops") return;
1140
1146
  if (typeof panel.pipeline !== "number" || !Number.isInteger(panel.pipeline) || panel.pipeline <= 0) {
1141
1147
  ctx.addIssue({
@@ -1248,11 +1254,29 @@ var pipelineActivitySchema = z4.object({
1248
1254
  name: z4.string().min(1),
1249
1255
  parent: z4.string().min(1).optional()
1250
1256
  });
1257
+ var testCountSchema = z4.discriminatedUnion("status", [
1258
+ z4.object({
1259
+ type: z4.literal("test-count"),
1260
+ status: z4.literal("reported"),
1261
+ total: z4.number().int().nonnegative(),
1262
+ passed: z4.number().int().nonnegative().optional(),
1263
+ failed: z4.number().int().nonnegative().optional(),
1264
+ skipped: z4.number().int().nonnegative().optional()
1265
+ }),
1266
+ z4.object({ type: z4.literal("test-count"), status: z4.literal("pending") }),
1267
+ z4.object({ type: z4.literal("test-count"), status: z4.literal("not-reported") })
1268
+ ]);
1269
+ var testEvidenceSchema = z4.discriminatedUnion("state", [
1270
+ z4.object({ state: z4.literal("ok"), observedAt: z4.iso.datetime(), signal: testCountSchema }),
1271
+ z4.object({ state: z4.literal("error"), observedAt: z4.iso.datetime(), error: envelopeErrorSchema })
1272
+ ]);
1251
1273
  var pipelineStatusSchema = z4.object({
1252
1274
  type: z4.literal("pipeline-status"),
1253
1275
  status: z4.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
1254
1276
  /** The source's unmodified status/result vocabulary, for an honest display. */
1255
1277
  rawStatus: z4.string(),
1278
+ /** Test evidence bound to this exact run; failures do not erase build status. */
1279
+ testResults: testEvidenceSchema.optional(),
1256
1280
  name: z4.string().min(1),
1257
1281
  /** The branch represented by this status, when the upstream supplies or filters by one. */
1258
1282
  branch: z4.string().min(1).optional(),
@@ -1269,18 +1293,6 @@ var pipelineStatusSchema = z4.object({
1269
1293
  /** When this workflow run was last updated by its source, distinct from our observation time. */
1270
1294
  sourceUpdatedAt: z4.iso.datetime().optional()
1271
1295
  });
1272
- var testCountSchema = z4.discriminatedUnion("status", [
1273
- z4.object({
1274
- type: z4.literal("test-count"),
1275
- status: z4.literal("reported"),
1276
- total: z4.number().int().nonnegative(),
1277
- passed: z4.number().int().nonnegative().optional(),
1278
- failed: z4.number().int().nonnegative().optional(),
1279
- skipped: z4.number().int().nonnegative().optional()
1280
- }),
1281
- z4.object({ type: z4.literal("test-count"), status: z4.literal("pending") }),
1282
- z4.object({ type: z4.literal("test-count"), status: z4.literal("not-reported") })
1283
- ]);
1284
1296
  var pullRequestHealthItemSchema = z4.object({
1285
1297
  label: z4.string().min(1),
1286
1298
  status: pipelineStatusSchema.shape.status,
@@ -2227,6 +2239,7 @@ function concat(chunks, length) {
2227
2239
 
2228
2240
  // packages/server/src/adapters/github-actions.ts
2229
2241
  var pipelinePanelSchema = z7.object({
2242
+ test_results: testResultsArtifactSchema.optional(),
2230
2243
  id: z7.string().min(1),
2231
2244
  type: z7.literal("pipeline-status"),
2232
2245
  source: z7.string().min(1),
@@ -2302,37 +2315,60 @@ function testCountCapabilities(panel, source) {
2302
2315
  async function fetchGithubActionsTestCount(args) {
2303
2316
  const { panel, source } = testCountCapabilities(args.panel, args.source);
2304
2317
  const githubClient = githubClientFor(args);
2305
- const noValidators = new Headers();
2306
- let failureLink = sourceLinkForWorkflow(source, panel.pipeline);
2307
- let failureObservedAt;
2308
2318
  try {
2309
2319
  const selected = await selectGithubWorkflowRun({
2310
2320
  ...args,
2311
2321
  source,
2312
2322
  workflow: panel.pipeline,
2313
- requestHeaders: noValidators,
2323
+ requestHeaders: new Headers(),
2314
2324
  githubClient
2315
2325
  });
2316
2326
  if (!selected.response.ok) return testCountFailure(panel.id, source, selected.response);
2317
- const { run } = selected;
2318
- if (!run?.id)
2327
+ if (!selected.run?.id)
2319
2328
  return testCountEnvelope(
2320
2329
  noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
2321
2330
  );
2322
- const link = run.html_url;
2323
- const runObservedAt = selected.observedAt;
2324
- failureLink = link;
2325
- failureObservedAt = runObservedAt;
2331
+ const evidence = await readGithubRunTestEvidence(
2332
+ { ...args, source, githubClient },
2333
+ {
2334
+ run: selected.run,
2335
+ observedAt: selected.observedAt
2336
+ },
2337
+ panel.test_results
2338
+ );
2339
+ return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
2340
+ } catch (error) {
2341
+ return testCountEnvelope(
2342
+ errorEnvelope(
2343
+ panel.id,
2344
+ error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
2345
+ error,
2346
+ sourceLinkForWorkflow(source, panel.pipeline)
2347
+ )
2348
+ );
2349
+ }
2350
+ }
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");
2326
2364
  if (run.status !== "completed")
2327
- return testCountEnvelope({
2328
- panelId: panel.id,
2365
+ return {
2329
2366
  state: "ok",
2330
2367
  observedAt: runObservedAt,
2331
- link,
2332
2368
  signal: { type: "test-count", status: "pending" }
2333
- });
2369
+ };
2334
2370
  const artifactsResponse = await githubFetch(
2335
- githubArtifactsCall(source, run.id, panel.test_results),
2371
+ githubArtifactsCall(source, run.id, artifactConfig),
2336
2372
  {
2337
2373
  ...args,
2338
2374
  source,
@@ -2340,57 +2376,37 @@ async function fetchGithubActionsTestCount(args) {
2340
2376
  githubClient
2341
2377
  }
2342
2378
  );
2343
- if (!artifactsResponse.ok) return testCountFailure(panel.id, source, artifactsResponse, link);
2379
+ if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
2344
2380
  const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
2345
2381
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
2346
2382
  const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
2347
- const matches = artifacts.filter((artifact2) => artifact2.name === panel.test_results.artifact);
2383
+ const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
2348
2384
  if (matches.length === 0)
2349
- return testCountEnvelope({
2350
- panelId: panel.id,
2385
+ return {
2351
2386
  state: "ok",
2352
2387
  observedAt: oldestObservation(runObservedAt, artifactObservedAt),
2353
- link,
2354
2388
  signal: { type: "test-count", status: "not-reported" }
2355
- });
2356
- if (matches.length !== 1 || matches[0]?.expired)
2357
- return testCountEnvelope(
2358
- errorEnvelope(
2359
- panel.id,
2360
- "upstream-error",
2361
- "The test-results artifact is unavailable.",
2362
- link
2363
- )
2364
- );
2389
+ };
2365
2390
  const [artifact] = matches;
2366
- if (!artifact)
2367
- return testCountEnvelope(
2368
- errorEnvelope(
2369
- panel.id,
2370
- "upstream-error",
2371
- "The test-results artifact is unavailable.",
2372
- link
2373
- )
2374
- );
2391
+ if (matches.length !== 1 || !artifact || artifact.expired)
2392
+ return evidenceError("upstream-error");
2375
2393
  const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
2376
2394
  ...args,
2377
2395
  source,
2378
2396
  requestHeaders: noValidators,
2379
2397
  githubClient
2380
2398
  });
2381
- if (!archiveResponse.ok) return testCountFailure(panel.id, source, archiveResponse, link);
2399
+ if (!archiveResponse.ok) return failedResponse(archiveResponse);
2382
2400
  const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
2383
2401
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
2384
2402
  const summary = testResultsSummarySchema.parse(
2385
- JSON.parse(await readTestResultsArtifact(archiveResponse, panel.test_results.entry))
2403
+ JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
2386
2404
  );
2387
2405
  if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
2388
2406
  throw new Error("Test-results manifest does not belong to the selected workflow run.");
2389
- return testCountEnvelope({
2390
- panelId: panel.id,
2407
+ return {
2391
2408
  state: "ok",
2392
2409
  observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
2393
- link,
2394
2410
  signal: {
2395
2411
  type: "test-count",
2396
2412
  status: "reported",
@@ -2399,16 +2415,10 @@ async function fetchGithubActionsTestCount(args) {
2399
2415
  ...summary.failed === void 0 ? {} : { failed: summary.failed },
2400
2416
  ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
2401
2417
  }
2402
- });
2418
+ };
2403
2419
  } catch (error) {
2404
- return testCountEnvelope(
2405
- errorEnvelope(
2406
- panel.id,
2407
- error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
2408
- error,
2409
- failureLink,
2410
- failureObservedAt
2411
- )
2420
+ return evidenceError(
2421
+ error instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
2412
2422
  );
2413
2423
  }
2414
2424
  }
@@ -2449,6 +2459,7 @@ async function fetchGithubActionsPipeline(args) {
2449
2459
  ...args,
2450
2460
  source: parsedSource,
2451
2461
  workflow: parsedPanel.pipeline,
2462
+ requestHeaders: parsedPanel.test_results ? new Headers() : args.requestHeaders,
2452
2463
  githubClient
2453
2464
  });
2454
2465
  } catch (error) {
@@ -2513,14 +2524,21 @@ async function fetchGithubActionsPipeline(args) {
2513
2524
  });
2514
2525
  if (activity) signal.activity = activity;
2515
2526
  }
2527
+ if (parsedPanel.test_results) {
2528
+ signal.testResults = await readGithubRunTestEvidence(
2529
+ { ...args, source: parsedSource, githubClient },
2530
+ { run, observedAt: selected.observedAt },
2531
+ parsedPanel.test_results
2532
+ );
2533
+ }
2516
2534
  const envelope = {
2517
2535
  panelId: args.panel.id,
2518
2536
  state: "ok",
2519
- observedAt: observedAt2(upstream.headers.get("date")),
2537
+ observedAt: signal.testResults ? oldestObservation(selected.observedAt, signal.testResults.observedAt) : selected.observedAt,
2520
2538
  link: run.html_url,
2521
2539
  signal
2522
2540
  };
2523
- return { envelope, response: upstream };
2541
+ return { envelope, response: parsedPanel.test_results ? new Response(null) : upstream };
2524
2542
  } catch (error) {
2525
2543
  return {
2526
2544
  response: new Response(
package/dist/lambda.mjs CHANGED
@@ -71277,11 +71277,11 @@ var panelSchema = external_exports.looseObject({
71277
71277
  path: ["test_results"],
71278
71278
  message: "test-count requires test_results artifact configuration"
71279
71279
  });
71280
- } else if (panel.test_results) {
71280
+ } else if (panel.test_results && panel.type !== "pipeline-status") {
71281
71281
  ctx.addIssue({
71282
71282
  code: "custom",
71283
71283
  path: ["test_results"],
71284
- message: "test_results is only supported by test-count panels"
71284
+ message: "test_results is only supported by test-count and pipeline-status panels"
71285
71285
  });
71286
71286
  }
71287
71287
  if (panel.type !== "http-value") return;
@@ -71531,6 +71531,12 @@ var boardConfigSchema = external_exports.object({
71531
71531
  }
71532
71532
  });
71533
71533
  }
71534
+ if (panel.type === "pipeline-status" && panel.test_results && source?.type !== "github-actions")
71535
+ ctx.addIssue({
71536
+ code: "custom",
71537
+ path: ["boards", boardName, "panels", panelIndex, "test_results"],
71538
+ message: "test_results requires a github-actions source"
71539
+ });
71534
71540
  if (panel.type !== "pipeline-status" || source?.type !== "azure-devops") return;
71535
71541
  if (typeof panel.pipeline !== "number" || !Number.isInteger(panel.pipeline) || panel.pipeline <= 0) {
71536
71542
  ctx.addIssue({
@@ -71643,11 +71649,29 @@ var pipelineActivitySchema = external_exports.object({
71643
71649
  name: external_exports.string().min(1),
71644
71650
  parent: external_exports.string().min(1).optional()
71645
71651
  });
71652
+ var testCountSchema = external_exports.discriminatedUnion("status", [
71653
+ external_exports.object({
71654
+ type: external_exports.literal("test-count"),
71655
+ status: external_exports.literal("reported"),
71656
+ total: external_exports.number().int().nonnegative(),
71657
+ passed: external_exports.number().int().nonnegative().optional(),
71658
+ failed: external_exports.number().int().nonnegative().optional(),
71659
+ skipped: external_exports.number().int().nonnegative().optional()
71660
+ }),
71661
+ external_exports.object({ type: external_exports.literal("test-count"), status: external_exports.literal("pending") }),
71662
+ external_exports.object({ type: external_exports.literal("test-count"), status: external_exports.literal("not-reported") })
71663
+ ]);
71664
+ var testEvidenceSchema = external_exports.discriminatedUnion("state", [
71665
+ external_exports.object({ state: external_exports.literal("ok"), observedAt: external_exports.iso.datetime(), signal: testCountSchema }),
71666
+ external_exports.object({ state: external_exports.literal("error"), observedAt: external_exports.iso.datetime(), error: envelopeErrorSchema })
71667
+ ]);
71646
71668
  var pipelineStatusSchema = external_exports.object({
71647
71669
  type: external_exports.literal("pipeline-status"),
71648
71670
  status: external_exports.enum(["passed", "failed", "warning", "running", "cancelled", "unknown"]),
71649
71671
  /** The source's unmodified status/result vocabulary, for an honest display. */
71650
71672
  rawStatus: external_exports.string(),
71673
+ /** Test evidence bound to this exact run; failures do not erase build status. */
71674
+ testResults: testEvidenceSchema.optional(),
71651
71675
  name: external_exports.string().min(1),
71652
71676
  /** The branch represented by this status, when the upstream supplies or filters by one. */
71653
71677
  branch: external_exports.string().min(1).optional(),
@@ -71664,18 +71688,6 @@ var pipelineStatusSchema = external_exports.object({
71664
71688
  /** When this workflow run was last updated by its source, distinct from our observation time. */
71665
71689
  sourceUpdatedAt: external_exports.iso.datetime().optional()
71666
71690
  });
71667
- var testCountSchema = external_exports.discriminatedUnion("status", [
71668
- external_exports.object({
71669
- type: external_exports.literal("test-count"),
71670
- status: external_exports.literal("reported"),
71671
- total: external_exports.number().int().nonnegative(),
71672
- passed: external_exports.number().int().nonnegative().optional(),
71673
- failed: external_exports.number().int().nonnegative().optional(),
71674
- skipped: external_exports.number().int().nonnegative().optional()
71675
- }),
71676
- external_exports.object({ type: external_exports.literal("test-count"), status: external_exports.literal("pending") }),
71677
- external_exports.object({ type: external_exports.literal("test-count"), status: external_exports.literal("not-reported") })
71678
- ]);
71679
71691
  var pullRequestHealthItemSchema = external_exports.object({
71680
71692
  label: external_exports.string().min(1),
71681
71693
  status: pipelineStatusSchema.shape.status,
@@ -72754,6 +72766,7 @@ function concat(chunks, length) {
72754
72766
 
72755
72767
  // packages/server/src/adapters/github-actions.ts
72756
72768
  var pipelinePanelSchema = external_exports.object({
72769
+ test_results: testResultsArtifactSchema.optional(),
72757
72770
  id: external_exports.string().min(1),
72758
72771
  type: external_exports.literal("pipeline-status"),
72759
72772
  source: external_exports.string().min(1),
@@ -72829,37 +72842,60 @@ function testCountCapabilities(panel, source) {
72829
72842
  async function fetchGithubActionsTestCount(args) {
72830
72843
  const { panel, source } = testCountCapabilities(args.panel, args.source);
72831
72844
  const githubClient = githubClientFor(args);
72832
- const noValidators = new Headers();
72833
- let failureLink = sourceLinkForWorkflow(source, panel.pipeline);
72834
- let failureObservedAt;
72835
72845
  try {
72836
72846
  const selected = await selectGithubWorkflowRun({
72837
72847
  ...args,
72838
72848
  source,
72839
72849
  workflow: panel.pipeline,
72840
- requestHeaders: noValidators,
72850
+ requestHeaders: new Headers(),
72841
72851
  githubClient
72842
72852
  });
72843
72853
  if (!selected.response.ok) return testCountFailure(panel.id, source, selected.response);
72844
- const { run } = selected;
72845
- if (!run?.id)
72854
+ if (!selected.run?.id)
72846
72855
  return testCountEnvelope(
72847
72856
  noRunEnvelope(panel.id, source, panel.pipeline, selected.response.headers.get("date"))
72848
72857
  );
72849
- const link = run.html_url;
72850
- const runObservedAt = selected.observedAt;
72851
- failureLink = link;
72852
- failureObservedAt = runObservedAt;
72858
+ const evidence = await readGithubRunTestEvidence(
72859
+ { ...args, source, githubClient },
72860
+ {
72861
+ run: selected.run,
72862
+ observedAt: selected.observedAt
72863
+ },
72864
+ panel.test_results
72865
+ );
72866
+ return testCountEnvelope({ ...evidence, panelId: panel.id, link: selected.run.html_url });
72867
+ } catch (error63) {
72868
+ return testCountEnvelope(
72869
+ errorEnvelope(
72870
+ panel.id,
72871
+ error63 instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
72872
+ error63,
72873
+ sourceLinkForWorkflow(source, panel.pipeline)
72874
+ )
72875
+ );
72876
+ }
72877
+ }
72878
+ async function readGithubRunTestEvidence(args, selected, artifactConfig) {
72879
+ const { run, observedAt: runObservedAt } = selected;
72880
+ const { source, githubClient } = args;
72881
+ const noValidators = new Headers();
72882
+ let failureObservedAt = runObservedAt;
72883
+ const evidenceError = (kind, at = failureObservedAt) => ({
72884
+ state: "error",
72885
+ observedAt: at,
72886
+ error: { kind, message: publicErrorMessage(kind) }
72887
+ });
72888
+ const failedResponse = (response) => evidenceError(errorKind(response.status), observedAt2(response.headers.get("date")));
72889
+ try {
72890
+ if (!run.id) return evidenceError("upstream-error");
72853
72891
  if (run.status !== "completed")
72854
- return testCountEnvelope({
72855
- panelId: panel.id,
72892
+ return {
72856
72893
  state: "ok",
72857
72894
  observedAt: runObservedAt,
72858
- link,
72859
72895
  signal: { type: "test-count", status: "pending" }
72860
- });
72896
+ };
72861
72897
  const artifactsResponse = await githubFetch(
72862
- githubArtifactsCall(source, run.id, panel.test_results),
72898
+ githubArtifactsCall(source, run.id, artifactConfig),
72863
72899
  {
72864
72900
  ...args,
72865
72901
  source,
@@ -72867,57 +72903,37 @@ async function fetchGithubActionsTestCount(args) {
72867
72903
  githubClient
72868
72904
  }
72869
72905
  );
72870
- if (!artifactsResponse.ok) return testCountFailure(panel.id, source, artifactsResponse, link);
72906
+ if (!artifactsResponse.ok) return failedResponse(artifactsResponse);
72871
72907
  const artifactObservedAt = observedAt2(artifactsResponse.headers.get("date"));
72872
72908
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt);
72873
72909
  const artifacts = artifactsSchema.parse(await artifactsResponse.json()).artifacts;
72874
- const matches = artifacts.filter((artifact2) => artifact2.name === panel.test_results.artifact);
72910
+ const matches = artifacts.filter((artifact2) => artifact2.name === artifactConfig.artifact);
72875
72911
  if (matches.length === 0)
72876
- return testCountEnvelope({
72877
- panelId: panel.id,
72912
+ return {
72878
72913
  state: "ok",
72879
72914
  observedAt: oldestObservation(runObservedAt, artifactObservedAt),
72880
- link,
72881
72915
  signal: { type: "test-count", status: "not-reported" }
72882
- });
72883
- if (matches.length !== 1 || matches[0]?.expired)
72884
- return testCountEnvelope(
72885
- errorEnvelope(
72886
- panel.id,
72887
- "upstream-error",
72888
- "The test-results artifact is unavailable.",
72889
- link
72890
- )
72891
- );
72916
+ };
72892
72917
  const [artifact] = matches;
72893
- if (!artifact)
72894
- return testCountEnvelope(
72895
- errorEnvelope(
72896
- panel.id,
72897
- "upstream-error",
72898
- "The test-results artifact is unavailable.",
72899
- link
72900
- )
72901
- );
72918
+ if (matches.length !== 1 || !artifact || artifact.expired)
72919
+ return evidenceError("upstream-error");
72902
72920
  const archiveResponse = await githubFetch(githubArtifactDownloadCall(source, artifact.id), {
72903
72921
  ...args,
72904
72922
  source,
72905
72923
  requestHeaders: noValidators,
72906
72924
  githubClient
72907
72925
  });
72908
- if (!archiveResponse.ok) return testCountFailure(panel.id, source, archiveResponse, link);
72926
+ if (!archiveResponse.ok) return failedResponse(archiveResponse);
72909
72927
  const archiveObservedAt = observedAt2(archiveResponse.headers.get("date"));
72910
72928
  failureObservedAt = oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt);
72911
72929
  const summary = testResultsSummarySchema.parse(
72912
- JSON.parse(await readTestResultsArtifact(archiveResponse, panel.test_results.entry))
72930
+ JSON.parse(await readTestResultsArtifact(archiveResponse, artifactConfig.entry))
72913
72931
  );
72914
72932
  if (summary.runId !== run.id || summary.runAttempt !== run.run_attempt || summary.headSha !== run.head_sha)
72915
72933
  throw new Error("Test-results manifest does not belong to the selected workflow run.");
72916
- return testCountEnvelope({
72917
- panelId: panel.id,
72934
+ return {
72918
72935
  state: "ok",
72919
72936
  observedAt: oldestObservation(runObservedAt, artifactObservedAt, archiveObservedAt),
72920
- link,
72921
72937
  signal: {
72922
72938
  type: "test-count",
72923
72939
  status: "reported",
@@ -72926,16 +72942,10 @@ async function fetchGithubActionsTestCount(args) {
72926
72942
  ...summary.failed === void 0 ? {} : { failed: summary.failed },
72927
72943
  ...summary.skipped === void 0 ? {} : { skipped: summary.skipped }
72928
72944
  }
72929
- });
72945
+ };
72930
72946
  } catch (error63) {
72931
- return testCountEnvelope(
72932
- errorEnvelope(
72933
- panel.id,
72934
- error63 instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error",
72935
- error63,
72936
- failureLink,
72937
- failureObservedAt
72938
- )
72947
+ return evidenceError(
72948
+ error63 instanceof GithubAuthenticationError ? "unauthorized" : "upstream-error"
72939
72949
  );
72940
72950
  }
72941
72951
  }
@@ -73151,6 +73161,7 @@ async function fetchGithubActionsPipeline(args) {
73151
73161
  ...args,
73152
73162
  source: parsedSource,
73153
73163
  workflow: parsedPanel.pipeline,
73164
+ requestHeaders: parsedPanel.test_results ? new Headers() : args.requestHeaders,
73154
73165
  githubClient
73155
73166
  });
73156
73167
  } catch (error63) {
@@ -73215,14 +73226,21 @@ async function fetchGithubActionsPipeline(args) {
73215
73226
  });
73216
73227
  if (activity) signal.activity = activity;
73217
73228
  }
73229
+ if (parsedPanel.test_results) {
73230
+ signal.testResults = await readGithubRunTestEvidence(
73231
+ { ...args, source: parsedSource, githubClient },
73232
+ { run, observedAt: selected.observedAt },
73233
+ parsedPanel.test_results
73234
+ );
73235
+ }
73218
73236
  const envelope = {
73219
73237
  panelId: args.panel.id,
73220
73238
  state: "ok",
73221
- observedAt: observedAt2(upstream.headers.get("date")),
73239
+ observedAt: signal.testResults ? oldestObservation(selected.observedAt, signal.testResults.observedAt) : selected.observedAt,
73222
73240
  link: run.html_url,
73223
73241
  signal
73224
73242
  };
73225
- return { envelope, response: upstream };
73243
+ return { envelope, response: parsedPanel.test_results ? new Response(null) : upstream };
73226
73244
  } catch (error63) {
73227
73245
  return {
73228
73246
  response: new Response(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@continuous-excellence/ze-great-dashboard-aws",
3
- "version": "0.31.54",
3
+ "version": "0.31.55",
4
4
  "type": "module",
5
5
  "description": "AWS server runtime and CloudFormation deployment tooling for Ze Great Dashboard.",
6
6
  "keywords": [