新增 release artifact JSON workflow API

This commit is contained in:
2026-06-16 13:34:48 +08:00
parent 640f1e4438
commit d789920d7f
9 changed files with 212 additions and 2 deletions

View File

@@ -59,6 +59,9 @@ continuation records are in `../text14.txt`.
`createProjectReleaseReadinessArtifactValidationActionPlan()` turns a blocked
artifact validation into the project release gate and artifact validation
commands to run next, plus the missing evidence rows.
`createProjectReleaseReadinessArtifactJsonWorkflow()` is the one-call
non-throwing JSON text workflow for dashboards that need parse, validation,
summary, and action-plan output from the readiness artifact.
Browser shells can also pass the JSON to
`linuxCncIniPanelWorkflowOverviewApi.validateWorkflowOverviewReleaseReadinessArtifactJson()`
through the workflow overview iframe and receive stable validation rows. They

View File

@@ -56,6 +56,7 @@ import {
createProjectReleaseGateActionPlan,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
@@ -237,6 +238,11 @@ browser shells without reinterpreting the artifact fields.
artifact validation result into the exact project release gate and artifact
validation commands to run next, plus the missing evidence list and shell
script. Ready validations return no commands.
`createProjectReleaseReadinessArtifactJsonWorkflow()` is the non-throwing
one-call wrapper for dashboards that receive artifact JSON text. It parses,
validates, builds the validation summary, and builds the action plan. Invalid
JSON returns a blocked workflow with `parsed: false` and the same next-command
action plan instead of throwing.
## OPFS/session persistence exports

View File

@@ -4,6 +4,7 @@ export {
createProjectReleaseGateActionPlan,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,

View File

@@ -444,6 +444,80 @@ export function parseProjectReleaseReadinessArtifactJson(text) {
return JSON.parse(String(text));
}
export function createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson = "" } = {}) {
try {
const artifact = parseProjectReleaseReadinessArtifactJson(artifactJson);
const validation = createProjectReleaseReadinessArtifactValidation(artifact);
const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation);
const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation);
return {
apiName: "project-release-readiness-artifact-json-workflow",
workflowVersion: 1,
phase: validation.ready === true ? "ready" : "blocked",
ready: validation.ready === true,
parsed: true,
parseError: null,
artifactApiName: validation.artifactApiName,
validation,
summaryViewModel,
actionPlan,
missing: validation.missing,
rows: [
{
id: "parse",
label: "Artifact JSON parse",
value: "ready",
},
{
id: "validation",
label: "Artifact validation",
value: validation.ready === true ? "ready" : "blocked",
},
{
id: "next-command",
label: "Next command",
value: actionPlan.nextCommand ?? "none",
},
],
};
} catch (error) {
const validation = createProjectReleaseReadinessArtifactValidation({});
const summaryViewModel = createProjectReleaseReadinessArtifactValidationSummaryViewModel(validation);
const actionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(validation);
const parseError = error?.message ?? "artifact JSON parse error";
return {
apiName: "project-release-readiness-artifact-json-workflow",
workflowVersion: 1,
phase: "blocked",
ready: false,
parsed: false,
parseError,
artifactApiName: null,
validation,
summaryViewModel,
actionPlan,
missing: ["artifact-json", ...validation.missing],
rows: [
{
id: "parse",
label: "Artifact JSON parse",
value: "blocked",
},
{
id: "validation",
label: "Artifact validation",
value: "blocked",
},
{
id: "next-command",
label: "Next command",
value: actionPlan.nextCommand ?? "none",
},
],
};
}
}
export function createProjectReleaseReadinessArtifactValidation(artifact = {}) {
const artifactObject = objectOrEmpty(artifact);
const releaseGate = objectOrEmpty(artifactObject.releaseGate);

View File

@@ -37,6 +37,7 @@ for (const phrase of [
"createProjectReleaseReadinessReport()",
"createProjectReleaseReadinessSummaryViewModel()",
"parseProjectReleaseReadinessArtifactJson()",
"createProjectReleaseReadinessArtifactJsonWorkflow()",
"createProjectReleaseReadinessArtifactValidation()",
"createProjectReleaseReadinessArtifactValidationActionPlan()",
"createProjectReleaseReadinessArtifactValidationSummaryViewModel()",
@@ -110,6 +111,7 @@ for (const phrase of [
"createProjectReleaseReadinessReport()",
"createProjectReleaseReadinessSummaryViewModel()",
"parseProjectReleaseReadinessArtifactJson()",
"createProjectReleaseReadinessArtifactJsonWorkflow()",
"createProjectReleaseReadinessArtifactValidation()",
"createProjectReleaseReadinessArtifactValidationActionPlan()",
"createProjectReleaseReadinessArtifactValidationSummaryViewModel()",

View File

@@ -4,6 +4,7 @@ import {
createProjectReleaseGateActionPlan,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
@@ -180,6 +181,9 @@ const artifactValidationSummary = createProjectReleaseReadinessArtifactValidatio
const artifactValidationActionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(
createProjectReleaseReadinessArtifactValidation(report),
);
const artifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(report),
});
assert.equal(
artifactValidationSummary.apiName,
"project-release-readiness-artifact-validation-summary-view-model",
@@ -227,11 +231,35 @@ assert.deepEqual(artifactValidationActionPlan, {
},
],
});
assert.equal(artifactJsonWorkflow.apiName, "project-release-readiness-artifact-json-workflow");
assert.equal(artifactJsonWorkflow.workflowVersion, 1);
assert.equal(artifactJsonWorkflow.phase, "ready");
assert.equal(artifactJsonWorkflow.ready, true);
assert.equal(artifactJsonWorkflow.parsed, true);
assert.equal(artifactJsonWorkflow.parseError, null);
assert.equal(artifactJsonWorkflow.artifactApiName, "project-release-readiness-report");
assert.equal(artifactJsonWorkflow.validation.ready, true);
assert.equal(artifactJsonWorkflow.summaryViewModel.statusLine, "Ready: Artifact evidence complete");
assert.equal(artifactJsonWorkflow.actionPlan.commandCount, 0);
assert.deepEqual(
artifactJsonWorkflow.rows.map(({ id, value }) => [id, value]),
[
["parse", "ready"],
["validation", "ready"],
["next-command", "none"],
],
);
const staleArtifactValidationSummary = createProjectReleaseReadinessArtifactValidationSummaryViewModel(
createProjectReleaseReadinessArtifactValidation({}),
);
const staleArtifactValidation = createProjectReleaseReadinessArtifactValidation({});
const staleArtifactValidationActionPlan = createProjectReleaseReadinessArtifactValidationActionPlan(staleArtifactValidation);
const staleArtifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({
artifactJson: "{}",
});
const invalidArtifactJsonWorkflow = createProjectReleaseReadinessArtifactJsonWorkflow({
artifactJson: "{not-json",
});
assert.equal(staleArtifactValidationSummary.phase, "blocked");
assert.match(staleArtifactValidationSummary.statusLine, /^Blocked: apiName, reportVersion/);
assert.equal(staleArtifactValidationSummary.rows.find(({ id }) => id === "gate-action-plan")?.value, "missing");
@@ -254,5 +282,27 @@ assert.equal(
staleArtifactValidationActionPlan.rows.find(({ id }) => id === "missing")?.value,
staleArtifactValidation.missing.join(", "),
);
assert.equal(staleArtifactJsonWorkflow.parsed, true);
assert.equal(staleArtifactJsonWorkflow.ready, false);
assert.equal(staleArtifactJsonWorkflow.phase, "blocked");
assert.equal(staleArtifactJsonWorkflow.actionPlan.commandCount, 2);
assert.deepEqual(staleArtifactJsonWorkflow.missing, staleArtifactValidation.missing);
assert.equal(invalidArtifactJsonWorkflow.parsed, false);
assert.equal(invalidArtifactJsonWorkflow.ready, false);
assert.equal(invalidArtifactJsonWorkflow.phase, "blocked");
assert.match(invalidArtifactJsonWorkflow.parseError, /JSON/);
assert.equal(invalidArtifactJsonWorkflow.missing[0], "artifact-json");
assert.equal(
invalidArtifactJsonWorkflow.actionPlan.nextCommand,
"wasm-port/tests/host/verify_project_release_gate.sh",
);
assert.deepEqual(
invalidArtifactJsonWorkflow.rows.map(({ id, value }) => [id, value]),
[
["parse", "blocked"],
["validation", "blocked"],
["next-command", "wasm-port/tests/host/verify_project_release_gate.sh"],
],
);
console.log("project_release_gate_manifest_node_smoke=ok");

View File

@@ -37,6 +37,7 @@ import {
createProjectReleaseGateActionPlan,
createProjectReleaseGateManifest,
createProjectReleaseGateResultMatrix,
createProjectReleaseReadinessArtifactJsonWorkflow,
createProjectReleaseReadinessArtifactValidation,
createProjectReleaseReadinessArtifactValidationActionPlan,
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
@@ -94,6 +95,7 @@ const requiredExports = [
["createProjectReleaseGateActionPlan", createProjectReleaseGateActionPlan],
["createProjectReleaseGateManifest", createProjectReleaseGateManifest],
["createProjectReleaseGateResultMatrix", createProjectReleaseGateResultMatrix],
["createProjectReleaseReadinessArtifactJsonWorkflow", createProjectReleaseReadinessArtifactJsonWorkflow],
["createProjectReleaseReadinessArtifactValidation", createProjectReleaseReadinessArtifactValidation],
[
"createProjectReleaseReadinessArtifactValidationActionPlan",
@@ -343,6 +345,16 @@ assert.equal(
.nextCommand,
"wasm-port/tests/host/verify_project_release_gate.sh",
);
assert.equal(
createProjectReleaseReadinessArtifactJsonWorkflow({
artifactJson: JSON.stringify(releaseReadinessArtifact),
}).summaryViewModel.statusLine,
"Ready: Artifact evidence complete",
);
assert.equal(
createProjectReleaseReadinessArtifactJsonWorkflow({ artifactJson: "not-json" }).parsed,
false,
);
assert.deepEqual(
createProjectReleaseReadinessArtifactValidation({}).missing,
[