This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Request an authenticated production refresh after a remote project update."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
|
||||
DISPATCH_URL = (
|
||||
"https://git.labyricorn.com/api/v1/repos/Labyricorn/labyricorn-site/"
|
||||
"actions/workflows/deploy.yml/dispatches"
|
||||
)
|
||||
TOKEN_ENVIRONMENT_VARIABLE = "LABYRICORN_REFRESH_TOKEN"
|
||||
|
||||
|
||||
class RefreshError(RuntimeError):
|
||||
"""Raised when Gitea does not accept a refresh request."""
|
||||
|
||||
|
||||
def dispatch_refresh(token: str, *, timeout: float = 15.0) -> None:
|
||||
token = token.strip()
|
||||
if not token:
|
||||
raise RefreshError("the refresh token is empty")
|
||||
if "\r" in token or "\n" in token:
|
||||
raise RefreshError("the refresh token contains an invalid newline")
|
||||
|
||||
request = Request(
|
||||
DISPATCH_URL,
|
||||
data=json.dumps({"ref": "main"}).encode("utf-8"),
|
||||
headers={
|
||||
"Accept": "application/json",
|
||||
"Authorization": f"token {token}",
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "labyricorn-project-refresh/1",
|
||||
},
|
||||
method="POST",
|
||||
)
|
||||
try:
|
||||
with urlopen(request, timeout=timeout) as response:
|
||||
status = response.getcode()
|
||||
except HTTPError as exc:
|
||||
raise RefreshError(f"Gitea rejected the refresh request (HTTP {exc.code})") from exc
|
||||
except URLError as exc:
|
||||
reason = getattr(exc, "reason", "connection failed")
|
||||
raise RefreshError(f"could not contact Gitea: {reason}") from exc
|
||||
except OSError as exc:
|
||||
raise RefreshError(f"could not send the refresh request: {exc}") from exc
|
||||
|
||||
if not 200 <= status < 300:
|
||||
raise RefreshError(f"Gitea returned unexpected HTTP status {status}")
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--dry-run",
|
||||
action="store_true",
|
||||
help="show the target workflow without sending a request or reading a token",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--timeout",
|
||||
type=float,
|
||||
default=15.0,
|
||||
help="request timeout in seconds (default: 15)",
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
if args.timeout <= 0:
|
||||
parser.error("--timeout must be greater than zero")
|
||||
|
||||
if args.dry_run:
|
||||
print(f"Would dispatch deploy.yml for main via {DISPATCH_URL}")
|
||||
return 0
|
||||
|
||||
token = os.environ.get(TOKEN_ENVIRONMENT_VARIABLE)
|
||||
if token is None:
|
||||
print(
|
||||
f"project-refresh: ERROR: {TOKEN_ENVIRONMENT_VARIABLE} is not set",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 2
|
||||
|
||||
try:
|
||||
dispatch_refresh(token, timeout=args.timeout)
|
||||
except RefreshError as exc:
|
||||
print(f"project-refresh: ERROR: {exc}", file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print("Production refresh requested for site main.")
|
||||
print("Verify the Deploy production Action and the published project revision.")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user