Reorganize repository into pc web shared monorepo
Separate the local recognition, web publishing, and shared data paths while preserving direct script execution and existing site content. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
"""Push climperor and dispatch site-traffic-notify via Gitea API.
|
||||
|
||||
Env: KEYZOO_ASSET_SECRET_PERSONAL_ACCESS_TOKEN_GITEA_1 (or GITEA_TOKEN),
|
||||
optional KEYZOO_ASSET_META_URL.
|
||||
Never prints the token.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
OWNER = "refining"
|
||||
REPO = "climperor"
|
||||
WORKFLOW_FILE = "site-traffic-notify.yml"
|
||||
|
||||
|
||||
def token() -> str:
|
||||
for name in (
|
||||
"KEYZOO_ASSET_SECRET_PERSONAL_ACCESS_TOKEN_GITEA_1",
|
||||
"KEYZOO_ASSET_SECRET_PERSONAL_ACCESS_TOKEN__GITEA_1",
|
||||
"KEYZOO_ASSET_TOKEN",
|
||||
"GITEA_TOKEN",
|
||||
):
|
||||
v = os.environ.get(name)
|
||||
if v:
|
||||
return v
|
||||
raise SystemExit("missing Gitea token")
|
||||
|
||||
|
||||
def base() -> str:
|
||||
return (
|
||||
os.environ.get("GITEA_URL")
|
||||
or os.environ.get("KEYZOO_ASSET_META_URL")
|
||||
or "https://gitea.refining.dev"
|
||||
).rstrip("/")
|
||||
|
||||
|
||||
def api(method: str, path: str, body: dict | None = None) -> tuple[int, dict | list | str]:
|
||||
url = base() + path
|
||||
data = None if body is None else json.dumps(body).encode()
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=data,
|
||||
method=method,
|
||||
headers={
|
||||
"Authorization": f"token {token()}",
|
||||
"Content-Type": "application/json",
|
||||
"Accept": "application/json",
|
||||
},
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=120) as r:
|
||||
raw = r.read().decode()
|
||||
if not raw:
|
||||
return r.status, {}
|
||||
try:
|
||||
return r.status, json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return r.status, raw
|
||||
except urllib.error.HTTPError as e:
|
||||
raw = e.read().decode(errors="replace")
|
||||
try:
|
||||
return e.code, json.loads(raw)
|
||||
except json.JSONDecodeError:
|
||||
return e.code, raw
|
||||
|
||||
|
||||
def push() -> None:
|
||||
# Prefer HTTPS with token in URL for non-interactive push.
|
||||
tok = token()
|
||||
remote = f"https://oauth2:{tok}@gitea.refining.dev/{OWNER}/{REPO}.git"
|
||||
env = os.environ.copy()
|
||||
# Avoid leaking via git trace
|
||||
env.pop("GIT_TRACE", None)
|
||||
r = subprocess.run(
|
||||
["git", "push", remote, "HEAD:main"],
|
||||
cwd=os.path.dirname(os.path.abspath(__file__)) or ".",
|
||||
capture_output=True,
|
||||
text=True,
|
||||
env=env,
|
||||
timeout=180,
|
||||
)
|
||||
# Redact token if it somehow appears
|
||||
out = (r.stdout or "") + (r.stderr or "")
|
||||
out = out.replace(tok, "***")
|
||||
print(out)
|
||||
if r.returncode != 0:
|
||||
raise SystemExit(f"git push failed: {r.returncode}")
|
||||
|
||||
|
||||
def dispatch(day: str = "") -> None:
|
||||
# Gitea: POST /repos/{owner}/{repo}/actions/workflows/{workflow_id}/dispatches
|
||||
# workflow_id can be filename
|
||||
body: dict = {"ref": "main"}
|
||||
if day:
|
||||
body["inputs"] = {"day": day}
|
||||
code, resp = api(
|
||||
"POST",
|
||||
f"/api/v1/repos/{OWNER}/{REPO}/actions/workflows/{WORKFLOW_FILE}/dispatches",
|
||||
body,
|
||||
)
|
||||
print(f"dispatch HTTP {code}: {resp}")
|
||||
if code not in (200, 201, 204):
|
||||
# Fallback: list workflows to find id
|
||||
c2, workflows = api("GET", f"/api/v1/repos/{OWNER}/{REPO}/actions/workflows")
|
||||
print(f"workflows HTTP {c2}: {workflows}")
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def latest_runs() -> None:
|
||||
code, resp = api("GET", f"/api/v1/repos/{OWNER}/{REPO}/actions/runs?limit=5")
|
||||
print(f"runs HTTP {code}")
|
||||
if isinstance(resp, dict):
|
||||
rows = resp.get("workflow_runs") or resp.get("runs") or []
|
||||
elif isinstance(resp, list):
|
||||
rows = resp
|
||||
else:
|
||||
print(resp)
|
||||
return
|
||||
for r in rows[:5]:
|
||||
if isinstance(r, dict):
|
||||
print(
|
||||
f" - id={r.get('id')} name={r.get('name') or r.get('workflow_id')} "
|
||||
f"status={r.get('status')} conclusion={r.get('conclusion')} "
|
||||
f"event={r.get('event')} created={r.get('created_at')}"
|
||||
)
|
||||
|
||||
|
||||
def main() -> int:
|
||||
cmd = sys.argv[1] if len(sys.argv) > 1 else "all"
|
||||
if cmd == "push":
|
||||
push()
|
||||
elif cmd == "dispatch":
|
||||
day = sys.argv[2] if len(sys.argv) > 2 else ""
|
||||
dispatch(day)
|
||||
elif cmd == "runs":
|
||||
latest_runs()
|
||||
elif cmd == "all":
|
||||
push()
|
||||
dispatch("2026-07-27")
|
||||
latest_runs()
|
||||
else:
|
||||
raise SystemExit("usage: push | dispatch [day] | runs | all")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user