-
Notifications
You must be signed in to change notification settings - Fork 68
200 lines (183 loc) Β· 7.43 KB
/
Copy pathrelease-desktop.yml
File metadata and controls
200 lines (183 loc) Β· 7.43 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
# Release pipeline (see docs/RELEASING.md for the maintainer guide).
#
# Two ways to ship, one pipeline:
# 1. Push a tag like v0.2.0 (usually via `pnpm release 0.2.0`).
# 2. GitHub UI: Actions β "Release desktop apps" β Run workflow β enter the
# version (e.g. 0.2.0). The prepare job then bumps both package.json
# files if needed, commits, and pushes the tag itself. GITHUB_TOKEN tag
# pushes do not re-trigger this workflow, so the dispatched run carries
# the release end to end. Leave the version empty for a build rehearsal
# that publishes nothing.
#
# Shape: draft-first, publish-last. A draft GitHub Release (auto-generated
# changelog + install instructions from .github/release-notes-header.md) is
# created before any build starts, the three platform jobs upload assets into
# that draft, and only after every asset and the checksum file are in place is
# the release flipped to published. A failed run therefore never leaves a
# public, half-uploaded release β just a draft that the next attempt reuses
# (uploads use --clobber, so re-running failed jobs is always safe).
name: Release desktop apps
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g. 0.2.0). Leave empty to rehearse the build without releasing."
required: false
type: string
permissions:
contents: write
concurrency:
group: release-desktop-${{ inputs.version || github.ref }}
cancel-in-progress: false
jobs:
prepare:
name: Prepare release
runs-on: ubuntu-latest
outputs:
is_release: ${{ steps.ctx.outputs.is_release }}
tag: ${{ steps.ctx.outputs.tag }}
build_ref: ${{ steps.ctx.outputs.build_ref }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Resolve release context (validate tag, or bump + tag on dispatch)
id: ctx
env:
INPUT_VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
is_release=false
tag=""
build_ref="$GITHUB_SHA"
if [[ "$GITHUB_REF" == refs/tags/* ]]; then
version="$(node -p 'require("./package.json").version')"
if [ "v${version}" != "$GITHUB_REF_NAME" ]; then
echo "::error::Tag $GITHUB_REF_NAME does not match package.json version ${version}. Bump the version (pnpm release) before tagging." >&2
exit 1
fi
is_release=true
tag="$GITHUB_REF_NAME"
build_ref="$GITHUB_REF_NAME"
elif [ -n "${INPUT_VERSION}" ]; then
if ! printf '%s' "$INPUT_VERSION" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
echo "::error::Version must look like 0.2.0 (got: ${INPUT_VERSION})." >&2
exit 1
fi
tag="v${INPUT_VERSION}"
if git ls-remote --exit-code origin "refs/tags/${tag}" >/dev/null 2>&1; then
echo "::error::Tag ${tag} already exists. Pick a new version, or delete the old tag first (see docs/RELEASING.md)." >&2
exit 1
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
current="$(node -p 'require("./package.json").version')"
if [ "$current" != "$INPUT_VERSION" ]; then
node scripts/set-version.mjs "$INPUT_VERSION"
git add package.json electron/package.json
git commit -m "release: ${tag}"
git push origin "HEAD:$GITHUB_REF_NAME"
fi
git tag -a "${tag}" -m "Codex Slides ${INPUT_VERSION}"
git push origin "refs/tags/${tag}"
is_release=true
build_ref="${tag}"
fi
{
echo "is_release=${is_release}"
echo "tag=${tag}"
echo "build_ref=${build_ref}"
} >> "$GITHUB_OUTPUT"
- name: Ensure draft release exists
if: steps.ctx.outputs.is_release == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ steps.ctx.outputs.tag }}
run: |
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
echo "Release $TAG already exists; reusing it."
exit 0
fi
gh api "repos/$GITHUB_REPOSITORY/releases/generate-notes" -f tag_name="$TAG" --jq .body > changelog.md
cat .github/release-notes-header.md changelog.md > notes.md
gh release create "$TAG" --repo "$GITHUB_REPOSITORY" --draft \
--title "Codex Slides ${TAG#v}" --notes-file notes.md
build:
name: Build ${{ matrix.platform }}
needs: prepare
strategy:
fail-fast: false
matrix:
include:
- platform: mac
os: macos-latest
builder_args: --mac --x64 --arm64
release_files: dist/*.dmg dist/*.zip
- platform: windows
os: windows-latest
builder_args: --win --x64
release_files: dist/*.exe
- platform: linux
os: ubuntu-latest
builder_args: --linux AppImage deb --x64
release_files: dist/*.AppImage dist/*.deb
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: ${{ needs.prepare.outputs.build_ref }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 11.9.0
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 24
cache: pnpm
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Verify desktop contract
run: pnpm electron:check
- name: Build standalone web server (includes server smoke test)
run: pnpm build:desktop
- name: Package desktop app
shell: bash
run: pnpm exec electron-builder ${{ matrix.builder_args }} --publish never
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CSC_IDENTITY_AUTO_DISCOVERY: "false"
- name: Smoke test packaged runtime
run: node scripts/smoke-server.mjs --packaged
- name: Upload release assets
if: needs.prepare.outputs.is_release == 'true'
shell: bash
run: gh release upload "$TAG" ${{ matrix.release_files }} --clobber --repo "$GITHUB_REPOSITORY"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.prepare.outputs.tag }}
publish:
name: Publish GitHub Release
if: needs.prepare.outputs.is_release == 'true'
needs: [prepare, build]
runs-on: ubuntu-latest
steps:
- name: Generate SHA-256 checksums
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.prepare.outputs.tag }}
run: |
gh release view "$TAG" --repo "$GITHUB_REPOSITORY" --json assets \
--jq '.assets[] | select(.name != "SHA256SUMS.txt" and .digest != null) | "\(.digest | sub("^sha256:"; "")) \(.name)"' \
| sort > SHA256SUMS.txt
# 2 dmg + 2 zip (mac arm64/x64) + 1 exe + 1 AppImage + 1 deb
test "$(wc -l < SHA256SUMS.txt)" -eq 7
gh release upload "$TAG" SHA256SUMS.txt --clobber --repo "$GITHUB_REPOSITORY"
- name: Publish release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ needs.prepare.outputs.tag }}
run: gh release edit "$TAG" --draft=false --latest --repo "$GITHUB_REPOSITORY"