#!/usr/bin/env python3 """Feishu Card Parser - extracts PR info from card messages""" import json import sys import os import requests import re # Load config from environment or use defaults APP_ID = os.environ.get("FEISHU_APP_ID", "cli_a929230e37789cd5") APP_SECRET = os.environ.get("FEISHU_APP_SECRET", "0CEneXXjOPMY9amQfziSagchD32GnKOB") def get_token(): """Get Feishu tenant access token""" resp = requests.post( "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal", json={"app_id": APP_ID, "app_secret": APP_SECRET} ) data = resp.json() if data.get("code") != 0: raise Exception(f"Failed to get token: {data}") return data.get("tenant_access_token") def get_message(msg_id, token): """Get message details from Feishu""" resp = requests.get( f"https://open.feishu.cn/open-apis/im/v1/messages/{msg_id}", headers={"Authorization": f"Bearer {token}"} ) data = resp.json() if data.get("code") != 0: raise Exception(f"Failed to get message: {data}") return data.get("data", {}) def extract_pr_info(text_content): """Extract PR info from card text content""" info = {} # Find GitHub PR URL pr_url_match = re.search(r'(https://github\.com/[^/\s]+/[^/\s]+/pull/\d+)', text_content) if pr_url_match: info["pr_url"] = pr_url_match.group(1) # Extract repo and PR number match = re.search(r'github\.com/([^/]+)/([^/]+)/pull/(\d+)', info["pr_url"]) if match: info["repo"] = match.group(1) info["repo_name"] = match.group(2) info["pr_number"] = match.group(3) return info def parse_card(msg_id): """Main parsing function""" token = get_token() message = get_message(msg_id, token) body = message.get("body", {}) msg_type = body.get("msg_type") result = { "message_id": msg_id, "msg_type": msg_type, } if msg_type == "interactive": card = body.get("card", {}) # Extract all text from card elements text_content = "" elements = card.get("elements", []) for elem in elements: if elem.get("tag") == "div": text_elem = elem.get("text", {}) text_content += text_elem.get("content", "") + "\n" elif elem.get("tag") == "markdown": text_content += elem.get("content", "") + "\n" elif elem.get("tag") == "h1" or elem.get("tag") == "h2" or elem.get("tag") == "h3": text_content += elem.get("content", "") + "\n" result["card_text"] = text_content.strip() # Extract PR info pr_info = extract_pr_info(text_content) if pr_info: result.update(pr_info) # Also extract header info header = card.get("header", {}) title_elem = header.get("title", {}) result["card_title"] = title_elem.get("content", "") result["card_template"] = header.get("template", "") elif msg_type == "text": result["text"] = body.get("content", {}).get("text", "") # Try to extract PR URL from text pr_info = extract_pr_info(result["text"]) if pr_info: result.update(pr_info) return result def main(): if len(sys.argv) < 2: # If no argument, try to read from stdin msg_id = sys.stdin.read().strip() if not msg_id: print("Usage: parse_card.py ") print("Or pipe message_id to stdin") sys.exit(1) else: msg_id = sys.argv[1] try: result = parse_card(msg_id) print(json.dumps(result, indent=2, ensure_ascii=False)) return result except Exception as e: print(json.dumps({"error": str(e)}, indent=2)) sys.exit(1) if __name__ == "__main__": main()