Skip to content

The AUR recipe ships itself - #389

Draft
ghackett wants to merge 5 commits into
mainfrom
aur-publish-on-tag
Draft

The AUR recipe ships itself#389
ghackett wants to merge 5 commits into
mainfrom
aur-publish-on-tag

Conversation

@ghackett

@ghackett ghackett commented Aug 18, 2026

Copy link
Copy Markdown
Member

BLOCKED

https://aur.archlinux.org/register was not accepting new registrations when this was written, so this PR is blocked on that coming back and setting the account up. The SSH key secret for it also hasn't been set up. (The register page now sits behind an anti-bot challenge, so whether it has reopened needs a browser to check.)

What

Adds an aur job to release.yml: every v* tag now publishes the updated PKGBUILD + .SRCINFO to the AUR package repo (ssh://aur@aur.archlinux.org/collins.git). The AUR hosts recipes, not binaries — the whole publish is a git push of two files, and each Arch user's machine fetches the tag tarball from GitHub and builds locally. ship-release.py creates the GitHub release before the tag ever reaches CI, so the tarball the job hashes always exists by the time it runs.

The Arch CI image

Since this branch was first written, release.yml's build and ppa jobs moved into prebuilt, content-addressed CI images (PRs 423 and 424). The aur job follows suit rather than pacman -S-ing its toolchain at run time:

  • A third tag from the same ci.Dockerfile. A new aur stage — a separate FROM archlinux:base-devel, unrelated to the Ubuntu stages — installs git, openssh, curl, and every package the PKGBUILD's depends/makedepends arrays name. It COPYs and sources the PKGBUILD for that list instead of mirroring it: on Arch the PKGBUILD is the canonical dependency list, the one every AUR user's makepkg installs from. It runs as uid 1001 like the Ubuntu stages, which also retires the useradd builder / runuser dance (makepkg refuses root).
  • The tag hashes the Dockerfile and the PKGBUILD (ci-image.yml now emits image_aur as <hash2>-aur; the other two tags are unchanged). A PR that edits the recipe rebuilds just this image, ~1–2 min — and a typo'd package name fails the image build on that PR, with pacman's "target not found", rather than at release time. The former run-time pacman -S typo check is therefore gone; makepkg's own dependency check still guards the release job (relevant for a manual dispatch, whose image comes from the dispatching branch's PKGBUILD, not the tag's).
  • A ppa-source-style rehearsal on every PR. ci.yml gains aur-build: everything the release job does short of pushing, in the same image. The tag the PKGBUILD names need not exist on a PR (pkgver is bumped ahead of the ship), so it builds from a git archive of HEAD placed under the name the source array expects — makepkg skips its download when the file is already there, and it is the same archive GitHub serves once the tag exists. It fails on .SRCINFO drift (the release job only warns, since a stale mirror should not stop a release) and checks the built package carries the launcher, desktop entry, icon and metainfo.

How the release job works

Runs in the Arch image and, in the spirit of the ppa job, refuses rather than guesses:

  • Fails if PKGBUILD's pkgver disagrees with the tag (the bump lands in the release version-bump PRs, so a mismatch means something got skipped).
  • Fails early if the new AUR_SSH_PRIVATE_KEY secret is missing.
  • Downloads the tag tarball and fills its sha256 into sha256sums — which stays SKIP in git by design, since the hash cannot exist before the tag does.
  • Regenerates .SRCINFO with makepkg --printsrcinfo and warns (without blocking the release) if the committed mirror has drifted from the PKGBUILD; the generated copy is what gets pushed, so the AUR is always consistent.
  • Test-builds the package before pushing anything: makepkg re-verifies the tarball hash and exercises the full recipe against the image's packages.
  • Pushes both files to the AUR with a pinned ed25519 host key (verified against ssh-keyscan; the collins name is currently unclaimed, and the first push simply creates the package — no registration step exists). Re-running an already-published tag's workflow finds nothing to commit and skips, mirroring the ppa job's idempotence.

Also in here

  • Fixes real drift in the committed .SRCINFO: PR 386 moved libspelling to optdepends and the earlier PKGBUILD gained gtksourceview5, but .SRCINFO never followed. (Exactly the failure mode the new aur-build check now fails a PR for.)
  • Rewrites packaging/aur/README.md around the automated flow (the image, the rehearsal, the one required secret), keeping the manual steps as a recovery/bootstrap path, and updates RELEASE_CHECKLIST.md, the packaging table, and the ship-release / release-branch skills — which stopped describing a manual post-ship AUR push.

Setup needed before the next release

One repo secret: AUR_SSH_PRIVATE_KEY — an OpenSSH private key whose public half is registered on the episode6 AUR account (My AccountSSH Public Key). Without it the job fails with a pointer to the docs; every other release channel is unaffected.

🤖 Generated with Claude Code

https://claude.ai/code/session_01EzNYMuC323PTuXJceq1KVN

@ghackett

Copy link
Copy Markdown
Member Author

@claude review

@claude

claude Bot commented Aug 18, 2026

Copy link
Copy Markdown

Claude finished @ghackett's task in 2m 53s —— View job


Review complete ✅

  • Gather context (diff, CLAUDE.md, workflow file)
  • Review .github/workflows/release.yml aur job
  • Review packaging/aur/PKGBUILD and .SRCINFO changes
  • Review docs updates (README, RELEASE_CHECKLIST)
  • Post review feedback

This is a well-engineered job that mirrors the ppa job's "refuse rather than guess" philosophy closely and consistently. Nice work.

Strengths

  • Fail-fast checks (pkgver mismatch, missing secret) happen before any network/build work, matching the ppa job's debian/changelog check pattern.
  • The .SRCINFO drift-diff in .github/workflows/release.yml:224-235 correctly normalizes away comments/blanks and the sha256sums line (which legitimately differs, since git keeps SKIP but the generated copy has the real hash) before diffing — so the warning only fires on genuine drift, and this PR's .SRCINFO fix (adding gtksourceview5/libspelling) means the very first run shouldn't warn.
  • The filename produced by collins-${GITHUB_REF_NAME#v}.tar.gz (release.yml:207) matches the $pkgname-$pkgver.tar.gz pattern in PKGBUILD's source=, so makepkg's later hash re-verification actually reuses the already-downloaded tarball instead of re-fetching — a nice touch that also validates the docs' "test-builds before pushing" claim.
  • SSH host key pinning + IdentitiesOnly=yes + StrictHostKeyChecking=yes (release.yml:262-266) is the right way to do this, and the docs point at how to refresh the pinned key if the AUR rotates it.
  • Docs (RELEASE_CHECKLIST.md, packaging/README.md, packaging/aur/README.md) are consistent with the workflow and with scripts/verify_versions.py's existing pkgver/.SRCINFO checks.

Minor, non-blocking observations

  1. .github/workflows/release.yml:249-250pacman -S --noconfirm --needed "${depends[@]}" "${makedepends[@]}" passes PKGBUILD's dependency array entries straight to pacman -S. That's fine today since none of the current depends/makedepends carry version constraints, but if one is ever added (e.g. foo>=1.2), pacman -S won't accept the comparator as a target — the test-build would break with a confusing error rather than the intended "typo'd dependency" message. Not urgent, just a latent fragility worth a one-line comment if you want to head it off.
  2. The AUR push step assumes AUR_SSH_PRIVATE_KEY contains real newlines (not escaped \n) when pasted into the GitHub secret — a common gotcha for private keys. Might be worth a one-line note in packaging/aur/README.md's secret table for whoever rotates/adds this key next.

Neither of these blocks merging — both are edge cases outside what this PR needs to handle today.

@ghackett

Copy link
Copy Markdown
Member Author

🤖 Addressed both observations in 5c36797:

  1. Rather than just documenting the latent fragility, the test-build dep install now strips version comparators before calling pacman -S ("${depends[@]%%[<>=]*}"), so a future foo>=1.2 constraint installs cleanly — makepkg still enforces the constraint itself at build time.
  2. Added the real-newlines note to the AUR_SSH_PRIVATE_KEY row in packaging/aur/README.md, with the gh secret set ... < key incantation that gets it right by construction.

@ghackett
ghackett marked this pull request as ready for review August 19, 2026 00:00
@ghackett
ghackett marked this pull request as draft August 19, 2026 23:19
@ghackett
ghackett force-pushed the aur-publish-on-tag branch 2 times, most recently from 0fe45a5 to ca4ca4c Compare August 22, 2026 23:26
ghackett and others added 4 commits August 27, 2026 07:57
Add an aur job to release.yml: on every v* tag it publishes the
PKGBUILD + .SRCINFO to the AUR package repo (the AUR hosts recipes,
not binaries, so the whole publish is a git push of two files).
ship-release.py creates the GitHub release before the tag reaches CI,
so the tag tarball exists by the time the job hashes it.

The job runs in an archlinux container and refuses rather than
guesses, like the ppa job: pkgver must equal the tag, and the package
must actually build (pacman resolving every declared dependency
catches a typo'd name; makepkg re-verifies the tarball hash) before
anything is pushed. sha256sums stays SKIP in git by design -- the
hash cannot exist before the tag does -- and gets filled in at
publish time. .SRCINFO is regenerated with makepkg --printsrcinfo;
drift in the committed mirror warns instead of blocking the release.
Re-running a published tag's workflow finds nothing to commit and
skips. The AUR's ed25519 host key is pinned in the workflow, and the
push authenticates with a new AUR_SSH_PRIVATE_KEY secret.

Also fix the committed .SRCINFO, which had drifted from the PKGBUILD
(missing gtksourceview5 in depends and the libspelling optdepends
line), and document the automated flow in packaging/aur/README.md
and RELEASE_CHECKLIST.md, keeping the manual steps as a
recovery/bootstrap path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzNYMuC323PTuXJceq1KVN
pacman -S takes bare package names, so the test-build dep install now
strips any version comparator from the PKGBUILD arrays (makepkg still
enforces the constraint itself), and the secret table warns that
AUR_SSH_PRIVATE_KEY must be pasted with real newlines.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzNYMuC323PTuXJceq1KVN
Main's workflow_dispatch tag input (PR 420) re-runs the ppa job for a
frozen tag; give the aur job the same TAG env and tag checkout so the
checklist's recovery step applies to both.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzNYMuC323PTuXJceq1KVN
The release workflow's build and ppa jobs moved into content-addressed
CI images (PRs 423/424) after this branch was written; the aur job was
still installing base-devel and the PKGBUILD's packages with pacman at
run time. It now runs in a third tag from the same ci.Dockerfile: an
`aur` stage on archlinux:base-devel that sources the PKGBUILD and
installs its depends/makedepends, plus git, openssh and curl. That tag
hashes the Dockerfile and the PKGBUILD together, so a PR that edits the
recipe rebuilds just that image -- and a typo'd package name fails the
image build on the PR, before any release. The image runs as uid 1001
like the Ubuntu stages, which also retires the useradd/runuser dance
(makepkg refuses root).

ci.yml gains an `aur-build` job in the spirit of ppa-source: everything
the release job does short of pushing, in the same image, from a git
archive of HEAD placed under the name the source array expects (the tag
the PKGBUILD names need not exist yet on a PR). It fails on .SRCINFO
drift, which the release job only warns about, and checks the built
package carries the launcher, desktop entry, icon and metainfo.

Docs follow: the AUR README describes the image and the rehearsal, the
checklist and packaging table name the new job, and the ship-release /
release-branch skills stop describing a manual post-ship AUR push.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZX48sPJZy3W23YWnw4nQn
@ghackett
ghackett force-pushed the aur-publish-on-tag branch from ca4ca4c to b34f62c Compare August 27, 2026 12:02
…th bsdtar

git archive roots the archive at the working directory, so run from
packaging/aur the stand-in tarball held only that subdirectory and the
build() step found no pyproject.toml. bsdtar (libarchive's, what makepkg
itself packs with) lists the .pkg.tar.zst without GNU tar needing to
find a zstd binary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017ZX48sPJZy3W23YWnw4nQn
@ghackett

Copy link
Copy Markdown
Member Author

@claude review

@claude

claude Bot commented Aug 27, 2026

Copy link
Copy Markdown

Claude finished @ghackett's task in 1m 30s —— View job


Review complete ✅

  • Gather context (diff, workflow files)
  • Review .github/workflows/release.yml aur job
  • Review .github/workflows/ci.yml aur-build job
  • Review .github/docker/ci.Dockerfile and ci-image.yml changes
  • Review packaging/aur/PKGBUILD and .SRCINFO changes
  • Review docs updates (READMEs, RELEASE_CHECKLIST, skills)
  • Post review feedback

Re-reviewed against origin/main (this includes commit 5c36797, which already addressed both observations from the previous pass).

Both prior findings are resolved correctly

  • .github/docker/ci.Dockerfile:88-93"${depends[@]%%[<>=]*}" "${makedepends[@]%%[<>=]*}" correctly strips version comparators before pacman -S: for each array element, %%[<>=]* removes the longest trailing match starting at a </>/= character (e.g. foo>=1.2foo), while names with no comparator pass through unchanged since the pattern simply doesn't match. makepkg still enforces the real constraint at build time, so nothing is lost.
  • packaging/aur/README.md's AUR_SSH_PRIVATE_KEY row now documents the real-newlines gotcha with the gh secret set ... < key incantation that avoids it by construction.

Everything else checks out

  • release.yml's new aur job (needs: [image, build], same if: startsWith(github.ref, 'refs/tags/') || inputs.tag != '') mirrors the ppa job's job-graph shape exactly — consistent with the rest of the file.
  • The image_aur output is wired end-to-end: computed in ci-image.yml:53-54 from hashFiles(Dockerfile, PKGBUILD), exposed via outputs.image_aur (ci-image.yml:32-34,45), built conditionally (ci-image.yml:99-109), and consumed by both release.yml's aur job and ci.yml's aur-build job.
  • The hash-fill step (release.yml:257-264) sed-patches sha256sums into the working tree's PKGBUILD before .SRCINFO regeneration and the AUR push — so both files pushed to the AUR carry the real hash, while the committed copy in this repo correctly stays SKIP (never committed back).
  • ci.yml's aur-build job builds from git archive of HEAD under the exact $pkgname-$pkgver.tar.gz name the source array expects, so makepkg skips the download and sha256sums=('SKIP') skips verification — works regardless of whether the PR's pkgver matches any real tag.
  • .SRCINFO/PKGBUILD drift fix (adding gtksourceview5/libspelling) is correct and is exactly the case the new aur-build drift check now guards.
  • Docs (RELEASE_CHECKLIST.md, packaging/README.md, packaging/aur/README.md, both skill files) are all consistent with the workflow behavior and with each other.

No further issues found — this is ready to merge once the AUR account registration and AUR_SSH_PRIVATE_KEY secret (both called out as blocked in the PR description) are in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant