-
-
Notifications
You must be signed in to change notification settings - Fork 4
272 lines (235 loc) · 10.7 KB
/
Copy pathproduct-release.yml
File metadata and controls
272 lines (235 loc) · 10.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
name: Product Release
on:
push:
tags:
- "v*"
- "!v*-launcher"
env:
PYTHON_VERSION: "3.12"
PYTHON_RUNTIME_VERSION: "3.12.12"
PYTHON_RUNTIME_ASSET: python-runtime-win-x64.zip
RELEASE_MANIFEST_ASSET: release-manifest.json
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
build:
runs-on: ubuntu-latest
outputs:
package_version: ${{ steps.package.outputs.version }}
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Set up Python
run: uv python install ${{ env.PYTHON_VERSION }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
cache-dependency-path: editor/package-lock.json
- name: Build editor
working-directory: editor
run: |
npm ci
npm run build
- name: Verify packaged editor build
run: |
test -f src/codaro/webBuild/index.html
test -d src/codaro/webBuild/_app
- name: Run tests
run: uv run --extra dev pytest tests/ -v --tb=short
- name: Build and verify distribution payload
run: uv run python -X utf8 docs/skills/ops/tools/buildPythonDistribution.py --output-root dist
- name: Verify Python SDK from the built wheel
run: uv run python -X utf8 tests/packaging/verifyPythonSdk.py --dist-root dist --skip-build
- name: Read package version
id: package
run: |
python - <<'PY' >> "$GITHUB_OUTPUT"
import tomllib
with open("pyproject.toml", "rb") as handle:
version = tomllib.load(handle)["project"]["version"]
print(f"version={version}")
PY
- name: Verify tag matches package version
run: |
if [ "${GITHUB_REF_NAME}" != "v${{ steps.package.outputs.version }}" ]; then
echo "tag ${GITHUB_REF_NAME} does not match package version v${{ steps.package.outputs.version }}" >&2
exit 1
fi
- name: Prepare package release assets
run: mkdir -p release-assets
- name: Generate package SPDX SBOM
uses: anchore/sbom-action@v0
with:
path: .
format: spdx-json
output-file: release-assets/codaro.spdx.json
- name: Upload dist artifact
uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
- name: Upload package release assets
uses: actions/upload-artifact@v4
with:
name: package-release-assets
path: release-assets/
windows-release-assets:
runs-on: windows-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install managed Python runtime
shell: pwsh
run: uv python install $env:PYTHON_RUNTIME_VERSION
- name: Package managed Python runtime
shell: pwsh
run: |
$python = (uv python find $env:PYTHON_RUNTIME_VERSION).Trim()
$runtimeRoot = Split-Path -Parent $python
$stage = Join-Path $env:RUNNER_TEMP "codaro-python-runtime"
$pythonStage = Join-Path $stage "python"
if (Test-Path $stage) {
Remove-Item -Recurse -Force $stage
}
New-Item -ItemType Directory -Force -Path $pythonStage | Out-Null
Copy-Item -Path (Join-Path $runtimeRoot "*") -Destination $pythonStage -Recurse -Force
# codaro 백엔드 런타임 의존성 + 커리큘럼 라이브러리를 런타임에 사전 설치한다. launcher provision은
# codaro wheel을 --no-deps로(오프라인) 설치하므로, 런타임이 의존성을 제공하지 않으면 (a) 백엔드가
# fastapi/pydantic 부재로 기동 실패하고, (b) 커리큘럼 레슨이 pandas/numpy/matplotlib 부재로 셀 실행
# 시 ModuleNotFoundError를 낸다. 셀은 백엔드 인터프리터에서 in-process로 실행되므로 레슨 라이브러리도
# 이 런타임에 있어야 한다. uv.lock 고정 버전을 curriculum extra 포함으로 export 해 설치한다.
$runtimePython = Join-Path $pythonStage "python.exe"
& $runtimePython -m ensurepip --upgrade | Out-Null
$depsFile = Join-Path $env:RUNNER_TEMP "codaro-backend-deps.txt"
uv export --no-dev --extra curriculum --no-emit-project --no-hashes --output-file $depsFile
if ($LASTEXITCODE -ne 0) { throw "uv export of backend + curriculum dependencies failed" }
& $runtimePython -m pip install --break-system-packages --disable-pip-version-check --no-warn-script-location -r $depsFile
if ($LASTEXITCODE -ne 0) { throw "failed to pre-install backend + curriculum dependencies into runtime" }
& $runtimePython -c "import fastapi, pydantic, uvicorn, yaml, requests; import pandas, numpy, matplotlib, sklearn, openpyxl; print('runtime backend + curriculum deps verified')"
if ($LASTEXITCODE -ne 0) { throw "runtime backend + curriculum dependency verification failed" }
New-Item -ItemType Directory -Force -Path "launcher/target/release" | Out-Null
$runtimeArchive = "launcher/target/release/$($env:PYTHON_RUNTIME_ASSET)"
Compress-Archive -Path (Join-Path $stage "python") -DestinationPath $runtimeArchive -Force
$hash = (Get-FileHash $runtimeArchive -Algorithm SHA256).Hash.ToLower()
"$hash $($env:PYTHON_RUNTIME_ASSET)" | Out-File -FilePath "$runtimeArchive.sha256" -Encoding utf8
- name: Build launcher release binary
working-directory: launcher/codaro-launcher
run: cargo build --release
- name: Rename launcher binary
shell: pwsh
run: |
Copy-Item "launcher/target/release/codaro-launcher.exe" "launcher/target/release/Codaro.exe"
- name: Compute launcher SHA256
shell: pwsh
run: |
$hash = (Get-FileHash "launcher/target/release/Codaro.exe" -Algorithm SHA256).Hash.ToLower()
"$hash Codaro.exe" | Out-File -FilePath "launcher/target/release/Codaro.exe.sha256" -Encoding utf8
- name: Generate launcher SPDX SBOM
uses: anchore/sbom-action@v0
with:
path: launcher/codaro-launcher
format: spdx-json
output-file: launcher/target/release/Codaro.exe.spdx.json
- name: Upload Windows release assets
uses: actions/upload-artifact@v4
with:
name: windows-release-assets
path: |
launcher/target/release/Codaro.exe
launcher/target/release/Codaro.exe.sha256
launcher/target/release/Codaro.exe.spdx.json
launcher/target/release/${{ env.PYTHON_RUNTIME_ASSET }}
launcher/target/release/${{ env.PYTHON_RUNTIME_ASSET }}.sha256
release:
needs: [build, windows-release-assets]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Download Windows release assets
uses: actions/download-artifact@v4
with:
name: windows-release-assets
path: release-assets/
- name: Download package release assets
uses: actions/download-artifact@v4
with:
name: package-release-assets
path: release-assets/
- name: Download backend dist
uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Prepare backend wheel release asset
id: backend_wheel
shell: bash
run: |
set -euo pipefail
wheel_count="$(find dist -maxdepth 1 -name 'codaro-*.whl' | wc -l | tr -d ' ')"
if [ "$wheel_count" != "1" ]; then
echo "expected exactly one codaro wheel in dist, found $wheel_count" >&2
find dist -maxdepth 1 -type f -print >&2
exit 1
fi
wheel_path="$(find dist -maxdepth 1 -name 'codaro-*.whl' -print -quit)"
wheel_name="$(basename "$wheel_path")"
wheel_sha="$(sha256sum "$wheel_path" | awk '{print $1}')"
cp "$wheel_path" "release-assets/$wheel_name"
printf '%s %s\n' "$wheel_sha" "$wheel_name" > "release-assets/$wheel_name.sha256"
echo "name=$wheel_name" >> "$GITHUB_OUTPUT"
echo "sha256=$wheel_sha" >> "$GITHUB_OUTPUT"
- name: Build release manifest
run: |
python docs/skills/ops/tools/buildReleaseManifest.py \
--tag "${GITHUB_REF_NAME}" \
--repo "${GITHUB_REPOSITORY}" \
--package-version "${{ needs.build.outputs.package_version }}" \
--backend-wheel-url "https://github.com/${GITHUB_REPOSITORY}/releases/download/${GITHUB_REF_NAME}/${{ steps.backend_wheel.outputs.name }}" \
--backend-sha256 "${{ steps.backend_wheel.outputs.sha256 }}" \
--python-runtime-version "${PYTHON_RUNTIME_VERSION}" \
--python-runtime-asset-name "${PYTHON_RUNTIME_ASSET}" \
--python-runtime-archive "release-assets/${PYTHON_RUNTIME_ASSET}" \
--output "release-assets/${RELEASE_MANIFEST_ASSET}"
- name: Generate release notes from changelog
shell: bash
run: |
set -euo pipefail
python docs/skills/ops/tools/extractChangelogSection.py \
--version "${{ needs.build.outputs.package_version }}" \
--output release-assets/release-notes.md
cat >> release-assets/release-notes.md <<'EOF'
---
Download `Codaro.exe`, verify `Codaro.exe.sha256`, then run the launcher. The release also includes `release-manifest.json`, the exact `codaro` backend wheel, a managed Windows Python runtime archive, checksums, and SPDX SBOM assets. The manifest pins the wheel asset and sha256 from this GitHub Release.
EOF
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
target_commitish: ${{ github.sha }}
name: Codaro ${{ github.ref_name }}
fail_on_unmatched_files: true
body_path: release-assets/release-notes.md
files: |
release-assets/Codaro.exe
release-assets/Codaro.exe.sha256
release-assets/Codaro.exe.spdx.json
release-assets/python-runtime-win-x64.zip
release-assets/python-runtime-win-x64.zip.sha256
release-assets/codaro-*.whl
release-assets/codaro-*.whl.sha256
release-assets/release-manifest.json
release-assets/codaro.spdx.json
generate_release_notes: false