fix(release): resolve package tags once
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Guard the release-tag flow in update-packages.yml against regressions."""
|
||||
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
|
||||
|
||||
WORKFLOW = Path(__file__).resolve().parents[1] / ".github/workflows/update-packages.yml"
|
||||
text = WORKFLOW.read_text(encoding="utf-8")
|
||||
errors: list[str] = []
|
||||
|
||||
|
||||
def require(condition: bool, message: str) -> None:
|
||||
if not condition:
|
||||
errors.append(message)
|
||||
|
||||
|
||||
def job(name: str) -> str:
|
||||
match = re.search(
|
||||
rf"(?ms)^ {re.escape(name)}:\n(.*?)(?=^ [a-zA-Z0-9_-]+:\n|\Z)", text
|
||||
)
|
||||
require(match is not None, f"missing {name} job")
|
||||
return match.group(0) if match else ""
|
||||
|
||||
|
||||
require(
|
||||
re.search(
|
||||
r"(?ms)^ workflow_dispatch:\n inputs:\n release_tag:\n"
|
||||
r".*? required: true\n",
|
||||
text,
|
||||
)
|
||||
is not None,
|
||||
"workflow_dispatch must require release_tag",
|
||||
)
|
||||
require("github.ref_name" not in text, "release tags must never fall back to a branch")
|
||||
require(
|
||||
text.count("github.event.release.tag_name") == 1,
|
||||
"only the resolver may read the release event tag",
|
||||
)
|
||||
|
||||
resolver = job("resolve-release")
|
||||
require("gh release view \"$REQUESTED_TAG\"" in resolver, "resolver must validate the tag")
|
||||
require("--json tagName,isDraft,publishedAt" in resolver, "resolver must require a published release")
|
||||
require(
|
||||
"tag: ${{ steps.release.outputs.tag }}" in resolver,
|
||||
"resolver must expose one validated tag output",
|
||||
)
|
||||
|
||||
homebrew = job("update-homebrew")
|
||||
winget = job("update-winget")
|
||||
appcast = job("update-appcast-branch")
|
||||
for name, block in (
|
||||
("update-homebrew", homebrew),
|
||||
("update-winget", winget),
|
||||
("update-appcast-branch", appcast),
|
||||
):
|
||||
require("needs: resolve-release" in block, f"{name} must depend on the resolver")
|
||||
|
||||
resolved_output = "${{ needs.resolve-release.outputs.tag }}"
|
||||
require(f"RELEASE_TAG: {resolved_output}" in homebrew, "Homebrew must use the resolved tag")
|
||||
require(f"release-tag: {resolved_output}" in winget, "WinGet must use the resolved tag")
|
||||
require(f"RELEASE_TAG: {resolved_output}" in appcast, "appcast must use the resolved tag")
|
||||
require(
|
||||
'git commit -m "chore: update cask to $RELEASE_TAG"' in homebrew,
|
||||
"Homebrew commit text must include the resolved tag",
|
||||
)
|
||||
require(
|
||||
'git commit-tree "$TREE" -m "Update appcast for $RELEASE_TAG"' in appcast,
|
||||
"appcast commit text must include the resolved tag",
|
||||
)
|
||||
require(
|
||||
'gh release download "$RELEASE_TAG"' in appcast,
|
||||
"appcast download must specify the resolved tag",
|
||||
)
|
||||
|
||||
if errors:
|
||||
for error in errors:
|
||||
print(f"ERROR: {error}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("update-packages workflow release-tag checks passed")
|
||||
Reference in New Issue
Block a user