CI / extension-version (push) Successful in 3s
CI / lint (push) Successful in 3s
Build images / sign-extension (push) Successful in 4s
Build images / build-ml (push) Successful in 4s
Build images / build-agent (push) Successful in 5s
Build images / build-web (push) Successful in 4s
CI / frontend-build (push) Successful in 18s
extension / lint (push) Successful in 25s
CI / backend-lint-and-test (push) Successful in 30s
CI / integration (push) Successful in 3m52s
Step 2 took the build consequence away from a `v*` tag — `main` has already built and published the commit by the time anyone tags it, and rebuilding would re-push `:c-<sha>`, which rule 145 forbids even when the source matches. That left the tag with nothing to do at all. This is the job it has instead. Step 6 put the derived version in the Settings footer, so an operator can say WHICH build they are running; this says what is in it that was not in the one they ran last month. Both halves of one question (note #3127 §5). The previous release is found by walking ANCESTRY, not by sorting a list. That is load-bearing here specifically: rule 148 moved the tag shape from `v26.05.22.0` to `v2026.08.28.2208`, and lexicographically `v2026...` sorts BEFORE `v26...` — the third character is `0` against `6`. A sorted implementation would reach back past every new-shape tag to the newest old-shape one and publish months of commits as "changes since", looking entirely correct while doing it. `git describe --exclude` is immune to the shape change, and reachability is the more honest question anyway. The publisher GETs and PATCHes rather than POSTing and recovering the id from a 409 — note #3127 §6.7, which is ThoughtSync #2182's bug. A `v*` tag is created once so the conflict path is rare, but "rare" is how that one survived to be found somewhere else. Cross-checks are reported on the release, not enforced. The tag is already pushed by the time this runs, so failing would leave the operator with a tag, no release, and a red lane to explain it — while the release is still the useful object. It says so at the top when the tag names a version the web image does not report, or when the commit is not on `main` and the `:c-` rollback refs it lists were never published. Nothing runs on a schedule and nothing auto-tags on merge. Release tags are bookmarks (note #3127 §0); FC went twelve weeks without one and nothing was wrong. Also here: - `scripts/` joins the ruff lane. release_notes.py runs only on a tag push, so a syntax error there would otherwise surface at the one moment nobody wants to be debugging a workflow. - version.spec.js reads the workflow directory instead of listing three files by hand. Its own comment says the assertion should survive consumers coming and going; the hardcoded list was the part that could not, and release.yml would have joined the directory without joining the check. Tests build a synthetic history spanning the tag-shape change rather than leaning on this repo's tags, so the span assertion holds whether or not a checkout brought the tags along — a span test that quietly skips is worse than one that fails.
81 lines
3.6 KiB
YAML
81 lines
3.6 KiB
YAML
name: Release
|
|
|
|
# A `v*` tag publishes a changelog. It does NOT build anything.
|
|
#
|
|
# Milestone 318 step 2 removed the tag trigger from build.yml: by the time
|
|
# anyone tags a commit, `main` has already built and published it, and a
|
|
# rebuild would re-push `:c-<sha>` — which rule 145 forbids even when the
|
|
# source matches, since image configs carry timestamps and "same source" does
|
|
# not mean "same manifest". That left the tag with no consequence at all.
|
|
#
|
|
# This is the consequence it has instead. Step 6 put the derived version in the
|
|
# Settings footer, so an operator can say WHICH build they are running; this
|
|
# says what is IN it that was not in the one they ran last month. Both halves
|
|
# of one question (note #3127 §5).
|
|
#
|
|
# Nothing here runs on a schedule and nothing auto-tags on merge. Release tags
|
|
# are bookmarks — cut one when you will want to point at that day by name,
|
|
# otherwise don't (note #3127 §0). FC went twelve weeks between v26.06.04.0 and
|
|
# the next one and nothing was wrong. A schedule would turn an optional
|
|
# bookmark back into ceremony, which is the thing this milestone is removing.
|
|
#
|
|
# Cutting the tag is an explicit operator action under rule 2 ("`main` — never
|
|
# without explicit request", which since 2026-08-28 covers PR, merge and tag
|
|
# alike). This lane only decides what happens once they do.
|
|
#
|
|
# Requires repo secret RELEASE_TOKEN with the `write:release` scope — the same
|
|
# PAT build.yml uses for the ext-<version> XPI asset cache.
|
|
|
|
on:
|
|
push:
|
|
tags: ['v*']
|
|
# So a release body can be regenerated after the fact — the publisher PATCHes
|
|
# an existing release rather than falling through on a conflict, so re-running
|
|
# this on a tag rewrites the body instead of silently keeping the first one
|
|
# (note #3127 §6.7).
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: 'Tag to (re)publish notes for'
|
|
required: true
|
|
|
|
jobs:
|
|
changelog:
|
|
runs-on: python-ci
|
|
container:
|
|
image: git.fabledsword.com/bvandeusen/ci-python:3.14
|
|
steps:
|
|
- uses: actions/checkout@v4
|
|
with:
|
|
# Load-bearing twice over: the previous release is found by walking
|
|
# ancestry back through the tag graph, and the cross-check against
|
|
# the derived web version calls artifacts.sh, which reads commit
|
|
# times. A shallow clone would find no previous tag and emit the
|
|
# entire history as the changelog — plausible-looking and wrong.
|
|
fetch-depth: 0
|
|
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
|
|
# The `:c-<sha>` rollback refs are only real if `main` built this commit.
|
|
# The script checks that against origin/main and downgrades the claim to
|
|
# "unverified" when it cannot resolve one; fetching it here means that
|
|
# downgrade stays an actual signal instead of firing on every release.
|
|
- name: Make main's history resolvable
|
|
run: git fetch --no-tags --quiet origin +main:refs/remotes/origin/main || true
|
|
|
|
# TAG goes through the environment, not through `${{ }}` inside the
|
|
# run block. The value is operator-supplied, and an expression expanded
|
|
# into a shell line is expanded BEFORE the shell sees it — there is no
|
|
# quoting that makes that safe. On a tag push it is empty and the script
|
|
# falls back to GITHUB_REF.
|
|
- name: Publish the derived changelog
|
|
env:
|
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
TAG: ${{ github.event.inputs.tag }}
|
|
run: |
|
|
set -eu
|
|
if [ -n "${TAG:-}" ]; then
|
|
python3 scripts/release_notes.py "$TAG"
|
|
else
|
|
python3 scripts/release_notes.py
|
|
fi
|