forked from unom/punktfunk
Three independent reasons Rust CI stayed slow despite sccache, fixed together because
they share the same measurement.
1. sccache only ever covered RUSTC. Every C/C++ dependency in the tree — aws-lc-sys,
openh264-sys2's vendored C++, the CMake-built libopus behind audiopus_sys — was
compiled from scratch on every job of every workflow. CMAKE_{C,CXX}_COMPILER_LAUNCHER
plus CC_/CXX_x86_64_unknown_linux_gnu route both build-script styles (cc-rs and
cmake-rs) through the same shared cache.
The CC_* vars are JOB-scoped in ci.yml and deb.yml, never workflow-scoped: the
arm64 cross image sets its own CC_x86_64_unknown_linux_gnu=pf-host-cc, the wrapper
that keeps ffmpeg-sys-next's host probe off the arm64 include dirs. Overwriting it
would surface as a header mismatch rather than as a CI config error.
2. Linking is cacheable by nothing, and these jobs relink the host, client, session,
cli, worker and tray on every run — twice per push for rpm (f43 + f44). The four
Linux builder images now install mold and carry a $CARGO_HOME/config.toml that uses
it for x86_64. aarch64 is deliberately left alone (cross driver, already-fast legs).
Each image asserts `mold --version` in its build, so an image can never ship the
flag without the linker: docker.yml goes red and :latest stays on the last good one.
3. THE EXPENSIVE ONE. ci.yml (debug) and deb.yml (release) named a byte-identical
target-cache key, under a comment claiming the release build reused ci.yml's
artifacts. It never could. actions/cache is first-saver-wins on an exact key and
ci.yml is the faster job, so the shared key always held a debug-only target/ — and,
worse, deb.yml could then never save its own, because the key was taken. Every
canary .deb has been a from-scratch release build for as long as both keys existed.
Same collision on the arm64 pair, and a third participant in
linux-client-screenshots.yml. Split into -debug-/-release- key families; that job
reads deb's tree via restore-keys but keeps its own exact key so it can never win
the save race and replace a full tree with its single-crate one.
Also: one scripts/ci/ensure-sccache.sh replaces ten copy-pasted bootstrap blocks that
had already drifted into two dialects (GNU tar --wildcards vs bsdtar), every Rust job
now ends with --show-stats so a cache regression is visible instead of just "CI got
slower", and deb.yml's web install joins every other CI install on --ignore-scripts.
No behaviour change to any artifact: same compilers, same flags, same outputs.
114 lines
5.3 KiB
YAML
114 lines
5.3 KiB
YAML
# Native Linux client screenshots for the app/marketing listings. The client renders
|
|
# host-free mock scenes (PUNKTFUNK_SHOT_SCENE) under a virtual X display; the driver
|
|
# (clients/linux/tools/screenshots.sh) grabs each one — no host, GPU, or Wayland. The
|
|
# Linux analogue of apple.yml's `screenshots` job, gated to STABLE RELEASE tags only.
|
|
# Standalone + best-effort: a failure here reds nothing else. PNGs land as a 30-day
|
|
# artifact; they are not committed or published.
|
|
name: linux-client-screenshots
|
|
# One pending run per workflow+ref: a newer push supersedes the queued/running one and cancels
|
|
# it (a canary only needs the latest commit; each release tag is its own ref so tag runs never
|
|
# cancel each other). Keeps a busy push cadence from piling ~10 queued runs per commit onto the
|
|
# runner fleet. Gitea honors this for push triggers (PR triggers: see gitea#35933).
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
|
|
on:
|
|
push:
|
|
tags: ["v*"]
|
|
workflow_dispatch:
|
|
|
|
# Shared compile cache: sccache -> RustFS S3 (storage.unom.io, LAN-pinned via ci-core's
|
|
# unbound). Keys include compiler hash + target + flags, so cross-OS/arch entries can
|
|
# never collide; every Rust job on every host feeds and reads one warm cache.
|
|
env:
|
|
RUSTC_WRAPPER: sccache
|
|
SCCACHE_BUCKET: unom-ci-sccache
|
|
SCCACHE_ENDPOINT: https://storage.unom.io
|
|
SCCACHE_REGION: home-central
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.SCCACHE_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.SCCACHE_SECRET_ACCESS_KEY }}
|
|
# The C/C++ half of the cache — same wiring as ci.yml/deb.yml. Safe at workflow level: no
|
|
# cross-compiling job here.
|
|
CMAKE_C_COMPILER_LAUNCHER: sccache
|
|
CMAKE_CXX_COMPILER_LAUNCHER: sccache
|
|
CC_x86_64_unknown_linux_gnu: sccache cc
|
|
CXX_x86_64_unknown_linux_gnu: sccache c++
|
|
# sccache and incremental compilation are mutually exclusive; CI wants the shared
|
|
# cache, dev boxes keep incremental.
|
|
CARGO_INCREMENTAL: "0"
|
|
|
|
jobs:
|
|
screenshots:
|
|
if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
|
|
runs-on: ubuntu-24.04
|
|
# Same image as ci.yml/deb.yml — already carries the Rust toolchain + GTK/SDL build deps.
|
|
container:
|
|
image: 192.168.1.58:5010/punktfunk-rust-ci:latest
|
|
timeout-minutes: 90
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
# Shared compile cache (sccache -> RustFS S3 over the LAN). Baked into the builder
|
|
# images; this heals the job while the running :latest predates the bake.
|
|
- name: sccache (no-op once the image bakes it)
|
|
run: sh scripts/ci/ensure-sccache.sh
|
|
|
|
# Client link deps (baked into the image; kept here so the job is green across image
|
|
# rebuilds — a no-op once present) PLUS the headless-render extras: a virtual X server,
|
|
# software GL+Vulkan (llvmpipe/lavapipe), the icon theme + fonts the UI draws with, and a
|
|
# root-window grab tool.
|
|
- name: Client link + headless-render deps
|
|
run: |
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends \
|
|
libgtk-4-dev libadwaita-1-dev libsdl3-dev libvulkan-dev \
|
|
xvfb x11-utils imagemagick scrot \
|
|
libgl1-mesa-dri mesa-vulkan-drivers \
|
|
adwaita-icon-theme fonts-cantarell fonts-dejavu-core
|
|
|
|
# Reuse the workspace cargo caches. The cargo-home (download) cache is shared verbatim —
|
|
# it is profile-independent.
|
|
- name: Cache keys
|
|
run: echo "rustc=$(rustc --version | cut -d' ' -f2)" >> "$GITHUB_ENV"
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: |
|
|
/usr/local/cargo/registry
|
|
/usr/local/cargo/git
|
|
key: cargo-home-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: cargo-home-
|
|
- uses: actions/cache@v4
|
|
with:
|
|
path: target
|
|
# This job builds RELEASE (see the build step) in the same image and target layout as
|
|
# deb.yml's `build-publish`, so it wants THAT tree — it used to name ci.yml's key, which
|
|
# holds a debug build and gave it nothing. (Third participant in the collision documented
|
|
# on ci.yml's `cargo-target-debug-v3-` key.)
|
|
#
|
|
# Its OWN exact key with deb's prefix as a FALLBACK restore-key, deliberately: both
|
|
# workflows run on a v* tag, and an exact-key match would make them race for the single
|
|
# save slot — this job builds one crate, so if it won that race it would replace deb's
|
|
# full release tree with a nearly empty one for the rest of the lockfile's life. This way
|
|
# it always READS the warm tree and never blocks the job that fills it.
|
|
key: cargo-target-shots-release-v1-${{ env.rustc }}-${{ hashFiles('Cargo.lock') }}
|
|
restore-keys: |
|
|
cargo-target-shots-release-v1-${{ env.rustc }}-
|
|
cargo-target-release-v3-${{ env.rustc }}-
|
|
|
|
- name: Build client
|
|
run: cargo build --release -p punktfunk-client-linux --locked
|
|
|
|
- name: Capture screenshots
|
|
run: bash clients/linux/tools/screenshots.sh
|
|
|
|
- name: Upload screenshots
|
|
if: always()
|
|
# v3: Gitea's API rejects upload-artifact@v4 (see apple.yml). Download is a zip.
|
|
uses: actions/upload-artifact@v3
|
|
with:
|
|
name: punktfunk-linux-client-screenshots
|
|
path: clients/linux/screenshots
|
|
retention-days: 30
|