feat(release): publish changelog-driven notes
This commit is contained in:
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Describe the Gitea request that creates or resynchronizes a release."""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
|
||||
_SEMVER = r"(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)"
|
||||
|
||||
|
||||
class ReleaseRequestError(ValueError):
|
||||
"""A release request could not be prepared safely."""
|
||||
|
||||
|
||||
def build_release_request(
|
||||
version: str, body: str, existing_release: dict[str, Any] | None
|
||||
) -> dict[str, Any]:
|
||||
"""Return the observable POST or PATCH request for a Gitea release."""
|
||||
if not re.fullmatch(_SEMVER, version):
|
||||
raise ReleaseRequestError(f"version is not bare semver: {version!r}")
|
||||
if existing_release is None:
|
||||
return {
|
||||
"method": "POST",
|
||||
"path": "/releases",
|
||||
"payload": {"tag_name": f"v{version}", "name": f"v{version}", "body": body},
|
||||
}
|
||||
|
||||
release_id = existing_release.get("id")
|
||||
if not isinstance(release_id, int):
|
||||
raise ReleaseRequestError("existing release does not contain an integer id")
|
||||
return {
|
||||
"method": "PATCH",
|
||||
"path": f"/releases/{release_id}",
|
||||
"payload": {"body": body},
|
||||
}
|
||||
|
||||
|
||||
def _read_json(path: Path) -> dict[str, Any]:
|
||||
try:
|
||||
value = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError) as error:
|
||||
raise ReleaseRequestError(f"cannot read existing release {path}: {error}") from error
|
||||
if not isinstance(value, dict):
|
||||
raise ReleaseRequestError("existing release must be a JSON object")
|
||||
return value
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--version", required=True)
|
||||
parser.add_argument("--body-file", type=Path, required=True)
|
||||
parser.add_argument("--existing-release", type=Path)
|
||||
args = parser.parse_args(argv)
|
||||
try:
|
||||
body = args.body_file.read_text(encoding="utf-8")
|
||||
existing = _read_json(args.existing_release) if args.existing_release else None
|
||||
print(json.dumps(build_release_request(args.version, body, existing)))
|
||||
except (OSError, ReleaseRequestError) as error:
|
||||
print(f"::error::{error}", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user