新增 release gate execution summary API

This commit is contained in:
2026-06-16 17:39:47 +08:00
parent 35bc25714d
commit 19eabdf06e
13 changed files with 411 additions and 14 deletions

View File

@@ -469,7 +469,7 @@ TOOL_TABLE = browser-shell-tool.tbl
);
assertEqual(
workflowOverviewReleaseArtifactRenderResult.rowCount,
7,
8,
"shell workflow overview release artifact render rows",
);
assertEqual(
@@ -477,6 +477,11 @@ TOOL_TABLE = browser-shell-tool.tbl
true,
"shell workflow overview release artifact execution manifest row",
);
assertEqual(
workflowOverviewReleaseArtifactRenderResult.rowIds.includes("gate-execution-summary"),
true,
"shell workflow overview release artifact execution summary row",
);
assertEqual(
workflowOverviewReleaseArtifactMountResult.ready,
true,

View File

@@ -262,14 +262,19 @@
.getWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(releaseArtifactUrlWorkflow);
assertEqual(releaseArtifactDomReadinessReady.ready, true, "workflow overview release artifact DOM readiness");
assertEqual(releaseArtifactRenderResult.rendered, true, "workflow overview release artifact render result");
assertEqual(releaseArtifactRenderResult.rowCount, 7, "workflow overview release artifact render row count");
assertEqual(releaseArtifactRenderResult.rowCount, 8, "workflow overview release artifact render row count");
assertEqual(
releaseArtifactRenderResult.rowIds.includes("gate-execution-manifest"),
true,
"workflow overview release artifact execution manifest row",
);
assertEqual(
releaseArtifactRenderResult.rowIds.includes("gate-execution-summary"),
true,
"workflow overview release artifact execution summary row",
);
assertEqual(releaseArtifactMountResult.ready, true, "workflow overview release artifact mount readiness");
assertEqual(releaseArtifactMountResult.renderResult.rowCount, 7, "workflow overview release artifact mount rows");
assertEqual(releaseArtifactMountResult.renderResult.rowCount, 8, "workflow overview release artifact mount rows");
assertEqual(releaseArtifactUrlWorkflow.ready, true, "workflow overview release artifact URL workflow readiness");
assertEqual(releaseArtifactUrlWorkflow.httpStatus, 200, "workflow overview release artifact URL workflow status");
assertEqual(

View File

@@ -35,6 +35,7 @@ for (const phrase of [
"createProjectReleaseGateResultMatrix()",
"createProjectReleaseGateActionPlan()",
"createProjectReleaseGateExecutionManifest()",
"createProjectReleaseGateExecutionSummaryViewModel()",
"createProjectReleaseReadinessReport()",
"createProjectReleaseReadinessSummaryViewModel()",
"parseProjectReleaseReadinessArtifactJson()",
@@ -118,6 +119,7 @@ for (const phrase of [
"createProjectReleaseGateManifest()",
"createProjectReleaseGateResultMatrix()",
"createProjectReleaseGateActionPlan()",
"createProjectReleaseGateExecutionSummaryViewModel()",
"createProjectReleaseReadinessReport()",
"createProjectReleaseReadinessSummaryViewModel()",
"parseProjectReleaseReadinessArtifactJson()",
@@ -127,6 +129,7 @@ for (const phrase of [
"createProjectReleaseReadinessArtifactValidationSummaryViewModel()",
"gateManifestReady",
"gateExecutionManifestReady",
"gateExecutionSummaryReady",
"gateResultMatrixReady",
"gateActionPlanReady",
"loadIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrl()",

View File

@@ -327,6 +327,169 @@
}
]
},
"gateExecutionSummaryViewModel": {
"apiName": "project-release-gate-execution-summary-view-model",
"viewModelVersion": 1,
"phase": "ready",
"ready": true,
"title": "Project release gate execution",
"statusText": "Ready",
"detailText": "All release gate evidence present",
"statusLine": "Ready: All release gate evidence present",
"gateCount": 11,
"passedCount": 11,
"unknownCount": 0,
"missingGateIds": [],
"nextGateId": null,
"evidenceCounts": {
"explicit-result": 1,
"expected-output": 10
},
"rows": [
{
"id": "gate-results",
"label": "Release gate evidence",
"value": "11/11 passed"
},
{
"id": "unknown-gates",
"label": "Unknown gates",
"value": "0"
},
{
"id": "next-gate",
"label": "Next gate",
"value": "none"
},
{
"id": "expected-output-evidence",
"label": "Expected-output evidence",
"value": "10"
},
{
"id": "explicit-result-evidence",
"label": "Explicit-result evidence",
"value": "1"
},
{
"id": "missing",
"label": "Missing gate evidence",
"value": "none"
}
],
"gateRows": [
{
"id": "diff-check",
"label": "Git diff check",
"command": "git diff --check",
"expectedOutput": null,
"observedOutput": null,
"evidence": "explicit-result",
"status": "passed",
"passed": true
},
{
"id": "vendor-sync",
"label": "Vendor sync guard",
"command": "wasm-port/tools/verify_vendor_sync.sh",
"expectedOutput": "vendor sync up to date",
"observedOutput": "vendor sync up to date",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "standalone-cnc-semantics",
"label": "Standalone CNC semantics guard",
"command": "wasm-port/tools/verify_no_standalone_cnc_semantics.sh",
"expectedOutput": "standalone CNC semantics guard complete",
"observedOutput": "standalone CNC semantics guard complete",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "interp-wasm",
"label": "Interpreter WASM Node smoke",
"command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_interp_wasm.sh",
"expectedOutput": "interp_wasm_node_smoke=ok",
"observedOutput": "interp_wasm_node_smoke=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "sim-config-inventory",
"label": "Sim config inventory WASM Node smoke",
"command": "SKIP_INTERP_BUILD=1 wasm-port/tests/wasm/node/verify_sim_configs_inventory_wasm.sh",
"expectedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0",
"observedOutput": "sim_configs_wasm_node_inventory_unexpected_fail=0",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "ini-panel-browser",
"label": "INI panel browser smoke",
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_ini_panel_browser.sh",
"expectedOutput": "browser_ini_shell_integration_workflow_smoke=ok",
"observedOutput": "browser_ini_shell_integration_workflow_smoke=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "opfs-session-browser",
"label": "OPFS session browser workflow smoke",
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_opfs_session_workflow_browser.sh",
"expectedOutput": "browser_opfs_session_workflow_smoke=ok",
"observedOutput": "browser_opfs_session_workflow_smoke=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "release-artifact-url-browser",
"label": "Release artifact URL browser workflow smoke",
"command": "SKIP_INI_BUILD=1 SKIP_INTERP_BUILD=1 wasm-port/tests/browser/verify_release_artifact_url_workflow_browser.sh",
"expectedOutput": "browser_release_artifact_url_workflow_smoke=ok",
"observedOutput": "browser_release_artifact_url_workflow_smoke=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "ui-node-smokes",
"label": "UI Node smokes",
"command": "wasm-port/tests/ui/node/verify_ui_node_smokes.sh",
"expectedOutput": "ui_node_smokes=ok",
"observedOutput": "ui_node_smokes=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "host-smokes",
"label": "Host aggregate smoke",
"command": "wasm-port/tests/host/verify_host_smokes.sh",
"expectedOutput": "host_wasm_opfs_browser_smokes=ok",
"observedOutput": "host_wasm_opfs_browser_smokes=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
},
{
"id": "project-release-gate",
"label": "Project release gate",
"command": "wasm-port/tests/host/verify_project_release_gate.sh",
"expectedOutput": "project_release_gate=ok",
"observedOutput": "project_release_gate=ok",
"evidence": "expected-output",
"status": "passed",
"passed": true
}
]
},
"gateResultMatrix": {
"apiName": "project-release-gate-result-matrix",
"matrixVersion": 1,

View File

@@ -24,6 +24,7 @@ assert.equal(validation.gateCount, 11);
assert.equal(validation.expectedGateCount, 11);
assert.equal(validation.gateManifestReady, true);
assert.equal(validation.gateExecutionManifestReady, true);
assert.equal(validation.gateExecutionSummaryReady, true);
assert.equal(validation.gateResultMatrixReady, true);
assert.equal(validation.gateActionPlanReady, true);
assert.deepEqual(validation.expectedGateIds, [
@@ -42,6 +43,8 @@ assert.deepEqual(validation.expectedGateIds, [
assert.equal(artifact.gateManifest.apiName, "project-release-gate-manifest");
assert.equal(artifact.gateExecutionManifest.apiName, "project-release-gate-execution-manifest");
assert.equal(artifact.gateExecutionManifest.passedCount, 11);
assert.equal(artifact.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model");
assert.equal(artifact.gateExecutionSummaryViewModel.rows[0].value, "11/11 passed");
assert.equal(artifact.gateResultMatrix.apiName, "project-release-gate-result-matrix");
assert.equal(artifact.gateActionPlan.apiName, "project-release-gate-action-plan");
assert.equal(artifact.gateActionPlan.pendingCount, 0);

View File

@@ -3,6 +3,7 @@ import assert from "node:assert/strict";
import {
createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest,
createProjectReleaseGateExecutionSummaryViewModel,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
@@ -126,6 +127,37 @@ assert.equal(
partialExecutionManifest.rows.find(({ id }) => id === "standalone-cnc-semantics")?.observedOutput,
null,
);
const partialExecutionSummary = createProjectReleaseGateExecutionSummaryViewModel(partialExecutionManifest);
assert.equal(partialExecutionSummary.apiName, "project-release-gate-execution-summary-view-model");
assert.equal(partialExecutionSummary.viewModelVersion, 1);
assert.equal(partialExecutionSummary.phase, "waiting");
assert.equal(partialExecutionSummary.ready, false);
assert.equal(partialExecutionSummary.statusLine, "Waiting: standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, ui-node-smokes, host-smokes, project-release-gate");
assert.equal(partialExecutionSummary.gateCount, 11);
assert.equal(partialExecutionSummary.passedCount, 3);
assert.equal(partialExecutionSummary.unknownCount, 8);
assert.equal(partialExecutionSummary.nextGateId, "standalone-cnc-semantics");
assert.deepEqual(partialExecutionSummary.evidenceCounts, {
"explicit-result": 1,
"expected-output": 2,
missing: 8,
});
assert.deepEqual(
partialExecutionSummary.rows.map(({ id, value }) => [id, value]),
[
["gate-results", "3/11 passed"],
["unknown-gates", "8"],
["next-gate", "standalone-cnc-semantics"],
["expected-output-evidence", "2"],
["explicit-result-evidence", "1"],
["missing", "standalone-cnc-semantics, interp-wasm, sim-config-inventory, ini-panel-browser, opfs-session-browser, ui-node-smokes, host-smokes, project-release-gate"],
],
);
assert.equal(partialExecutionSummary.gateRows.length, manifest.gateCount);
assert.equal(
partialExecutionSummary.gateRows.find(({ id }) => id === "vendor-sync")?.evidence,
"expected-output",
);
const partialActionPlan = createProjectReleaseGateActionPlan({ gateResultMatrix: partialMatrix });
assert.equal(partialActionPlan.apiName, "project-release-gate-action-plan");
@@ -166,6 +198,10 @@ assert.deepEqual(report.gateManifest, manifest);
assert.equal(report.gateExecutionManifest.apiName, "project-release-gate-execution-manifest");
assert.equal(report.gateExecutionManifest.ready, true);
assert.equal(report.gateExecutionManifest.passedCount, manifest.gateCount);
assert.equal(report.gateExecutionSummaryViewModel.apiName, "project-release-gate-execution-summary-view-model");
assert.equal(report.gateExecutionSummaryViewModel.statusLine, "Ready: All release gate evidence present");
assert.equal(report.gateExecutionSummaryViewModel.rows[0].value, "11/11 passed");
assert.equal(report.gateExecutionSummaryViewModel.nextGateId, null);
assert.equal(report.gateResultMatrix.ready, true);
assert.equal(report.gateResultMatrix.passedCount, manifest.gateCount);
assert.equal(report.gateActionPlan.ready, true);
@@ -256,6 +292,7 @@ assert.deepEqual(
["gate-count", "11/11"],
["gate-manifest", "ready"],
["gate-execution-manifest", "ready"],
["gate-execution-summary", "ready"],
["gate-result-matrix", "ready"],
["gate-action-plan", "ready"],
["missing", "none"],
@@ -383,6 +420,10 @@ assert.equal(
staleArtifactValidationSummary.rows.find(({ id }) => id === "gate-execution-manifest")?.value,
"missing",
);
assert.equal(
staleArtifactValidationSummary.rows.find(({ id }) => id === "gate-execution-summary")?.value,
"missing",
);
assert.equal(staleArtifactValidationActionPlan.phase, "blocked");
assert.equal(staleArtifactValidationActionPlan.ready, false);
assert.equal(staleArtifactValidationActionPlan.missingCount, staleArtifactValidation.missing.length);

View File

@@ -36,6 +36,7 @@ import {
createMachineSessionPersistenceSummary,
createProjectReleaseGateActionPlan,
createProjectReleaseGateExecutionManifest,
createProjectReleaseGateExecutionSummaryViewModel,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
@@ -98,6 +99,7 @@ const requiredExports = [
["createLinuxCncInterpSdk", createLinuxCncInterpSdk],
["createProjectReleaseGateActionPlan", createProjectReleaseGateActionPlan],
["createProjectReleaseGateExecutionManifest", createProjectReleaseGateExecutionManifest],
["createProjectReleaseGateExecutionSummaryViewModel", createProjectReleaseGateExecutionSummaryViewModel],
["createProjectReleaseGateManifest", createProjectReleaseGateManifest],
["createProjectReleaseGateResultMatrix", createProjectReleaseGateResultMatrix],
["createProjectReleaseReadinessArtifactJsonWorkflow", createProjectReleaseReadinessArtifactJsonWorkflow],
@@ -294,6 +296,7 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
expectedGateIds: createProjectReleaseGateManifest().gateIds,
gateManifestReady: true,
gateExecutionManifestReady: true,
gateExecutionSummaryReady: true,
gateResultMatrixReady: true,
gateActionPlanReady: true,
blockedRuntimeFamilies: [
@@ -322,6 +325,11 @@ assert.deepEqual(releaseReadinessArtifactValidation, {
label: "Gate execution manifest",
value: "ready",
},
{
id: "gate-execution-summary",
label: "Gate execution summary",
value: "ready",
},
{
id: "gate-result-matrix",
label: "Gate result matrix",
@@ -426,6 +434,7 @@ assert.deepEqual(
"blockedRuntimeFamilies",
"gateManifest",
"gateExecutionManifest",
"gateExecutionSummaryViewModel",
"gateResultMatrix",
"gateActionPlan",
"gates.length",

View File

@@ -1366,18 +1366,22 @@ const releaseArtifactMountResult = mountIniPanelShellWorkflowOverviewReleaseRead
rowsNode: releaseArtifactRowsNode,
});
assert.equal(releaseArtifactRenderResult.rendered, true);
assert.equal(releaseArtifactRenderResult.rowCount, 7);
assert.equal(releaseArtifactRenderResult.rowCount, 8);
assert.equal(releaseArtifactRenderResult.dataset.handoffScope, "workflow-overview-release-readiness-artifact");
assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-execution-manifest"),
true,
);
assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-execution-summary"),
true,
);
assert.equal(
releaseArtifactRenderResult.rowIds.includes("gate-action-plan"),
true,
);
assert.equal(releaseArtifactMountResult.ready, true);
assert.equal(releaseArtifactMountResult.renderResult.rowCount, 7);
assert.equal(releaseArtifactMountResult.renderResult.rowCount, 8);
assert.deepEqual(
validateIniPanelShellWorkflowOverviewReleaseReadinessArtifactJson("{").missing,
["artifact-json"],
@@ -1418,7 +1422,7 @@ assert.equal(
);
assert.equal(releaseArtifactUrlWorkflow.renderState.statusLine, "Ready: No blocking reasons");
assert.equal(releaseArtifactUrlWorkflow.mountResult.ready, true);
assert.equal(releaseArtifactUrlWorkflow.mountResult.renderResult.rowCount, 7);
assert.equal(releaseArtifactUrlWorkflow.mountResult.renderResult.rowCount, 8);
const releaseArtifactUrlWorkflowSummary =
createIniPanelShellWorkflowOverviewReleaseReadinessArtifactUrlWorkflowSummaryViewModel(
releaseArtifactUrlWorkflow,