xanarch-td/tools/forgejo_setup.py
2026-06-03 21:53:16 -04:00

101 lines
3.8 KiB
Python

#!/usr/bin/env python3
"""
forgejo_setup.py
----------------
Creates labels and milestones on your Forgejo repo via the API.
Usage:
python3 tools/forgejo_setup.py \
--url https://your-forgejo.example.com \
--token YOUR_API_TOKEN \
--owner YOUR_USERNAME \
--repo squadron-td
Get a token: Forgejo → Settings → Applications → Generate Token (needs repo scope).
"""
import argparse
import sys
import urllib.request
import urllib.error
import json
def api(base_url, token, method, path, body=None):
url = f"{base_url}/api/v1{path}"
data = json.dumps(body).encode() if body else None
req = urllib.request.Request(url, data=data, method=method)
req.add_header("Authorization", f"token {token}")
req.add_header("Content-Type", "application/json")
try:
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
except urllib.error.HTTPError as e:
body = e.read().decode()
# 422 = already exists — safe to ignore
if e.code == 422:
print(f" (already exists, skipping)")
return None
print(f" ERROR {e.code}: {body}")
return None
LABELS = [
{"name": "type: feature", "color": "#0075ca"},
{"name": "type: fix", "color": "#d73a4a"},
{"name": "type: data", "color": "#e4e669"},
{"name": "type: chore", "color": "#cccccc"},
{"name": "type: docs", "color": "#0052cc"},
{"name": "scope: towers", "color": "#b60205"},
{"name": "scope: economy", "color": "#fbca04"},
{"name": "scope: waves", "color": "#006b75"},
{"name": "scope: ui", "color": "#e99695"},
{"name": "scope: ai", "color": "#c5def5"},
{"name": "scope: multiplayer","color": "#bfd4f2"},
{"name": "priority: high", "color": "#b60205"},
{"name": "priority: low", "color": "#eeeeee"},
{"name": "status: blocked", "color": "#e4e669"},
{"name": "good first issue", "color": "#7057ff"},
]
MILESTONES = [
{"title": "v0.1 — Prototype", "description": "Single lane, 1 race, 10 waves, no economy"},
{"title": "v0.2 — Economy", "description": "Workers, minerals, gas, send system"},
{"title": "v0.3 — Full Waves", "description": "All 31 waves with data-driven definitions"},
{"title": "v0.4 — All Races", "description": "4 builder races with full tower trees"},
{"title": "v0.5 — Multiplayer", "description": "2-player co-op over local network"},
{"title": "v1.0 — Release", "description": "Polished, tested, exportable build"},
]
def main():
p = argparse.ArgumentParser()
p.add_argument("--url", required=True, help="Forgejo base URL (no trailing slash)")
p.add_argument("--token", required=True, help="API token")
p.add_argument("--owner", required=True, help="Repo owner (username or org)")
p.add_argument("--repo", required=True, help="Repo name")
args = p.parse_args()
repo_path = f"/repos/{args.owner}/{args.repo}"
print("=== Creating labels ===")
for label in LABELS:
print(f" {label['name']} ...", end=" ")
result = api(args.url, args.token, "POST", f"{repo_path}/labels", label)
if result:
print(f"created (id={result['id']})")
print("\n=== Creating milestones ===")
for ms in MILESTONES:
print(f" {ms['title']} ...", end=" ")
result = api(args.url, args.token, "POST", f"{repo_path}/milestones", ms)
if result:
print(f"created (id={result['id']})")
print("\n=== Setting default branch to 'develop' ===")
result = api(args.url, args.token, "PATCH", f"{repo_path}",
{"default_branch": "develop"})
if result:
print(f" Default branch set to: {result.get('default_branch')}")
print("\nDone! Visit your repo to verify.")
if __name__ == "__main__":
main()