@@ -8,6 +8,16 @@ name: release
88# - push of a tag matching `v*` (the release flow)
99# - manual workflow_dispatch (dry-run; uploads to a draft release
1010# so we can inspect the artefact before cutting a real tag)
11+ #
12+ # Architecture strategy (since v1.0.8):
13+ # All builds run on macos-14 (arm64). The Swift helper is built
14+ # universal2 (single binary with both arm64 + x86_64 slices) and
15+ # shipped in both per-arch release tarballs. The PyInstaller-frozen
16+ # Python binary IS arch-specific, so we build it twice — once
17+ # natively on the arm64 host, once under Rosetta 2 (`arch -x86_64`)
18+ # for the Intel slice. Avoids the macos-13 runner queue, which
19+ # was starving so badly that the Intel tarball was effectively
20+ # never landing.
1121
1222on :
1323 push :
2030 required : false
2131 default : " "
2232
23- # Block concurrent runs on the same ref so two tag pushes in
24- # quick succession can't produce a racy double-upload.
2533concurrency :
2634 group : release-${{ github.ref }}
2735 cancel-in-progress : false
2836
2937permissions :
30- # gh release upload needs to write to the release.
3138 contents : write
3239
3340jobs :
3441 build :
35- strategy :
36- fail-fast : false
37- matrix :
38- include :
39- - os : macos-14 # M1 hosted runner → arm64
40- arch : arm64
41- - os : macos-13 # x86_64 hosted runner → x86_64
42- arch : x86_64
43-
44- runs-on : ${{ matrix.os }}
45-
42+ # Both arches build from this single arm64 runner.
43+ runs-on : macos-14
4644 steps :
4745 - uses : actions/checkout@v4
4846
@@ -58,49 +56,113 @@ jobs:
5856 echo "version=$VERSION" >> "$GITHUB_OUTPUT"
5957 echo "num_version=${VERSION#v}" >> "$GITHUB_OUTPUT"
6058
59+ - name : Ensure Rosetta 2 is installed
60+ # GitHub macos-14 runners normally have Rosetta installed,
61+ # but `softwareupdate --install-rosetta --agree-to-license`
62+ # is the official idempotent way to be sure. The flag is a
63+ # no-op if Rosetta is already there.
64+ run : softwareupdate --install-rosetta --agree-to-license || true
65+
6166 - name : Install uv
6267 uses : astral-sh/setup-uv@v5
6368 with :
6469 enable-cache : true
6570
66- - name : Set up Python 3.11
71+ # ---- Swift helper: build once, universal2, used by both
72+ # tarballs. The helper bundle is signed ad-hoc which produces
73+ # a stable cdhash across both arches — same cdhash means the
74+ # TCC grants the user accumulates carry across arm64 / x86_64
75+ # installs of the same release.
76+ - name : Build Swift helper (universal2)
77+ env :
78+ DITING_HELPER_UNIVERSAL : " 1"
79+ run : ( cd helper && ./build.sh )
80+
81+ # ---- arm64 build (native) -----------------------------------
82+ - name : Set up Python 3.11 (arm64 native)
6783 run : uv python install 3.11
6884
69- - name : Sync release dependencies
70- # PyInstaller lives in the [release] group. --all-groups
71- # also pulls dev tools we don't need; --group release keeps
72- # the build env lean.
85+ - name : Sync release deps (arm64)
7386 run : uv sync --group release --python 3.11
7487
75- - name : Build Swift helper
76- run : ( cd helper && ./build.sh )
77-
78- - name : Run package_release.sh
79- env :
80- # Stage everything under the workspace so the upload step
81- # can find the tarball + sha256 by glob.
82- DITING_RELEASE_VERSION : ${{ steps.ver.outputs.num_version }}
88+ - name : Package arm64 tarball
8389 run : |
8490 uv run --python 3.11 \
8591 bash scripts/package_release.sh "${{ steps.ver.outputs.num_version }}"
8692
87- - name : Upload tarball to release
93+ - name : Stash arm64 tarball + sha256
94+ run : |
95+ mkdir -p stash
96+ mv dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz stash/
97+ mv dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz.sha256 stash/
98+
99+ # ---- x86_64 build (Rosetta) ---------------------------------
100+ # PyInstaller takes the arch of the currently-running Python.
101+ # uv can install an x86_64 Python build on an arm64 host via
102+ # the --python-platform flag; we then create a separate venv
103+ # for it. All subsequent commands wrapped in `arch -x86_64`
104+ # so uv, python, and any subprocess they invoke run as x86_64
105+ # under Rosetta.
106+ - name : Set up Python 3.11 (x86_64 via Rosetta)
107+ run : |
108+ arch -x86_64 /bin/bash -c '
109+ curl -fsSL https://astral.sh/uv/install.sh | sh
110+ '
111+ # The Rosetta-installed uv lives under
112+ # ~/.local/bin/uv. Use a separate cache dir so it does not
113+ # collide with the arm64 uv's state.
114+ echo "ROSETTA_UV=$HOME/.local/bin/uv" >> $GITHUB_ENV
115+
116+ - name : Install x86_64 Python via Rosetta uv
117+ run : |
118+ arch -x86_64 "$ROSETTA_UV" python install 3.11
119+
120+ - name : Wipe arm64 venv before x86_64 sync
121+ # `uv sync` reuses .venv/ if present. The arm64 build above
122+ # populated it with arm64 wheels (pyobjc et al.); we need a
123+ # clean slate for the x86_64 install so the right wheels get
124+ # pulled.
125+ run : rm -rf .venv
126+
127+ - name : Sync release deps (x86_64)
128+ run : |
129+ arch -x86_64 "$ROSETTA_UV" sync --group release --python 3.11
130+
131+ - name : Clean previous build artefacts
132+ # PyInstaller and the staging dir from the arm64 run.
133+ run : rm -rf build dist
134+
135+ - name : Package x86_64 tarball
136+ run : |
137+ arch -x86_64 "$ROSETTA_UV" run --python 3.11 \
138+ bash scripts/package_release.sh "${{ steps.ver.outputs.num_version }}"
139+
140+ - name : Restore arm64 tarball alongside x86_64
141+ run : |
142+ mv stash/* dist/
143+
144+ # ---- Upload both tarballs -----------------------------------
145+ - name : Upload tarballs to release
88146 uses : softprops/action-gh-release@v2
89147 if : github.event_name == 'push'
90148 with :
91149 tag_name : ${{ steps.ver.outputs.version }}
92150 files : |
93- dist/diting-${{ steps.ver.outputs.num_version }}-darwin-${{ matrix.arch }}.tar.gz
94- dist/diting-${{ steps.ver.outputs.num_version }}-darwin-${{ matrix.arch }}.tar.gz.sha256
151+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz
152+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz.sha256
153+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-x86_64.tar.gz
154+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-x86_64.tar.gz.sha256
95155
96- - name : Upload tarball as workflow artifact (dispatch dry-runs)
156+ - name : Upload tarballs as workflow artifacts (dispatch dry-runs)
97157 if : github.event_name == 'workflow_dispatch'
98158 uses : actions/upload-artifact@v4
99159 with :
100- name : diting-${{ steps.ver.outputs.num_version }}-darwin-${{ matrix.arch }}
160+ name : diting-${{ steps.ver.outputs.num_version }}-darwin
101161 path : |
102- dist/diting-${{ steps.ver.outputs.num_version }}-darwin-${{ matrix.arch }}.tar.gz
103- dist/diting-${{ steps.ver.outputs.num_version }}-darwin-${{ matrix.arch }}.tar.gz.sha256
162+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz
163+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-arm64.tar.gz.sha256
164+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-x86_64.tar.gz
165+ dist/diting-${{ steps.ver.outputs.num_version }}-darwin-x86_64.tar.gz.sha256
104166 retention-days : 14
105167
106168 shasums :
0 commit comments