feat(static-sites): add scoped Bunny purge gateway
All checks were successful
Test / test (push) Successful in 12s

This commit is contained in:
Eric Wendland 2026-07-17 19:50:31 +02:00
commit 86964aa187
4 changed files with 123 additions and 7 deletions

View file

@ -197,7 +197,44 @@ def purge_bunny_pull_zone(pull_zone_id: str, api_key: str) -> None:
raise DeployError(f"Bunny cache purge failed: {exc.reason}") from exc
def purge_bunny_gateway(endpoint: str, zone: str, password: str) -> None:
parsed = urllib.parse.urlsplit(endpoint)
if (
parsed.scheme != "https"
or not parsed.hostname
or parsed.username is not None
or parsed.password is not None
or parsed.port is not None
or parsed.path not in ("", "/")
or parsed.query
or parsed.fragment
):
raise DeployError("BUNNY_PURGE_ENDPOINT must be an HTTPS origin without a path")
url = (
f"https://{parsed.hostname}/v1/purge/"
f"{urllib.parse.quote(zone, safe='')}"
)
request = urllib.request.Request(
url,
data=b"",
headers={"Authorization": f"Bearer {password}", "Accept": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(request, timeout=60):
return
except urllib.error.HTTPError as exc:
exc.read()
raise DeployError(f"Bunny purge gateway failed: HTTP {exc.code}") from exc
except urllib.error.URLError as exc:
raise DeployError(f"Bunny purge gateway failed: {exc.reason}") from exc
def deploy_bunny(args: argparse.Namespace) -> dict[str, Any]:
if args.purge_endpoint and args.pull_zone_id:
raise DeployError(
"BUNNY_PURGE_ENDPOINT and BUNNY_PULL_ZONE_ID are mutually exclusive"
)
files = collect_files(args.directory)
storage = BunnyStorage(args.zone, args.password, args.endpoint)
remote = parse_manifest(storage.get_manifest())
@ -210,15 +247,19 @@ def deploy_bunny(args: argparse.Namespace) -> dict[str, Any]:
"delete": delete,
"purged": False,
}
if args.dry_run or not result["changed"]:
if args.dry_run:
return result
for path in upload:
storage.upload(files[path])
for path in delete:
storage.delete(path)
storage.upload_manifest(manifest_for(files))
if args.pull_zone_id:
if result["changed"]:
for path in upload:
storage.upload(files[path])
for path in delete:
storage.delete(path)
storage.upload_manifest(manifest_for(files))
if args.purge_endpoint:
purge_bunny_gateway(args.purge_endpoint, args.zone, args.password)
result["purged"] = True
elif args.pull_zone_id:
purge_bunny_pull_zone(args.pull_zone_id, args.api_key)
result["purged"] = True
return result
@ -278,6 +319,9 @@ def parser() -> argparse.ArgumentParser:
bunny.add_argument(
"--pull-zone-id", default=os.environ.get("BUNNY_PULL_ZONE_ID", "")
)
bunny.add_argument(
"--purge-endpoint", default=os.environ.get("BUNNY_PURGE_ENDPOINT", "")
)
bunny.add_argument("--dry-run", action="store_true")
bunny.set_defaults(
handler=deploy_bunny,