





















@@ -29,6 +29,10 @@ function readQaProfileEvidenceWorkflow() {
2929return parse(readFileSync(".github/workflows/qa-profile-evidence.yml", "utf8"));
3030}
313132+function readReleaseChecksWorkflow() {
33+return parse(readFileSync(".github/workflows/openclaw-release-checks.yml", "utf8"));
34+}
35+3236function readCriticalQualityWorkflow() {
3337return readFileSync(".github/workflows/codeql-critical-quality.yml", "utf8");
3438}
@@ -608,6 +612,34 @@ describe("ci workflow guards", () => {
608612const publishJob = maturityWorkflow.jobs.publish;
609613const qaRunJob = qaEvidenceWorkflow.jobs.run_qa_profile;
610614615+expect(maturityWorkflow.on.workflow_call.inputs).toMatchObject({
616+qa_evidence_run_id: {
617+description: "Optional workflow run id containing qa-evidence.json",
618+required: false,
619+default: "",
620+type: "string",
621+},
622+ref: {
623+description: "OpenClaw branch, tag, or SHA containing the maturity score source",
624+required: true,
625+type: "string",
626+},
627+expected_sha: {
628+description: "Optional full SHA that ref must resolve to",
629+required: false,
630+default: "",
631+type: "string",
632+},
633+});
634+expect(maturityWorkflow.on.workflow_call.secrets.OPENAI_API_KEY.required).toBe(true);
635+expect(
636+maturityWorkflow.on.workflow_call.secrets.OPENCLAW_MATURITY_SCORECARD_AGENT_OPENAI_API_KEY
637+.required,
638+).toBe(false);
639+expect(maturityWorkflow.on.workflow_call.secrets.GH_APP_PRIVATE_KEY.required).toBe(false);
640+expect(maturityWorkflow.on.workflow_call.secrets.GH_APP_PRIVATE_KEY_FALLBACK.required).toBe(
641+false,
642+);
611643expect(qaEvidenceWorkflow.on.workflow_dispatch.inputs).not.toHaveProperty("fail_on_qa_failure");
612644expect(qaEvidenceWorkflow.on.workflow_call.inputs).not.toHaveProperty("fail_on_qa_failure");
613645expect(qaEvidenceWorkflow.on.workflow_dispatch.inputs.qa_profile).not.toHaveProperty("options");
@@ -627,10 +659,18 @@ describe("ci workflow guards", () => {
627659expect(generateJob.uses).toBe("./.github/workflows/qa-profile-evidence.yml");
628660expect(generateJob.with).toMatchObject({
629661ref: "${{ needs.validate_selected_ref.outputs.selected_revision }}",
662+expected_sha: "${{ needs.validate_selected_ref.outputs.selected_revision }}",
630663qa_profile: "all",
631664});
632665expect(generateJob.with).not.toHaveProperty("fail_on_qa_failure");
633666667+const validateRefStep = maturityWorkflow.jobs.validate_selected_ref.steps.find(
668+(step) => step.name === "Validate selected ref",
669+);
670+expect(validateRefStep.env.EXPECTED_SHA).toBe("${{ inputs.expected_sha }}");
671+expect(validateRefStep.run).toContain("expected_sha must be a full 40-character SHA");
672+expect(validateRefStep.run).toContain('"${selected_revision,,}" != "$expected_sha"');
673+634674const generatedDownloadStep = publishJob.steps.find(
635675(step) => step.name === "Download generated QA evidence artifact",
636676);
@@ -671,6 +711,49 @@ describe("ci workflow guards", () => {
671711672712const qaFailStep = qaRunJob.steps.find((step) => step.name === "Fail if QA profile failed");
673713expect(qaFailStep.if).toBe("always()");
714+715+const createTokenStep = publishJob.steps.find(
716+(step) => step.name === "Create generated docs PR app token",
717+);
718+const createFallbackTokenStep = publishJob.steps.find(
719+(step) => step.name === "Create generated docs PR fallback app token",
720+);
721+const openDocsPrStep = publishJob.steps.find((step) => step.name === "Open generated docs PR");
722+expect(createTokenStep.if).toBe("${{ github.event_name == 'workflow_dispatch' }}");
723+expect(createFallbackTokenStep.if).toBe(
724+"${{ github.event_name == 'workflow_dispatch' && steps.app-token.outcome == 'failure' }}",
725+);
726+expect(openDocsPrStep.if).toBe("${{ github.event_name == 'workflow_dispatch' }}");
727+});
728+729+it("runs maturity scorecard from release checks", () => {
730+const releaseWorkflow = readReleaseChecksWorkflow();
731+const job = releaseWorkflow.jobs.maturity_scorecard_release_checks;
732+const summaryJob = releaseWorkflow.jobs.summary;
733+const verifyStep = summaryJob.steps.find(
734+(step) => step.name === "Verify release check results",
735+);
736+737+expect(releaseWorkflow.jobs).not.toHaveProperty("qa_profile_release_evidence_release_checks");
738+expect(job.name).toBe("Render maturity scorecard release docs");
739+expect(job.if).toBe(
740+'contains(fromJSON(\'["all","qa"]\'), needs.resolve_target.outputs.rerun_group)',
741+);
742+expect(job.permissions).toMatchObject({
743+actions: "read",
744+contents: "read",
745+});
746+expect(job.uses).toBe("./.github/workflows/maturity-scorecard.yml");
747+expect(job.with).toMatchObject({
748+ref: "${{ needs.resolve_target.outputs.ref }}",
749+expected_sha: "${{ needs.resolve_target.outputs.revision }}",
750+});
751+expect(job.with).not.toHaveProperty("qa_profile");
752+expect(summaryJob.needs).toContain("maturity_scorecard_release_checks");
753+expect(verifyStep.run).toContain(
754+'"maturity_scorecard_release_checks=${{ needs.maturity_scorecard_release_checks.result }}"',
755+);
756+expect(verifyStep.run).not.toContain("qa_profile_release_evidence_release_checks");
674757});
675758676759it("keeps workflow guards in fast CI-routing checks", () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。