diff --git a/.gitea/workflows/ci.yaml b/.gitea/workflows/ci.yaml index ac594f0..70053c0 100644 --- a/.gitea/workflows/ci.yaml +++ b/.gitea/workflows/ci.yaml @@ -101,3 +101,33 @@ jobs: # file. - name: Selftests run: bash scripts/selftest.sh + + release-tag: + name: move v1 to main + # `needs:` is what makes this "after the gate is green" rather than + # merely "after a push": a failed selftest skips this job outright, so + # v1 can never advance onto a broken build. The `if:` restricts it to an + # actual push to main -- a pull_request run targeting main shares this + # workflow but has no ref worth tagging. + needs: selftest + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + runs-on: ubuntu-latest + timeout-minutes: 2 + # Requests write access from the run's built-in token (see README's + # Versioning section for what's actually verified about it). Without + # this the checkout below still succeeds -- it's the push that would be + # rejected, which is a red job, not a silent no-op. + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + + # Lightweight tag, matching what v1 already is (`git cat-file -t v1` + # reports `commit`, not `tag`) -- no identity needed to move it, only + # to push it. + - name: Force v1 to this commit + run: | + git tag -f v1 "${{ github.sha }}" + git push --force origin v1 diff --git a/README.md b/README.md index ef66069..9b916af 100644 --- a/README.md +++ b/README.md @@ -634,13 +634,20 @@ entry, another permission — is a `v2`, not a `v1` move. Everything else moves `v1`: correctness fixes, new optional inputs, and anything internal to `scripts/`. -**Moving the tag is a release step, and it is the operator's.** Merging to -`main` ships nothing to anybody. `v1` is a lightweight tag and does not follow -a branch, so until it is re-pointed every consumer keeps fetching the commit it -already named, whatever `main` now says. The gap is deliberate: re-pointing -`v1` changes what another repository's CI executes on its next run, so it is a -decision taken once, knowingly, after the merge — never something a merge does -by itself. +**Moving the tag is automatic, gated on the same build that gates a PR.** A +`release-tag` job in `.gitea/workflows/ci.yaml` runs on every push to `main`, +`needs: selftest`, and force-moves `v1` to that commit once selftest +succeeds — a broken build never reaches it, so `v1` can't advance onto one. +It pushes with the run's built-in `GITHUB_TOKEN`; if that token turns out not +to have write access, the push step fails and the job goes red in the Actions +UI. That's a loud failure, not the silent one this replaced: `v1` stays put, +and nobody has to notice on their own that it lagged. + +This used to be a manual step, treated as a deliberate release decision taken +once, knowingly, after the merge — in practice it was still forgotten +(gitdan-actions#27): PR #25 merged to `main` and `v1` stayed on the previous +release until someone asked whether it had moved. The manual form below is +now the recovery path, for when the automated job can't push: ```bash git fetch origin @@ -651,9 +658,8 @@ git ls-remote --tags origin v1 # must equal git rev-parse origin/main **Downstream** are emowheel, which pins `cargo-cache@v1` and `cargo-cache-publish@v1` across its CI workflow, and zemyna, migrating to the -same pin. Both pick a move up on their next run with no change on their side, -which is the whole point of the moving pointer and also the reason the move is -not automatic. +same pin. Both pick a move up automatically on their next run with no change +on their side, which is the whole point of the moving pointer. ---