ci: move the release workflow's inline Python into tested scripts #479
No reviewers
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis!479
Loading…
Reference in a new issue
No description provided.
Delete branch "ci/release-scripts"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The release page and baseline steps in
release.ymlwere heredoc Python between curl calls, and they run only on a tag push. A mistake in them surfaced at the moment a release was being cut, and nothing exercised the safety properties they encode: draft first, never replace a published release, every asset present before publishing, and the baseline job's early exits.What moved where:
tools/release/publish.py release <tag> <notes> <asset>...(existing-draft check and delete, draft creation, uploads, missing-assets check, publish).tools/release/publish.py baseline <tag>(newest-release check, asset download and comparison, the "main already carries it" check,BREAKING.mdrewrite, branch push, open-PR check, PR creation).verify.py --identity --bundled-client.publish_test.pyfakes the Forgejo release and pull API with a localhttp.serverand uses a bare git remote reached through aurl.insteadOfrewrite of the push URL. It covers 24 cases, and each safety property was checked by mutating the script and confirming the matching case fails. It runs throughpublish.py --self-test(alsojust release-publish-test), and the release and baseline jobs run it before they act.verify_test.pygains the bundled-client cases.Token handling: every forge call runs
curl -fsS -K <conf>, and uploads use-F attachment=@<file>, the same transport the workflow already used. The Authorization header lives in a 0600 curl config, and git authenticates through an extraHeader in a 0600GIT_CONFIG_GLOBALfile. Both are written to a private temporary directory underRUNNER_TEMPthat is removed on exit. Only a 404 on the tag lookup means "no release": that call reads-w '%{http_code}'without-f. The steps run undernix develop .#publish, which gainspython3.Not wired here:
pr.ymldoes not run the new self-test yet. Only the tag jobs andjust release-publish-testrun it, so a PR-level run needs a line next to the existingverify.py --self-test, or the plannedselftestaggregate.The release path only runs on a tag, so replacing the transport the workflow had proven (curl with a -K config file, curl -F multipart, curl's redirect handling) with urllib, a hand-built multipart body and a custom redirect handler traded untested YAML for an untested transport. publish.py now shells out to curl for every forge call, with the Authorization header in a 0600 curl config under a private RUNNER_TEMP directory that is removed when the script exits, the same way the git extraHeader file already was. The one behavior kept from the urllib version is that only a 404 on the tag lookup means "no release": that call runs without -f and reads the status through -w '%{http_code}', so a forge error there fails the job instead of proceeding to a POST. The release and baseline steps run under `nix develop .#publish`, which pins curl; python3 joins that shell, the smaller change than adding curl to the default dev shell. Assisted-by: Claude Code