-
Notifications
You must be signed in to change notification settings - Fork 36
226 lines (214 loc) · 8.58 KB
/
Copy pathrelease.yml
File metadata and controls
226 lines (214 loc) · 8.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
225
226
name: Release
# Tag a version (e.g. `git tag v0.0.5 && git push --tags`) to build the
# Duckle binary for every OS and attach it directly to a draft GitHub
# release. We do NOT ship installers (no NSIS / MSI / DMG / DEB / RPM /
# AppImage). The asset on the release is the raw executable that the
# user can run.
on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
release_tag:
description: 'Existing release tag to (re)upload binaries to. Builds from the branch this run is dispatched on; the tag itself is never moved. Leave empty on a normal tag push.'
required: false
default: ''
jobs:
# Single point that creates the draft release so the per-OS build
# jobs don't race on `gh release create`.
prepare-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Create draft release if missing
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
REL_TAG: ${{ github.event.inputs.release_tag || github.ref_name }}
run: |
set -e
tag="$REL_TAG"
if gh release view "$tag" >/dev/null 2>&1; then
echo "release $tag already exists"
else
gh release create "$tag" --draft --title "Duckle $tag"
fi
# Build the static Linux runner ONCE and hand it to the per-OS build jobs as a
# workflow artifact (NOT a release asset). Each desktop build embeds it so the
# shipped binary can cross-build a Linux pipeline file from any OS. No separate
# runner is published anywhere; the release page still carries only the desktop
# apps. The job fails loudly if the runner is not produced, so a release can
# never ship with the Linux target silently disabled.
build-linux-runner:
needs: prepare-release
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- name: Build the static Linux duckle-runner (musl, in Docker)
run: bash scripts/build-runner-linux.sh
- name: Upload as a workflow artifact (not a release asset)
uses: actions/upload-artifact@v4
with:
name: duckle-runner-linux-x64
path: apps/desktop/bin/duckle-runner-linux-x64
if-no-files-found: error
build:
needs: [prepare-release, build-linux-runner]
strategy:
fail-fast: false
matrix:
include:
# Linux
- os: ubuntu-24.04
binary: duckle
asset: Duckle-linux-x64
- os: ubuntu-24.04-arm
binary: duckle
asset: Duckle-linux-arm64
# macOS - both built on the macos-14 (Apple Silicon) runner.
# The Intel binary is cross-compiled to x86_64-apple-darwin
# rather than run on a macos-13 runner: GitHub's Intel-mac
# runners are scarce / being deprecated and routinely leave
# the job queued for hours, stalling the whole release.
- os: macos-14
binary: duckle
asset: Duckle-macos-x64
target: x86_64-apple-darwin
- os: macos-14
binary: duckle
asset: Duckle-macos-arm64
# Windows
- os: windows-latest
binary: duckle.exe
asset: Duckle-windows-x64.exe
- os: windows-11-arm
binary: duckle.exe
asset: Duckle-windows-arm64.exe
runs-on: ${{ matrix.os }}
permissions:
contents: write
steps:
- uses: actions/checkout@v4
# Reclaim ~20 GB on Linux runners so the full workspace + embedded
# binaries build does not hit "No space left on device".
- name: Free disk space (Linux)
if: runner.os == 'Linux'
shell: bash
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache/CodeQL /usr/local/.ghcup /usr/local/share/boost \
/usr/local/share/powershell /usr/share/swift || true
sudo docker image prune --all --force || true
df -h /
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
cache-dependency-path: frontend/package-lock.json
- name: Install frontend deps
run: npm --prefix frontend ci
- name: Build frontend (embedded into the Rust binary)
run: npm --prefix frontend run build
- uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target || '' }}
- uses: Swatinem/rust-cache@v2
- name: Install Linux WebView deps (Tauri)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev libgtk-3-dev \
libayatana-appindicator3-dev librsvg2-dev libsoup-3.0-dev
- name: Build duckle-runner + duckle-mcp (bundled into the app)
shell: bash
run: |
set -e
if [ -n "${{ matrix.target }}" ]; then
cargo build --profile release-runner --target "${{ matrix.target }}" -p duckle-runner -p duckle-mcp
base="target/${{ matrix.target }}/release-runner"
else
cargo build --profile release-runner -p duckle-runner -p duckle-mcp
base="target/release-runner"
fi
mkdir -p apps/desktop/bin
if [ "${{ runner.os }}" = "Windows" ]; then
cp "$base/duckle-runner.exe" apps/desktop/bin/duckle-runner.exe
cp "$base/duckle-mcp.exe" apps/desktop/bin/duckle-mcp.exe
else
cp "$base/duckle-runner" apps/desktop/bin/duckle-runner
cp "$base/duckle-mcp" apps/desktop/bin/duckle-mcp
fi
# Stage the prebuilt static Linux runner so build.rs embeds it into THIS
# desktop binary, enabling Build Pipeline -> Linux from any OS. This is a
# workflow artifact from the build-linux-runner job, never a release asset.
- name: Stage the embedded Linux runner
uses: actions/download-artifact@v4
with:
name: duckle-runner-linux-x64
path: apps/desktop/bin
- name: Build raw Duckle binary
shell: bash
run: |
set -e
if [ -n "${{ matrix.target }}" ]; then
cargo build --release --target "${{ matrix.target }}" \
--manifest-path apps/desktop/Cargo.toml --features custom-protocol
else
cargo build --release \
--manifest-path apps/desktop/Cargo.toml --features custom-protocol
fi
- name: Stage release assets
shell: bash
run: |
set -e
mkdir -p _release
if [ -n "${{ matrix.target }}" ]; then
src="target/${{ matrix.target }}/release/${{ matrix.binary }}"
else
src="target/release/${{ matrix.binary }}"
fi
# The standalone desktop binary, named exactly as before so the
# in-app update check (apps/desktop/src/update_check.rs) and the
# README download table keep matching it. Single file, double-click.
# The duckle-runner is embedded into this binary at compile time
# (no separate with-runner asset needed).
cp "$src" "_release/${{ matrix.asset }}"
- name: Upload to release
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
REL_TAG: ${{ github.event.inputs.release_tag || github.ref_name }}
run: |
set -e
asset="${{ matrix.asset }}"
gh release upload "$REL_TAG" "_release/$asset" --clobber
# Publish SHA256SUMS.txt covering the 6 binaries so the in-app self-updater
# can verify a downloaded build before swapping it in. Uploads are per-matrix
# job, so checksums must be a separate job that pulls the finished assets back.
checksums:
name: Publish SHA256SUMS
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download assets, checksum, upload
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
REL_TAG: ${{ github.event.inputs.release_tag || github.ref_name }}
run: |
set -e
mkdir -p _sums && cd _sums
gh release download "$REL_TAG" --clobber
# Checksum exactly the 6 published binaries (not any prior SHA file).
sha256sum \
Duckle-linux-x64 Duckle-linux-arm64 \
Duckle-macos-x64 Duckle-macos-arm64 \
Duckle-windows-x64.exe Duckle-windows-arm64.exe > SHA256SUMS.txt
cat SHA256SUMS.txt
gh release upload "$REL_TAG" SHA256SUMS.txt --clobber