#!/usr/bin/env python3 """TeamBition 数据拉取入口 - 隐秘之潮项目""" import sys import os import json from datetime import datetime # Add project root to path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from tb.tb_config import TBConfig from tb.teambition_api import TeambitionAPI from tb.task_analyzer import TaskAnalyzer from tb.task_manager import TaskManager def fetch_tb_data(send_to_dingtalk=False, mode="daily"): """拉取 TeamBition 任务数据并分析""" config = TBConfig() api = TeambitionAPI(config) analyzer = TaskAnalyzer(config) task_manager = TaskManager( os.path.join(os.path.dirname(__file__), "data", "tb", "task_state.json") ) project_id = config.get("teambition.project_id", "unknown") print(f"\n{'='*60}") print(f"拉取 TeamBition 任务数据 - 项目: {project_id}") print(f"{'='*60}\n") # 1. Export tasks via TeamBition API csv_content = api.fetch_tasks() if not csv_content: print("获取任务数据失败") return None # 2. Save CSV output_dir = os.path.join(os.path.dirname(__file__), "data", "tb") os.makedirs(output_dir, exist_ok=True) csv_path = api.save_csv(csv_content, output_dir=output_dir) if not csv_path: print("保存 CSV 失败") return None # 3. Analyze df = analyzer.load_csv(csv_path) if df.empty: print("CSV 数据为空") return None # 4. Fetch task activities for contribution tracking id_col = next( (c for c in ["任务 ObjectId", "_id", "id", "taskId", "任务ID"] if c in df.columns), None, ) activities = [] if id_col: task_ids = [t for t in df[id_col].dropna().astype(str).tolist() if t and t != "nan"] if task_ids: print(f"获取 {len(task_ids)} 个任务的动态...") try: activities = api.fetch_tasks_activities(task_ids) except Exception as e: print(f"[Warning] 获取动态失败: {e}") # 5. Generate summary summary = analyzer.analyze_tasks(df, activities) summary_path = os.path.join(output_dir, "summary.json") analyzer.save_summary(summary) # 6. Detect changes current_tasks = analyzer.get_task_dict(df) old_state = task_manager.load_state() prev_tasks = old_state.get("tasks", {}) changes = task_manager.detect_changes(prev_tasks, current_tasks) if changes: print("\n[变动检测]") for c in changes: print(f" {c}") else: print("\n[变动检测] 无变动") task_manager.save_state(current_tasks) # 7. Optionally send to DingTalk if send_to_dingtalk: from tb.dingtalk_sender import DingTalkSender dingtalk_config = config.get("dingtalk", {}) if dingtalk_config.get("enabled"): robots = dingtalk_config.get("robots", {}) user_roles = config.get("user_roles", {}) user_mobiles = config.get("user_mobiles", {}) switches = dingtalk_config.get("switches", {}) temp_sender = DingTalkSender("") report, at_mobiles = temp_sender.format_task_report( summary, user_roles, user_mobiles, dashboard_url=config.get("dashboard_url"), switches=switches, ) if switches.get("daily_diff", True): report = temp_sender.format_diff_report(changes, report) for name, bot_cfg in robots.items(): webhook = bot_cfg.get("webhook") secret = bot_cfg.get("secret") if webhook: sender = DingTalkSender(webhook) sender.send_markdown("Teambition 任务日报", report, secret=secret, at_mobiles=at_mobiles) print(f"已发送到钉钉机器人: {name}") # 8. Cleanup CSV if csv_path and os.path.exists(csv_path): os.remove(csv_path) print(f"\n完成! 共 {summary.get('total_tasks', 0)} 个任务") return summary if __name__ == "__main__": import argparse parser = argparse.ArgumentParser(description="TeamBition 数据拉取") parser.add_argument("--dingtalk", action="store_true", help="发送到钉钉群") parser.add_argument("--mode", default="daily", choices=["daily", "interval"]) args = parser.parse_args() fetch_tb_data(send_to_dingtalk=args.dingtalk, mode=args.mode)