Skip to content

Commit 7e70cc1

Browse files
committed
ci: release actions
1 parent 5d2f420 commit 7e70cc1

2 files changed

Lines changed: 221 additions & 0 deletions

File tree

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
name: Release Desktop
2+
3+
permissions:
4+
contents: write
5+
6+
on:
7+
push:
8+
tags:
9+
- "v*"
10+
workflow_dispatch:
11+
inputs:
12+
release_tag:
13+
description: Release tag to build and publish, for example v0.1.0
14+
required: true
15+
type: string
16+
17+
concurrency:
18+
group: release-desktop-${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag || github.ref_name }}
19+
cancel-in-progress: false
20+
21+
jobs:
22+
release-desktop:
23+
name: Release Desktop (${{ matrix.bundle_name }})
24+
strategy:
25+
fail-fast: false
26+
max-parallel: 1
27+
matrix:
28+
include:
29+
- runner: ubuntu-24.04
30+
target: x86_64-unknown-linux-gnu
31+
bundle_name: Linux x64
32+
platform: linux
33+
- runner: macos-15
34+
target: aarch64-apple-darwin
35+
bundle_name: Apple Silicon
36+
platform: macos
37+
- runner: macos-15-intel
38+
target: x86_64-apple-darwin
39+
bundle_name: Intel
40+
platform: macos
41+
runs-on: ${{ matrix.runner }}
42+
env:
43+
RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag || github.ref_name }}
44+
steps:
45+
- name: Checkout
46+
uses: actions/checkout@v4
47+
with:
48+
fetch-depth: 0
49+
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.release_tag || github.ref }}
50+
51+
- name: Setup pnpm
52+
uses: pnpm/action-setup@v4
53+
with:
54+
version: 9
55+
56+
- name: Setup Node.js
57+
uses: actions/setup-node@v4
58+
with:
59+
node-version: 20
60+
cache: pnpm
61+
cache-dependency-path: pnpm-lock.yaml
62+
63+
- name: Setup Rust
64+
uses: dtolnay/rust-toolchain@stable
65+
with:
66+
targets: ${{ matrix.target }}
67+
68+
- name: Install Linux dependencies for Tauri
69+
if: matrix.platform == 'linux'
70+
run: |
71+
sudo apt-get update
72+
sudo apt-get install -y \
73+
build-essential \
74+
curl \
75+
file \
76+
libayatana-appindicator3-dev \
77+
libgtk-3-dev \
78+
librsvg2-dev \
79+
libsoup-3.0-dev \
80+
libwebkit2gtk-4.1-dev \
81+
libxdo-dev \
82+
patchelf
83+
84+
- name: Cache Rust build
85+
uses: swatinem/rust-cache@v2
86+
with:
87+
workspaces: apps/desktop/src-tauri -> target
88+
89+
- name: Install dependencies
90+
run: pnpm install --frozen-lockfile
91+
92+
- name: Verify tag matches desktop version
93+
shell: bash
94+
run: |
95+
release_tag="$RELEASE_TAG"
96+
app_version="$(sed -nE 's/^version = "([^"]+)"$/\1/p' apps/desktop/src-tauri/Cargo.toml | head -n 1)"
97+
tag_version="${release_tag#v}"
98+
99+
if [[ ! "$release_tag" =~ ^v[0-9] ]]; then
100+
echo "Release tag must start with v and include a version number, got: $release_tag"
101+
exit 1
102+
fi
103+
104+
if [[ -z "$app_version" ]]; then
105+
echo "Unable to determine desktop app version from apps/desktop/src-tauri/Cargo.toml"
106+
exit 1
107+
fi
108+
109+
if [[ "$app_version" != "$tag_version" ]]; then
110+
echo "Release tag ${release_tag} does not match desktop app version ${app_version}"
111+
exit 1
112+
fi
113+
114+
- name: Reconstruct App Store Connect API key
115+
if: matrix.platform == 'macos'
116+
env:
117+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
118+
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
119+
shell: bash
120+
run: |
121+
api_key_path="$RUNNER_TEMP/AuthKey_${APPLE_API_KEY}.p8"
122+
printf '%s' "$APPLE_API_KEY_P8_BASE64" | openssl base64 -d -A -out "$api_key_path"
123+
chmod 600 "$api_key_path"
124+
echo "APPLE_API_KEY_PATH=$api_key_path" >> "$GITHUB_ENV"
125+
126+
- name: Import Apple signing certificate
127+
if: matrix.platform == 'macos'
128+
env:
129+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
130+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
131+
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
132+
shell: bash
133+
run: |
134+
cert_path="$RUNNER_TEMP/apple-signing-cert.p12"
135+
keychain_path="$RUNNER_TEMP/codelegate-release.keychain-db"
136+
137+
printf '%s' "$APPLE_CERTIFICATE" | openssl base64 -d -A -out "$cert_path"
138+
139+
security create-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
140+
security set-keychain-settings -lut 21600 "$keychain_path"
141+
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$keychain_path"
142+
security import "$cert_path" -k "$keychain_path" -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign -T /usr/bin/security
143+
security list-keychains -d user -s "$keychain_path"
144+
security default-keychain -d user -s "$keychain_path"
145+
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" "$keychain_path"
146+
147+
- name: Build and publish macOS release
148+
if: matrix.platform == 'macos'
149+
uses: tauri-apps/tauri-action@v1
150+
env:
151+
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
152+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
153+
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
154+
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
155+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
156+
with:
157+
projectPath: apps/desktop
158+
tauriScript: pnpm tauri
159+
tagName: ${{ env.RELEASE_TAG }}
160+
releaseName: Codelegate ${{ env.RELEASE_TAG }}
161+
releaseDraft: false
162+
prerelease: false
163+
generateReleaseNotes: true
164+
args: --target ${{ matrix.target }}
165+
166+
- name: Build and publish Linux release
167+
if: matrix.platform == 'linux'
168+
uses: tauri-apps/tauri-action@v1
169+
env:
170+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
171+
with:
172+
projectPath: apps/desktop
173+
tauriScript: pnpm tauri
174+
tagName: ${{ env.RELEASE_TAG }}
175+
releaseName: Codelegate ${{ env.RELEASE_TAG }}
176+
releaseDraft: false
177+
prerelease: false
178+
generateReleaseNotes: true
179+
180+
- name: Cleanup signing files
181+
if: always() && matrix.platform == 'macos'
182+
env:
183+
APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
184+
shell: bash
185+
run: |
186+
rm -f "$RUNNER_TEMP/AuthKey_${APPLE_API_KEY}.p8"
187+
rm -f "$RUNNER_TEMP/apple-signing-cert.p12"
188+
security delete-keychain "$RUNNER_TEMP/codelegate-release.keychain-db" || true

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,39 @@ pnpm build:desktop
153153
pnpm --filter @codelegate/desktop tauri build --no-bundle
154154
```
155155

156+
## Desktop Releases
157+
- Release workflow: `.github/workflows/release-desktop.yml`
158+
- Trigger: push a Git tag matching `v*` such as `v0.1.0`
159+
- Manual run: start the workflow from the Actions tab and provide `release_tag` with the same tag value, such as `v0.1.0`
160+
- The pushed tag must match `apps/desktop/src-tauri/Cargo.toml` `version`
161+
- The workflow builds the Tauri desktop app from `apps/desktop`, creates or updates the GitHub Release, uploads Linux and macOS artifacts, and enables GitHub-generated release notes
162+
- macOS bundles are signed and notarized in CI
163+
- Linux bundles are built on Ubuntu and published to the same GitHub Release
164+
165+
Required GitHub Actions secrets:
166+
167+
| Secret | Value |
168+
| --- | --- |
169+
| `APPLE_CERTIFICATE` | Base64-encoded `.p12` signing certificate exported from Keychain Access. |
170+
| `APPLE_CERTIFICATE_PASSWORD` | Password used when exporting the `.p12` certificate. |
171+
| `KEYCHAIN_PASSWORD` | Password for the temporary macOS keychain created during CI signing. |
172+
| `APPLE_API_KEY` | App Store Connect API Key ID. |
173+
| `APPLE_API_ISSUER` | App Store Connect Issuer ID. |
174+
| `APPLE_API_KEY_P8_BASE64` | Base64-encoded contents of `AuthKey_<KEY_ID>.p8`. |
175+
176+
Release steps:
177+
178+
1. Update `apps/desktop/src-tauri/Cargo.toml` to the release version.
179+
2. Commit the version change and push it to the branch you want to release from.
180+
3. Create and push the matching tag:
181+
182+
```bash
183+
git tag v0.1.0
184+
git push origin v0.1.0
185+
```
186+
187+
After the tag is pushed, GitHub Actions runs the desktop release workflow on GitHub-hosted macOS and Linux runners, builds Linux and macOS bundles, signs and notarizes the macOS artifacts with the configured Apple credentials, then publishes all generated assets to the GitHub Release page for that tag.
188+
156189
## Data Locations
157190
- Settings: `~/.codelegate/config.json`
158191
- Recent directories are stored under `settings.recentDirs`.

0 commit comments

Comments
 (0)