新增 release artifact JSON workflow API
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ export {
|
||||
createProjectReleaseGateActionPlan,
|
||||
createProjectReleaseGateManifest,
|
||||
createProjectReleaseGateResultMatrix,
|
||||
createProjectReleaseReadinessArtifactJsonWorkflow,
|
||||
createProjectReleaseReadinessArtifactValidation,
|
||||
createProjectReleaseReadinessArtifactValidationActionPlan,
|
||||
createProjectReleaseReadinessArtifactValidationSummaryViewModel,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()",
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user