welcome/.gitea/sync_beads.py
rootiest bcd734ccba
Some checks failed
Sync Beads to Gitea Issues / sync-beads (push) Failing after 7s
fix: beads-gitea sync
2026-01-19 19:51:53 -05:00

95 lines
3.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import os
import requests
import sys
# Configuration from Environment
TOKEN = os.getenv("GITEA_TOKEN")
URL = os.getenv("GITEA_URL")
REPO = os.getenv("REPO_NAME")
HEADERS = {"Authorization": f"token {TOKEN}", "Content-Type": "application/json"}
def sync():
beads_path = ".beads/issues.jsonl"
if not os.path.exists(beads_path):
print(f"❌ ERROR: {beads_path} not found.")
sys.exit(1)
print(f"🔍 Reading Beads from: {beads_path}")
# 1. Fetch existing issues from Gitea
try:
# state=all includes closed issues so we don't create duplicates of finished tasks
api_url = f"{URL}/api/v1/repos/{REPO}/issues?state=all"
resp = requests.get(api_url, headers=HEADERS)
resp.raise_for_status()
# Map by [ID] to identify existing ones
existing = {
i["title"].split("]")[0][1:]: i for i in resp.json() if "]" in i["title"]
}
print(f"📡 Found {len(existing)} existing issues in Gitea.")
except Exception as e:
print(f"❌ Gitea API Connection Failed: {e}")
sys.exit(1)
# 2. Parse the Beads JSONL file
processed_count = 0
with open(beads_path, "r") as f:
for line in f:
processed_count += 1
line = line.strip()
if not line:
continue
print(f"DEBUG: Processing line -> {line}")
try:
data = json.loads(line)
bid = data.get("id")
title = data.get("title")
# Matches your 'cat' output: "issue_type":"task"
itype = data.get("issue_type", "unknown")
if not bid:
print("⚠️ Skipping line: No ID found.")
continue
unique_title = f"[{bid}] {title}"
payload = {
"title": unique_title,
"body": f"{data.get('description', 'No description provided.')}\n\n---\n**Beads ID:** `{bid}`\n**Type:** `{itype}`",
"state": "closed"
if data.get("status") in ["closed", "done"]
else "open",
}
if bid in existing:
print(
f"✅ Updating Gitea Issue #{existing[bid]['number']} for {bid}"
)
requests.patch(
f"{URL}/api/v1/repos/{REPO}/issues/{existing[bid]['number']}",
headers=HEADERS,
json=payload,
)
else:
print(f" Creating New Gitea Issue for {bid}")
r = requests.post(
f"{URL}/api/v1/repos/{REPO}/issues",
headers=HEADERS,
json=payload,
)
r.raise_for_status()
except Exception as e:
print(f"⚠️ Error processing bead: {e}")
print(f"🏁 Finished. Processed {processed_count} beads.")
if processed_count == 0:
print("❌ ERROR: File was found but it was EMPTY. Check your git push.")
sys.exit(1)
if __name__ == "__main__":
sync()