fix(release): create stable drafts before dispatch
This commit is contained in:
@@ -62,7 +62,7 @@ def _require_ancestry(repo: Path, commit: str) -> None:
|
||||
|
||||
|
||||
def release(commit: str, *, bump: str, repo: Path, remote: str, repository: str,
|
||||
dispatch, autopublish: bool = False) -> dict:
|
||||
execute, autopublish: bool = False) -> dict:
|
||||
"""Claim the derived version, cut its draft, and start the gate."""
|
||||
_require_ancestry(repo, commit)
|
||||
version = derive_next_version(published=None, claims=_claims(repo), bump=bump)
|
||||
@@ -71,7 +71,15 @@ def release(commit: str, *, bump: str, repo: Path, remote: str, repository: str,
|
||||
_git(repo, "push", remote, f"refs/tags/{tag}")
|
||||
url = f"https://github.com/{repository}/releases/tag/{tag}"
|
||||
try:
|
||||
dispatch(["gh", "workflow", "run", WORKFLOW, "--ref", tag, "--repo", repository])
|
||||
execute([
|
||||
"gh", "release", "create", tag, "--repo", repository,
|
||||
"--verify-tag", "--draft", "--generate-notes", "--title", f"Hermes Agent v{version}",
|
||||
])
|
||||
execute([
|
||||
"gh", "workflow", "run", WORKFLOW, "--ref", tag, "--repo", repository,
|
||||
"--raw-field", f"tag={tag}",
|
||||
"--raw-field", f"autopublish={str(autopublish).lower()}",
|
||||
])
|
||||
except Exception as exc:
|
||||
raise ReleaseRefused(f"release {tag} never started: {exc}") from exc
|
||||
return {"version": version, "tag": tag, "commit": commit, "url": url,
|
||||
@@ -104,11 +112,11 @@ def cmd_release(args) -> None:
|
||||
raise SystemExit(f"release: remote {remote!r} does not point at a GitHub repository")
|
||||
commit = _git(repo, "rev-parse", "--verify", f"{args.commit}^{{commit}}")
|
||||
|
||||
def dispatch(command: list[str]) -> None:
|
||||
def execute(command: list[str]) -> None:
|
||||
completed = subprocess.run(command, cwd=repo, capture_output=True, text=True, encoding="utf-8")
|
||||
if completed.returncode != 0:
|
||||
raise RuntimeError(completed.stderr.strip() or "workflow dispatch failed")
|
||||
raise RuntimeError(completed.stderr.strip() or "release command failed")
|
||||
|
||||
result = release(commit, bump=args.bump, repo=repo, remote=remote, repository=repository,
|
||||
dispatch=dispatch, autopublish=args.autopublish)
|
||||
execute=execute, autopublish=args.autopublish)
|
||||
print(result["url"])
|
||||
|
||||
@@ -36,21 +36,26 @@ def _claim(repo, version, commit, actor="release-bot", when="2026-09-22T00:14:00
|
||||
git(repo, "push", "--quiet", "origin", f"refs/tags/v{version}-rc")
|
||||
|
||||
|
||||
def test_release_claims_the_derived_version_and_dispatches(source):
|
||||
def test_release_claims_the_derived_version_creates_a_draft_and_dispatches(source):
|
||||
from scripts.releases.entrypoint import release
|
||||
|
||||
commit = git(source, "rev-parse", "HEAD")
|
||||
calls = []
|
||||
result = release(commit, bump="patch", repo=source, remote="origin",
|
||||
repository="example/hermes-agent", dispatch=calls.append)
|
||||
repository="example/hermes-agent", execute=calls.append, autopublish=True)
|
||||
|
||||
assert result["version"] == "0.21.5"
|
||||
assert result["tag"] == "v0.21.5-rc"
|
||||
assert result["commit"] == commit
|
||||
assert result["url"] == "https://github.com/example/hermes-agent/releases/tag/v0.21.5-rc"
|
||||
assert git(source, "rev-parse", "v0.21.5-rc^{commit}") == commit
|
||||
assert calls == [["gh", "workflow", "run", "stable-release.yml",
|
||||
"--ref", "v0.21.5-rc", "--repo", "example/hermes-agent"]]
|
||||
assert calls == [
|
||||
["gh", "release", "create", "v0.21.5-rc", "--repo", "example/hermes-agent",
|
||||
"--verify-tag", "--draft", "--generate-notes", "--title", "Hermes Agent v0.21.5"],
|
||||
["gh", "workflow", "run", "stable-release.yml", "--ref", "v0.21.5-rc",
|
||||
"--repo", "example/hermes-agent", "--raw-field", "tag=v0.21.5-rc",
|
||||
"--raw-field", "autopublish=true"],
|
||||
]
|
||||
# The claim push names the claim ref and nothing else.
|
||||
pushed = git(source, "ls-remote", "origin", "refs/tags/v0.21.5-rc")
|
||||
assert pushed.startswith(git(source, "rev-parse", "v0.21.5-rc"))
|
||||
@@ -66,19 +71,20 @@ def test_a_commit_behind_an_outstanding_claim_is_refused(source):
|
||||
|
||||
with pytest.raises(ReleaseRefused, match="0\\.21\\.5 already claimed"):
|
||||
release(earlier, bump="patch", repo=source, remote="origin",
|
||||
repository="example/hermes-agent", dispatch=lambda _cmd: pytest.fail("must not dispatch"))
|
||||
repository="example/hermes-agent", execute=lambda _cmd: pytest.fail("must not execute"))
|
||||
assert "v0.21.6-rc" not in git(source, "tag", "--list")
|
||||
|
||||
|
||||
def test_a_dispatch_that_never_starts_is_an_error(source):
|
||||
from scripts.releases.entrypoint import ReleaseRefused, release
|
||||
|
||||
def refuse(_cmd):
|
||||
raise RuntimeError("workflow dispatch rejected")
|
||||
def refuse(command):
|
||||
if command[1:3] == ["workflow", "run"]:
|
||||
raise RuntimeError("workflow dispatch rejected")
|
||||
|
||||
with pytest.raises(ReleaseRefused, match="never started"):
|
||||
release(git(source, "rev-parse", "HEAD"), bump="patch", repo=source, remote="origin",
|
||||
repository="example/hermes-agent", dispatch=refuse)
|
||||
repository="example/hermes-agent", execute=refuse)
|
||||
# The claim stands: a failed start burns the version rather than retrying it.
|
||||
assert "v0.21.5-rc" in git(source, "tag", "--list")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user