返回 CodeWhale
release-candidate.yml
根目录 / .github / workflows / release-candidate.yml
1 name: Release candidate
2
3 # Safe pre-publication artifact proof. This workflow never creates a tag or
4 # release and never writes to a registry, container repository, tap, or deploy.
5 on:
6 workflow_dispatch:
7 inputs:
8 expected_sha:
9 description: Exact 40-character commit selected by --ref (must match the dispatch SHA)
10 required: true
11 type: string
12
13 permissions:
14 contents: read
15
16 concurrency:
17 group: release-candidate-${{ github.sha }}
18 cancel-in-progress: false
19
20 jobs:
21 resolve:
22 name: Resolve exact candidate source
23 runs-on: ubuntu-latest
24 outputs:
25 sha: ${{ steps.source.outputs.sha }}
26 version: ${{ steps.source.outputs.version }}
27 steps:
28 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
29 with:
30 fetch-depth: 0
31 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
32 with:
33 node-version: 20
34 - uses: dtolnay/rust-toolchain@2c7215f132e9ebf062739d9130488b56d53c060c # stable 2026-07-18
35 with:
36 toolchain: stable
37 - name: Match dispatch to the requested commit
38 id: source
39 shell: bash
40 env:
41 EXPECTED_SHA: ${{ inputs.expected_sha }}
42 run: |
43 set -euo pipefail
44 if [[ "${#EXPECTED_SHA}" -ne 40 || "${EXPECTED_SHA}" =~ [^0-9a-fA-F] ]]; then
45 echo "::error::expected_sha must be a full 40-character commit SHA." >&2
46 exit 1
47 fi
48 actual="$(git rev-parse HEAD)"
49 expected_normalized="$(printf '%s' "${EXPECTED_SHA}" | tr '[:upper:]' '[:lower:]')"
50 if [[ "${actual}" != "${expected_normalized}" ]]; then
51 echo "::error::Dispatch resolved to ${actual}, not requested ${EXPECTED_SHA}." >&2
52 exit 1
53 fi
54
55 workspace_version="$(grep -E '^version = "' Cargo.toml | head -n1 | sed -E 's/^version = "([^"]+)".*/\1/')"
56 npm_version="$(node -p "require('./npm/codewhale/package.json').version")"
57 binary_version="$(node -p "require('./npm/codewhale/package.json').codewhaleBinaryVersion")"
58 if [[ "${workspace_version}" != "${npm_version}" ]]; then
59 echo "::error::Candidate version drift: workspace=${workspace_version}, npm=${npm_version}, binary=${binary_version}." >&2
60 exit 1
61 fi
62 if [[ "${workspace_version}" != "${binary_version}" ]]; then
63 echo "::error::Candidate version drift: workspace=${workspace_version}, npm=${npm_version}, binary=${binary_version}." >&2
64 exit 1
65 fi
66
67 echo "sha=${actual}" >> "${GITHUB_OUTPUT}"
68 echo "version=${workspace_version}" >> "${GITHUB_OUTPUT}"
69 - name: Check version and OHOS release contracts
70 run: |
71 ./scripts/release/check-versions.sh
72 ./scripts/release/check-ohos-deps.sh
73 - name: Reconfirm clean source snapshot
74 run: git diff --exit-code
75
76 web:
77 name: Verify exact candidate web surface
78 needs: resolve
79 if: ${{ !cancelled() && needs.resolve.result == 'success' }}
80 runs-on: ubuntu-latest
81 defaults:
82 run:
83 working-directory: web
84 steps:
85 - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
86 with:
87 ref: ${{ needs.resolve.outputs.sha }}
88 - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
89 with:
90 node-version: 22
91 cache: npm
92 cache-dependency-path: web/package-lock.json
93 - name: Install web dependencies
94 run: npm ci
95 - name: Check public facts drift
96 run: npm run check:facts
97 - name: Generate derived facts
98 run: npm run prebuild
99 - name: Check public docs parity
100 run: npm run check:docs
101 - name: Run web tests
102 run: npm test
103 - name: Run web lint
104 run: npm run lint
105 - name: Run web type check
106 run: npx tsc --noEmit
107 - name: Build production web surface
108 run: npm run build
109
110 artifacts:
111 needs: [resolve, web]
112 if: ${{ !cancelled() && needs.resolve.result == 'success' && needs.web.result == 'success' }}
113 uses: ./.github/workflows/release-artifacts.yml
114 with:
115 source_sha: ${{ needs.resolve.outputs.sha }}
116 version: ${{ needs.resolve.outputs.version }}
117 retention_days: 7
118
118 lines YAML