MicroFish/.github/workflows/sync-labels.yml

110 lines
3.5 KiB
YAML

name: Sync Labels
on:
workflow_dispatch:
push:
paths:
- ".github/labels.yml"
permissions:
contents: read
issues: write
jobs:
sync:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Install dependencies
run: python -m pip install --disable-pip-version-check pyyaml
- name: Sync labels
env:
GITHUB_TOKEN: ${{ github.token }}
GITHUB_REPOSITORY: ${{ github.repository }}
run: |
python - <<'PY'
import json
import os
import urllib.error
import urllib.parse
import urllib.request
import yaml
token = os.environ["GITHUB_TOKEN"]
owner_repo = os.environ["GITHUB_REPOSITORY"]
base_url = f"https://api.github.com/repos/{owner_repo}"
with open(".github/labels.yml", "r", encoding="utf-8") as fh:
config = yaml.safe_load(fh) or {}
desired_labels = config.get("labels", [])
desired_by_name = {label["name"]: label for label in desired_labels}
headers = {
"Accept": "application/vnd.github+json",
"Authorization": f"Bearer {token}",
"X-GitHub-Api-Version": "2022-11-28",
"User-Agent": "mirofish-label-sync",
}
def request(method, url, payload=None):
data = None
if payload is not None:
data = json.dumps(payload).encode("utf-8")
req = urllib.request.Request(url, data=data, headers=headers, method=method)
with urllib.request.urlopen(req) as response:
raw = response.read()
return json.loads(raw.decode("utf-8")) if raw else None
existing = []
page = 1
while True:
url = f"{base_url}/labels?per_page=100&page={page}"
batch = request("GET", url)
if not batch:
break
existing.extend(batch)
if len(batch) < 100:
break
page += 1
existing_by_name = {label["name"]: label for label in existing}
for name, desired in desired_by_name.items():
payload = {
"new_name": desired["name"],
"color": desired["color"],
"description": desired["description"],
}
if name in existing_by_name:
url = f"{base_url}/labels/{urllib.parse.quote(name, safe='')}"
request("PATCH", url, payload)
print(f"updated {name}")
else:
url = f"{base_url}/labels"
request("POST", url, {
"name": desired["name"],
"color": desired["color"],
"description": desired["description"],
})
print(f"created {name}")
for name in sorted(existing_by_name):
if name not in desired_by_name:
url = f"{base_url}/labels/{urllib.parse.quote(name, safe='')}"
try:
request("DELETE", url)
print(f"deleted {name}")
except urllib.error.HTTPError as exc:
raise RuntimeError(f"Failed to delete label '{name}': {exc.read().decode('utf-8')}") from exc
PY