-
Notifications
You must be signed in to change notification settings - Fork 1
324 lines (294 loc) · 12.8 KB
/
Copy pathrelease.yml
File metadata and controls
324 lines (294 loc) · 12.8 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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
name: Build release bundles
# tag v* -> full build + attach to GitHub Release. workflow_dispatch -> build only.
on:
push:
tags:
- 'v*'
workflow_dispatch:
permissions:
contents: write # needed for the release-upload step on tag builds
jobs:
build:
name: ${{ matrix.label }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- label: windows-x64
runner: windows-latest
os: windows
arch: x64
python: '3.10'
- label: windows-arm64
runner: windows-11-arm
os: windows
arch: arm64
python: '3.11' # setup-python has no 3.10 build for win-arm64
- label: linux-x64
runner: ubuntu-22.04
os: linux
arch: x64
python: '3.10'
- label: linux-arm64
runner: ubuntu-22.04-arm
os: linux
arch: arm64
python: '3.10'
- label: macos-arm64
runner: macos-14
os: macos
arch: arm64
python: '3.10'
- label: macos-x64
runner: macos-15-intel
os: macos
arch: x64
python: '3.10'
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Set up Python ${{ matrix.python }}
uses: actions/setup-python@v7
with:
python-version: ${{ matrix.python }}
architecture: ${{ matrix.arch == 'arm64' && 'arm64' || 'x64' }}
- name: Install Linux system dependencies
if: matrix.os == 'linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
libegl1 libgl1 libxkbcommon0 libxcb-cursor0 libxcb-icccm4 \
libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 \
libxcb-shape0 libxcb-sync1 libxcb-xfixes0 libxcb-xkb1 libxcb-xinerama0 \
libdbus-1-3 libfontconfig1 libnss3 \
ruby ruby-dev build-essential rpm
sudo gem install --no-document fpm
- name: Install NSIS (Windows)
if: matrix.os == 'windows'
shell: pwsh
run: |
choco install nsis -y --no-progress
echo "C:\Program Files (x86)\NSIS" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
# bare CI runner lacks the DLLs fbs.freeze.windows._add_missing_dlls expects
- name: Install Visual C++ redistributables (Windows x64)
if: matrix.os == 'windows' && matrix.arch == 'x64'
shell: pwsh
run: |
choco install vcredist2010 vcredist2012 -y --no-progress
- name: Upgrade pip
run: python -m pip install --upgrade pip setuptools wheel
# fbs Pro sdist downloaded from a private repo via PAT (fine-grained, contents:read). secrets: FBS_PRO_REPO/TAG/ASSET/TOKEN
- name: Download fbs Pro tarball
env:
GH_TOKEN: ${{ secrets.FBS_PRO_TOKEN }}
FBS_PRO_REPO: ${{ secrets.FBS_PRO_REPO }}
FBS_PRO_TAG: ${{ secrets.FBS_PRO_TAG }}
FBS_PRO_ASSET: ${{ secrets.FBS_PRO_ASSET }}
shell: bash
run: |
set -euo pipefail
if [ -z "${GH_TOKEN:-}" ] || [ -z "${FBS_PRO_REPO:-}" ] || [ -z "${FBS_PRO_TAG:-}" ] || [ -z "${FBS_PRO_ASSET:-}" ]; then
echo "::error::Missing one of FBS_PRO_TOKEN/FBS_PRO_REPO/FBS_PRO_TAG/FBS_PRO_ASSET secrets."
exit 1
fi
mkdir -p "$RUNNER_TEMP/fbspro"
gh release download "$FBS_PRO_TAG" \
--repo "$FBS_PRO_REPO" \
--pattern "$FBS_PRO_ASSET" \
--dir "$RUNNER_TEMP/fbspro"
ls -la "$RUNNER_TEMP/fbspro"
# Expose path for the next step
echo "FBS_PRO_PATH=$RUNNER_TEMP/fbspro/$FBS_PRO_ASSET" >> "$GITHUB_ENV"
- name: Install fbs Pro and Python dependencies
shell: bash
run: |
set -euo pipefail
pip install "$FBS_PRO_PATH"
pip install PyInstaller
pip install -e .
# fbs wants per-OS settings stubs next to base.json; create empty ones if missing
- name: Ensure per-OS fbs settings exist (bash)
if: matrix.os != 'windows'
run: |
cd src/build/settings
[ -f linux.json ] || echo '{}' > linux.json
[ -f windows.json ] || echo '{}' > windows.json
- name: Ensure per-OS fbs settings exist (Windows shell)
if: matrix.os == 'windows'
shell: pwsh
run: |
cd src/build/settings
if (-not (Test-Path linux.json)) { '{}' | Out-File -Encoding ascii linux.json }
if (-not (Test-Path windows.json)) { '{}' | Out-File -Encoding ascii windows.json }
# arm64 doesn't link to x86/x64 VC DLLs; no redist would help, so patch the call out
- name: Patch fbs _add_missing_dlls no-op (Windows arm64)
if: matrix.os == 'windows' && matrix.arch == 'arm64'
shell: bash
run: |
set -euo pipefail
python <<'PY'
import re, pathlib, fbs.freeze.windows as m
p = pathlib.Path(m.__file__)
src = p.read_text()
src = re.sub(r'^(\s+)_add_missing_dlls\(\)\s*$', r'\1pass', src, flags=re.M)
p.write_text(src)
print(f'patched {p}')
PY
# secrets: MACOS_CERT_P12_BASE64, MACOS_CERT_PASSWORD
- name: Import signing certificate (macOS)
if: matrix.os == 'macos'
env:
MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
run: |
set -euo pipefail
CERT_PATH="$RUNNER_TEMP/cert.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/build.keychain"
KEYCHAIN_PWD="$(openssl rand -base64 24)"
echo "$MACOS_CERT_P12_BASE64" | base64 --decode > "$CERT_PATH"
security create-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PWD" "$KEYCHAIN_PATH"
security import "$CERT_PATH" -P "$MACOS_CERT_PASSWORD" \
-A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple:,codesign: \
-s -k "$KEYCHAIN_PWD" "$KEYCHAIN_PATH" >/dev/null
# prepend temp keychain so codesign finds the identity ahead of login.keychain
existing="$(security list-keychain -d user | sed -e 's/^[[:space:]]*"\(.*\)"$/\1/')"
security list-keychain -d user -s "$KEYCHAIN_PATH" $existing
rm -f "$CERT_PATH"
echo "BUILD_KEYCHAIN_PATH=$KEYCHAIN_PATH" >> "$GITHUB_ENV"
- name: Freeze app with fbs
run: fbs freeze
# english-only app + no QtQml/Quick/Pdf/VirtualKeyboard usage. trim before signing on macos.
# pyinstaller on linux puts the actual .so files in _internal/PySide6/Qt/lib/ and symlinks them
# at _internal/ root; find -name -delete kills both ends so fbs copytree doesnt trip on broken symlinks
- name: Slim PySide6 bundle (Linux)
if: matrix.os == 'linux'
shell: bash
run: |
set -euo pipefail
find target -type d -name translations -path '*/PySide6/*' -prune -exec rm -rf {} +
for lib in libQt6Quick.so.6 libQt6Qml.so.6 libQt6QmlModels.so.6 \
libQt6QmlMeta.so.6 libQt6QmlWorkerScript.so.6 \
libQt6Pdf.so.6 libQt6VirtualKeyboard.so.6 libQt6VirtualKeyboardQml.so.6 \
libQt6WaylandClient.so.6 libQt6WaylandCompositor.so.6 \
libQt6WlShellIntegration.so.6 libQt6EglFSDeviceIntegration.so.6 \
libQt6EglFsKmsSupport.so.6; do
find target -name "$lib" -delete 2>/dev/null || true
done
- name: Slim PySide6 bundle (Windows)
if: matrix.os == 'windows'
shell: bash
run: |
set -euo pipefail
PYS="target/Emu68 Hatcher/_internal/PySide6"
if [ ! -d "$PYS" ]; then echo "::error::expected PySide6 dir at $PYS not found"; ls -la "target/Emu68 Hatcher/_internal" || true; exit 1; fi
rm -rf "$PYS/translations"
cd "$PYS"
rm -f Qt6Quick.dll Qt6Qml.dll Qt6QmlModels.dll Qt6QmlMeta.dll Qt6QmlWorkerScript.dll \
Qt6Pdf.dll Qt6VirtualKeyboard.dll Qt6VirtualKeyboardQml.dll
# signing reseals the bundle after trimming; do this before "Sign .app (macOS)"
# translations exist in both Frameworks/ and Resources/ (one is a symlink); nuke both so xattr -cr in sign doesnt hit a dangling symlink
- name: Slim PySide6 bundle (macOS)
if: matrix.os == 'macos'
shell: bash
run: |
set -euo pipefail
APP="target/Emu68 Hatcher.app/Contents"
LIB="$APP/Frameworks/PySide6/Qt/lib"
if [ ! -d "$LIB" ]; then echo "::error::expected Qt lib dir at $LIB not found"; ls -la "$APP/Frameworks" || true; exit 1; fi
rm -rf "$APP/Resources/PySide6/Qt/translations" "$APP/Frameworks/PySide6/Qt/translations"
for name in QtQuick QtQml QtQmlModels QtQmlMeta QtQmlWorkerScript QtPdf QtVirtualKeyboard QtVirtualKeyboardQml; do
rm -rf "$LIB/${name}.framework"
rm -f "$APP/Frameworks/$name" "$APP/Resources/$name"
done
# fbs leaves CFBundleIdentifier empty; TCC needs a non-empty id to file FDA grants
- name: Patch CFBundleIdentifier (macOS)
if: matrix.os == 'macos'
run: |
set -euo pipefail
PLIST="target/Emu68 Hatcher.app/Contents/Info.plist"
/usr/libexec/PlistBuddy -c "Set :CFBundleIdentifier com.emu68hatcher.hatcher" "$PLIST" 2>/dev/null \
|| /usr/libexec/PlistBuddy -c "Add :CFBundleIdentifier string com.emu68hatcher.hatcher" "$PLIST"
- name: Sign .app (macOS)
if: matrix.os == 'macos'
env:
MACOS_SIGN_IDENTITY: ${{ secrets.MACOS_SIGN_IDENTITY }}
run: scripts/macos-sign.sh "target/Emu68 Hatcher.app"
# produces target/<AppName>Setup.exe (windows, NSIS) or target/<AppName>.deb (linux, fpm+dpkg on ubuntu)
- name: Build installer
run: fbs installer
# fbs/fpm default = gzip; xz cuts the .deb by ~30 MB. Ubuntu 18.04+/Debian 10+ install xz debs fine.
- name: Recompress .deb with xz (Linux)
if: matrix.os == 'linux'
shell: bash
run: |
set -euo pipefail
DEB="target/emu68hatcher.deb"
TMP="$(mktemp -d)"
dpkg-deb -R "$DEB" "$TMP/extracted"
dpkg-deb -Zxz -z9 -b "$TMP/extracted" "$DEB"
ls -lh "$DEB"
- name: Sign + notarize + staple .dmg (macOS)
if: matrix.os == 'macos'
env:
MACOS_SIGN_IDENTITY: ${{ secrets.MACOS_SIGN_IDENTITY }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_APP_PWD: ${{ secrets.APPLE_APP_PWD }}
run: |
set -euo pipefail
DMG="target/Emu68 Hatcher.dmg"
codesign --force --sign "$MACOS_SIGN_IDENTITY" --timestamp "$DMG"
scripts/macos-notarize.sh "$DMG"
- name: Rename artifact
shell: bash
run: |
set -euo pipefail
version=$(python -c "import json; print(json.load(open('src/build/settings/base.json'))['version'])")
cd target
case "${{ matrix.os }}" in
windows) mv "Emu68 HatcherSetup.exe" "emu68hatcher-${version}-${{ matrix.label }}.exe" ;;
linux) mv "emu68hatcher.deb" "emu68hatcher-${version}-${{ matrix.label }}.deb" ;;
macos) mv "Emu68 Hatcher.dmg" "emu68hatcher-${version}-${{ matrix.label }}.dmg" ;;
esac
ls -la
- name: List built artifacts
shell: bash
run: ls -la target/
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: emu68hatcher-${{ matrix.label }}
path: |
target/*.exe
target/*.deb
target/*.dmg
target/*.rpm
if-no-files-found: error
retention-days: 14
- name: Clean up signing keychain (macOS)
if: always() && matrix.os == 'macos'
run: |
if [[ -n "${BUILD_KEYCHAIN_PATH:-}" && -f "$BUILD_KEYCHAIN_PATH" ]]; then
security delete-keychain "$BUILD_KEYCHAIN_PATH" || true
fi
release:
name: Publish GitHub Release
needs: build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v8
with:
path: dist
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
files: dist/**/*
generate_release_notes: true
draft: true # flip to false once you're happy with the process
prerelease: false