Repository navigation
328 lines (304 loc) · 14.6 KB
/
Copy pathfull.yml
File metadata and controls
328 lines (304 loc) · 14.6 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
325
326
327
328
name: full
# The whole application, Slint included — **the only CI**, and **where a release is built** since
# 2026-10-03, when the user had every build and test that ran twice taken out: core.yml (its tests
# were a subset of this workflow's windows-msvc job, run again on every push) and release.yml
# (the windows-msvc build over again on the same commit, ~40 minutes, only so the exe could name
# a tag that did not exist yet when this ran). What went with core.yml: the quicker first answer,
# and its check that the engine builds without Slint ever being fetched.
#
# **No schedule**, by the user on 2026-10-05. A weekly run (Mondays, 06:00 UTC) dated from when
# this ran only on demand; once every push that touches the code ran it, the weekly one only
# tested main again — and GitHub, starting it seven hours late, put it in this concurrency group on
# top of 1.3.0's release run and cancelled that.
#
# **A release:** push the bump commit and its annotated tag together —
# `git push --atomic origin main vX.Y.Z` — so the tag is there when this checks out, and every
# binary built here names it. When all three jobs pass on a commit a `v*` tag points at, the
# windows-msvc job's files are attached to that tag's GitHub Release (the `publish` job below),
# with the tag's message as the notes. A tag pushed after its commit's run: rerun that run
# (`gh run rerun <id>`); its checkout then has the tag. A push to main while a release run is
# building cancels it (the concurrency group below): rerun it the same way.
#
# **Slint is cached** (2026-10-03, the same request): it was 26 of the windows-msvc job's 42
# minutes of building, every run, and it changes only when the pins below do. See "Slint, from
# the cache".
#
# This workflow is ENABLED, by the user on 2026-09-14. It had been `disabled_manually` since
# 2026-09-04, which left a UI change covered by nothing. That was noticed while releasing 0.9.6
# — a release whose every changed file was under src/ui/ — and the answer was to turn this back
# on rather than to keep dispatching it by hand and forgetting to.
#
# WINDOWS ONLY, by the user, 2026-09-06: it used to cost ≈150 billable minutes because macOS is
# billed at 10× and Slint takes 7–25 minutes to build. The macOS and Linux app entries are
# commented out rather than deleted so bringing them back is uncommenting — but bring them back
# knowing what they used to cost.
#
# **Plus the sanitizers, on every push the path filter below lets through (every push that
# touches the code), by the user on 2026-09-23** (the audit's T4, which
# found that neither had ever run in CI and that `linux-tsan` had never run anywhere):
# AddressSanitizer over the whole tree, the UI included, on Windows; and ThreadSanitizer on
# Linux, because there is no ThreadSanitizer for Windows at all. takt4's threads — the audio
# callback, the model, the tracker, the output thread, the UI, the OSC and MIDI listeners
# and Link's own — are the reason. The cost was put to the user and accepted.
#
# The path filter covers everything that can change the app (the audit found src/core,
# tests/ui, tests/CMakeLists.txt, assets and tools/embed_asset.py all missing from it, so a
# change there was not built when it was pushed; and the audit of 2026-09-25, B4, the Rust
# pin, which is the compiler Slint is built with, and LICENSE and THIRD-PARTY-NOTICES.txt,
# which are embedded in takt4.exe). Documentation alone does not trigger it.
#
# Note the concurrency group below cancels in-progress runs for the same ref: a second push
# to main while this is building kills the first run rather than queueing behind it.
on:
push:
branches: [main]
paths:
- 'src/**'
- 'tests/**'
- 'assets/**'
- 'third_party/**'
- 'cmake/**'
- 'CMakeLists.txt'
- 'CMakePresets.json'
- 'tools/embed_asset.py'
- 'rust-toolchain.toml'
- 'LICENSE'
- 'THIRD-PARTY-NOTICES.txt'
- '.github/workflows/full.yml'
pull_request:
paths:
- 'src/**'
- 'tests/**'
- 'assets/**'
- 'third_party/**'
- 'cmake/**'
- 'CMakeLists.txt'
- 'CMakePresets.json'
- 'tools/embed_asset.py'
- 'rust-toolchain.toml'
- 'LICENSE'
- 'THIRD-PARTY-NOTICES.txt'
- '.github/workflows/full.yml'
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
defaults:
run:
shell: bash
jobs:
build:
name: ${{ matrix.preset }}
runs-on: ${{ matrix.os }}
# The ASan job builds the whole tree instrumented and runs every test under it.
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
include:
# The hosted Windows images (windows-latest and windows-2025 alike, as of the
# 2026-08-24 image) ship Visual Studio 2026 only. The preset names no
# generator, so CMake picks whatever Visual Studio is installed.
- os: windows-latest
preset: windows-msvc
app: build/windows-msvc/bin/Release/takt4.exe
cli: build/windows-msvc/bin/Release/takt4-cli.exe
# Where Corrosion has cargo build Slint: `<build>/<platform>/<config>/cargo` under
# Visual Studio, `<build>/cargo` under Ninja (Corrosion.cmake, `cargo_target_dir`).
cargo: build/windows-msvc/x64/Release/cargo
# AddressSanitizer over everything, UI included. cmake/sanitizers.cmake copies the
# ASan runtime DLL beside the binaries, so they start without Visual Studio's PATH.
- os: windows-latest
preset: windows-asan
app: build/windows-asan/bin/Release/takt4.exe
cli: build/windows-asan/bin/Release/takt4-cli.exe
cargo: build/windows-asan/x64/Release/cargo
# ThreadSanitizer: Linux is where it exists. TSAN_OPTIONS makes a report fail the
# test that produced it rather than scroll past in a passing run.
- os: ubuntu-24.04
preset: linux-tsan
app: build/linux-tsan/bin/takt4
cli: build/linux-tsan/bin/takt4-cli
cargo: build/linux-tsan/cargo
# Windows only for now; see the note at the top of this file.
# - os: macos-latest
# preset: macos
# app: build/macos/bin/takt4
# cli: build/macos/bin/takt4-cli
# - os: ubuntu-24.04
# preset: linux
# app: build/linux/bin/takt4
# cli: build/linux/bin/takt4-cli
steps:
- uses: actions/checkout@v7
with:
submodules: recursive
# Every commit and tag, so `git describe` — what `--version` prints — names a release's
# tag rather than a hash. The whole history is ~33 MB.
fetch-depth: 0
- name: Install Linux packages
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
pkg-config libasound2-dev libjack-jackd2-dev libfontconfig-dev libfreetype-dev
# The hosted images ship CMake, Ninja and a Rust toolchain that satisfy the
# requirements in README.md. Record what was actually used.
- name: Toolchain versions
run: |
cmake --version
ninja --version || true
rustc --version || true
cargo --version || true
# **Slint, from the cache**: its source and everything cargo built from it, so a run builds
# only takt4 itself. Both are needed — cargo judges Slint's own crates stale by their
# sources' file times, and a fresh clone is newer than anything it built — so the source
# lives at one fixed place, handed to CMake (FETCHCONTENT_SOURCE_DIR_SLINT, below) and
# cached with its times, and is never cloned over. **And Slint's CMake build directory**
# (`_deps/slint-build`, ~1 MB): its build script writes the C++ headers there
# (`generated_include/private/slint_internal.h` …), outside cargo's own output, and a cargo
# that finds its output fresh does not run the script again — the first cached run, on
# 2026-10-03, restored everything else and failed on that header.
#
# The key is everything that decides what was built: the build type, the runner image
# (the C++ inside Slint's cargo build — Skia's bindings, ICU, harfbuzz — is compiled with
# the image's compiler), the Rust pin, and cmake/deps.cmake, which holds Slint's tag, its
# commit and its features. No fallback key: a near miss would mix two compilers' objects.
# `v2`: what is cached changed (the build directory above); a v1 cache lacks the headers.
# The image is read in a step: ImageOS and ImageVersion are the runner's environment, which
# the `env` context of an expression does not see.
- name: The runner image
id: image
run: echo "image=${ImageOS:?}-${ImageVersion:?}" >> "$GITHUB_OUTPUT"
- name: Slint, from the cache
id: slint
uses: actions/cache/restore@v6
with:
key: slint-v2-${{ matrix.preset }}-${{ steps.image.outputs.image }}-${{ hashFiles('rust-toolchain.toml', 'cmake/deps.cmake') }}
path: |
build/slint-src
build/${{ matrix.preset }}/_deps/slint-build
${{ matrix.cargo }}
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
# The tag cmake/deps.cmake fetches, cloned as FetchContent would; deps.cmake still checks
# the commit it checked out against the one it records.
- name: Slint source
if: steps.slint.outputs.cache-hit != 'true'
run: |
tag=$(grep -A1 'GIT_REPOSITORY https://github.com/slint-ui/slint.git' cmake/deps.cmake \
| sed -n 's/^ *GIT_TAG \(v[0-9.]*\)$/\1/p')
test -n "$tag"
rm -rf build/slint-src
git clone --depth 1 --branch "$tag" https://github.com/slint-ui/slint.git build/slint-src
# A path CMake reads on both systems: Git Bash's `pwd -W` is D:/a/..., Linux has no -W.
- name: Configure
run: |
src="$(pwd -W 2>/dev/null || pwd)/build/slint-src"
cmake --preset ${{ matrix.preset }} -DFETCHCONTENT_SOURCE_DIR_SLINT="$src"
# Linux goes on past the first error (Ninja's -k 0), so a run reports every file GCC
# refuses rather than one per run: GCC warns about things MSVC does not, and this tree
# builds with warnings as errors.
- name: Build
run: cmake --build --preset ${{ matrix.preset }} --parallel ${{ runner.os == 'Linux' && '-- -k 0' || '' }}
# Saved as soon as Slint is built, not at the end: a test that fails must not cost the next
# run the build. Two runs missing at once both try; the second is refused, harmlessly.
- name: Slint, into the cache
if: steps.slint.outputs.cache-hit != 'true'
continue-on-error: true
uses: actions/cache/save@v6
with:
key: ${{ steps.slint.outputs.cache-primary-key }}
path: |
build/slint-src
build/${{ matrix.preset }}/_deps/slint-build
${{ matrix.cargo }}
~/.cargo/registry/index
~/.cargo/registry/cache
~/.cargo/git/db
# `-all`: a runner has no show on it to disturb, so it runs the [network] and [hardware]
# tests the default presets leave out on a rig (the audit's T2).
- name: Test
env:
TSAN_OPTIONS: halt_on_error=1:second_deadlock_stack=1
run: ctest --preset ${{ matrix.preset }}-all
- name: Version banner
run: ${{ matrix.app }} --version
- name: Console tool
run: |
${{ matrix.cli }} --version
${{ matrix.cli }} devices
# **A release's file**, on a commit a `v*` tag points at, pushed or dispatched — never a pull
# request. The tag must be the version in CMakeLists.txt, and takt4.exe must say it is exactly
# that tag: not "-dirty", not a commit after it. takt4.exe alone: takt4-cli is the development
# console, built and tested here but not released. Handed to `publish`, which attaches it
# once every job here has passed.
- name: Release files
id: release
if: matrix.preset == 'windows-msvc' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
run: |
tag=$(git tag --points-at HEAD 'v*' | head -1)
if [ -z "$tag" ]; then
echo "No v* tag on $GITHUB_SHA: not a release."
exit 0
fi
version=$(sed -n 's/^ VERSION \([0-9.]*\)$/\1/p' CMakeLists.txt | head -1)
echo "CMakeLists.txt says $version; the tag is $tag"
test "v$version" = "$tag"
bin=build/windows-msvc/bin/Release
"$bin/takt4.exe" --version | tee app.txt
grep -qx " commit: $tag" app.txt
mkdir dist
cp "$bin/takt4.exe" dist/
ls -l dist
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Keep the release files
if: steps.release.outputs.tag != ''
uses: actions/upload-artifact@v7
with:
name: release
path: dist/
retention-days: 3
# Attaches the windows-msvc job's files to the tag's Release — created from the tag's message if
# there is none yet, the files replaced if one was made by hand — once all three jobs passed.
# Nothing to do on a commit no `v*` tag points at.
publish:
needs: build
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
runs-on: ubuntu-24.04
timeout-minutes: 15
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
# This token can write releases; it is handed to `gh` below and not left in .git.
persist-credentials: false
- name: Which release
id: tag
run: |
tag=$(git tag --points-at HEAD 'v*' | head -1)
echo "tag=$tag" >> "$GITHUB_OUTPUT"
if [ -z "$tag" ]; then echo "No v* tag on $GITHUB_SHA: nothing to publish."; fi
- name: The release files
if: steps.tag.outputs.tag != ''
uses: actions/download-artifact@v8
with:
name: release
path: dist
- name: Attach to the release
if: steps.tag.outputs.tag != ''
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ steps.tag.outputs.tag }}
run: |
ls -l dist
if gh release view "$TAG" > /dev/null 2>&1; then
gh release upload "$TAG" dist/* --clobber
else
gh release create "$TAG" dist/* --verify-tag --notes-from-tag --title "takt4 ${TAG#v}"
fi