Files
openclaw/tools/github_to_kanban.py
Clawd Bot ca9b510922 chore: align with upstream openclaw/openclaw and overlay local additions
- Reset master to upstream/main (16,697 commits)
- Overlay 2,271 local-only files (skills, tools, workspace, configs, apps)
- Restore IDENTITY.md and USER.md templates
- Build verified, gateway running, Discord working

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:40:46 +01:00

160 lines
4.9 KiB
Python

#!/usr/bin/env python3
"""Import GitHub OpenClaw repos into Kanban as idea tasks.
Usage:
github_to_kanban.py /tmp/github-openclaw.jsonl --min-stars 1
"""
from __future__ import annotations
import argparse
import json
import sys
import time
import urllib.request
from collections import defaultdict
KANBAN_API = "http://localhost:5003/api/tasks"
KANBAN_KEY = "openclaw-tasks-2026"
def http_json(method: str, url: str, payload: dict | None = None) -> dict:
data = None
headers = {
"User-Agent": "openclaw-github-to-kanban/1.0",
}
if payload is not None:
raw = json.dumps(payload).encode("utf-8")
data = raw
headers["Content-Type"] = "application/json"
headers["X-API-Key"] = KANBAN_KEY
req = urllib.request.Request(url, data=data, method=method, headers=headers)
with urllib.request.urlopen(req, timeout=25) as resp:
return json.loads(resp.read().decode("utf-8"))
def get_existing_github_repos() -> set[str]:
"""Get set of GitHub repos already in Kanban."""
tasks = http_json("GET", KANBAN_API)
repos: set[str] = set()
for t in tasks:
title = (t.get("title") or "").lower()
desc = (t.get("description") or "")
# Check title for "GitHub: owner/repo" pattern
if title.startswith("github:"):
repo_name = title.replace("github:", "").strip()
repos.add(repo_name)
# Look for GitHub URLs in description
for line in desc.split("\n"):
if "github.com/" in line:
# Extract repo full name
parts = line.split("github.com/")
if len(parts) > 1:
repo_path = parts[1].split()[0].split("/")[:2]
if len(repo_path) == 2:
full_name = "/".join(repo_path).rstrip(").,;")
repos.add(full_name.lower())
return repos
def main(argv: list[str]) -> int:
ap = argparse.ArgumentParser()
ap.add_argument("jsonl", help="path to GitHub scanner JSONL output")
ap.add_argument("--min-stars", type=int, default=1, help="minimum stars")
ap.add_argument("--dry-run", action="store_true", help="show what would be imported")
ap.add_argument("--sleep", type=float, default=0.2, help="sleep between API calls")
args = ap.parse_args(argv[1:])
existing = get_existing_github_repos()
print(f"# Found {len(existing)} GitHub repos already in Kanban", file=sys.stderr)
created_ids: list[int] = []
skipped_count = 0
with open(args.jsonl, "r", encoding="utf-8") as f:
for line in f:
d = json.loads(line)
repo = d.get("repo", "")
url = d.get("url", "")
description = d.get("description") or "no description"
stars = d.get("stars", 0)
language = d.get("language") or "unknown"
if not repo or not url:
continue
if stars < args.min_stars:
skipped_count += 1
if args.dry_run:
print(f"[SKIP] {repo} ({stars}⭐ < {args.min_stars})", file=sys.stderr)
continue
# Skip if already imported
if repo.lower() in existing:
skipped_count += 1
if args.dry_run:
print(f"[SKIP] {repo} (already in Kanban)", file=sys.stderr)
continue
task_title = f"GitHub: {repo}"
if len(task_title) > 160:
task_title = task_title[:157] + ""
desc_text = (
f"**GitHub OpenClaw Build**\n\n"
f"Repo: {url}\n"
f"Stars: {stars}\n"
f"Language: {language}\n\n"
f"Description: {description}\n\n"
f"Review this build and decide if it's useful for our OpenClaw setup."
)
if args.dry_run:
print(f"[KEEP] {repo} ({stars}⭐)", file=sys.stderr)
created_ids.append(0)
continue
task = http_json(
"POST",
KANBAN_API,
{
"title": task_title,
"description": desc_text,
"status": "queue",
},
)
task_id = int(task.get("id"))
# Tag as GitHub build
tags = f"idea,openclaw,github,build"
if stars >= 10:
tags += ",popular"
http_json(
"PATCH",
f"{KANBAN_API}/{task_id}",
{"tags": tags},
)
created_ids.append(task_id)
time.sleep(args.sleep)
result = {
"dry_run": args.dry_run,
"created": len(created_ids),
"skipped": skipped_count,
}
if not args.dry_run:
result["created_ids"] = created_ids[:20]
print(json.dumps(result, indent=2))
return 0
if __name__ == "__main__":
raise SystemExit(main(sys.argv))