`punktfunk-gamescope` had never been published to the apt registry — not in any release. It was built inside the host job's Ubuntu 24.04 image, where it cannot build: our pin vendors wlroots 0.19.3, which floors `wayland-server` at 1.23.1, and noble ships 1.22.0 (it also lacks libxcb-errors-dev and has only libdisplay-info 0.1.1). Every rung of that path was a `::warning::` returning 0 and the one hard gate ran last by design, so v0.26.0 and v0.27.0 both released with the package missing while docs-site told apt users to install it. The same tags shipped it fine for Arch, Fedora 44 and Bazzite. It now builds in its own job on Debian 13 (ci/gamescope-trixie.Dockerfile), the oldest apt base the tree configures on. One package serves Debian 13 AND Ubuntu 26.04 — measured by installing and running it on both — because the build also vendors libdisplay-info via the new `--extra-fallback` option: linked against the distro copy it demands `libdisplay-info2` on trixie, which Ubuntu 26.04 does not have (it carries libdisplay-info3). The option is opt-in, so the Arch/Fedora/nix outputs are byte-for-byte unchanged. Ubuntu 24.04 gets no gamescope package and cannot — its wayland is too old to run one however built. Debian 13 is now a documented host target. That needed no packaging change at all: the host .deb's glibc-2.39 floor and bundled FFmpeg already made it installable, and it had been working for a long time while docs-site said Debian was unsupported and unverified. Verified by installing: host, web console and plugin runner install, resolve every soname and run. The desktop client stays Ubuntu-26.04-only (built there, floors at `libc6 >= 2.43`; Debian 13 has 2.41). Compositor detection now answers Cinnamon (Mint, LMDE) with the route that works instead of advice that cannot help. Muffin forked from Mutter 3.36: `org.cinnamon.Muffin.ScreenCast` has only RecordMonitor/RecordWindow, never RecordVirtual, and xdg-desktop-portal-xapp implements no ScreenCast — so no value of PUNKTFUNK_COMPOSITOR makes a Cinnamon desktop host a virtual display. The error names headless gamescope, which needs no desktop compositor. The XDG sniff moved into a pure function so those branches are testable; Cinnamon is matched before GNOME, since it is a GNOME derivative and the generic arm would otherwise hand it the Mutter backend (caught by the new test). New `smoke-install` job installs every published package from the registry in pristine ubuntu:24.04, ubuntu:26.04 and debian:trixie images, asserts each binary resolves its libraries and runs, and insists the version served is the one this run built. Nothing in deb.yml had ever installed a package it produced, which is how both of the above survived unnoticed. ⚠ Bootstrap: seed `punktfunk-gamescope-trixie:latest` into the LAN registry once (docker.yml builds it thereafter) or the new job cannot start.
133 lines
6.3 KiB
Bash
Executable File
133 lines
6.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Install the published .debs on every supported apt distro, in a pristine image, the way a user
|
|
# would — repo key, sources.list line, `apt-get install`.
|
|
#
|
|
# WHY THIS EXISTS: nothing in deb.yml ever installed a package it built. Two facts survived a long
|
|
# time in that blind spot, in opposite directions:
|
|
# * `punktfunk-host` installed cleanly on Debian 13 for months while docs-site said Debian was
|
|
# unsupported and unverified.
|
|
# * `punktfunk-gamescope` was missing from the apt registry across two releases, while the docs
|
|
# told Debian/Ubuntu users to `apt install` it.
|
|
# Both are what a five-minute install check catches.
|
|
#
|
|
# Usage: bash scripts/ci/deb-install-smoke.sh
|
|
# PF_APT_DISTRIBUTION stable | canary (default: stable)
|
|
# PF_EXPECT_VERSION if set, `punktfunk-host --version` must contain it — proves the run is
|
|
# testing the artifact THIS run published and not a leftover from an
|
|
# earlier one (the failure mode that makes a green check meaningless).
|
|
# PF_SMOKE_IMAGES override the image list, space-separated (local runs / bisecting).
|
|
set -euo pipefail
|
|
|
|
DIST="${PF_APT_DISTRIBUTION:-stable}"
|
|
EXPECT="${PF_EXPECT_VERSION:-}"
|
|
REPO_URL="https://git.unom.io/api/packages/unom/debian"
|
|
|
|
# THE SUPPORT MATRIX, as an assertion instead of a paragraph. Each row is
|
|
# "<image>|<packages that must install>". A package absent from a row is one we do NOT claim works
|
|
# there, and it is deliberately NOT asserted absent — that would turn every future improvement into
|
|
# a red build. The omissions and their reasons:
|
|
# ubuntu:24.04 no client — built on 26.04, floors at libc6 >= 2.43 (noble has 2.39)
|
|
# no gamescope — noble's wayland is 1.22.0; the vendored wlroots needs >= 1.23.1,
|
|
# so the binary cannot even load there
|
|
# debian:trixie no client — same libc6 >= 2.43 floor (trixie has 2.41), plus GTK4 >= 4.20
|
|
# Debian 12 (bookworm) is absent entirely: glibc 2.36 is below the host's 2.39 floor, so nothing
|
|
# we ship installs there and there is nothing to smoke-test.
|
|
MATRIX=(
|
|
"ubuntu:24.04|punktfunk-host punktfunk-web punktfunk-scripting"
|
|
"ubuntu:26.04|punktfunk-host punktfunk-web punktfunk-scripting punktfunk-client punktfunk-gamescope"
|
|
"debian:trixie|punktfunk-host punktfunk-web punktfunk-scripting punktfunk-gamescope"
|
|
)
|
|
|
|
if [ -n "${PF_SMOKE_IMAGES:-}" ]; then
|
|
FILTERED=()
|
|
for row in "${MATRIX[@]}"; do
|
|
for want in $PF_SMOKE_IMAGES; do
|
|
[ "${row%%|*}" = "$want" ] && FILTERED+=("$row")
|
|
done
|
|
done
|
|
MATRIX=("${FILTERED[@]}")
|
|
fi
|
|
|
|
echo "smoke-installing from '$DIST'${EXPECT:+ (expecting host version $EXPECT)}"
|
|
FAILED=()
|
|
|
|
for row in "${MATRIX[@]}"; do
|
|
IMAGE="${row%%|*}"
|
|
PACKAGES="${row#*|}"
|
|
echo
|
|
echo "==================== $IMAGE ===================="
|
|
echo "packages: $PACKAGES"
|
|
|
|
# `docker run` inherits nothing from this shell — every value the container needs is passed
|
|
# explicitly, so a typo here is a hard failure rather than a silently empty variable.
|
|
if docker run --rm --platform linux/amd64 \
|
|
-e DEBIAN_FRONTEND=noninteractive \
|
|
-e DIST="$DIST" -e PACKAGES="$PACKAGES" -e EXPECT="$EXPECT" -e REPO_URL="$REPO_URL" \
|
|
"$IMAGE" bash -euxc '
|
|
apt-get update -qq
|
|
apt-get install -y -qq --no-install-recommends curl ca-certificates
|
|
install -d -m 0755 /etc/apt/keyrings
|
|
curl -fsSL --max-time 60 "$REPO_URL/repository.key" -o /etc/apt/keyrings/punktfunk.asc
|
|
echo "deb [signed-by=/etc/apt/keyrings/punktfunk.asc] $REPO_URL $DIST main" \
|
|
> /etc/apt/sources.list.d/punktfunk.list
|
|
apt-get update -qq
|
|
|
|
# Wait for the index to actually carry the version this run published. Gitea regenerates
|
|
# the apt Packages file after an upload, so a smoke job that starts immediately can see
|
|
# the PREVIOUS build — install it, pass, and prove nothing about the new one. Bounded:
|
|
# if it never appears, that is a real publishing failure and the job should say so.
|
|
if [ -n "$EXPECT" ]; then
|
|
for i in $(seq 1 10); do
|
|
apt-cache policy punktfunk-host | grep -qF "$EXPECT" && break
|
|
echo "index does not carry $EXPECT yet (attempt $i) — waiting"
|
|
sleep 15
|
|
apt-get update -qq
|
|
done
|
|
apt-cache policy punktfunk-host | grep -qF "$EXPECT" || {
|
|
echo "the apt index never served $EXPECT — publish did not land"
|
|
apt-cache policy punktfunk-host
|
|
exit 1
|
|
}
|
|
fi
|
|
|
|
# The real thing: unpack + run every maintainer script, exactly as a user would.
|
|
apt-get install -y $PACKAGES
|
|
|
|
# Installed is not the same as working. Assert every shipped binary RESOLVED its shared
|
|
# libraries and, where it is safe to run headless, that it executes — an unsatisfied
|
|
# soname is invisible to dpkg but fatal to the user, and it is exactly what a
|
|
# distro-mismatched build produces.
|
|
# (`if ldd | grep; then fail` rather than `grep && exit 1`: the latter leaves the block
|
|
# returning grep NOT-found = 1, which under `set -e` fails the container on success.)
|
|
for pkg in $PACKAGES; do
|
|
for bin in $(dpkg -L "$pkg" | grep "^/usr/bin/" || true); do
|
|
if ldd "$bin" 2>/dev/null | grep -F "not found"; then
|
|
echo "UNRESOLVED SONAME in $bin (from $pkg)"
|
|
exit 1
|
|
fi
|
|
done
|
|
done
|
|
# --version is the cheapest proof of "actually runs". Only for binaries that answer it
|
|
# without a session/GPU: the client opens GTK, the console is a bun bundle.
|
|
if echo "$PACKAGES" | grep -q punktfunk-host; then
|
|
punktfunk-host --version
|
|
[ -z "$EXPECT" ] || punktfunk-host --version | grep -F "$EXPECT"
|
|
fi
|
|
if echo "$PACKAGES" | grep -q punktfunk-gamescope; then
|
|
punktfunk-gamescope --version
|
|
fi
|
|
'; then
|
|
echo "PASS: $IMAGE"
|
|
else
|
|
echo "::error::$IMAGE — the published packages do not install ($PACKAGES)"
|
|
FAILED+=("$IMAGE")
|
|
fi
|
|
done
|
|
|
|
echo
|
|
if [ ${#FAILED[@]} -gt 0 ]; then
|
|
echo "install smoke FAILED on: ${FAILED[*]}"
|
|
exit 1
|
|
fi
|
|
echo "install smoke passed on every supported distro"
|