From 1f01affc41b310661916b85b74364421c6013568 Mon Sep 17 00:00:00 2001 From: Jens Tirsvad Nielsen Date: Sat, 3 Oct 2026 12:47:54 +0800 Subject: [PATCH] Add GitHub metadata sync workflow --- .gitea/workflows/sync-github-metadata.yml | 96 +++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 .gitea/workflows/sync-github-metadata.yml diff --git a/.gitea/workflows/sync-github-metadata.yml b/.gitea/workflows/sync-github-metadata.yml new file mode 100644 index 0000000..a5daba4 --- /dev/null +++ b/.gitea/workflows/sync-github-metadata.yml @@ -0,0 +1,96 @@ +name: Sync GitHub mirror metadata + +on: + push: + workflow_dispatch: + schedule: + - cron: "17 3 * * *" + +jobs: + sync-metadata: + runs-on: ubuntu-latest + steps: + - name: Sync description and topics + env: + GITEA_API_URL: ${{ gitea.api_url }} + GITEA_TOKEN: ${{ gitea.token }} + SOURCE_REPOSITORY: ${{ gitea.repository }} + GITHUB_CREDENTIALS: ${{ secrets.CREDENTIALS_FOR_GITHUB }} + GITHUB_REPO: Tirsvad-Udemy-100_days_of_code + run: | + python3 - <<'PY' + import json + import os + import urllib.error + import urllib.request + + def request_json(url, method="GET", headers=None, body=None): + request = urllib.request.Request( + url, + data=json.dumps(body).encode("utf-8") if body is not None else None, + headers=headers or {}, + method=method, + ) + try: + with urllib.request.urlopen(request, timeout=30) as response: + content = response.read() + return json.loads(content) if content else None + except urllib.error.HTTPError as error: + raise RuntimeError( + f"API request failed with HTTP {error.code} ({error.reason})" + ) from None + + credentials = json.loads(os.environ["GITHUB_CREDENTIALS"]) + github_token = credentials.get("GITHUB_PAT") + github_user = credentials.get("GITHUB_USER") + + if not github_token or not github_user: + raise RuntimeError( + "CREDENTIALS_FOR_GITHUB must contain GITHUB_PAT and GITHUB_USER." + ) + + source_owner, separator, source_repo = os.environ[ + "SOURCE_REPOSITORY" + ].partition("/") + if not separator or not source_owner or not source_repo: + raise RuntimeError("Could not determine the Gitea source repository.") + + gitea_api_url = os.environ["GITEA_API_URL"].rstrip("/") + source_url = ( + f"{gitea_api_url}/repos/{source_owner}/{source_repo}" + ) + source = request_json( + source_url, + headers={ + "Authorization": f"token {os.environ['GITEA_TOKEN']}", + "Accept": "application/json", + }, + ) + + github_repo = os.environ["GITHUB_REPO"] + github_api_url = ( + f"https://api.github.com/repos/{github_user}/{github_repo}" + ) + github_headers = { + "Authorization": f"Bearer {github_token}", + "Accept": "application/vnd.github+json", + "X-GitHub-Api-Version": "2022-11-28", + "Content-Type": "application/json", + } + + request_json( + github_api_url, + method="PATCH", + headers=github_headers, + body={"description": source.get("description") or ""}, + ) + + request_json( + f"{github_api_url}/topics", + method="PUT", + headers=github_headers, + body={"names": source.get("topics") or []}, + ) + + print(f"Synced description and topics to {github_user}/{github_repo}.") + PY