3 Commits

Author SHA1 Message Date
ea7e491ba3 fix(release): tag only, before the cutover fires this for the first time
All checks were successful
PR Checks / rust-gates (pull_request) Successful in -35s
The same two faults link/release.yml has, in the copy this repo was
forked from -- and this one has never run at all, so the cutover would
have been its first execution.

An empty template expression written literally in a comment makes the
runner fail to build the "Commit version bump and push tag" step and
skip it WITHOUT failing the job. link carried that for six releases,
which is why its Cargo.toml still says 0.1.0 while its tags reach
v1.1.1; the tags exist because the release API creates one when it
publishes.

And the step pushes to main, which is protected -- the bundle job
proved that today with `pre-receive hook declined`. A first release
must not depend on a write to a protected branch.

So the tag is the version, as in servuo-plugins. The version is still
written into Cargo.toml before building, so a released binary
self-reports correctly; it is simply not committed back.

The prerequisites header said `main` must accept a direct push from the
CI user. It does not, and it should not; that line is replaced with the
reason.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 17:18:42 -05:00
ae53546446 Merge pull request 'ci(bundle): recognize a linux-aarch64 link asset' (#9) from ci/bundle-aarch64-key into main
Some checks failed
sync-project-tree / sync (push) Successful in 6s
Release installer / release (push) Successful in -32s
Compose bundle / compose (push) Failing after 21s
Reviewed-on: #9
Reviewed-by: Colby Whitlock <whitlocktech@gmail.com>
2026-08-05 17:51:06 +00:00
fd59a74912 ci(bundle): recognize a linux-aarch64 link asset
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 5s
Step 1 of PLAN.md §5.2's four, and it has to be first. Two rules in this
job are strict in opposite directions: an unrecognized link asset name
fails the run, and a missing REQUIRED platform key fails it too. So the
name must be taught before the release that carries it, and the key can
only be required after one exists -- requiring it first would fail every
bundle for as long as the gap lasts.

This is therefore the mapping only. linux-aarch64 is not in REQUIRED
yet; step 3 promotes it once a link release actually ships the binary,
after which a dropped target reddens CI instead of vanishing silently
from every bundle.

The compose step needed no change: it builds the asset map from the
platform TSV, so a third key costs it nothing.

Edited on `main` and deliberately not on `edge`. The compose job runs
from `main`, and leaving `edge`'s copy untouched means the eventual
cutover merge has nothing to conflict over.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-05 05:22:59 -05:00
3 changed files with 45 additions and 20 deletions

View File

@@ -173,13 +173,23 @@ jobs:
# Map link's binaries onto platform keys. The pattern is asserted, not
# assumed: an unrecognized asset name is a hard failure so that adding
# a target to link's release.yml (aarch64, macOS) surfaces here as a
# red run, rather than being silently dropped from every bundle.
# a target to link's release.yml (macOS, a Windows arm64) surfaces here
# as a red run, rather than being silently dropped from every bundle.
#
# linux-aarch64 is recognized here BEFORE link publishes one
# (PLAN.md §5.2, step 1 of 4). That order is forced by the two rules
# below being strict in opposite directions: an unknown name fails the
# run, and a missing REQUIRED key fails it too. So the name has to be
# taught before the release that carries it, and the key can only be
# required after — requiring it first would fail every bundle for as
# long as the gap lasts. Step 3 promotes it into REQUIRED once a link
# release actually ships the binary.
: > work/link-platforms.tsv
while IFS="$(printf '\t')" read -r NAME URL; do
[ -n "$NAME" ] || continue
case "$NAME" in
*-linux-x86_64) PLAT=linux-x86_64 ;;
*-linux-aarch64) PLAT=linux-aarch64 ;;
*-windows-x86_64.exe) PLAT=windows-x86_64 ;;
*) fail "unrecognized link asset '${NAME}' — bundle.yml does not know what platform to file it under. Teach it this name or the bundle would silently omit the asset." ;;
esac

View File

@@ -39,11 +39,11 @@
# Prerequisites (Settings → Actions → Secrets on RunicGateway/installer):
# REGISTRY_USER — Gitea username the token below belongs to
# REGISTRY_TOKEN — Gitea access token with `write:repository`, so it can push
# the bump commit + tag and create the release.
# Also: `main` must accept a direct push from that user (disable branch
# protection for it, or add it as an exception) — the bump commit lands on main.
# the release tag and create the release.
#
# The bump commit carries `[skip ci]`, so it does not re-trigger this workflow.
# `main` needs NO push exception: this workflow tags and publishes, and never
# writes to a branch. Keeping it that way is deliberate — a first release that
# depends on a write to a protected branch fails at the worst possible moment.
name: Release installer
@@ -66,7 +66,8 @@ env:
jobs:
release:
runs-on: ubuntu-latest
# Don't loop on our own bump commit (belt-and-suspenders with [skip ci]).
# Vestigial since this workflow stopped writing a bump commit, and kept as
# belt-and-braces in case one ever returns.
# Quoted because the expression contains a colon (`chore(release):`), which an
# unquoted YAML scalar would misparse as a mapping value.
if: "${{ !contains(github.event.head_commit.message, 'chore(release): bump version') }}"
@@ -300,33 +301,45 @@ jobs:
ls -l dist && echo "----" && cat dist/SHA256SUMS
# ── RELEASE ENGINE: commit the bump, tag, push ───────────────────────
- name: Commit version bump and push tag
# Tag only — `main` is never pushed to.
#
# This step used to commit the version bump back to main first, and it has
# never executed in any repo that carries it: an EMPTY template expression
# written literally in the comment below (the `$`+`{{ }}` token, spelled
# out here for that reason) makes the runner fail to build the script and
# skip the step WITHOUT failing the job. link/release.yml carried the same
# bug for six releases, which is why its Cargo.toml still says 0.1.0 while
# its tags reach v1.1.1 — the release API creates the tag when it
# publishes, so the pipeline worked by accident.
#
# It also would have been declined if it had run: `main` is protected, and
# the bundle job proved that on 2026-08-05 (`pre-receive hook declined`).
# A first release must not depend on a write to a protected branch.
#
# So the tag is the version, as in servuo-plugins. The version is still
# written into Cargo.toml before building, so a released binary
# self-reports correctly; it is simply not committed back. The next
# version is computed from the newest tag, never from the file.
- name: Push the release tag
if: ${{ steps.plan.outputs.release == 'true' }}
env:
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
run: |
set -euo pipefail
VERSION="${{ steps.plan.outputs.version }}"
TAG="${{ steps.plan.outputs.tag }}"
# Secrets can arrive with a trailing newline (depending on how they were
# pasted); a stray CR/LF corrupts the remote URL ("credential url cannot
# be parsed"). Strip line breaks before building the URL. Passing them via
# env (not inline ${{ }}) also keeps a newline from breaking this script.
# be parsed"). Strip line breaks before building the URL. They are passed
# via env rather than interpolated into this script, so a newline cannot
# break it — do NOT write a template token literally in a comment here,
# or the runner will skip this step without failing the job.
CI_USER="$(printf '%s' "${REGISTRY_USER}" | tr -d '\r\n')"
CI_TOKEN="$(printf '%s' "${REGISTRY_TOKEN}" | tr -d '\r\n')"
git config user.name "installer-ci"
git config user.email "ci@whitlocktech.com"
git remote set-url origin \
"https://${CI_USER}:${CI_TOKEN}@${GITEA_HOST}/${REPO}.git"
git add Cargo.toml Cargo.lock
if ! git diff --cached --quiet; then
git commit -m "chore(release): bump version to ${TAG} [skip ci]"
git push origin "HEAD:main"
else
echo "Version unchanged (first release) — no bump commit needed."
fi
# The tag may already exist when finishing a run that died after
# tagging (see the plan step). `git tag` on an existing name fails
# under `set -e`; pushing an identical existing tag is a harmless

View File

@@ -56,9 +56,11 @@ protocol) or to either component's release version. All three move independently
"tag": "v1.1.0",
"version": "1.1.0",
"protocol": 3,
"assets": { // per-platform: the installer runs on both
"assets": { // per-platform: the installer runs on each
"linux-x86_64": { "name": "…", "url": "…", "sha256": "…" },
"windows-x86_64": { "name": "…", "url": "…", "sha256": "…" }
// "linux-aarch64" joins these from link's first release built for it;
// bundle.yml already knows the name (PLAN.md §5.2)
}
},