intermediate commit
This commit is contained in:
84
tools/release/release-plan.py
Normal file
84
tools/release/release-plan.py
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Generate a dry-run selective GovOPlaN release plan."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
from datetime import UTC, datetime
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from govoplan_release import build_dashboard, build_selective_release_plan
|
||||
from govoplan_release.model import to_jsonable
|
||||
from govoplan_release.workspace import DEFAULT_WORKSPACE_ROOT, META_ROOT
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--workspace-root", type=Path, default=DEFAULT_WORKSPACE_ROOT)
|
||||
parser.add_argument("--repo", action="append", default=[], help="Repository to include. May be repeated.")
|
||||
parser.add_argument("--target-version", help="Default target version for selected repositories.")
|
||||
parser.add_argument(
|
||||
"--repo-version",
|
||||
action="append",
|
||||
default=[],
|
||||
metavar="REPO=VERSION",
|
||||
help="Per-repository target version. May be repeated.",
|
||||
)
|
||||
parser.add_argument("--channel", default="stable", help="Release channel to plan for. Defaults to stable.")
|
||||
parser.add_argument("--online", action="store_true", help="Check published catalog/keyring.")
|
||||
parser.add_argument("--remote-tags", action="store_true", help="Also check remote Git tags. This can be slow across many repositories.")
|
||||
parser.add_argument("--include-migrations", action="store_true", help="Run migration audits before planning.")
|
||||
parser.add_argument("--output", type=Path, help="Write JSON plan to this path.")
|
||||
args = parser.parse_args()
|
||||
|
||||
dashboard = build_dashboard(
|
||||
workspace_root=args.workspace_root,
|
||||
target_version=args.target_version,
|
||||
online=args.online,
|
||||
check_remote_tags=args.remote_tags,
|
||||
check_public_catalog=args.online,
|
||||
include_migrations=args.include_migrations,
|
||||
channel=args.channel,
|
||||
)
|
||||
plan = build_selective_release_plan(
|
||||
dashboard,
|
||||
selected_repos=tuple(args.repo),
|
||||
target_version=args.target_version,
|
||||
repo_versions=parse_repo_versions(tuple(args.repo_version)),
|
||||
channel=args.channel,
|
||||
)
|
||||
payload = json.dumps(to_jsonable(plan), indent=2, sort_keys=True) + "\n"
|
||||
if args.output:
|
||||
output = args.output.expanduser()
|
||||
if not output.is_absolute():
|
||||
output = META_ROOT / output
|
||||
output.parent.mkdir(parents=True, exist_ok=True)
|
||||
output.write_text(payload, encoding="utf-8")
|
||||
print(output)
|
||||
else:
|
||||
print(payload, end="")
|
||||
return 1 if plan.status == "blocked" else 0
|
||||
|
||||
|
||||
def parse_repo_versions(values: tuple[str, ...]) -> dict[str, str]:
|
||||
result: dict[str, str] = {}
|
||||
for value in values:
|
||||
if "=" not in value:
|
||||
raise SystemExit(f"--repo-version must use REPO=VERSION: {value}")
|
||||
repo, version = value.split("=", 1)
|
||||
repo = repo.strip()
|
||||
version = version.strip()
|
||||
if not repo or not version:
|
||||
raise SystemExit(f"--repo-version must use REPO=VERSION: {value}")
|
||||
result[repo] = version
|
||||
return result
|
||||
|
||||
|
||||
def default_plan_path(channel: str) -> Path:
|
||||
stamp = datetime.now(tz=UTC).strftime("%Y%m%d-%H%M%S")
|
||||
return META_ROOT / "runtime" / "release-plans" / f"{channel}-{stamp}.json"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user