diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index b59d401..5e72aae 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -28,6 +28,11 @@ # write:package; THIS workflow additionally needs # `write:repository` so it can push the bump commit + tag # and create the release. Grant that scope to the token. +# The final step also dispatches RunicGateway/installer's +# bundle workflow, so the token ideally has write there too +# — but that is a nicety, not a requirement: without it the +# step warns and the installer's nightly cron picks the +# release up instead. # 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. # @@ -51,6 +56,9 @@ env: BIN: uo-link-sidecar LINUX_TARGET: x86_64-unknown-linux-gnu WINDOWS_TARGET: x86_64-pc-windows-gnu + # Notified after a release so the installer's compat matrix picks up this + # version immediately rather than at its next nightly run (PLAN.md §7.2). + INSTALLER_REPO: RunicGateway/installer jobs: release: @@ -256,3 +264,45 @@ jobs: -F "attachment=@dist/${f}" >/dev/null echo " uploaded ${f}" done + + # ── Recompose the installer's bundle manifest ──────────────────────── + # The installer does not resolve "latest" at run time — it installs the + # exact combination named by a published bundle (docs/installer/PLAN.md + # §7.1). So a sidecar release that nobody recomposes around is a release + # no operator will ever be offered. This step tells the installer repo to + # rebuild that manifest now, instead of leaving the new version invisible + # until its nightly cron. + # + # DISPATCH, DON'T WAIT (PLAN.md §7.3). Gitea's workflow-dispatch endpoint + # returns no run handle, so there is nothing to poll: a waiting step would + # have to guess which run is its own and hold a runner idle to do it. The + # bundle job runs its own gates regardless of who started it. + # + # A failure here is a WARNING, never a failure of this job. The release is + # already published and correct by this point; failing the run would + # misreport that. The installer's nightly cron recomposes from whatever + # the latest releases actually are, so a dropped dispatch self-heals — it + # costs latency, not correctness. + # + # `repository_dispatch` is deliberately not used: support for it is + # uncertain on this Gitea version, while dispatching an existing + # workflow_dispatch workflow via the API works today. + - name: Ask the installer repo to recompose its bundle + if: ${{ steps.plan.outputs.release == 'true' }} + env: + REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} + run: | + set -euo pipefail + CI_TOKEN="$(printf '%s' "${REGISTRY_TOKEN}" | tr -d '\r\n')" + HTTP="$(curl -s -o /dev/null -w '%{http_code}' -X POST \ + -H "Authorization: token ${CI_TOKEN}" \ + -H "Content-Type: application/json" \ + -d '{"ref":"main"}' \ + "https://${GITEA_HOST}/api/v1/repos/${INSTALLER_REPO}/actions/workflows/bundle.yml/dispatches" || echo 000)" + case "$HTTP" in + 20*) echo "Dispatched ${INSTALLER_REPO} bundle.yml (HTTP ${HTTP}) — not waiting for it." ;; + 403|404) + echo "::warning::Could not dispatch ${INSTALLER_REPO} bundle.yml (HTTP ${HTTP}). REGISTRY_TOKEN likely lacks write:repository on that repo. Release ${{ steps.plan.outputs.tag }} is published and fine; its bundle will be composed by the installer's nightly cron instead." ;; + *) + echo "::warning::Dispatching ${INSTALLER_REPO} bundle.yml returned HTTP ${HTTP}. Release ${{ steps.plan.outputs.tag }} is published and fine; the nightly cron will recompose the bundle." ;; + esac