From 95cd7d045718a3fae2e04e1fad37a37044ec39e5 Mon Sep 17 00:00:00 2001 From: flowey Date: Thu, 17 Sep 2026 05:20:21 +0000 Subject: [PATCH] ci: fix flake update (#8) Co-authored-by: Floweynt <50057682+Floweynt@users.noreply.github.com> Reviewed-on: https://git.floweytf.com/server/server-config/pulls/8 --- .github/workflows/diff-pr.yml | 10 ++++++++- .github/workflows/flake-update.yml | 8 +++----- ci.py | 33 ++++++++++++++++++++++-------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/.github/workflows/diff-pr.yml b/.github/workflows/diff-pr.yml index 17b0abf..d8fbabb 100644 --- a/.github/workflows/diff-pr.yml +++ b/.github/workflows/diff-pr.yml @@ -17,10 +17,18 @@ jobs: steps: - uses: actions/checkout@v4 with: + ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 + - name: merge base branch + run: | + git config user.email "ci@localhost" + git config user.name "CI" + git fetch origin ${{ github.event.pull_request.base.ref }} + git merge --no-edit origin/${{ github.event.pull_request.base.ref }} + - name: worktree base for diff - run: git worktree add "$RUNNER_TEMP/base" "${{ github.event.pull_request.base.sha }}" + run: git worktree add "$RUNNER_TEMP/base" "origin/${{ github.event.pull_request.base.ref }}" - name: build closures and render diff run: | diff --git a/.github/workflows/flake-update.yml b/.github/workflows/flake-update.yml index 27ec96d..2baadce 100644 --- a/.github/workflows/flake-update.yml +++ b/.github/workflows/flake-update.yml @@ -5,21 +5,19 @@ on: - cron: "17 4 * * *" workflow_dispatch: -permissions: - contents: write - pull-requests: write - jobs: update: runs-on: nix steps: - uses: actions/checkout@v4 + with: + persist-credentials: false - run: nix flake update -L - name: open/update PR env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ secrets.BOT_TOKEN }} API: ${{ github.api_url }} REPO: ${{ github.repository }} run: | diff --git a/ci.py b/ci.py index 61076ea..a3d8db0 100644 --- a/ci.py +++ b/ci.py @@ -8,6 +8,7 @@ import re import subprocess import subprocess_tee import sys +import urllib.error import urllib.request from collections import Counter from pathlib import Path @@ -26,6 +27,10 @@ def git(*args, check=True): return run("git", *args, check=check, capture_output=True) +class GiteaError(Exception): + pass + + def gitea(method, path, body=None): url = f'{os.environ["API"]}/repos/{os.environ["REPO"]}{path}' data = json.dumps(body).encode() if body is not None else None @@ -37,7 +42,11 @@ def gitea(method, path, body=None): with urllib.request.urlopen(req) as resp: raw = resp.read() except urllib.error.HTTPError as e: - sys.exit(f"gitea {method} {path}: {e.code} {e.reason}\n{e.read().decode()}") + try: + detail = json.loads(e.read()).get("message", e.reason) + except (json.JSONDecodeError, UnicodeDecodeError): + detail = e.reason + raise GiteaError(f"{method} {path}: {e.code} {detail}") from None return json.loads(raw) if raw else None @@ -466,16 +475,24 @@ def open_pr(args): host = os.environ["API"].removesuffix("/api/v1") auth = base64.b64encode(f'token:{os.environ["GH_TOKEN"]}'.encode()).decode() - git("-c", f"http.extraHeader=Authorization: Basic {auth}", - "push", "-f", f'{host}/{os.environ["REPO"]}.git', f"HEAD:{args.branch}") + push = git("-c", f"http.extraHeader=Authorization: Basic {auth}", + "push", "-f", f'{host}/{os.environ["REPO"]}.git', f"HEAD:{args.branch}", + check=False) + if push.returncode != 0: + raise RuntimeError(f"git push failed:\n{push.stderr}") - owner = os.environ["REPO"].split("/")[0] - if gitea("GET", f"/pulls?state=open&head={owner}:{args.branch}"): + pulls = gitea("GET", f"/pulls?state=open&base_branch={args.base}") + existing = next((pr for pr in pulls if pr["head"]["ref"] == args.branch), None) + if existing: + print(f"PR #{existing['number']} already open, pushed update") return labels = [label_id(args.label)] if args.label else [] - gitea("POST", "/pulls", - {"title": args.title, "head": args.branch, "base": args.base, - "body": Path(args.body_file).read_text(), "labels": labels}) + pr = gitea("POST", "/pulls", + {"title": args.title, "head": args.branch, "base": args.base, + "body": Path(args.body_file).read_text(), "labels": labels}) + if not pr or "number" not in pr: + raise GiteaError(f"POST /pulls: unexpected response: {json.dumps(pr)}") + print(f"opened PR #{pr['number']}") def main():