Files
lzstealth b3e1eaaae7
Build renameable item readme / build (push) Successful in 9s
Package resourcepack release / release (push) Successful in 4s
Restrict release archive contents
2026-08-12 13:22:47 +01:00

136 lines
5.0 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import os
import sys
import urllib.error
import urllib.parse
import urllib.request
import zipfile
from pathlib import Path
REQUEST_TIMEOUT_SECONDS = 30
def log(message: str) -> None:
print(message, file=sys.stderr, flush=True)
def add_payload_file(archive: zipfile.ZipFile, source_file: Path, relative_path: Path) -> None:
if source_file.exists() and source_file.is_file():
archive.write(source_file, relative_path.as_posix())
def zip_resourcepack(resourcepack_root: Path, archive_path: Path) -> None:
archive_path.parent.mkdir(parents=True, exist_ok=True)
with zipfile.ZipFile(archive_path, mode="w", compression=zipfile.ZIP_DEFLATED) as archive:
add_payload_file(archive, resourcepack_root / "pack.mcmeta", Path("pack.mcmeta"))
add_payload_file(archive, resourcepack_root / "pack.png", Path("pack.png"))
for directory_name in ("assets", "data"):
directory = resourcepack_root / directory_name
if not directory.is_dir():
continue
for source_file in sorted(directory.rglob("*")):
if source_file.is_dir():
continue
relative_path = source_file.relative_to(resourcepack_root)
archive.write(source_file, relative_path.as_posix())
def request_json(request: urllib.request.Request) -> dict[str, object]:
with urllib.request.urlopen(request, timeout=REQUEST_TIMEOUT_SECONDS) as response:
return json.load(response)
def create_release(api_base: str, repository: str, token: str, tag: str, name: str, body: str) -> dict[str, object]:
payload = json.dumps(
{
"tag_name": tag,
"name": name,
"body": body,
"draft": False,
"prerelease": False,
}
).encode("utf-8")
request = urllib.request.Request(
f"{api_base}/repos/{repository}/releases",
data=payload,
method="POST",
headers={
"Authorization": f"token {token}",
"Content-Type": "application/json",
"Accept": "application/json",
},
)
return request_json(request)
def upload_asset(api_base: str, repository: str, token: str, release_id: int, archive_path: Path, asset_name: str) -> dict[str, object]:
with archive_path.open("rb") as handle:
payload = handle.read()
query = urllib.parse.urlencode({"name": asset_name})
request = urllib.request.Request(
f"{api_base}/repos/{repository}/releases/{release_id}/assets?{query}",
data=payload,
method="POST",
headers={
"Authorization": f"token {token}",
"Content-Type": "application/zip",
"Accept": "application/json",
},
)
return request_json(request)
def main() -> int:
parser = argparse.ArgumentParser(description="Package the resource pack and publish it as a Gitea release asset.")
parser.add_argument("--resourcepack-root", default="resourcepack", help="Path to the resource pack root")
parser.add_argument("--archive-path", default="build/resourcepack.zip", help="Path to the generated zip archive")
parser.add_argument("--tag", required=True, help="Release tag to publish")
parser.add_argument("--name", default=None, help="Release name to publish")
parser.add_argument("--body", default=None, help="Release notes/body text")
args = parser.parse_args()
token = os.environ.get("RELEASE_TOKEN") or os.environ.get("GITEA_TOKEN") or os.environ.get("GITHUB_TOKEN")
server_url = os.environ.get("GITEA_SERVER_URL") or os.environ.get("GITHUB_SERVER_URL")
repository = os.environ.get("GITEA_REPOSITORY") or os.environ.get("GITHUB_REPOSITORY")
if not token:
raise SystemExit("RELEASE_TOKEN is required")
if not server_url:
raise SystemExit("GITEA_SERVER_URL or GITHUB_SERVER_URL is required")
if not repository:
raise SystemExit("GITEA_REPOSITORY or GITHUB_REPOSITORY is required")
api_base = server_url.rstrip("/") + "/api/v1"
resourcepack_root = Path(args.resourcepack_root).resolve()
archive_path = Path(args.archive_path).resolve()
release_name = args.name or args.tag
release_body = args.body or f"Automated resource pack release for {args.tag}."
asset_name = f"resourcepack-{args.tag}.zip"
log(f"Packaging resource pack from {resourcepack_root}")
zip_resourcepack(resourcepack_root, archive_path)
log(f"Creating release {args.tag} at {api_base}")
release = create_release(api_base, repository, token, args.tag, release_name, release_body)
release_id = release.get("id")
if not isinstance(release_id, int):
raise SystemExit("Release creation did not return a numeric release id")
log(f"Uploading {asset_name} to release {release_id}")
upload_asset(api_base, repository, token, release_id, archive_path, asset_name)
return 0
if __name__ == "__main__":
raise SystemExit(main())