mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-30 07:37:36 +00:00
A manual dispatch of the AUR workflow that names a tag built and linted the branch it was dispatched from, then published the tag. The two trees were never compared, so a republish could push a PKGBUILD that namcap and makepkg had never seen. The build-and-lint job now checks out the tag a dispatch names, and the event's own ref otherwise, which is what the publish job resolves. The gate scripts and their fixture tests come from a second, sparse checkout of the workflow's own revision, so republishing a tag cut before they existed still runs them. The job reports the commit it linted, and the publish job refuses to continue, before its package wait, unless the tag resolves to that commit.
311 lines
14 KiB
YAML
311 lines
14 KiB
YAML
name: AUR Publish
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
- maint
|
|
- next
|
|
tags:
|
|
- 'v*'
|
|
pull_request:
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Release tag to publish (e.g. v0.4.0). Defaults to the tag the workflow was dispatched from.'
|
|
required: false
|
|
default: ''
|
|
pkgrel:
|
|
description: 'AUR pkgrel to publish. Use 2+ for packaging-only republishes of an existing tag.'
|
|
required: false
|
|
default: '1'
|
|
|
|
jobs:
|
|
# ───────────────────────────────────────────────────────────────────────────
|
|
# Build + lint the AUR package on every trigger, matching the coverage the
|
|
# other package workflows (linux/macos/windows/openwrt) give their artifacts:
|
|
# branch pushes, pull requests, tags, and manual dispatch. Uses makepkg +
|
|
# namcap in an Arch container (neither tool exists on ubuntu-latest) and builds
|
|
# the *checked-out tree* from a local git-archive tarball, so it works for
|
|
# branch/PR builds and unreleased rc tags whose GitHub source archive does not
|
|
# exist yet. The lint fails the job on namcap error-level (E:) findings;
|
|
# warnings (W:) are advisory. This job never publishes.
|
|
#
|
|
# The tree it builds and lints is the tree the publish job below publishes:
|
|
# a dispatch naming a tag checks out that tag here too, and every other
|
|
# trigger checks out the event's own ref, which is what the publish job
|
|
# resolves when no tag is given. The gate scripts and their fixture tests
|
|
# come from this workflow's own revision instead (gate-src), so republishing
|
|
# a tag cut before they existed still runs them. The job reports the commit
|
|
# it linted, and the publish job refuses any other.
|
|
# ───────────────────────────────────────────────────────────────────────────
|
|
aur-build:
|
|
name: Build and lint fips AUR package
|
|
runs-on: ubuntu-latest
|
|
container: archlinux:base-devel
|
|
outputs:
|
|
linted: ${{ steps.linted.outputs.sha }}
|
|
|
|
steps:
|
|
- name: Install build and lint tooling
|
|
run: |
|
|
set -euo pipefail
|
|
pacman -Sy --noconfirm --needed base-devel namcap git curl jq
|
|
|
|
# The tree to build, lint and (in the publish job) publish. inputs.tag
|
|
# is empty unless a dispatch names a tag, and an empty ref checks out
|
|
# the event's ref.
|
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
with:
|
|
ref: ${{ inputs.tag }}
|
|
|
|
# The gate scripts, from this workflow's own revision. The second path
|
|
# is for the publish gate's test, which discovers the real workflows
|
|
# relative to the script.
|
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
with:
|
|
path: gate-src
|
|
sparse-checkout: |
|
|
packaging/aur
|
|
.github/workflows
|
|
|
|
- name: Record the commit being linted
|
|
id: linted
|
|
env:
|
|
INPUT_TAG: ${{ inputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
SHA=$(git -C "$GITHUB_WORKSPACE" rev-parse 'HEAD^{commit}')
|
|
echo "sha=${SHA}" >> "$GITHUB_OUTPUT"
|
|
echo "Linting ${SHA} (${INPUT_TAG:-$GITHUB_REF})"
|
|
|
|
- name: Test the publish gate
|
|
# Fixture tests for the script the publish job below waits with. They
|
|
# run here, on every trigger, so a change to the gate is exercised
|
|
# before a release tag depends on it.
|
|
run: bash gate-src/packaging/aur/test-await-package-runs.sh
|
|
|
|
- name: Test the namcap gate
|
|
# Fixture tests, with canned namcap output, for the script the lint
|
|
# below runs namcap through.
|
|
run: bash gate-src/packaging/aur/test-namcap-gate.sh
|
|
|
|
- name: Resolve package version
|
|
id: ver
|
|
env:
|
|
INPUT_TAG: ${{ inputs.tag }}
|
|
INPUT_PKGREL: ${{ inputs.pkgrel }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -n "${INPUT_TAG:-}" ]; then
|
|
RAW="${INPUT_TAG#v}"
|
|
elif [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
|
|
RAW="${GITHUB_REF_NAME#v}"
|
|
else
|
|
# Branch push / PR: derive the version from the crate manifest.
|
|
RAW=$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')
|
|
fi
|
|
# makepkg forbids '-' in pkgver; map e.g. 0.4.0-rc1 -> 0.4.0rc1,
|
|
# 0.4.0-dev -> 0.4.0dev. The build only needs an internally consistent
|
|
# pkgver (it matches the git-archive prefix below); this is not the
|
|
# value the real publish uses.
|
|
VERSION="${RAW//-/}"
|
|
PKGREL="${INPUT_PKGREL:-1}"
|
|
case "$PKGREL" in
|
|
''|*[!0-9]*|0) echo "pkgrel '$PKGREL' must be a positive integer"; exit 1 ;;
|
|
esac
|
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "pkgrel=${PKGREL}" >> "$GITHUB_OUTPUT"
|
|
echo "Resolved AUR pkgver=${VERSION} pkgrel=${PKGREL}"
|
|
|
|
- name: Create non-root build user and fix ownership
|
|
run: |
|
|
set -euo pipefail
|
|
# makepkg refuses to run as root; create an unprivileged build user
|
|
# with passwordless sudo (needed for pacman dep installs during -s).
|
|
useradd -m -s /bin/bash builder
|
|
echo 'builder ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/builder
|
|
chmod 0440 /etc/sudoers.d/builder
|
|
# The checkout is owned by root; hand it to the build user.
|
|
chown -R builder:builder "$GITHUB_WORKSPACE"
|
|
|
|
- name: Prove the namcap gate against real namcap
|
|
# Builds toy packages, one declared correctly and two missing a
|
|
# dependency, and checks the gate passes the first and fails the others
|
|
# with this run's namcap. Runs as the build user because makepkg
|
|
# refuses root and because that is how the lint below runs.
|
|
run: sudo -u builder bash gate-src/packaging/aur/test-namcap-gate.sh --live
|
|
|
|
- name: Build a local source tarball of the checkout
|
|
env:
|
|
VERSION: ${{ steps.ver.outputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
# The PKGBUILD source= points at GitHub archive/<tag>.tar.gz, which does
|
|
# not exist for a branch push, a PR, or an unreleased rc tag and would
|
|
# 404. Instead build the checked-out tree by packing it into a local
|
|
# tarball whose top-level directory matches what the PKGBUILD expects
|
|
# ("fips-<pkgver>/"); patch-pkgbuild.sh repoints source= at it.
|
|
TARBALL="packaging/aur/fips-${VERSION}.tar.gz"
|
|
git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
|
git -C "$GITHUB_WORKSPACE" archive --format=tar.gz \
|
|
--prefix="fips-${VERSION}/" -o "$TARBALL" HEAD
|
|
chown builder:builder "$TARBALL"
|
|
ls -l "$TARBALL"
|
|
|
|
- name: Patch PKGBUILD
|
|
env:
|
|
TAG: v${{ steps.ver.outputs.version }}
|
|
VERSION: ${{ steps.ver.outputs.version }}
|
|
PKGREL: ${{ steps.ver.outputs.pkgrel }}
|
|
run: |
|
|
set -euo pipefail
|
|
LOCAL_TARBALL="packaging/aur/fips-${VERSION}.tar.gz" \
|
|
bash packaging/aur/patch-pkgbuild.sh
|
|
chown builder:builder packaging/aur/PKGBUILD
|
|
|
|
- name: makepkg build and namcap lint (as build user)
|
|
run: |
|
|
set -euo pipefail
|
|
# The gate comes from gate-src (see the checkouts above). sudo resets
|
|
# the environment, so the path is relative to packaging/aur.
|
|
sudo -u builder bash -euo pipefail -c '
|
|
cd packaging/aur
|
|
gate=../../gate-src/packaging/aur/namcap-gate.sh
|
|
echo "::group::namcap PKGBUILD"
|
|
bash "$gate" PKGBUILD
|
|
echo "::endgroup::"
|
|
echo "::group::makepkg build"
|
|
# No --nocheck. makepkg runs check() by default, so every AUR user
|
|
# runs it and this job must too. ci.yml runs the tests, but not this
|
|
# way: frozen and offline against what prepare fetched, with the
|
|
# Arch toolchain, in this container.
|
|
makepkg -s --noconfirm
|
|
echo "::endgroup::"
|
|
echo "::group::namcap built package"
|
|
bash "$gate" ./*.pkg.tar.*
|
|
echo "::endgroup::"
|
|
'
|
|
|
|
# ───────────────────────────────────────────────────────────────────────────
|
|
# Publish to the AUR. Runs only on a real (non-prerelease) release tag push,
|
|
# or a manual dispatch (packaging-only republish with explicit tag + pkgrel).
|
|
# Branch pushes and pull requests build+lint above but never reach this job.
|
|
# Gated on aur-build so a package that fails to build/lint is never published.
|
|
# It also waits for every package-*.yml run on the tag to succeed before it
|
|
# pushes: the AUR must not point at a tag whose release assets are still
|
|
# uploading or failed, and once it does, withdrawing the tag breaks the AUR
|
|
# package (its b2sum pins the tag's source archive).
|
|
#
|
|
# Before anything else it checks that the tag resolves to the commit
|
|
# aur-build built and linted, so a tag moved between the two jobs, or an
|
|
# edit that makes the two checkouts diverge, stops the publish.
|
|
# ───────────────────────────────────────────────────────────────────────────
|
|
aur-publish-fips:
|
|
name: Publish fips to AUR
|
|
needs: aur-build
|
|
runs-on: ubuntu-latest
|
|
# Above the gate's own 60-minute budget, so the gate reports a timeout
|
|
# rather than the runner killing it.
|
|
timeout-minutes: 90
|
|
permissions:
|
|
contents: read
|
|
actions: read
|
|
if: >-
|
|
github.event_name == 'workflow_dispatch'
|
|
|| (github.event_name == 'push'
|
|
&& startsWith(github.ref, 'refs/tags/v')
|
|
&& !contains(github.ref_name, '-'))
|
|
|
|
steps:
|
|
- name: Resolve release tag
|
|
id: tag
|
|
env:
|
|
INPUT_TAG: ${{ inputs.tag }}
|
|
INPUT_PKGREL: ${{ inputs.pkgrel }}
|
|
run: |
|
|
set -euo pipefail
|
|
TAG="${INPUT_TAG:-$GITHUB_REF_NAME}"
|
|
PKGREL="${INPUT_PKGREL:-1}"
|
|
case "$TAG" in
|
|
v*) ;;
|
|
*) echo "Tag '$TAG' does not look like a release tag (vX.Y.Z)"; exit 1 ;;
|
|
esac
|
|
case "$PKGREL" in
|
|
''|*[!0-9]*|0) echo "pkgrel '$PKGREL' must be a positive integer"; exit 1 ;;
|
|
esac
|
|
case "$TAG" in
|
|
*-*)
|
|
if [ "$GITHUB_EVENT_NAME" != "workflow_dispatch" ]; then
|
|
echo "Pre-release tag '$TAG' — skipping AUR publish"
|
|
exit 1
|
|
fi
|
|
;;
|
|
esac
|
|
echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
|
|
echo "version=${TAG#v}" >> "$GITHUB_OUTPUT"
|
|
echo "pkgrel=${PKGREL}" >> "$GITHUB_OUTPUT"
|
|
|
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
with:
|
|
ref: ${{ steps.tag.outputs.tag }}
|
|
|
|
- name: Refuse a commit aur-build did not lint
|
|
env:
|
|
LINTED: ${{ needs.aur-build.outputs.linted }}
|
|
run: |
|
|
set -euo pipefail
|
|
SHA=$(git rev-parse 'HEAD^{commit}')
|
|
if [ -z "${LINTED:-}" ]; then
|
|
echo "::error::aur-build reported no linted commit; refusing to publish ${SHA}"
|
|
exit 1
|
|
fi
|
|
if [ "$SHA" != "$LINTED" ]; then
|
|
echo "::error::aur-build linted ${LINTED}, but the tag resolves to ${SHA}; refusing to publish"
|
|
exit 1
|
|
fi
|
|
echo "Publishing ${SHA}, the commit aur-build linted"
|
|
|
|
# The gate script comes from this workflow's own revision, not the tag:
|
|
# a dispatch republishing a tag cut before the gate existed would not
|
|
# find it in the tag's tree. The workflows it waits on still come from
|
|
# the tag's tree, which is what the tag push triggered.
|
|
- uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
with:
|
|
path: gate-src
|
|
sparse-checkout: packaging/aur
|
|
|
|
- name: Wait for the tag's package workflows
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
TAG: ${{ steps.tag.outputs.tag }}
|
|
run: |
|
|
set -euo pipefail
|
|
SHA=$(git rev-parse 'HEAD^{commit}')
|
|
echo "Tag $TAG is at $SHA"
|
|
SHA="$SHA" WORKFLOW_DIR=.github/workflows \
|
|
bash gate-src/packaging/aur/await-package-runs.sh
|
|
|
|
- name: Patch PKGBUILD with pkgver, pkgrel, conflicts, and b2sums
|
|
env:
|
|
TAG: ${{ steps.tag.outputs.tag }}
|
|
VERSION: ${{ steps.tag.outputs.version }}
|
|
PKGREL: ${{ steps.tag.outputs.pkgrel }}
|
|
run: bash packaging/aur/patch-pkgbuild.sh
|
|
|
|
- name: Publish to AUR
|
|
uses: KSXGitHub/github-actions-deploy-aur@abe8ac26b51011c88be58c8809fd2ac674068ea5 # v4.1.2
|
|
with:
|
|
pkgname: fips
|
|
pkgbuild: packaging/aur/PKGBUILD
|
|
updpkgsums: false
|
|
assets: |
|
|
packaging/aur/fips.sysusers
|
|
packaging/aur/fips.tmpfiles
|
|
packaging/aur/fips.install
|
|
commit_username: ${{ github.repository_owner }}
|
|
commit_email: ${{ secrets.AUR_EMAIL }}
|
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
|
commit_message: "Update to ${{ steps.tag.outputs.tag }}"
|