Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
92 changes: 77 additions & 15 deletions .github/workflows/_ci-desktop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
desktop-tauri:
name: Desktop Tauri (${{ matrix.lane }})
runs-on: ubuntu-latest
# A lane needs up to ~15m. ci-apt-retry.sh bounds the apt step at ~34m worst
# A lane needs up to ~15m. ci-apt-retry.sh bounds the apt steps at ~34m worst
# case (update ~8.5m + install ~25m); 55m fits both, so a degraded mirror
# fails with the wrapper's error instead of the job timeout.
timeout-minutes: 55
Expand All @@ -93,6 +93,22 @@ jobs:
run: just desktop-tauri-test-compiled-flags
permissions:
contents: read
env:
# Resolved and installed by the steps below; the .deb cache key hashes
# what apt resolves for this list.
TAURI_APT_PACKAGES: >-
build-essential
curl
file
libasound2-dev
libayatana-appindicator3-dev
libgtk-3-dev
librsvg2-dev
libssl-dev
libwebkit2gtk-4.1-dev
libxdo-dev
patchelf
wget
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
with:
Expand All @@ -104,24 +120,70 @@ jobs:
workspaces: desktop/src-tauri
shared-key: ${{ matrix.cache }}
save-if: ${{ matrix.save-cache && github.event_name != 'pull_request' }}
# A degraded Ubuntu mirror serves .debs at ~50 KB/s, and the ~62 MB
# Tauri download (one 25.5 MB libwebkit2gtk .deb) then outlasts every
# ci-apt-retry.sh attempt. Cache the .debs in the Actions cache so the
# mirror only serves `apt-get update` and packages Ubuntu has updated
# since main last saved.
- name: Resolve Tauri apt archives
id: tauri-debs
run: |
set -euo pipefail
CI_APT_ATTEMPT_SECONDS=90 scripts/ci-apt-retry.sh sudo apt-get update
read -ra packages <<< "$TAURI_APT_PACKAGES"
# Name, size and SHA256 (from the signed index) of each .deb the
# install will fetch. The mirror URI is left out so the key doesn't
# depend on which mirror answered. Runs before the restore:
# --print-uris omits files that are already in
# /var/cache/apt/archives.
sudo apt-get install --print-uris -qq -y --no-install-recommends \
-o Acquire::ForceHash=SHA256 "${packages[@]}" |
awk '{print $2, $3, $4}' | sort > "$RUNNER_TEMP/tauri-debs.txt"
. /etc/os-release
prefix="tauri-debs-${ID}${VERSION_ID}-"
echo "prefix=$prefix" >> "$GITHUB_OUTPUT"
echo "key=$prefix$(sha256sum "$RUNNER_TEMP/tauri-debs.txt" | cut -c1-16)" >> "$GITHUB_OUTPUT"
- name: Restore Tauri apt archives
id: tauri-debs-cache
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ~/.cache/tauri-debs
key: ${{ steps.tauri-debs.outputs.key }}
restore-keys: ${{ steps.tauri-debs.outputs.prefix }}
- name: Install Tauri dependencies (Linux)
id: tauri-debs-install
env:
DEBIAN_FRONTEND: noninteractive
run: |
CI_APT_ATTEMPT_SECONDS=90 scripts/ci-apt-retry.sh sudo apt-get update
scripts/ci-apt-retry.sh sudo apt-get install -y --no-install-recommends \
build-essential \
curl \
file \
libasound2-dev \
libayatana-appindicator3-dev \
libgtk-3-dev \
librsvg2-dev \
libssl-dev \
libwebkit2gtk-4.1-dev \
libxdo-dev \
patchelf \
wget
set -euo pipefail
debs=~/.cache/tauri-debs
mkdir -p "$debs"
# apt reuses an archived .deb of the expected size without checking
# its hash, so seed only restored files whose SHA256 matches the
# signed index. apt downloads and verifies the rest. sha256sum exits
# non-zero when a file fails or none is restored; neither is fatal.
awk '{sub(/^SHA256:/, "", $3); print $3 " " $1}' "$RUNNER_TEMP/tauri-debs.txt" > "$RUNNER_TEMP/tauri-debs.sha256"
(cd "$debs" && { sha256sum --check --ignore-missing "$RUNNER_TEMP/tauri-debs.sha256" || true; }) |
sed -n 's/: OK$//p' | (cd "$debs" && xargs -r sudo cp -t /var/cache/apt/archives/)
read -ra packages <<< "$TAURI_APT_PACKAGES"
scripts/ci-apt-retry.sh sudo apt-get install -y --no-install-recommends "${packages[@]}"
# Keep exactly the resolved files, so a restore-keys fallback can't
# pile up superseded versions. The packages are installed by now, so
# a failure here only warns and skips the save.
if rm -rf "$debs" && mkdir -p "$debs" &&
awk '{print "/var/cache/apt/archives/" $1}' "$RUNNER_TEMP/tauri-debs.txt" | xargs -r cp -t "$debs"; then
echo "rebuilt=true" >> "$GITHUB_OUTPUT"
else
echo "::warning::Could not rebuild the Tauri apt archive cache; not saving it."
fi
# Like the other caches here, only pushes save; PR runs restore. All
# three lanes resolve the same key, so one lane saves it.
- name: Save Tauri apt archives
if: matrix.lane == 'core' && github.event_name == 'push' && steps.tauri-debs-cache.outputs.cache-hit != 'true' && steps.tauri-debs-install.outputs.rebuilt == 'true'
uses: actions/cache/save@caa296126883cff596d87d8935842f9db880ef25 # v5
with:
path: ~/.cache/tauri-debs
key: ${{ steps.tauri-debs.outputs.key }}
- name: Desktop Tauri ${{ matrix.lane }}
run: ${{ matrix.run }}
env:
Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/_ci-rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,12 @@ jobs:
windows-rust:
name: Windows Rust (x86_64-pc-windows-msvc)
runs-on: windows-latest
# Windows runners are slow and this compiles the workspace + Tauri crate
# cold across four steps; budget generously.
timeout-minutes: 45
# With no rust-cache (after a toolchain bump or eviction), the steps take
# 39-41m on main (2026-10-22..26): clippy 17-18m, Tauri check ~6m, Tauri
# tests 10-11m, the rest ~5m. The cache save that follows takes ~4.5m and
# runs inside this cap. If the cap kills it, nothing is saved and the next
# push is cold again. 60m leaves ~15m over that; warm runs take 15-23m.
timeout-minutes: 60
if: inputs.lane == 'required' && (github.event_name == 'push' || inputs.rust || inputs.desktop_rust)
permissions:
contents: read
Expand Down Expand Up @@ -144,10 +147,10 @@ jobs:
for bin in buzz-acp buzz-agent buzz-dev-mcp git-credential-nostr buzz; do
touch "desktop/src-tauri/binaries/${bin}-${TARGET}.exe"
done
# Clippy type-checks everything `cargo check` would, so no separate
# workspace check step.
- name: Clippy (workspace)
run: cargo clippy --workspace --all-targets --target $env:TARGET -- -D warnings
- name: Check (workspace)
run: cargo check --workspace --all-targets --target $env:TARGET
- name: Test (buzz-dev-mcp)
# The Windows-only bash resolver lives in buzz-dev-mcp; its unit tests
# only gate if this crate is tested ON Windows.
Expand Down
20 changes: 13 additions & 7 deletions scripts/flake-check.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -1077,14 +1077,20 @@ test("repeat invocations mirror the lanes they stand in for", () => {
runner,
);
// The Tauri lane builds what the Desktop Tauri core lane does: the same
// workspace cache, system packages and sidecar stubs.
// workspace cache, system packages and sidecar stubs. The core lane lists
// its packages in TAURI_APT_PACKAGES, which its .deb cache key hashes.
const desktop = read("../.github/workflows/_ci-desktop.yml");
const packages = (text) =>
/apt-get install -y --no-install-recommends \\\n((?: {12}\S+(?: \\)?\n)+)/.exec(
text,
)?.[1];
assert.ok(packages(desktop), "Desktop Tauri apt packages");
assert.equal(packages(flake), packages(desktop));
const desktopPackages = /^ {6}TAURI_APT_PACKAGES: >-\n((?: {8}\S+\n)+)/m
.exec(desktop)?.[1]
.split(/\s+/)
.filter(Boolean);
const flakePackages =
/apt-get install -y --no-install-recommends \\\n((?: {12}\S+(?: \\)?\n)+)/
.exec(flake)?.[1]
.split(/[\s\\]+/)
.filter(Boolean);
assert.ok(desktopPackages?.length, "Desktop Tauri apt packages");
assert.deepEqual(flakePackages, desktopPackages);
assert.match(
flake,
/flake-tauri:\n(?: {4}.*\n)*? {6}- uses: Swatinem\/rust-cache@\w+\n {8}with:\n {10}workspaces: desktop\/src-tauri\n {10}shared-key: desktop-core\n {10}save-if: false\n/,
Expand Down
Loading