fix: beads-gitea sync
Some checks failed
Sync Beads to Gitea Issues / sync-beads (push) Failing after 7s
Some checks failed
Sync Beads to Gitea Issues / sync-beads (push) Failing after 7s
This commit is contained in:
parent
d6124c3959
commit
bcd734ccba
@ -1,54 +1,94 @@
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import requests
|
import requests
|
||||||
|
import sys
|
||||||
|
|
||||||
# Configuration
|
# Configuration from Environment
|
||||||
TOKEN = os.getenv("GITEA_TOKEN")
|
TOKEN = os.getenv("GITEA_TOKEN")
|
||||||
URL = os.getenv("GITEA_URL")
|
URL = os.getenv("GITEA_URL")
|
||||||
REPO = os.getenv("REPO_NAME")
|
REPO = os.getenv("REPO_NAME")
|
||||||
HEADERS = {"Authorization": f"token {TOKEN}", "Content-Type": "application/json"}
|
HEADERS = {"Authorization": f"token {TOKEN}", "Content-Type": "application/json"}
|
||||||
|
|
||||||
def get_gitea_issues():
|
|
||||||
"""Fetch all issues from Gitea to map by their Beads ID."""
|
|
||||||
url = f"{URL}/api/v1/repos/{REPO}/issues?state=all"
|
|
||||||
resp = requests.get(url, headers=HEADERS)
|
|
||||||
resp.raise_for_status()
|
|
||||||
# We store the Beads ID in the title or a hidden comment to track them
|
|
||||||
return {issue['title'].split(']')[0][1:]: issue for issue in resp.json() if ']' in issue['title']}
|
|
||||||
|
|
||||||
def sync():
|
def sync():
|
||||||
beads_file = ".beads/issues.jsonl"
|
beads_path = ".beads/issues.jsonl"
|
||||||
if not os.path.exists(beads_file):
|
|
||||||
print("No beads found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
gitea_issues = get_gitea_issues()
|
if not os.path.exists(beads_path):
|
||||||
|
print(f"❌ ERROR: {beads_path} not found.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
with open(beads_file, "r") as f:
|
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:
|
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)
|
data = json.loads(line)
|
||||||
bid = data.get("id")
|
bid = data.get("id")
|
||||||
title = data.get("title")
|
title = data.get("title")
|
||||||
desc = data.get("description", "")
|
# Matches your 'cat' output: "issue_type":"task"
|
||||||
# Mapping Beads status to Gitea states
|
itype = data.get("issue_type", "unknown")
|
||||||
is_closed = data.get("status") in ["closed", "done", "finished"]
|
|
||||||
target_state = "closed" if is_closed else "open"
|
|
||||||
|
|
||||||
|
if not bid:
|
||||||
|
print("⚠️ Skipping line: No ID found.")
|
||||||
|
continue
|
||||||
|
|
||||||
|
unique_title = f"[{bid}] {title}"
|
||||||
payload = {
|
payload = {
|
||||||
"title": f"[{bid}] {title}",
|
"title": unique_title,
|
||||||
"body": f"{desc}\n\n---\n**Beads ID:** `{bid}`\n**Priority:** {data.get('priority', 'N/A')}",
|
"body": f"{data.get('description', 'No description provided.')}\n\n---\n**Beads ID:** `{bid}`\n**Type:** `{itype}`",
|
||||||
"state": target_state
|
"state": "closed"
|
||||||
|
if data.get("status") in ["closed", "done"]
|
||||||
|
else "open",
|
||||||
}
|
}
|
||||||
|
|
||||||
if bid in gitea_issues:
|
if bid in existing:
|
||||||
# Update existing issue if state or title changed
|
print(
|
||||||
issue_number = gitea_issues[bid]['number']
|
f"✅ Updating Gitea Issue #{existing[bid]['number']} for {bid}"
|
||||||
print(f"Updating Issue #{issue_number} ({bid})")
|
)
|
||||||
requests.patch(f"{URL}/api/v1/repos/{REPO}/issues/{issue_number}", headers=HEADERS, json=payload)
|
requests.patch(
|
||||||
|
f"{URL}/api/v1/repos/{REPO}/issues/{existing[bid]['number']}",
|
||||||
|
headers=HEADERS,
|
||||||
|
json=payload,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
# Create new issue
|
print(f"➕ Creating New Gitea Issue for {bid}")
|
||||||
print(f"Creating New Issue for {bid}")
|
r = requests.post(
|
||||||
requests.post(f"{URL}/api/v1/repos/{REPO}/issues", headers=HEADERS, json=payload)
|
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__":
|
if __name__ == "__main__":
|
||||||
sync()
|
sync()
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user