Repository navigation
224 lines (185 loc) · 7.58 KB
/
Copy pathrelease.yml
File metadata and controls
224 lines (185 loc) · 7.58 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
name: Release Build
on:
push:
tags:
- 'v*'
pull_request:
branches:
- main
types: [opened, synchronize, reopened]
jobs:
release:
name: Build Release - ${{ matrix.platform }}
runs-on: ${{ matrix.os }}
# Trigger conditions:
# 1. When a version tag (v*) is pushed (production release)
# 2. When a PR with 'release' label is updated (test build before merge)
if: startsWith(github.ref, 'refs/tags/v') || contains(github.event.pull_request.labels.*.name, 'release')
strategy:
fail-fast: false
matrix:
include:
- platform: macos
os: macos-latest
targets: aarch64-apple-darwin,x86_64-apple-darwin
- platform: windows
os: windows-latest
targets: x86_64-pc-windows-msvc
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: 9
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.14'
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.targets }}
- name: Install dependencies (macOS)
if: matrix.platform == 'macos'
run: |
pnpm setup
pnpm install
- name: Install dependencies (Windows)
if: matrix.platform == 'windows'
run: |
pnpm setup:win
pnpm install
- name: Import Code Signing Certificate (macOS)
if: matrix.platform == 'macos' && env.APPLE_CERTIFICATE != ''
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
run: |
# Create temporary keychain
KEYCHAIN_PATH=$RUNNER_TEMP/build.keychain
KEYCHAIN_PASSWORD=$(openssl rand -base64 32)
# Decode certificate
echo "${{ secrets.APPLE_CERTIFICATE }}" | base64 --decode > certificate.p12
# Also extract the certificate in PEM format for trust settings
openssl pkcs12 -in certificate.p12 -out cert.pem -clcerts -nokeys -passin pass:"${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" -legacy 2>/dev/null || \
openssl pkcs12 -in certificate.p12 -out cert.pem -clcerts -nokeys -passin pass:"${{ secrets.APPLE_CERTIFICATE_PASSWORD }}"
# Create keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Configure keychain settings
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate with access control
security import certificate.p12 \
-k $KEYCHAIN_PATH \
-P "${{ secrets.APPLE_CERTIFICATE_PASSWORD }}" \
-T /usr/bin/codesign \
-T /usr/bin/security \
-A
# Add keychain to search list (make it first priority)
security list-keychain -d user -s $KEYCHAIN_PATH $(security list-keychains -d user | sed s/\"//g)
# Set partition list to avoid password prompts
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Make default keychain
security default-keychain -s $KEYCHAIN_PATH
# For self-signed certificates: add trust for code signing
# This requires admin privileges, so we use a different approach
# Instead of trusting the cert, we'll use the certificate hash directly
# List all identities (not just valid ones) to find our certificate
echo "All identities in keychain:"
security find-identity $KEYCHAIN_PATH
# Extract the SHA-1 hash of the signing identity
IDENTITY_HASH=$(security find-identity $KEYCHAIN_PATH | grep -oE '[A-F0-9]{40}' | head -1)
echo "Detected identity hash: $IDENTITY_HASH"
# Also try to get the identity name
IDENTITY_NAME=$(security find-identity $KEYCHAIN_PATH | grep -oE '"[^"]+"' | head -1 | tr -d '"')
echo "Detected identity name: $IDENTITY_NAME"
# Use hash as the signing identity (works even without trust)
if [ -n "$IDENTITY_HASH" ]; then
echo "Using certificate hash as signing identity"
echo "APPLE_SIGNING_IDENTITY=$IDENTITY_HASH" >> $GITHUB_ENV
elif [ -n "$IDENTITY_NAME" ]; then
echo "Using certificate name as signing identity"
echo "APPLE_SIGNING_IDENTITY=$IDENTITY_NAME" >> $GITHUB_ENV
else
echo "::warning::Could not extract signing identity from certificate"
fi
# Store keychain info for later use
echo "KEYCHAIN_PATH=$KEYCHAIN_PATH" >> $GITHUB_ENV
echo "KEYCHAIN_PASSWORD=$KEYCHAIN_PASSWORD" >> $GITHUB_ENV
# Clean up certificate files
rm -f certificate.p12 cert.pem
- name: Unlock Keychain Before Build (macOS)
if: matrix.platform == 'macos' && env.KEYCHAIN_PATH != ''
run: |
# Unlock keychain before build to ensure codesign can access it
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
- name: Build application (macOS)
if: matrix.platform == 'macos'
run: pnpm bundle
env:
# Set signing identity - Tauri expects APPLE_SIGNING_IDENTITY
APPLE_SIGNING_IDENTITY: ${{ env.APPLE_SIGNING_IDENTITY }}
- name: Cleanup Keychain (macOS)
if: always() && matrix.platform == 'macos' && env.KEYCHAIN_PATH != ''
run: |
# Remove temporary keychain
security delete-keychain "$KEYCHAIN_PATH" || true
- name: Build application (Windows)
if: matrix.platform == 'windows'
run: pnpm bundle:win
- name: Upload artifacts (macOS)
if: matrix.platform == 'macos'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}-release
path: |
src-tauri/target/bundle-release/bundle/macos/*.app
src-tauri/target/bundle-release/bundle/dmg/*.dmg
if-no-files-found: error
- name: Upload artifacts (Windows)
if: matrix.platform == 'windows'
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.platform }}-release
path: |
src-tauri/target/bundle-release/bundle/msi/*.msi
if-no-files-found: error
create-release:
name: Create GitHub Release
needs: release
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Display structure of downloaded files
run: ls -R artifacts
- name: Extract version from tag
id: version
run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.version }}
name: Release ${{ steps.version.outputs.version }}
draft: false
prerelease: false
generate_release_notes: true
files: |
artifacts/**/*.dmg
artifacts/**/*.app
artifacts/**/*.msi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}