scripts/ had ~80 flat files. Entry points (ci_*.sh, codegen.sh, run_tests.sh, format_native.sh, setup_hooks.sh, upload-symbols.*) and the shared pubspec_version.py stay at the root; checkers, generators, maestro tooling and release tooling move into subdirectories with their tests. Updated every reference: workflow steps, guard-test glob, Docker COPY paths and .dockerignore whitelist, website audit path, dart test imports, and regenerated the five outputs whose headers embed generator paths.
83 lines
2.5 KiB
Python
83 lines
2.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Guard the release-tag flow in update-packages.yml against regressions."""
|
|
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
|
|
from workflow_yaml import job_block
|
|
|
|
|
|
WORKFLOW = Path(__file__).resolve().parents[2] / ".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:
|
|
block = job_block(text, name)
|
|
require(bool(block), f"missing {name} job")
|
|
return block
|
|
|
|
|
|
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")
|