The publish step failed the whole run with "login_data is empty" when SNAPCRAFT_STORE_CREDENTIALS is unset, even though both binaries compiled and the amd64 snap packed fine. Move the secret to job level and gate the publish step on it: with no secret the snap is still built and uploaded as an artifact, publish is skipped (green run) instead of failing. Applies to both arches. cc
293 lines
11 KiB
YAML
293 lines
11 KiB
YAML
name: Release Snap (Slint, all-hosted)
|
|
|
|
# All-hosted Snap pipeline for the native (Slint) qbz — BOTH arches. NOTHING
|
|
# runs on the dev box, so the lack of systemd/snapd there does not matter. Two
|
|
# independent tracks, each = build-binary -> dump-pack -> publish:
|
|
# amd64: build-binary (ubuntu-24.04, MIN-tier + 18 GB swap) -> snap
|
|
# (packaging/snap-slint/snapcraft.yaml, plugin: dump).
|
|
# arm64: build-binary-arm64 (native ubuntu-24.04-arm, free for public repos,
|
|
# reuses release-linux-aarch64.yml's cargo cache) -> snap-arm64
|
|
# (packaging/snap-slint/snapcraft-arm64.yaml, plugin: dump).
|
|
# The heavy compile is on free public runners; the snap pack (dump, no compile)
|
|
# runs in seconds on a runner that has snapd. This CI upload is the SOLE publish
|
|
# path — no Launchpad / "Build from GitHub" is used (the root snapcraft.yaml is
|
|
# reference/local-dev only and is removed from the CI working copy below).
|
|
#
|
|
# NOTE: build-binary* duplicates the deb/rpm builders' compile. When the release
|
|
# pipeline is unified (build-once -> fan out to deb/rpm/appimage/snap/flatpak),
|
|
# these jobs become `download-artifact` of the shared per-arch binaries instead.
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Release tag to package (e.g. v1.2.16). Defaults to the pushed tag."
|
|
required: false
|
|
type: string
|
|
channel:
|
|
description: "Snap Store channel"
|
|
required: false
|
|
default: edge
|
|
type: choice
|
|
options: [edge, beta, candidate, stable]
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
|
|
# A tag never builds twice; distinct tags never cancel each other. Never abort a
|
|
# half-published release.
|
|
concurrency:
|
|
group: release-snap-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
build-binary:
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 180
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Free disk + swap (sized for the ~30 GB qbz_ui peak)
|
|
run: |
|
|
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android \
|
|
/opt/hostedtoolcache /usr/local/share/boost /usr/share/swift \
|
|
/usr/local/lib/node_modules || true
|
|
sudo docker image prune --all --force || true
|
|
( sudo fallocate -l 18G /swap_extra \
|
|
&& sudo chmod 600 /swap_extra \
|
|
&& sudo mkswap /swap_extra \
|
|
&& sudo swapon /swap_extra ) || echo "extra swap skipped (non-fatal)"
|
|
free -h; df -h /
|
|
|
|
- name: System dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential pkg-config cmake clang libclang-dev mold nasm \
|
|
libasound2-dev libjack-jackd2-dev \
|
|
libfontconfig1-dev libfreetype-dev \
|
|
libxkbcommon-dev libwayland-dev libxcb1-dev \
|
|
libgl1-mesa-dev libegl1-mesa-dev \
|
|
libdbus-1-dev libssl-dev \
|
|
libharfbuzz-dev libjbig2dec0-dev libopenjp2-7-dev \
|
|
libjpeg-dev zlib1g-dev libgumbo-dev
|
|
|
|
- name: Rust toolchain (pinned dated nightly)
|
|
uses: dtolnay/rust-toolchain@master
|
|
with:
|
|
toolchain: nightly-2026-06-23
|
|
|
|
- name: Cargo cache (Swatinem/rust-cache)
|
|
uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: crates -> target
|
|
shared-key: slint-linux
|
|
cache-on-failure: true
|
|
# share the SAME cache as build-slint.yml (same shared-key) so the
|
|
# heavy qbz_ui rlib is reused across both workflows.
|
|
save-if: false
|
|
|
|
- name: Build qbz (memory-tuned MIN tier, swap-backed)
|
|
env:
|
|
CARGO_INCREMENTAL: '0'
|
|
CARGO_BUILD_JOBS: '1'
|
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '256'
|
|
CARGO_PROFILE_RELEASE_OPT_LEVEL: '2'
|
|
RUSTFLAGS: '-C link-arg=-fuse-ld=mold -Z threads=1'
|
|
run: |
|
|
cargo build --release --manifest-path crates/Cargo.toml -p qbz
|
|
strip crates/target/release/qbz || true
|
|
ls -lh crates/target/release/qbz
|
|
|
|
- name: Upload binary artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: qbz-bin-amd64
|
|
path: crates/target/release/qbz
|
|
if-no-files-found: error
|
|
|
|
build-binary-arm64:
|
|
# Native arm64 build (mirrors release-linux-aarch64.yml). Reuses that
|
|
# workflow's cargo cache (shared-key slint-linux-aarch64) so it does not
|
|
# recompile qbz_ui from cold when the aarch64 build already ran.
|
|
runs-on: ubuntu-24.04-arm
|
|
timeout-minutes: 180
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Free disk + swap (sized for the ~30 GB qbz_ui peak)
|
|
run: |
|
|
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android \
|
|
/opt/hostedtoolcache /usr/local/share/boost /usr/share/swift \
|
|
/usr/local/lib/node_modules || true
|
|
sudo docker image prune --all --force || true
|
|
( sudo fallocate -l 18G /swap_extra \
|
|
&& sudo chmod 600 /swap_extra \
|
|
&& sudo mkswap /swap_extra \
|
|
&& sudo swapon /swap_extra ) || echo "extra swap skipped (non-fatal)"
|
|
free -h; df -h /
|
|
|
|
- name: System dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y --no-install-recommends \
|
|
build-essential pkg-config cmake clang libclang-dev mold nasm \
|
|
libasound2-dev libjack-jackd2-dev \
|
|
libfontconfig1-dev libfreetype-dev \
|
|
libxkbcommon-dev libwayland-dev libxcb1-dev \
|
|
libgl1-mesa-dev libegl1-mesa-dev \
|
|
libdbus-1-dev libssl-dev \
|
|
libharfbuzz-dev libjbig2dec0-dev libopenjp2-7-dev \
|
|
libjpeg-dev zlib1g-dev libgumbo-dev
|
|
|
|
- name: Rust toolchain (pinned dated nightly)
|
|
uses: dtolnay/rust-toolchain@master
|
|
with:
|
|
toolchain: nightly-2026-06-23
|
|
|
|
- name: Cargo cache (Swatinem/rust-cache)
|
|
uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: crates -> target
|
|
shared-key: slint-linux-aarch64
|
|
cache-on-failure: true
|
|
# reuse release-linux-aarch64.yml's cache (same shared-key); do not
|
|
# clobber it from here.
|
|
save-if: false
|
|
|
|
- name: Build qbz (memory-tuned MIN tier, swap-backed)
|
|
env:
|
|
CARGO_INCREMENTAL: '0'
|
|
CARGO_BUILD_JOBS: '1'
|
|
CARGO_PROFILE_RELEASE_CODEGEN_UNITS: '256'
|
|
CARGO_PROFILE_RELEASE_OPT_LEVEL: '2'
|
|
# No x86 target-features here (aarch64 baseline has NEON).
|
|
RUSTFLAGS: '-C link-arg=-fuse-ld=mold -Z threads=1'
|
|
run: |
|
|
cargo build --release --manifest-path crates/Cargo.toml -p qbz
|
|
strip crates/target/release/qbz || true
|
|
ls -lh crates/target/release/qbz
|
|
|
|
- name: Upload binary artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: qbz-bin-arm64
|
|
path: crates/target/release/qbz
|
|
if-no-files-found: error
|
|
|
|
snap:
|
|
needs: build-binary
|
|
runs-on: ubuntu-24.04
|
|
# 30 min was too tight: the v2.0.0 tag run got axed mid-snapcraft (LXD
|
|
# setup + platform snaps + pack ran past it). The job does no compilation,
|
|
# but snapcraft's container bootstrap alone is highly variable on public
|
|
# runners — give it real headroom.
|
|
timeout-minutes: 90
|
|
# Credentials at job level so the publish step can gate on them: an empty /
|
|
# unset secret SKIPS publish instead of failing the whole run (the snap is
|
|
# still built and uploaded as an artifact).
|
|
env:
|
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download prebuilt binary
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: qbz-bin-amd64
|
|
path: dl
|
|
|
|
- name: Stage snap payload (binary + desktop + icon) and recipe
|
|
run: |
|
|
set -eux
|
|
TAG="${{ github.event.inputs.tag || github.ref_name }}"
|
|
VER="${TAG#v}"
|
|
mkdir -p snap-payload
|
|
install -m755 dl/qbz snap-payload/qbz
|
|
cp packaging/snap/snap/gui/qbz.desktop snap-payload/qbz.desktop
|
|
cp packaging/snap/snap/gui/qbz.png snap-payload/qbz.png
|
|
# Place the dump recipe where snapcraft looks for it, and stamp version.
|
|
mkdir -p snap
|
|
cp packaging/snap-slint/snapcraft.yaml snap/snapcraft.yaml
|
|
sed -i "s/^version:.*/version: '${VER}'/" snap/snapcraft.yaml
|
|
# The repo ROOT also carries snapcraft.yaml (the SOURCE-build recipe
|
|
# for Snap Store remote builders) and snapcraft resolves it over
|
|
# snap/snapcraft.yaml — the v2.0.0 run recompiled the whole
|
|
# workspace inside LXD and OOM'd the container. Remove the root
|
|
# recipes from the CI working copy so only the dump recipe exists.
|
|
rm -f snapcraft.yaml .snapcraft.yaml
|
|
echo "Built snap version: ${VER}"
|
|
cat snap/snapcraft.yaml | head -20
|
|
|
|
- name: Build the snap (no compilation — dump of the prebuilt binary)
|
|
id: build
|
|
uses: snapcore/action-build@v1
|
|
|
|
- name: Upload .snap artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: qbz-snap-amd64
|
|
path: ${{ steps.build.outputs.snap }}
|
|
if-no-files-found: error
|
|
|
|
- name: Publish to the Snap Store (skipped when no store credentials)
|
|
if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' }}
|
|
uses: snapcore/action-publish@v1
|
|
with:
|
|
snap: ${{ steps.build.outputs.snap }}
|
|
release: ${{ github.event.inputs.channel || 'edge' }}
|
|
|
|
snap-arm64:
|
|
needs: build-binary-arm64
|
|
runs-on: ubuntu-24.04-arm
|
|
# No compilation here (plugin: dump); the headroom is for snapcraft's LXD
|
|
# bootstrap, which is variable on hosted runners.
|
|
timeout-minutes: 90
|
|
env:
|
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
|
|
- name: Download prebuilt binary
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
name: qbz-bin-arm64
|
|
path: dl
|
|
|
|
- name: Stage snap payload (binary + desktop + icon) and recipe
|
|
run: |
|
|
set -eux
|
|
TAG="${{ github.event.inputs.tag || github.ref_name }}"
|
|
VER="${TAG#v}"
|
|
mkdir -p snap-payload
|
|
install -m755 dl/qbz snap-payload/qbz
|
|
cp packaging/snap/snap/gui/qbz.desktop snap-payload/qbz.desktop
|
|
cp packaging/snap/snap/gui/qbz.png snap-payload/qbz.png
|
|
# Place the arm64 dump recipe where snapcraft looks for it, stamp version.
|
|
mkdir -p snap
|
|
cp packaging/snap-slint/snapcraft-arm64.yaml snap/snapcraft.yaml
|
|
sed -i "s/^version:.*/version: '${VER}'/" snap/snapcraft.yaml
|
|
# Remove the root source-build recipe from the CI working copy so
|
|
# snapcraft resolves ONLY the dump recipe (see the amd64 job).
|
|
rm -f snapcraft.yaml .snapcraft.yaml
|
|
echo "Built snap version: ${VER} (arm64)"
|
|
cat snap/snapcraft.yaml | head -20
|
|
|
|
- name: Build the snap (no compilation — dump of the prebuilt binary)
|
|
id: build
|
|
uses: snapcore/action-build@v1
|
|
|
|
- name: Upload .snap artifact
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: qbz-snap-arm64
|
|
path: ${{ steps.build.outputs.snap }}
|
|
if-no-files-found: error
|
|
|
|
- name: Publish to the Snap Store (skipped when no store credentials)
|
|
if: ${{ env.SNAPCRAFT_STORE_CREDENTIALS != '' }}
|
|
uses: snapcore/action-publish@v1
|
|
with:
|
|
snap: ${{ steps.build.outputs.snap }}
|
|
release: ${{ github.event.inputs.channel || 'edge' }}
|