3213c1b61c
apple / swift (push) Successful in 1m22s
apple / screenshots (push) Successful in 6m43s
ci / web (push) Successful in 50s
ci / docs-site (push) Successful in 1m17s
ci / rust (push) Failing after 7m10s
ci / bench (push) Successful in 6m57s
decky / build-publish (push) Successful in 26s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 11s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 11s
arch / build-publish (push) Successful in 12m9s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 13s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 11s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 11s
deb / build-publish (push) Successful in 8m55s
android / android (push) Successful in 17m5s
deb / build-publish-host (push) Successful in 9m25s
docker / deploy-docs (push) Successful in 23s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 15m5s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 14m38s
flatpak / build-publish (push) Failing after 8m1s
The flathub remote-add has now burned its entire retry budget and failed the job on three consecutive tag builds — v0.15.0, the v0.15.0 re-point, and v0.16.0 — each one needing a manual re-run to land the bundle. The cause was already root-caused here on 2026-07-11 (see the Tooling step's comment): home-runner-1's Docker embedded resolver at 127.0.0.11 drops UDP lookups while the shared multi-org fleet is saturated. Nothing retransmits a dropped datagram, so the lookup simply times out. The fix then was to widen retry.sh to 10 attempts (~9 min), which comfortably outlasts a main push's ~8-workflow fan-out — but a TAG push starts 13 workflows at once, and that burst now outlives the whole budget. Retrying harder is chasing the symptom; the transport is the problem. `options use-vc` moves resolution to TCP, where the kernel retransmits and a query cannot be silently lost under load. Same resolver and search path — only the transport changes — so internal names still resolve exactly as before. Deliberately no additional nameservers: a public resolver in the list could answer an internal name (git.unom.io) with NXDOMAIN. retry.sh stays as the backstop for real upstream blips. Applied non-fatally, because Docker bind-mounts /etc/resolv.conf and may present it read-only: a DNS tuning that cannot be applied must not be the thing that fails a release build. If the write is refused we warn and stay on UDP, i.e. exactly today's behaviour. Scoped to the flatpak workflow, where the failure is actually evidenced, rather than applied fleet-wide on suspicion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
382 lines
24 KiB
YAML
382 lines
24 KiB
YAML
# Build the native punktfunk Linux CLIENT as a single-file Flatpak bundle and publish it to
|
|
# Gitea's GENERIC package registry, so the Steam Deck (and any flatpak distro) installs it
|
|
# the SteamOS-native, update-survivable way: `flatpak install --user <downloaded>.flatpak`.
|
|
# (The HOST stays an RPM/deb — it needs unsandboxed /dev/uinput + zero-copy NVENC; only the
|
|
# CLIENT is sandbox-friendly. See packaging/README.md and packaging/flatpak/README.md.)
|
|
#
|
|
# Gitea has NO flatpak/ostree registry, so the bundle lives in the generic registry:
|
|
# PUT https://git.unom.io/api/packages/unom/generic/punktfunk-client-flatpak/<version>/<file>
|
|
# GET https://git.unom.io/api/packages/unom/generic/punktfunk-client-flatpak/<version>/<file>
|
|
# On tags the bundle is ALSO attached to the Gitea release (mirrors release.yml's DMG).
|
|
#
|
|
# PRIVILEGED-BUILD CONSTRAINT: flatpak-builder runs bubblewrap, which needs user namespaces.
|
|
# In a Gitea/act_runner Docker executor that means the job container must be --privileged
|
|
# (the same runner already runs `docker build` in docker.yml, so its Docker daemon allows it).
|
|
# If your runner CANNOT grant --privileged, this job will fail at `flatpak-builder` with
|
|
# "Creating new namespace failed: Operation not permitted" — see the fallback in
|
|
# packaging/flatpak/README.md (build on the Deck via org.flatpak.Builder, or on a Linux box,
|
|
# then upload with the curl line below).
|
|
#
|
|
# REGISTRY_TOKEN: repo Actions secret, a PAT with write:package scope (shared with deb/rpm/docker).
|
|
name: flatpak
|
|
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
# The flatpak is the CLIENT — only rebuild when the client/core/manifest change, not on every
|
|
# design/host push (this is a heavy flatpak-builder run). Tags (v*, the client release) build too.
|
|
# The bundle ships BOTH client binaries (shell + Vulkan session), so every crate in either
|
|
# binary's dependency closure must be listed here.
|
|
paths:
|
|
- 'clients/linux/**'
|
|
- 'clients/session/**'
|
|
- 'crates/punktfunk-core/**'
|
|
- 'crates/pf-client-core/**'
|
|
- 'crates/pf-presenter/**'
|
|
- 'crates/pf-console-ui/**'
|
|
- 'packaging/flatpak/**'
|
|
- 'Cargo.lock'
|
|
- '.gitea/workflows/flatpak.yml'
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
REGISTRY: git.unom.io
|
|
OWNER: unom
|
|
APP_ID: io.unom.Punktfunk
|
|
MANIFEST: packaging/flatpak/io.unom.Punktfunk.yml
|
|
PACKAGE: punktfunk-client-flatpak # generic-registry package name
|
|
REPO_URL: https://flatpak.unom.io # shared unom OSTree repo (reusable across unom apps)
|
|
DEPLOY_DIR: unom-flatpak # ~/<dir> on unom-1 (compose + ./site tree)
|
|
|
|
jobs:
|
|
build-publish:
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 120
|
|
container:
|
|
# Fedora ships a recent flatpak + flatpak-builder + the kernel userns support.
|
|
# --privileged is required for bubblewrap inside the Docker executor (see header).
|
|
image: fedora:43
|
|
options: --privileged
|
|
steps:
|
|
# DNS fix — MUST run before any network step. fedora:43's nsswitch.conf is
|
|
# `hosts: files myhostname resolve [!UNAVAIL=return] dns`: the `resolve`
|
|
# module is nss-resolve (systemd-resolved), which isn't running in a CI
|
|
# container. glibc getaddrinfo (git, curl, dnf) mostly falls through to the
|
|
# `dns` module -> Docker's embedded 127.0.0.11 -> works. flatpak/ostree's
|
|
# resolver does NOT fall through: the absent-daemon socket connect trips
|
|
# `[!UNAVAIL=return]` and it reports "[6] Could not resolve hostname". This
|
|
# was masked as an intermittent "busy runner drops DNS" and papered over
|
|
# with retry.sh — but it's deterministic on a runner where the resolve
|
|
# module tips that way (surfaced when jobs began landing on home-runner-2).
|
|
# Drop the `resolve` entry so host lookups use plain `dns`. NOTE: this alone is not
|
|
# sufficient — the Tooling step's dnf install pulls a systemd package upgrade whose RPM
|
|
# trigger re-runs authselect and regenerates this file, undoing the fix. It's reapplied
|
|
# there, right before the first `flatpak` network call.
|
|
- name: Fix container DNS (drop nss-resolve, resolve over TCP)
|
|
run: |
|
|
sed -i 's/resolve \[!UNAVAIL=return\] //' /etc/nsswitch.conf
|
|
# Resolve over TCP instead of UDP. The documented root cause of the flathub
|
|
# bootstrap failures (investigated 2026-07-11, see the Tooling step) is this box's
|
|
# Docker embedded resolver at 127.0.0.11 DROPPING UDP lookups while the shared
|
|
# runner fleet is saturated — a datagram nobody retransmits, so the lookup just
|
|
# times out. The answer then was to widen retry.sh's budget to 10 attempts (~9 min),
|
|
# which is enough to outlast a main push's ~8-workflow fan-out but NOT a TAG push's
|
|
# 13: v0.15.0 (twice) and v0.16.0 each burned all 10 attempts and failed the job,
|
|
# each needing a manual re-run.
|
|
#
|
|
# `use-vc` makes glibc use TCP, where the kernel retransmits and the query cannot be
|
|
# silently lost under load. Same resolver, same search path — only the transport
|
|
# changes, so internal names (git.unom.io) resolve exactly as before; deliberately
|
|
# NO extra nameservers, which would risk answering an internal name from a public
|
|
# resolver. Docker's embedded DNS serves TCP on 127.0.0.11:53 as well as UDP.
|
|
# retry.sh stays as the backstop for genuine upstream blips.
|
|
#
|
|
# Non-fatal: Docker bind-mounts /etc/resolv.conf and can present it read-only, and a
|
|
# DNS tuning that cannot be applied must not be what fails the release build — that
|
|
# would trade an occasional re-run for a hard stop. Falling back to UDP just restores
|
|
# today's behaviour, which retry.sh already covers.
|
|
if ! grep -q '^options .*use-vc' /etc/resolv.conf 2>/dev/null; then
|
|
echo 'options use-vc timeout:3 attempts:3' >> /etc/resolv.conf \
|
|
|| echo "::warning::could not set use-vc (read-only resolv.conf?); staying on UDP"
|
|
fi
|
|
cat /etc/resolv.conf || true
|
|
|
|
# fedora:43 has no node, but actions/checkout (a JS action) needs it. A plain `run:` step
|
|
# executes via the container shell (no node needed), so install node BEFORE checkout.
|
|
- name: node for the JS actions
|
|
run: dnf -y install nodejs
|
|
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Tooling
|
|
run: |
|
|
# flatpak-cargo-generator.py (master) needs aiohttp + tomlkit (NOT the old `toml`).
|
|
# gnupg2/rsync/openssh-clients: sign the OSTree repo + rsync it to unom-1 (see the deploy step).
|
|
dnf -y install flatpak flatpak-builder git python3 python3-aiohttp python3-tomlkit curl jq \
|
|
gnupg2 rsync openssh-clients
|
|
# Belt-and-suspenders: keep nsswitch on plain `dns` even if this dnf transaction pulled
|
|
# in a fresh systemd-resolved (it does — flatpak recommends xdg-desktop-portal ->
|
|
# pipewire/wireplumber -> systemd-networkd/-resolved). Verified on the real runner
|
|
# (2026-07-11) this dnf install does NOT actually rewrite /etc/nsswitch.conf — no
|
|
# authselect trigger fires — so this line alone was never the fix for the failures
|
|
# below. See the retry.sh bump for the real cause.
|
|
sed -i 's/resolve \[!UNAVAIL=return\] //' /etc/nsswitch.conf
|
|
# Flathub provides the GNOME runtime/SDK + the rust-stable + ffmpeg-full extensions.
|
|
#
|
|
# ROOT CAUSE (confirmed 2026-07-11 by watching a live run on home-runner-1): this is
|
|
# NOT a deterministic nsswitch/DNS-config bug. gitea-runner-fleet on home-runner-1 is
|
|
# a SHARED, resource-capped fleet (3 replicas, --cpus 5 --memory 7g each, on a 16c/24G
|
|
# box) serving punktfunk AND several other orgs' repos (chatwoot, website, cms, data,
|
|
# infra, tempblade, played...). A push to punktfunk's main fans out ~8 workflows at
|
|
# once, and this runner box's Docker embedded DNS resolver (127.0.0.11) genuinely
|
|
# drops UDP lookups under that concurrent load — exactly what retry.sh's own header
|
|
# comment already documented. Reproduced: manually dispatching this job when the box
|
|
# was idle (1 container running) succeeded immediately, with or without the sed above.
|
|
# 5 attempts (~100s total) isn't always enough to outlast a synchronized multi-org
|
|
# burst, so bump the bootstrap fetch's budget — never fail the job on a single-shot
|
|
# fetch. Same treatment for every network command below.
|
|
bash scripts/ci/retry.sh 10 flatpak remote-add --user --if-not-exists flathub \
|
|
https://dl.flathub.org/repo/flathub.flatpakrepo
|
|
git config --global --add safe.directory "$PWD"
|
|
|
|
- name: Version + channel
|
|
# Tag vX.Y.Z -> X.Y.Z on the OSTree `stable` branch (a real release); a main push ->
|
|
# <next-minor>-ciN.g<sha> on the `canary` branch (base one minor ahead of the latest stable
|
|
# tag via scripts/ci/pf-version.sh). The two branches live side-by-side in one repo
|
|
# (rsync runs without --delete), each tracked by its own .flatpakref, so `flatpak update`
|
|
# on a stable box never jumps to a canary build. The generic-registry version string allows
|
|
# letters/dots/hyphens.
|
|
run: |
|
|
eval "$(bash scripts/ci/pf-version.sh)" # -> PF_BASE (one minor ahead of the latest stable tag)
|
|
SHORT=$(echo "$GITHUB_SHA" | cut -c1-8)
|
|
case "$GITHUB_REF" in
|
|
refs/tags/v*) V="${GITHUB_REF_NAME#v}"; BRANCH=stable; ALIAS=latest ;;
|
|
*) V="${PF_BASE}-ci${GITHUB_RUN_NUMBER}.g${SHORT}"; BRANCH=canary; ALIAS=canary ;;
|
|
esac
|
|
echo "VERSION=$V" >> "$GITHUB_ENV"
|
|
echo "BUNDLE=punktfunk-client-${V}.flatpak" >> "$GITHUB_ENV"
|
|
echo "FLATPAK_BRANCH=$BRANCH" >> "$GITHUB_ENV"
|
|
echo "ALIAS=$ALIAS" >> "$GITHUB_ENV"
|
|
echo "flatpak version $V -> branch '$BRANCH' alias '$ALIAS'"
|
|
|
|
- name: Generate offline cargo sources
|
|
# flatpak builds with no network; vendor every crate from Cargo.lock into
|
|
# cargo-sources.json next to the manifest (referenced by the manifest's
|
|
# punktfunk-client module).
|
|
#
|
|
# Prune the microsoft/windows-rs git crates first: they belong to
|
|
# punktfunk-client-windows, which the flatpak never builds, and leaving them in makes
|
|
# flatpak-builder full-clone that multi-GB repo at build time → "No space left on
|
|
# device" (see packaging/flatpak/prune-windows-lock.py). The committed Cargo.lock is
|
|
# untouched; cargo --offline only needs sources for the crates it compiles.
|
|
run: |
|
|
curl -fsSL --retry 5 --retry-all-errors --retry-delay 5 -o /tmp/flatpak-cargo-generator.py \
|
|
https://raw.githubusercontent.com/flatpak/flatpak-builder-tools/master/cargo/flatpak-cargo-generator.py
|
|
python3 packaging/flatpak/prune-windows-lock.py Cargo.lock /tmp/Cargo.flatpak.lock
|
|
python3 /tmp/flatpak-cargo-generator.py /tmp/Cargo.flatpak.lock \
|
|
-o packaging/flatpak/cargo-sources.json
|
|
|
|
- name: Seed the local OSTree repo from the live server (keep BOTH channels in the summary)
|
|
# Each CI run builds only ONE branch (canary on main, stable on a tag). The deploy step's
|
|
# `flatpak build-update-repo` regenerates the repo SUMMARY from whatever refs are in the
|
|
# LOCAL repo, and the rsync publishes it (without --delete). A fresh single-branch local
|
|
# repo therefore produces a single-branch summary that CLOBBERS the other channel on the
|
|
# server — the exact bug that made `app/io.unom.Punktfunk/x86_64/stable` unresolvable
|
|
# ("No such ref") after a canary main-push overwrote the post-release summary, even though
|
|
# the stable commit's objects were still on disk. Fix: mirror the published repo DOWN first,
|
|
# so the local repo carries every existing branch; the build below then only ADDS this run's
|
|
# commit and the regenerated+signed summary keeps both channels. No-op on a fresh repo (first
|
|
# publish) or when the deploy secrets aren't set (the build still produces a valid bundle).
|
|
env:
|
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
|
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${DEPLOY_HOST:-}" ] || [ -z "${DEPLOY_SSH_KEY:-}" ]; then
|
|
echo "::warning::DEPLOY_* not set — no seed; building a fresh single-branch repo."
|
|
exit 0
|
|
fi
|
|
install -d -m700 ~/.ssh
|
|
printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy; chmod 600 ~/.ssh/deploy
|
|
SSH="ssh -i $HOME/.ssh/deploy -p ${DEPLOY_PORT:-22} -o StrictHostKeyChecking=accept-new"
|
|
DEST="${DEPLOY_USER}@${DEPLOY_HOST}"
|
|
mkdir -p "$PWD/repo"
|
|
# Pull the currently-published repo (all channels' objects + refs) into the repo the build
|
|
# will extend. No --delete: the local repo starts empty, so this only ADDS.
|
|
# Probe first (retried) whether a published repo exists at all: ONLY that case may
|
|
# continue with a fresh repo. A transient network failure must FAIL the job instead —
|
|
# a blanket `rsync || continue` here is exactly how a flaky link produces the
|
|
# single-branch summary that clobbers the other channel (the bug described above).
|
|
PRESENT=$(bash scripts/ci/retry.sh 5 $SSH "$DEST" \
|
|
"[ -d $DEPLOY_DIR/site/repo/refs ] && echo present || echo absent")
|
|
if [ "$PRESENT" = present ]; then
|
|
bash scripts/ci/retry.sh 5 rsync -az --info=stats1 -e "$SSH" \
|
|
"$DEST:$DEPLOY_DIR/site/repo/" "$PWD/repo/"
|
|
else
|
|
echo "::warning::no published repo on the server (first publish) — continuing fresh"
|
|
fi
|
|
echo "seeded refs:"; ls "$PWD/repo/refs/heads/app/$APP_ID/x86_64/" 2>/dev/null || echo " (none)"
|
|
|
|
- name: Prefetch deps + sources (retried — the network phase, split off the build)
|
|
run: |
|
|
# All of the job's heavy network I/O happens HERE, retried, so a dropped DNS lookup
|
|
# or TCP dial costs a backoff-retry instead of the whole (long) compile:
|
|
# 1) --install-deps-only pulls everything the manifest declares from Flathub: the
|
|
# GNOME 50 runtime/SDK + the rust-stable (//25.08, rustc 1.96) and llvm20 SDK
|
|
# extensions, plus the runtime's auto codecs-extra (HEVC libavcodec).
|
|
# 2) --download-only fetches every source (all crates in cargo-sources.json) into
|
|
# the .flatpak-builder state dir. Both are resumable/idempotent, so re-running
|
|
# after a partial failure is safe and cheap.
|
|
# --disable-rofiles-fuse is the container-safe path (no FUSE).
|
|
# 10 attempts (~9min budget), matching the remote-add bootstrap above — same shared,
|
|
# load-sensitive runner, same flathub.org resolution path.
|
|
bash scripts/ci/retry.sh 10 flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
|
--install-deps-from=flathub --install-deps-only \
|
|
"$PWD/build-dir" "$MANIFEST"
|
|
bash scripts/ci/retry.sh 10 flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
|
--download-only \
|
|
"$PWD/build-dir" "$MANIFEST"
|
|
|
|
- name: Build the flatpak (offline — deps + sources prefetched above)
|
|
run: |
|
|
# Everything is already local (state dir warmed by the prefetch step), so this long
|
|
# step needs no network; --install-deps-from stays as a no-op safety net.
|
|
# --default-branch=$FLATPAK_BRANCH pins the ref to app/io.unom.Punktfunk/x86_64/<branch>
|
|
# (canary or stable) so the matching hosted .flatpakref resolves deterministically
|
|
# (manifest sets no branch).
|
|
flatpak-builder --user --force-clean --disable-rofiles-fuse \
|
|
--default-branch="$FLATPAK_BRANCH" \
|
|
--install-deps-from=flathub \
|
|
--repo="$PWD/repo" \
|
|
"$PWD/build-dir" "$MANIFEST"
|
|
|
|
- name: Export single-file bundle
|
|
run: |
|
|
# Branch must be passed explicitly (matches --default-branch above); build-bundle
|
|
# otherwise defaults to `master` and errors "Refspec … not found".
|
|
flatpak build-bundle "$PWD/repo" "$BUNDLE" "$APP_ID" "$FLATPAK_BRANCH"
|
|
ls -lh "$BUNDLE"
|
|
|
|
- name: Publish to the Gitea generic registry
|
|
env:
|
|
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
run: |
|
|
BASE="https://$REGISTRY/api/packages/$OWNER/generic/$PACKAGE"
|
|
# 1) Versioned URL. A re-tagged release re-fires this workflow and the registry 409s on
|
|
# duplicate uploads — delete any prior copy first (404 on the first publish is fine).
|
|
curl -fsS -o /dev/null --user "enricobuehler:$TOKEN" -X DELETE \
|
|
"$BASE/$VERSION/$BUNDLE" || true
|
|
curl -fsS --user "enricobuehler:$TOKEN" --upload-file "$BUNDLE" \
|
|
"$BASE/$VERSION/$BUNDLE"
|
|
echo "published $BASE/$VERSION/$BUNDLE"
|
|
# 2) Channel alias (stable release -> latest/, canary main build -> canary/) for the
|
|
# Decky fallback + scripts. The generic registry rejects re-uploading an existing
|
|
# version/file (409), so delete the prior alias file first (ignore 404 on run #1).
|
|
curl -fsS -o /dev/null --user "enricobuehler:$TOKEN" -X DELETE \
|
|
"$BASE/$ALIAS/punktfunk-client.flatpak" || true
|
|
curl -fsS --user "enricobuehler:$TOKEN" --upload-file "$BUNDLE" \
|
|
"$BASE/$ALIAS/punktfunk-client.flatpak"
|
|
echo "published $BASE/$ALIAS/punktfunk-client.flatpak"
|
|
|
|
# Sign the OSTree repo flatpak-builder already produced and publish it to flatpak.unom.io on
|
|
# unom-1, so users get `flatpak update` (the single-file bundle above has no remote). Mirrors
|
|
# docker.yml's deploy-docs (DEPLOY_* = the unom-ci-deploy key). No-ops cleanly until the GPG
|
|
# secret + DEPLOY_* exist, so the bundle build stays green during setup.
|
|
- name: Sign + deploy the OSTree repo to unom-1 (flatpak.unom.io)
|
|
env:
|
|
FLATPAK_GPG_PRIVATE_KEY: ${{ secrets.FLATPAK_GPG_PRIVATE_KEY }}
|
|
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
|
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
|
|
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -z "${FLATPAK_GPG_PRIVATE_KEY:-}" ] || [ -z "${DEPLOY_HOST:-}" ]; then
|
|
echo "::warning::FLATPAK_GPG_PRIVATE_KEY/DEPLOY_* not set — skipping repo deploy (bundle still published)."
|
|
exit 0
|
|
fi
|
|
# 1) Import the signing key into a throwaway keyring; sign the repo.
|
|
export GNUPGHOME="$(mktemp -d)"; chmod 700 "$GNUPGHOME"
|
|
echo "$FLATPAK_GPG_PRIVATE_KEY" | base64 -d | gpg --batch --import
|
|
KEYID="$(gpg --list-keys --with-colons | awk -F: '/^fpr:/{print $10; exit}')"
|
|
# build-sign signs the COMMIT objects; build-update-repo signs the SUMMARY. Both are
|
|
# required — clients with gpg-verify=true verify the commit, so summary-only signing
|
|
# fails the pull with "GPG verification enabled, but no signatures found".
|
|
flatpak build-sign "$PWD/repo" "$APP_ID" "$FLATPAK_BRANCH" \
|
|
--gpg-sign="$KEYID" --gpg-homedir="$GNUPGHOME"
|
|
flatpak build-update-repo --generate-static-deltas \
|
|
--gpg-sign="$KEYID" --gpg-homedir="$GNUPGHOME" "$PWD/repo"
|
|
# The regenerated summary advertises exactly these refs — must include EVERY channel that
|
|
# has ever published (the seed step ensures the other channel's commit is present). If this
|
|
# ever shows only one branch on a repo that had two, the seed didn't run — investigate.
|
|
echo "published summary advertises:"; ls "$PWD/repo/refs/heads/app/$APP_ID/x86_64/" 2>/dev/null || echo " (none)"
|
|
# 2) Build the install descriptors (GPGKey = the committed public key, base64).
|
|
GPGKEY="$(base64 -w0 packaging/flatpak/unom-flatpak.gpg)"
|
|
rm -rf site && mkdir -p site
|
|
cat > site/unom.flatpakrepo <<EOF
|
|
[Flatpak Repo]
|
|
Title=unom
|
|
Url=$REPO_URL/repo/
|
|
Homepage=https://punktfunk.unom.io
|
|
Comment=unom Flatpak applications
|
|
GPGKey=$GPGKEY
|
|
EOF
|
|
# Two refs, one per channel. Both descriptor files are regenerated every run and rsync'd
|
|
# without --delete; the repo SUMMARY carries both branches because the build was seeded
|
|
# from the live repo above (so build-update-repo below re-signs a summary listing every
|
|
# published channel, not just this run's). The stable ref resolves for good once any
|
|
# release has built the `stable` branch. A box installs ONE; `flatpak update` then tracks
|
|
# that channel's branch.
|
|
write_ref() { # <filename> <branch> <title>
|
|
cat > "site/$1" <<EOF
|
|
[Flatpak Ref]
|
|
Name=$APP_ID
|
|
Branch=$2
|
|
Url=$REPO_URL/repo/
|
|
Title=$3
|
|
Homepage=https://punktfunk.unom.io
|
|
IsRuntime=false
|
|
GPGKey=$GPGKEY
|
|
RuntimeRepo=https://dl.flathub.org/repo/flathub.flatpakrepo
|
|
EOF
|
|
}
|
|
write_ref "${APP_ID}.flatpakref" stable "Punktfunk"
|
|
write_ref "${APP_ID}.Canary.flatpakref" canary "Punktfunk (Canary)"
|
|
cat > site/index.html <<EOF
|
|
<!doctype html><meta charset=utf-8><title>unom flatpak repo</title>
|
|
<h1>unom Flatpak repository</h1>
|
|
<p>Install the Punktfunk Linux client (auto-adds Flathub for the GNOME runtime, then tracks updates).</p>
|
|
<p><b>Stable</b> (recommended — only moves on releases):</p>
|
|
<pre>flatpak install --user $REPO_URL/${APP_ID}.flatpakref
|
|
flatpak run $APP_ID</pre>
|
|
<p><b>Canary</b> (latest main build, unstable):</p>
|
|
<pre>flatpak install --user $REPO_URL/${APP_ID}.Canary.flatpakref</pre>
|
|
<p>Or add the whole remote: <code>flatpak remote-add --user --if-not-exists unom $REPO_URL/unom.flatpakrepo</code></p>
|
|
EOF
|
|
# 3) Ship to unom-1 and (re)start the static server. rsync WITHOUT --delete keeps old
|
|
# objects so clients mid-update aren't broken; the fresh signed summary advertises latest.
|
|
install -d -m700 ~/.ssh
|
|
printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/deploy; chmod 600 ~/.ssh/deploy
|
|
SSH="ssh -i $HOME/.ssh/deploy -p ${DEPLOY_PORT:-22} -o StrictHostKeyChecking=accept-new"
|
|
DEST="${DEPLOY_USER}@${DEPLOY_HOST}"
|
|
# All idempotent — retried because the runner's link to unom-1 drops TCP dials under
|
|
# load (the same flake that hits docker.yml's deploy-docs with "dial tcp: i/o timeout").
|
|
bash scripts/ci/retry.sh 5 $SSH "$DEST" "mkdir -p ~/$DEPLOY_DIR/site/repo"
|
|
bash scripts/ci/retry.sh 5 rsync -az --info=stats1 -e "$SSH" repo/ "$DEST:$DEPLOY_DIR/site/repo/"
|
|
bash scripts/ci/retry.sh 5 rsync -az -e "$SSH" site/unom.flatpakrepo "site/${APP_ID}.flatpakref" "site/${APP_ID}.Canary.flatpakref" site/index.html "$DEST:$DEPLOY_DIR/site/"
|
|
bash scripts/ci/retry.sh 5 rsync -az -e "$SSH" packaging/flatpak/server/compose.production.yml packaging/flatpak/server/Caddyfile "$DEST:$DEPLOY_DIR/"
|
|
bash scripts/ci/retry.sh 5 $SSH "$DEST" "cd ~/$DEPLOY_DIR && docker compose -f compose.production.yml up -d"
|
|
echo "deployed → $REPO_URL/${APP_ID}.flatpakref"
|
|
|
|
- name: Attach bundle to the Gitea release (stable tags only)
|
|
if: startsWith(gitea.ref, 'refs/tags/v')
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
run: |
|
|
. scripts/ci/gitea-release.sh
|
|
RID=$(ensure_release "$GITHUB_REF_NAME" "$GITHUB_REF_NAME" auto)
|
|
upsert_asset "$RID" "$BUNDLE"
|