You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
emrg: the release tag has a maintained push path when git-over-https is down - #2796
Release stage 2 — publishing the annotated tag — had no maintained path when git-over-https is
unreachable, so releasing under an outage meant writing a throwaway script from notes each time. scripts/push-branch-from-api.py exists to end exactly that flow for the push direction, but it
only pushed refs/heads. This adds --tag beside --branch.
What changed
push_tag + parse_tag + _remote_tag_target in scripts/push-branch-from-api.py, on the
same api() seam the branch path uses. The tag object is created with POST /git/tags, carrying
the tagger's own instant and offset parsed from the local object — a tag stamped "now" is a
different object from the one that was cut — then refs/tags/<name> is created with POST /git/refs. Creating that ref is what fires build-release.yml, so this is the whole of
stage 2.
Four refusals before the first request, each because the alternative costs a build: a
lightweight tag (the workflow's own verify-tag job would refuse it only after a four-platform
build), a tag absent locally, an already-published tag naming a different commit (a version number
is not a branch to rewrite), and neither-or-both of --branch/--tag. Re-running stage 2 after a
dropped connection is a no-op, not an error.
The ref is read back and the run fails if it does not name the object that was created.
How it is verified
tests/test_push_branch_from_api.py grows from 14 to 19 tests, using the fake GitHub the branch
tests already use — extended here with POST /git/tags, GET /git/tags/<sha> and the singular GET /git/ref/tags/<name>, recomputing tag shas with real git hash-object so the payload's
byte-exactness is the thing measured. The offset assertion reads the posted payload
(2023-11-15T06:13:20+08:00 from a +0800 author env), not the object rebuilt from it.
Each refusal was armed in both directions — mutated, its own test watched red, restored:
The module is 19 passed; tests/test_script_output_ascii.py 7 passed (the new output is ASCII, as
that guard requires) and scripts/check-undefined-names.py reads OK over 420 files.
What was not measured
The whole Python suite was not run for this branch, and this PR's CI is pending — the two legs
are the first reading of it. The tool itself was just used to publish this branch (remote dfd4e346, content identical to the local tip), which exercises the branch path but not the new
tag path against the real API.
The test leg went red on the head this PR was opened from, and the cause was in this PR's own new test: tests/test_push_branch_from_api.py spawned the script with text=True and no encoding=, which tests/test_script_decode_is_locale_independent.py::test_every_text_mode_subprocess_pins_its_encoding refuses — a text-mode child decodes with the locale codec, so a non-UTF-8 host (cp936/GBK, cp1252) either raises or silently mojibakes correctly-UTF-8 output.
Fixed in 9b5fcc8d by pinning encoding="utf-8", errors="replace" on that call. Measured both ways on this tree:
with the pin: tests/test_script_decode_is_locale_independent.py + tests/test_push_branch_from_api.py — 38 passed;
with the pin removed: the guard reddens with exactly tests/test_push_branch_from_api.py:742 ... has no encoding= (child not statically known);
tree restored: 19 passed.
The other subprocess.run in the file (the git helper, line 52) passes bytes and takes input=, so it is not in the guard's class and was left as it is.
CI on the new head is pending; nothing here is claimed as green.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2795
Release stage 2 — publishing the annotated tag — had no maintained path when git-over-https is
unreachable, so releasing under an outage meant writing a throwaway script from notes each time.
scripts/push-branch-from-api.pyexists to end exactly that flow for the push direction, but itonly pushed
refs/heads. This adds--tagbeside--branch.What changed
push_tag+parse_tag+_remote_tag_targetinscripts/push-branch-from-api.py, on thesame
api()seam the branch path uses. The tag object is created withPOST /git/tags, carryingthe tagger's own instant and offset parsed from the local object — a tag stamped "now" is a
different object from the one that was cut — then
refs/tags/<name>is created withPOST /git/refs. Creating that ref is what firesbuild-release.yml, so this is the whole ofstage 2.
lightweight tag (the workflow's own
verify-tagjob would refuse it only after a four-platformbuild), a tag absent locally, an already-published tag naming a different commit (a version number
is not a branch to rewrite), and neither-or-both of
--branch/--tag. Re-running stage 2 after adropped connection is a no-op, not an error.
How it is verified
tests/test_push_branch_from_api.pygrows from 14 to 19 tests, using the fake GitHub the branchtests already use — extended here with
POST /git/tags,GET /git/tags/<sha>and the singularGET /git/ref/tags/<name>, recomputing tag shas with realgit hash-objectso the payload'sbyte-exactness is the thing measured. The offset assertion reads the posted payload
(
2023-11-15T06:13:20+08:00from a+0800author env), not the object rebuilt from it.Each refusal was armed in both directions — mutated, its own test watched red, restored:
test_a_lightweight_tag_is_refused_before_any_requesttest_push_tag_creates_the_tag_object_before_the_reftest_push_tag_refuses_to_move_a_published_tagtest_the_cli_takes_exactly_one_of_branch_or_tagThe module is 19 passed;
tests/test_script_output_ascii.py7 passed (the new output is ASCII, asthat guard requires) and
scripts/check-undefined-names.pyreads OK over 420 files.What was not measured
The whole Python suite was not run for this branch, and this PR's CI is pending — the two legs
are the first reading of it. The tool itself was just used to publish this branch (remote
dfd4e346, content identical to the local tip), which exercises the branch path but not the newtag path against the real API.