welcome/.gitea/sync_beads.py
rootiest 0bc5fc7030
Some checks failed
Sync Beads to Gitea Issues / sync-beads (push) Failing after 7s
update beads sync conditions
2026-01-19 21:25:59 -05:00

102 lines
3.4 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("URL") # Ensure your Gitea Action uses this variable name
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:
api_url = f"{URL}/api/v1/repos/{REPO}/issues?state=all"
resp = requests.get(api_url, headers=HEADERS)
resp.raise_for_status()
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
skipped_count = 0
with open(beads_path, "r") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
data = json.loads(line)
bid = data.get("id")
status = data.get("status")
title = data.get("title")
itype = data.get("issue_type", "unknown")
# --- THE FIX: FILTER TOMBSTONES ---
if status == "tombstone":
print(f"👻 Skipping tombstone: {bid} ({title})")
skipped_count += 1
continue
# ----------------------------------
if not bid:
print("⚠️ Skipping line: No ID found.")
continue
processed_count += 1
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 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. Active: {processed_count}, Skipped: {skipped_count}")
# We check if we have ANY beads (active or tombstone) to validate the file isn't broken
if (processed_count + skipped_count) == 0:
print("❌ ERROR: File was found but it was EMPTY.")
sys.exit(1)
if __name__ == "__main__":
sync()