name: Build and Publish HeiniRemote Agent Flatpak on: # New upstream release: the daily check rebuilds when HeiniRemote has a # version (tag or main commit) with no matching tag here yet. schedule: - cron: '0 3 * * *' # daily at 03:00 # Code change: rebuild whenever the packaging itself changes. Scoped to # `main` on purpose — the job force-pushes the `pages` branch and creates # tags, and those must NOT re-trigger it (that would loop). push: branches: - main paths-ignore: - 'README.md' - 'docs/**' - 'LICENSE*' - '.gitignore' workflow_dispatch: inputs: force: description: 'Rebuild even if this version was already published' type: boolean default: false permissions: contents: write jobs: build: runs-on: ubuntu-latest container: # ubuntu:24.04 (glibc 2.39, GStreamer 1.24) is older than the # freedesktop 25.08 runtime (glibc 2.41, GStreamer 1.26), so the # cargo-built binary runs unmodified inside the runtime (same sonames, # forward-compatible symbol versions). 25.08 is required: 24.08 ships # libpipewire 1.2 whose buffer negotiation fails against KWin 6.7 / # PipeWire 1.6 hosts ("pipewiresrc: error alloc buffers"). Privileged # so Flatpak's bwrap works where needed (runtime install triggers). image: ubuntu:24.04 options: --privileged steps: - name: Install build dependencies run: | apt-get update DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ ca-certificates curl git jq flatpak wl-clipboard \ librsvg2-common `# gdk-pixbuf SVG loader — build-export icon validation` \ build-essential pkg-config \ libglib2.0-dev libdbus-1-dev libxkbcommon-dev \ libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev \ libgstreamer-plugins-bad1.0-dev \ libpipewire-0.3-dev # Plain git clone instead of actions/checkout@v4: the bare ubuntu image # has no Node.js, so JavaScript actions fail with exit 127. # # Token split: the auto-provided GITHUB_TOKEN covers everything in THIS # repo (checkout, pages push, tag, release). HeiniRemoteFlatpakActionReleases # — a read-only PAT (repository: read) — is only needed where the private # upstream HeiniRemote is cloned, which GITHUB_TOKEN cannot reach. - name: Checkout env: TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | AUTH_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/${GITHUB_REPOSITORY}.git" git init -q git config --global --add safe.directory "$GITHUB_WORKSPACE" git remote add origin "$AUTH_URL" git fetch -q --depth 1 origin "${GITHUB_SHA:-$GITHUB_REF_NAME}" git checkout -q FETCH_HEAD - name: Resolve upstream HeiniRemote version id: ver env: TOKEN: ${{ secrets.HeiniRemoteFlatpakActionReleases }} run: | chmod +x scripts/*.sh export UPSTREAM_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/pc-heini/HeiniRemote.git" eval "$(scripts/get-latest-version.sh)" { echo "version=$version" echo "ref=$ref" } >> "$GITHUB_OUTPUT" echo "Packaging HeiniRemote $version (ref $ref)" - name: Decide whether to build id: check run: | # A code push (or a manual force) rebuilds even if this version is # already published — the point is to test the changed packaging. if [ "${{ inputs.force }}" = "true" ] || [ "${{ github.event_name }}" = "push" ]; then echo "build=true" >> "$GITHUB_OUTPUT" echo "Rebuild requested (${{ github.event_name }})." elif git ls-remote --tags origin "refs/tags/v${{ steps.ver.outputs.version }}" | grep -q .; then echo "build=false" >> "$GITHUB_OUTPUT" echo "v${{ steps.ver.outputs.version }} already published — nothing to do." else echo "build=true" >> "$GITHUB_OUTPUT" echo "New version v${{ steps.ver.outputs.version }} — building." fi - name: Install Rust if: steps.check.outputs.build == 'true' run: | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - name: Fetch upstream source if: steps.check.outputs.build == 'true' env: TOKEN: ${{ secrets.HeiniRemoteFlatpakActionReleases }} run: | UPSTREAM_URL="$(echo "${GITHUB_SERVER_URL}" | sed "s#://#://${GITHUB_ACTOR}:${TOKEN}@#")/pc-heini/HeiniRemote.git" # init+fetch instead of clone: works for tags and bare commit shas alike. rm -rf upstream && git init -q upstream git -C upstream remote add origin "$UPSTREAM_URL" git -C upstream fetch -q --depth 1 origin "${{ steps.ver.outputs.ref }}" git -C upstream checkout -q FETCH_HEAD # Same cache layout as the upstream workflows: without it every build # compiled all dependencies from scratch (the bulk of the job's time). - name: Cache cargo if: steps.check.outputs.build == 'true' uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git upstream/target key: cargo-flatpak-${{ hashFiles('upstream/Cargo.lock') }} restore-keys: cargo-flatpak- - name: Build agent from upstream source if: steps.check.outputs.build == 'true' run: cargo build --release -p heiniremote-agent --manifest-path upstream/Cargo.toml - name: Install Flatpak runtime and SDK if: steps.check.outputs.build == 'true' run: | flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo flatpak install -y flathub org.freedesktop.Platform//25.08 org.freedesktop.Sdk//25.08 - name: Stamp version into AppStream metadata if: steps.check.outputs.build == 'true' run: | sed -i -E \ "s###" \ de.pc_heini.HeiniRemoteAgent.metainfo.xml - name: Build Flatpak into OSTree repo if: steps.check.outputs.build == 'true' run: | AGENT_BIN=upstream/target/release/heiniremote-agent scripts/make-flatpak.sh # Single-file bundle for direct installs without adding the remote. mkdir -p dist flatpak build-bundle repo \ "dist/heiniremote-agent-${{ steps.ver.outputs.version }}.flatpak" \ de.pc_heini.HeiniRemoteAgent stable # Free disk before publishing (repo/ + dist/ are all we still need). rm -rf build-dir upstream - name: Generate .flatpakrepo if: steps.check.outputs.build == 'true' run: | BASE="${{ github.server_url }}/${{ github.repository }}/raw/branch/pages" cat > repo/heiniremote.flatpakrepo </dev/null || echo "Asset already attached."