




















1+name: Maturity scorecard
2+3+on:
4+workflow_dispatch:
5+inputs:
6+source_run_id:
7+description: Optional workflow run id containing qa-evidence.json artifacts
8+required: false
9+type: string
10+artifact_pattern:
11+description: Artifact name pattern to download from source_run_id
12+required: false
13+default: "*qa*"
14+type: string
15+strict_inputs:
16+description: Fail when score or QA evidence inputs have non-fatal drift
17+required: false
18+default: false
19+type: boolean
20+21+permissions:
22+actions: read
23+contents: read
24+25+concurrency:
26+group: ${{ format('{0}-{1}', github.workflow, github.ref) }}
27+cancel-in-progress: true
28+29+env:
30+FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
31+NODE_VERSION: "24.x"
32+33+jobs:
34+validate:
35+name: Validate maturity score sources
36+# Disabled until the initial generated docs and refreshed score snapshot land together.
37+if: ${{ false }}
38+runs-on: ubuntu-24.04
39+timeout-minutes: 20
40+steps:
41+ - name: Checkout
42+uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
43+with:
44+fetch-depth: 1
45+fetch-tags: false
46+persist-credentials: false
47+submodules: false
48+49+ - name: Setup Node environment
50+uses: ./.github/actions/setup-node-env
51+with:
52+node-version: ${{ env.NODE_VERSION }}
53+install-bun: "false"
54+55+ - name: Validate maturity score sources
56+run: |
57+ node --import tsx --input-type=module <<'NODE'
58+ import { readValidatedQaMaturityScoreSources } from "./extensions/qa-lab/src/scorecard-taxonomy.ts";
59+60+ const { warnings } = readValidatedQaMaturityScoreSources({
61+ scoresPath: "qa/maturity-scores.yaml",
62+ taxonomyPath: "taxonomy.yaml",
63+ });
64+ for (const warning of warnings) {
65+ console.error(`warning: ${warning}`);
66+ }
67+ NODE
68+69+ publish:
70+name: Publish maturity docs PR
71+# Disabled until the initial generated docs and refreshed score snapshot land together.
72+if: ${{ false }}
73+needs: validate
74+runs-on: ubuntu-24.04
75+timeout-minutes: 20
76+permissions:
77+actions: read
78+contents: read
79+steps:
80+ - name: Checkout
81+uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
82+with:
83+fetch-depth: 1
84+fetch-tags: false
85+persist-credentials: false
86+submodules: false
87+88+ - name: Setup Node environment
89+uses: ./.github/actions/setup-node-env
90+with:
91+node-version: ${{ env.NODE_VERSION }}
92+install-bun: "false"
93+94+ - name: Download QA evidence artifacts
95+if: ${{ inputs.source_run_id != '' }}
96+env:
97+GH_TOKEN: ${{ github.token }}
98+SOURCE_RUN_ID: ${{ inputs.source_run_id }}
99+ARTIFACT_PATTERN: ${{ inputs.artifact_pattern }}
100+run: |
101+ set -euo pipefail
102+ mkdir -p .artifacts/maturity-evidence
103+ gh run download "$SOURCE_RUN_ID" \
104+ --repo "$GITHUB_REPOSITORY" \
105+ --pattern "$ARTIFACT_PATTERN" \
106+ --dir .artifacts/maturity-evidence
107+ find .artifacts/maturity-evidence -name qa-evidence.json -print
108+109+ - name: Check QA evidence artifacts
110+id: evidence
111+run: |
112+ set -euo pipefail
113+ if find .artifacts/maturity-evidence -name qa-evidence.json -print -quit 2>/dev/null | grep -q .; then
114+ echo "has_evidence=true" >> "$GITHUB_OUTPUT"
115+ else
116+ echo "has_evidence=false" >> "$GITHUB_OUTPUT"
117+ fi
118+119+ - name: Require QA evidence for manual scorecard render
120+if: ${{ github.event_name == 'workflow_dispatch' && steps.evidence.outputs.has_evidence != 'true' }}
121+run: |
122+ echo "Maturity scorecard rendering requires release QA evidence artifacts." >&2
123+ exit 1
124+125+ - name: Render artifact docs
126+if: ${{ steps.evidence.outputs.has_evidence == 'true' }}
127+env:
128+STRICT_INPUTS: ${{ github.event_name == 'workflow_dispatch' && inputs.strict_inputs }}
129+run: |
130+ set -euo pipefail
131+ args=(--output-dir .artifacts/maturity-docs --static-assets-dir .artifacts/maturity-docs/assets/maturity --evidence-dir .artifacts/maturity-evidence)
132+ if [[ "$STRICT_INPUTS" == "true" ]]; then
133+ args+=(--strict-inputs)
134+ fi
135+ pnpm maturity:render -- "${args[@]}"
136+ {
137+ echo "### Maturity scorecard docs"
138+ echo
139+ echo "- Source validation: passed"
140+ echo "- Artifact docs: \`.artifacts/maturity-docs\`"
141+ echo "- Strict inputs: \`${STRICT_INPUTS:-false}\`"
142+ echo "- QA evidence: included"
143+ } >> "$GITHUB_STEP_SUMMARY"
144+145+ - name: Render committed docs preview
146+if: ${{ steps.evidence.outputs.has_evidence == 'true' }}
147+run: |
148+ set -euo pipefail
149+ pnpm maturity:render -- \
150+ --output-dir docs \
151+ --evidence-dir .artifacts/maturity-evidence
152+153+ - name: Create generated docs PR app token
154+if: ${{ steps.evidence.outputs.has_evidence == 'true' }}
155+id: app-token
156+continue-on-error: true
157+uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
158+with:
159+app-id: "2729701"
160+private-key: ${{ secrets.GH_APP_PRIVATE_KEY }}
161+permission-contents: write
162+permission-pull-requests: write
163+164+ - name: Create generated docs PR fallback app token
165+if: ${{ steps.evidence.outputs.has_evidence == 'true' && steps.app-token.outcome == 'failure' }}
166+id: app-token-fallback
167+uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3
168+with:
169+app-id: "2971289"
170+private-key: ${{ secrets.GH_APP_PRIVATE_KEY_FALLBACK }}
171+permission-contents: write
172+permission-pull-requests: write
173+174+ - name: Open generated docs PR
175+if: ${{ steps.evidence.outputs.has_evidence == 'true' }}
176+env:
177+GH_TOKEN: ${{ steps.app-token.outputs.token || steps.app-token-fallback.outputs.token }}
178+SOURCE_RUN_ID: ${{ inputs.source_run_id }}
179+run: |
180+ set -euo pipefail
181+ if [[ -z "${GH_TOKEN:-}" ]]; then
182+ echo "Maturity scorecard PR creation requires the OpenClaw GitHub App token secrets." >&2
183+ exit 1
184+ fi
185+186+ if [[ -z "$(git status --porcelain -- docs/maturity/scorecard.md docs/maturity/taxonomy.md)" ]]; then
187+ {
188+ echo
189+ echo "- Pull request: skipped; generated docs match current branch"
190+ } >> "$GITHUB_STEP_SUMMARY"
191+ exit 0
192+ fi
193+194+ branch="automation/maturity-scorecard-${SOURCE_RUN_ID:-$GITHUB_RUN_ID}"
195+ base_branch="${GITHUB_REF_NAME:-main}"
196+ git config user.name "github-actions[bot]"
197+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
198+ gh auth setup-git
199+ git fetch --no-tags --depth=1 origin "refs/heads/${branch}:refs/remotes/origin/${branch}" || true
200+ git switch -C "$branch"
201+ git add docs/maturity/scorecard.md docs/maturity/taxonomy.md
202+ git commit -m "docs: update maturity scorecard"
203+ git push --force-with-lease origin "$branch"
204+205+ body_file=".artifacts/maturity-scorecard-pr-body.md"
206+ mkdir -p "$(dirname "$body_file")"
207+ cat > "$body_file" <<BODY
208+ ## Summary
209+210+ - refresh generated maturity scorecard docs from release QA evidence
211+ - source workflow run: ${SOURCE_RUN_ID}
212+213+ ## Verification
214+215+ - Maturity scorecard workflow rendered docs from release profile qa-evidence.json artifacts
216+ BODY
217+218+ pr_url="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url // ""')"
219+ if [[ -n "$pr_url" ]]; then
220+ gh pr edit "$pr_url" \
221+ --title "docs: update maturity scorecard" \
222+ --body-file "$body_file"
223+ else
224+ pr_url="$(gh pr create \
225+ --base "$base_branch" \
226+ --head "$branch" \
227+ --title "docs: update maturity scorecard" \
228+ --body-file "$body_file")"
229+ fi
230+ {
231+ echo
232+ echo "- Pull request: ${pr_url}"
233+ } >> "$GITHUB_STEP_SUMMARY"
234+235+ - name: Upload maturity docs artifact
236+if: ${{ steps.evidence.outputs.has_evidence == 'true' }}
237+uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
238+with:
239+name: maturity-scorecard-docs-${{ github.run_id }}-${{ github.run_attempt }}
240+path: .artifacts/maturity-docs/
241+retention-days: 30
242+if-no-files-found: error
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。