diff --git a/scripts/record-state.sh b/scripts/record-state.sh index c21c2de..c7e8b16 100755 --- a/scripts/record-state.sh +++ b/scripts/record-state.sh @@ -2,14 +2,23 @@ # Commit state.json back to this repo so the next scheduled run knows what was # already built. Without this the daily check would rebuild every night. # -# STATE_PUSH_TOKEN token with write access to this repo (required) +# The commit is made through Gitea's file-contents API rather than git push: +# git over HTTP is disabled on this Gitea ("Interacting with repositories by +# HTTP protocol is not allowed"), and the job has no SSH key for the repo. +# +# STATE_PUSH_TOKEN token with write access to this repo (required) +# GITHUB_SERVER_URL set by the runner, e.g. https://gitea.example.org +# GITHUB_REPOSITORY set by the runner, owner/repo +# GITHUB_REF_NAME branch to commit to (default master) set -euo pipefail : "${STATE_PUSH_TOKEN:?STATE_PUSH_TOKEN is required}" +: "${GITHUB_SERVER_URL:?GITHUB_SERVER_URL is required}" +: "${GITHUB_REPOSITORY:?GITHUB_REPOSITORY is required}" python3 - <<'PY' -import json +import base64, json, os, urllib.error, urllib.request meta = json.load(open("release-meta.json")) state = { @@ -22,28 +31,43 @@ state = { "sha256": meta["sha256"], "download_url": meta["download_url"], } -with open("state.json", "w") as fh: - json.dump(state, fh, indent=2) - fh.write("\n") -print(json.dumps(state, indent=2)) +body = json.dumps(state, indent=2) + "\n" +print(body, end="") + +api = f'{os.environ["GITHUB_SERVER_URL"].rstrip("/")}/api/v1/repos/{os.environ["GITHUB_REPOSITORY"]}/contents/state.json' +branch = os.environ.get("GITHUB_REF_NAME") or "master" +headers = { + "Authorization": f'token {os.environ["STATE_PUSH_TOKEN"]}', + "Content-Type": "application/json", +} + +def call(method, url, payload=None): + req = urllib.request.Request(url, method=method, headers=headers, + data=json.dumps(payload).encode() if payload else None) + with urllib.request.urlopen(req, timeout=60) as r: + return json.load(r) + +# Updating an existing file needs its blob sha; a missing file is a create. +existing_sha = None +try: + current = call("GET", f"{api}?ref={branch}") + if base64.b64decode(current["content"]).decode() == body: + print(":: state.json unchanged") + raise SystemExit(0) + existing_sha = current["sha"] +except urllib.error.HTTPError as e: + if e.code != 404: + raise + +payload = { + "branch": branch, + "content": base64.b64encode(body.encode()).decode(), + "message": f'Record build of {meta["jasp_version"]}-{meta["pkgrel"]}', + "author": {"name": "jasp-bin autobuilder", "email": "noreply@weircon.dk"}, + "committer": {"name": "jasp-bin autobuilder", "email": "noreply@weircon.dk"}, +} +if existing_sha: + payload["sha"] = existing_sha +result = call("PUT" if existing_sha else "POST", api, payload) +print(f':: state recorded in {result["commit"]["sha"][:7]}') PY - -# Stage first: `git diff` ignores untracked files, so on the very first run -# (no state.json in the repo yet) it reported "unchanged" and nothing was ever -# recorded, which would have rebuilt and republished every night. -git add state.json -if git diff --cached --quiet -- state.json; then - echo ":: state.json unchanged" - exit 0 -fi - -git config user.name "jasp-bin autobuilder" -git config user.email "noreply@weircon.dk" -git commit -m "Record build of ${GITHUB_REF_NAME:-build}: $(python3 -c 'import json;print(json.load(open("state.json"))["jasp_version"])')" - -origin="$(git remote get-url origin)" -host_path="${origin#*://}" -host_path="${host_path#*@}" -git push "https://x-access-token:${STATE_PUSH_TOKEN}@${host_path}" HEAD:"${GITHUB_REF_NAME:-master}" - -echo ":: state recorded"