reposync/issue_sync_web.py

1163 lines
48 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
独立的Issue同步Web服务
避免与主项目的Pydantic兼容性问题
"""
import time
import sys
import os
from typing import Dict, Any, Optional
# 添加issue_sync_module到Python路径
issue_sync_path = os.path.join(os.path.dirname(__file__), 'issue_sync_module')
if issue_sync_path not in sys.path:
sys.path.append(issue_sync_path)
try:
from fastapi import FastAPI, BackgroundTasks, Body, Request
from pydantic import BaseModel
import uvicorn
from clients.sync_service import IssueSyncService
from webhook.webhook_handler import WebhookHandler
DEPENDENCIES_AVAILABLE = True
except ImportError as e:
print("缺少依赖: {}".format(str(e)))
DEPENDENCIES_AVAILABLE = False
app = FastAPI(
title="Issue同步服务",
description="在GitHub、Gitee、GitLink之间同步Issues和评论",
version="1.0.0"
)
# 初始化Webhook处理器
webhook_handler = WebhookHandler() if DEPENDENCIES_AVAILABLE else None
class IssueSyncRequest(BaseModel):
"""Issue同步请求"""
source_org: str
source_repo: str
source_platform: str # github, gitee, gitlink
target_org: str
target_repo: str
target_platform: str # github, gitee, gitlink
sync_comments: bool = False
sync_milestones: bool = True # 添加里程碑同步选项,默认启用
update_existing: bool = True # 是否更新已存在的Issue默认启用
enable_deletion: bool = False # 是否启用Issue删除同步默认禁用
class CommentSyncRequest(BaseModel):
"""评论同步请求"""
source_org: str
source_repo: str
source_platform: str
target_org: str
target_repo: str
target_platform: str
issue_title: str
class BatchCommentSyncRequest(BaseModel):
"""批量评论同步请求"""
source_org: str
source_repo: str
source_platform: str
target_org: str
target_repo: str
target_platform: str
class MilestoneSyncRequest(BaseModel):
"""里程碑同步请求"""
source_org: str
source_repo: str
source_platform: str # github, gitee, gitlink
target_org: str
target_repo: str
target_platform: str # github, gitee, gitlink
class BidirectionalSyncRequest(BaseModel):
"""双向同步请求"""
platform_a_org: str
platform_a_repo: str
platform_a: str # github, gitee, gitlink
platform_b_org: str
platform_b_repo: str
platform_b: str # github, gitee, gitlink
conflict_strategy: str = 'prefer_newer' # prefer_newer, prefer_gitlink, prefer_github, prefer_gitee
sync_milestones: bool = True
sync_comments: bool = False # 仅GitLink相关时启用
enable_deletion: bool = False
@app.get("/")
async def root():
"""根路径"""
return {
"service": "Issue同步服务",
"version": "1.0.0",
"status": "运行中",
"dependencies_available": DEPENDENCIES_AVAILABLE,
"endpoints": {
"docs": "/docs",
"status": "/status",
"sync": "/sync",
"sync_bidirectional": "/sync/bidirectional",
"sync_comments": "/sync/comments",
"sync_comments_batch": "/sync/comments/batch",
"sync_milestones": "/sync/milestones"
}
}
@app.get("/status")
async def get_status():
"""获取服务状态"""
return {
"success": True,
"data": {
"service_available": DEPENDENCIES_AVAILABLE,
"supported_platforms": ["github", "gitee", "gitlink"],
"supported_directions": [
"github → gitee",
"gitee → github",
"gitlink → github",
"gitlink → gitee",
"github → gitlink",
"gitee → gitlink"
],
"bidirectional_sync_support": [
"GitLink ↔ GitHub",
"GitLink ↔ Gitee",
"GitHub ↔ Gitee"
],
"milestone_sync_support": {
"gitee → gitlink": True,
"gitlink → gitee": True,
"github → gitlink": True,
"other_directions": "可根据需要扩展"
},
"features": [
"单向Issue同步",
"双向Issue同步",
"Issue内容更新",
"Issue删除同步",
"评论同步",
"里程碑双向同步",
"智能冲突解决",
"批量操作"
],
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
},
"message": "服务状态获取成功"
}
@app.post("/sync")
async def sync_issues(
background_tasks: BackgroundTasks,
request: IssueSyncRequest = Body(..., description='同步请求参数')
):
"""执行Issue同步"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证参数
if not request.source_org or not request.source_repo:
return {
"success": False,
"message": "源仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.target_org or not request.target_repo:
return {
"success": False,
"message": "目标仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证平台类型
valid_platforms = ["github", "gitee", "gitlink"]
if request.source_platform not in valid_platforms or request.target_platform not in valid_platforms:
return {
"success": False,
"message": "不支持的平台类型。支持的平台: {}".format(valid_platforms),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 创建同步服务
sync_service = IssueSyncService()
# 根据平台组合执行同步
sync_method = get_sync_method(sync_service, request.source_platform, request.target_platform)
if not sync_method:
return {
"success": False,
"message": "不支持的同步方向: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 在后台执行同步
background_tasks.add_task(
execute_sync_task,
sync_method,
request.source_org,
request.source_repo,
request.target_org,
request.target_repo,
request.sync_comments,
request.sync_milestones,
request.update_existing,
request.enable_deletion
)
return {
"success": True,
"message": "Issue同步任务已启动: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"task_info": {
"source": "{}/{}".format(request.source_org, request.source_repo),
"target": "{}/{}".format(request.target_org, request.target_repo),
"sync_comments": request.sync_comments,
"sync_milestones": request.sync_milestones,
"update_existing": request.update_existing,
"enable_deletion": request.enable_deletion
}
}
except Exception as e:
print("Issue同步失败: {}".format(str(e)))
return {
"success": False,
"message": "Issue同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/immediate")
async def sync_issues_immediate(
request: IssueSyncRequest = Body(..., description='同步请求参数')
):
"""立即执行Issue同步并返回结果"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证参数
if not request.source_org or not request.source_repo:
return {
"success": False,
"message": "源仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.target_org or not request.target_repo:
return {
"success": False,
"message": "目标仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证平台类型
valid_platforms = ["github", "gitee", "gitlink"]
if request.source_platform not in valid_platforms or request.target_platform not in valid_platforms:
return {
"success": False,
"message": "不支持的平台类型。支持的平台: {}".format(valid_platforms),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 创建同步服务
sync_service = IssueSyncService()
# 根据平台组合执行同步
sync_method = get_sync_method(sync_service, request.source_platform, request.target_platform)
if not sync_method:
return {
"success": False,
"message": "不支持的同步方向: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
print("🚀 开始执行Issue同步: {}/{}{}/{}".format(
request.source_org, request.source_repo, request.target_org, request.target_repo))
print(" • 平台: {}{}".format(request.source_platform, request.target_platform))
print(" • 评论同步: {}".format("启用" if request.sync_comments else "禁用"))
print(" • 里程碑同步: {}".format("启用" if request.sync_milestones else "禁用"))
print(" • 更新已存在Issue: {}".format("启用" if request.update_existing else "禁用"))
print(" • Issue删除同步: {}".format("启用" if request.enable_deletion else "禁用"))
# 检查同步方法支持的参数
import inspect
sig = inspect.signature(sync_method)
# 构建参数字典
kwargs = {}
if 'sync_comments' in sig.parameters:
kwargs['sync_comments'] = request.sync_comments
if 'sync_milestones' in sig.parameters:
kwargs['sync_milestones'] = request.sync_milestones
if 'update_existing' in sig.parameters:
kwargs['update_existing'] = request.update_existing
if 'enable_deletion' in sig.parameters:
kwargs['enable_deletion'] = request.enable_deletion
# 立即执行同步
result = sync_method(
request.source_org,
request.source_repo,
request.target_org,
request.target_repo,
**kwargs
)
if result:
print("✅ Issue同步成功: {}/{}{}/{}".format(
request.source_org, request.source_repo, request.target_org, request.target_repo))
return {
"success": True,
"message": "Issue同步成功完成: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"result": {
"sync_success": True,
"source": "{}/{}".format(request.source_org, request.source_repo),
"target": "{}/{}".format(request.target_org, request.target_repo),
"platform_direction": "{}{}".format(request.source_platform, request.target_platform),
"options_applied": {
"sync_comments": request.sync_comments,
"sync_milestones": request.sync_milestones,
"update_existing": request.update_existing,
"enable_deletion": request.enable_deletion
}
}
}
else:
print("❌ Issue同步失败: {}/{}{}/{}".format(
request.source_org, request.source_repo, request.target_org, request.target_repo))
return {
"success": False,
"message": "Issue同步执行失败",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
except Exception as e:
print("💥 Issue同步任务执行异常: {}".format(str(e)))
return {
"success": False,
"message": "Issue同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/comments")
async def sync_issue_comments(
background_tasks: BackgroundTasks,
request: CommentSyncRequest = Body(..., description='评论同步请求参数')
):
"""同步指定Issue的评论"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.issue_title:
return {
"success": False,
"message": "Issue标题不能为空",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
sync_service = IssueSyncService()
# 根据平台组合选择评论同步方法
comment_method = get_comment_sync_method(sync_service, request.source_platform, request.target_platform)
if not comment_method:
return {
"success": False,
"message": "不支持的评论同步方向: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 在后台执行评论同步
background_tasks.add_task(
execute_comment_sync_task,
comment_method,
request.source_org,
request.source_repo,
request.target_org,
request.target_repo,
request.issue_title
)
return {
"success": True,
"message": "评论同步任务已启动: {}".format(request.issue_title),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"task_info": {
"source": "{}/{}".format(request.source_org, request.source_repo),
"target": "{}/{}".format(request.target_org, request.target_repo),
"issue_title": request.issue_title
}
}
except Exception as e:
print("评论同步失败: {}".format(str(e)))
return {
"success": False,
"message": "评论同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/comments/batch")
async def sync_all_comments(
background_tasks: BackgroundTasks,
request: BatchCommentSyncRequest = Body(..., description='批量评论同步请求参数')
):
"""批量同步所有Issue的评论"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
sync_service = IssueSyncService()
# 在后台执行批量评论同步
background_tasks.add_task(
execute_batch_comment_sync_task,
sync_service,
request.source_org,
request.source_repo,
request.source_platform,
request.target_org,
request.target_repo,
request.target_platform
)
return {
"success": True,
"message": "批量评论同步任务已启动: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"task_info": {
"source": "{}/{}".format(request.source_org, request.source_repo),
"target": "{}/{}".format(request.target_org, request.target_repo)
}
}
except Exception as e:
print("批量评论同步失败: {}".format(str(e)))
return {
"success": False,
"message": "批量评论同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/milestones")
async def sync_milestones(
background_tasks: BackgroundTasks,
request: MilestoneSyncRequest = Body(..., description='里程碑同步请求参数')
):
"""执行里程碑同步"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证参数
if not request.source_org or not request.source_repo:
return {
"success": False,
"message": "源仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.target_org or not request.target_repo:
return {
"success": False,
"message": "目标仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证平台类型
valid_platforms = ["github", "gitee", "gitlink"]
if request.source_platform not in valid_platforms or request.target_platform not in valid_platforms:
return {
"success": False,
"message": "不支持的平台类型。支持的平台: {}".format(valid_platforms),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 创建同步服务
sync_service = IssueSyncService()
# 根据平台组合获取里程碑同步方法
milestone_method = get_milestone_sync_method(sync_service, request.source_platform, request.target_platform)
if not milestone_method:
return {
"success": False,
"message": "不支持的里程碑同步方向: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 在后台执行里程碑同步
background_tasks.add_task(
execute_milestone_sync_task,
milestone_method,
request.source_org,
request.source_repo,
request.target_org,
request.target_repo,
request.source_platform,
request.target_platform
)
return {
"success": True,
"message": "里程碑同步任务已启动: {}{}".format(request.source_platform, request.target_platform),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"task_info": {
"source": "{}/{}".format(request.source_org, request.source_repo),
"target": "{}/{}".format(request.target_org, request.target_repo),
"sync_direction": "{}{}".format(request.source_platform, request.target_platform)
}
}
except Exception as e:
print("里程碑同步失败: {}".format(str(e)))
return {
"success": False,
"message": "里程碑同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/bidirectional")
async def bidirectional_sync(
background_tasks: BackgroundTasks,
request: BidirectionalSyncRequest = Body(..., description='双向同步请求参数')
):
"""执行双向Issue同步"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证参数
if not request.platform_a_org or not request.platform_a_repo:
return {
"success": False,
"message": "平台A仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.platform_b_org or not request.platform_b_repo:
return {
"success": False,
"message": "平台B仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证平台类型
valid_platforms = ["github", "gitee", "gitlink"]
if request.platform_a not in valid_platforms or request.platform_b not in valid_platforms:
return {
"success": False,
"message": "不支持的平台类型。支持的平台: {}".format(valid_platforms),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证不能选择相同平台
if request.platform_a == request.platform_b:
return {
"success": False,
"message": "双向同步的两个平台不能相同",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 创建同步服务
sync_service = IssueSyncService()
# 根据平台组合获取双向同步方法
bidirectional_method = get_bidirectional_sync_method(sync_service, request.platform_a, request.platform_b)
if not bidirectional_method:
return {
"success": False,
"message": "不支持的双向同步平台组合: {}{}".format(request.platform_a, request.platform_b),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 在后台执行双向同步
background_tasks.add_task(
execute_bidirectional_sync_task,
bidirectional_method,
request.platform_a_org,
request.platform_a_repo,
request.platform_a,
request.platform_b_org,
request.platform_b_repo,
request.platform_b,
request.conflict_strategy,
request.sync_milestones,
request.sync_comments,
request.enable_deletion
)
return {
"success": True,
"message": "双向同步任务已启动: {}{}".format(request.platform_a, request.platform_b),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"task_info": {
"platform_a": "{}/{}".format(request.platform_a_org, request.platform_a_repo),
"platform_b": "{}/{}".format(request.platform_b_org, request.platform_b_repo),
"conflict_strategy": request.conflict_strategy,
"sync_milestones": request.sync_milestones,
"sync_comments": request.sync_comments,
"enable_deletion": request.enable_deletion
}
}
except Exception as e:
print("双向同步失败: {}".format(str(e)))
return {
"success": False,
"message": "双向同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.post("/sync/bidirectional/immediate")
async def bidirectional_sync_immediate(
request: BidirectionalSyncRequest = Body(..., description='双向同步请求参数')
):
"""立即执行双向Issue同步并返回结果"""
try:
if not DEPENDENCIES_AVAILABLE:
return {
"success": False,
"message": "Issue同步服务依赖不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证参数
if not request.platform_a_org or not request.platform_a_repo:
return {
"success": False,
"message": "平台A仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if not request.platform_b_org or not request.platform_b_repo:
return {
"success": False,
"message": "平台B仓库信息不完整",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证平台类型
valid_platforms = ["github", "gitee", "gitlink"]
if request.platform_a not in valid_platforms or request.platform_b not in valid_platforms:
return {
"success": False,
"message": "不支持的平台类型。支持的平台: {}".format(valid_platforms),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 验证不能选择相同平台
if request.platform_a == request.platform_b:
return {
"success": False,
"message": "双向同步的两个平台不能相同",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 创建同步服务
sync_service = IssueSyncService()
# 根据平台组合获取双向同步方法
bidirectional_method = get_bidirectional_sync_method(sync_service, request.platform_a, request.platform_b)
if not bidirectional_method:
return {
"success": False,
"message": "不支持的双向同步平台组合: {}{}".format(request.platform_a, request.platform_b),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
print("🔄 开始执行双向同步: {}{}".format(request.platform_a, request.platform_b))
print(" • 平台A: {}/{}".format(request.platform_a_org, request.platform_a_repo))
print(" • 平台B: {}/{}".format(request.platform_b_org, request.platform_b_repo))
print(" • 冲突策略: {}".format(request.conflict_strategy))
print(" • 里程碑同步: {}".format("启用" if request.sync_milestones else "禁用"))
print(" • 评论同步: {}".format("启用" if request.sync_comments else "禁用"))
print(" • Issue删除同步: {}".format("启用" if request.enable_deletion else "禁用"))
# 检查双向同步方法支持的参数
import inspect
sig = inspect.signature(bidirectional_method)
# 构建参数字典
kwargs = {}
if 'conflict_strategy' in sig.parameters:
kwargs['conflict_strategy'] = request.conflict_strategy
if 'sync_milestones' in sig.parameters:
kwargs['sync_milestones'] = request.sync_milestones
if 'sync_comments' in sig.parameters:
kwargs['sync_comments'] = request.sync_comments
if 'enable_deletion' in sig.parameters:
kwargs['enable_deletion'] = request.enable_deletion
# 根据方法名和平台顺序调用相应的双向同步方法
method_name = bidirectional_method.__name__
if method_name == 'bidirectional_sync_gitlink_github':
# 确定GitLink和GitHub的顺序
if request.platform_a == 'gitlink':
result = bidirectional_method(
request.platform_a_org, request.platform_a_repo, # GitLink
request.platform_b_org, request.platform_b_repo, # GitHub
**kwargs
)
else: # GitHub是平台A
result = bidirectional_method(
request.platform_b_org, request.platform_b_repo, # GitLink
request.platform_a_org, request.platform_a_repo, # GitHub
**kwargs
)
elif method_name == 'bidirectional_sync_gitlink_gitee':
# 确定GitLink和Gitee的顺序
if request.platform_a == 'gitlink':
result = bidirectional_method(
request.platform_a_org, request.platform_a_repo, # GitLink
request.platform_b_org, request.platform_b_repo, # Gitee
**kwargs
)
else: # Gitee是平台A
result = bidirectional_method(
request.platform_b_org, request.platform_b_repo, # GitLink
request.platform_a_org, request.platform_a_repo, # Gitee
**kwargs
)
elif method_name == 'bidirectional_sync_github_gitee':
# 确定GitHub和Gitee的顺序
if request.platform_a == 'github':
result = bidirectional_method(
request.platform_a_org, request.platform_a_repo, # GitHub
request.platform_b_org, request.platform_b_repo, # Gitee
**kwargs
)
else: # Gitee是平台A
result = bidirectional_method(
request.platform_b_org, request.platform_b_repo, # GitHub
request.platform_a_org, request.platform_a_repo, # Gitee
**kwargs
)
else:
print("❌ 未知的双向同步方法: {}".format(method_name))
return {
"success": False,
"message": "未知的双向同步方法: {}".format(method_name),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if result and isinstance(result, dict):
print("✅ 双向同步完成!")
# 分析同步结果
total_created = 0
total_updated = 0
total_conflicts = result.get('conflicts_resolved', 0)
total_processed = result.get('total_processed', 0)
# 统计各方向的结果
direction_results = {}
for direction_key in result:
if '_to_' in direction_key and isinstance(result[direction_key], dict):
direction_stats = result[direction_key]
direction_name = direction_key.replace('_', '').title()
direction_results[direction_name] = direction_stats
total_created += direction_stats.get('created', 0)
total_updated += direction_stats.get('updated', 0)
return {
"success": True,
"message": "双向同步成功完成: {}{}".format(request.platform_a, request.platform_b),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S'),
"result": {
"sync_success": True,
"platform_a": "{}/{}".format(request.platform_a_org, request.platform_a_repo),
"platform_b": "{}/{}".format(request.platform_b_org, request.platform_b_repo),
"platform_combination": "{}{}".format(request.platform_a, request.platform_b),
"summary": {
"total_processed": total_processed,
"total_created": total_created,
"total_updated": total_updated,
"conflicts_resolved": total_conflicts
},
"direction_details": direction_results,
"options_applied": {
"conflict_strategy": request.conflict_strategy,
"sync_milestones": request.sync_milestones,
"sync_comments": request.sync_comments,
"enable_deletion": request.enable_deletion
},
"raw_result": result
}
}
else:
print("❌ 双向同步失败")
return {
"success": False,
"message": "双向同步执行失败",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
except Exception as e:
print("💥 双向同步任务执行异常: {}".format(str(e)))
return {
"success": False,
"message": "双向同步失败: {}".format(str(e)),
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
def get_sync_method(sync_service: IssueSyncService, source_platform: str, target_platform: str):
"""根据平台获取对应的同步方法"""
sync_mapping = {
("github", "gitee"): sync_service.sync_github_to_gitee,
("gitee", "github"): sync_service.sync_gitee_to_github,
("gitlink", "github"): sync_service.sync_gitlink_to_github,
("gitlink", "gitee"): sync_service.sync_gitlink_to_gitee,
("github", "gitlink"): sync_service.sync_github_to_gitlink,
("gitee", "gitlink"): sync_service.sync_gitee_to_gitlink,
}
return sync_mapping.get((source_platform, target_platform))
def get_comment_sync_method(sync_service: IssueSyncService, source_platform: str, target_platform: str):
"""根据平台获取对应的评论同步方法"""
comment_mapping = {
("github", "gitee"): sync_service.sync_issue_comments_github_to_gitee,
("gitee", "github"): sync_service.sync_issue_comments_gitee_to_github,
("gitlink", "github"): sync_service.sync_issue_comments_gitlink_to_github,
("gitlink", "gitee"): sync_service.sync_issue_comments_gitlink_to_gitee,
}
return comment_mapping.get((source_platform, target_platform))
def get_milestone_sync_method(sync_service: IssueSyncService, source_platform: str, target_platform: str):
"""根据平台获取对应的里程碑同步方法"""
milestone_mapping = {
("gitee", "gitlink"): sync_service.sync_milestones_gitee_to_gitlink,
("gitlink", "gitee"): sync_service.sync_milestones_gitlink_to_gitee,
("github", "gitlink"): sync_service.sync_milestones_github_to_gitlink,
}
return milestone_mapping.get((source_platform, target_platform))
def get_bidirectional_sync_method(sync_service: IssueSyncService, platform_a: str, platform_b: str):
"""根据平台组合获取对应的双向同步方法"""
# 双向同步支持的平台组合(顺序不重要)
bidirectional_mapping = {
("gitlink", "github"): sync_service.bidirectional_sync_gitlink_github,
("github", "gitlink"): sync_service.bidirectional_sync_gitlink_github,
("gitlink", "gitee"): sync_service.bidirectional_sync_gitlink_gitee,
("gitee", "gitlink"): sync_service.bidirectional_sync_gitlink_gitee,
("github", "gitee"): sync_service.bidirectional_sync_github_gitee,
("gitee", "github"): sync_service.bidirectional_sync_github_gitee,
}
return bidirectional_mapping.get((platform_a, platform_b))
async def execute_sync_task(sync_method, source_org: str, source_repo: str,
target_org: str, target_repo: str, sync_comments: bool, sync_milestones: bool = True,
update_existing: bool = True, enable_deletion: bool = False):
"""执行同步任务"""
try:
print("🚀 开始执行Issue同步: {}/{}{}/{}".format(source_org, source_repo, target_org, target_repo))
print(" • 评论同步: {}".format("启用" if sync_comments else "禁用"))
print(" • 里程碑同步: {}".format("启用" if sync_milestones else "禁用"))
print(" • 更新已存在Issue: {}".format("启用" if update_existing else "禁用"))
print(" • Issue删除同步: {}".format("启用" if enable_deletion else "禁用"))
# 检查同步方法支持的参数
import inspect
sig = inspect.signature(sync_method)
# 构建参数字典
kwargs = {}
if 'sync_comments' in sig.parameters:
kwargs['sync_comments'] = sync_comments
if 'sync_milestones' in sig.parameters:
kwargs['sync_milestones'] = sync_milestones
if 'update_existing' in sig.parameters:
kwargs['update_existing'] = update_existing
if 'enable_deletion' in sig.parameters:
kwargs['enable_deletion'] = enable_deletion
# 执行同步
result = sync_method(source_org, source_repo, target_org, target_repo, **kwargs)
if result:
print("✅ Issue同步成功: {}/{}{}/{}".format(source_org, source_repo, target_org, target_repo))
else:
print("❌ Issue同步失败: {}/{}{}/{}".format(source_org, source_repo, target_org, target_repo))
except Exception as e:
print("💥 Issue同步任务执行异常: {}".format(str(e)))
async def execute_comment_sync_task(comment_method, source_org: str, source_repo: str,
target_org: str, target_repo: str, issue_title: str):
"""执行评论同步任务"""
try:
print("🚀 开始执行评论同步: {}".format(issue_title))
result = comment_method(source_org, source_repo, target_org, target_repo, issue_title)
if result:
print("✅ 评论同步成功: {}".format(issue_title))
else:
print("❌ 评论同步失败: {}".format(issue_title))
except Exception as e:
print("💥 评论同步任务执行异常: {}".format(str(e)))
async def execute_batch_comment_sync_task(sync_service: IssueSyncService,
source_org: str, source_repo: str, source_platform: str,
target_org: str, target_repo: str, target_platform: str):
"""执行批量评论同步任务"""
try:
print("🚀 开始执行批量评论同步: {}{}".format(source_platform, target_platform))
result = sync_service.sync_all_issue_comments(
source_org, source_repo, source_platform,
target_org, target_repo, target_platform
)
if result:
print("✅ 批量评论同步成功: {}{}".format(source_platform, target_platform))
else:
print("❌ 批量评论同步失败: {}{}".format(source_platform, target_platform))
except Exception as e:
print("💥 批量评论同步任务执行异常: {}".format(str(e)))
async def execute_milestone_sync_task(milestone_method, source_org: str, source_repo: str,
target_org: str, target_repo: str,
source_platform: str, target_platform: str):
"""执行里程碑同步任务"""
try:
print("🎯 开始执行里程碑同步: {}{}".format(source_platform, target_platform))
print(" • 源仓库: {}/{}".format(source_org, source_repo))
print(" • 目标仓库: {}/{}".format(target_org, target_repo))
result = milestone_method(source_org, source_repo, target_org, target_repo)
if result and isinstance(result, dict):
print("✅ 里程碑同步完成!")
print("📊 同步统计:")
print(" • 源平台里程碑总数: {}".format(result.get('total_gitee_milestones', result.get('total_github_milestones', result.get('total_gitlink_milestones', 0)))))
print(" • 目标平台已存在: {}".format(result.get('existing_in_gitlink', result.get('existing_in_gitee', 0))))
print(" • 成功创建: {}".format(result.get('created_in_gitlink', result.get('created_in_gitee', 0))))
print(" • 创建失败: {}".format(result.get('failed_to_create', 0)))
print(" • 建立映射关系: {}".format(len(result.get('milestone_mapping', {}))))
if result.get('created_milestones'):
print("📝 已创建的里程碑:")
for milestone in result['created_milestones']:
print(" - '{}'".format(milestone.get('gitee_title', milestone.get('github_title', milestone.get('gitlink_title', '未知')))))
else:
print("❌ 里程碑同步失败")
except Exception as e:
print("💥 里程碑同步任务执行异常: {}".format(str(e)))
async def execute_bidirectional_sync_task(bidirectional_method,
platform_a_org: str, platform_a_repo: str, platform_a: str,
platform_b_org: str, platform_b_repo: str, platform_b: str,
conflict_strategy: str, sync_milestones: bool,
sync_comments: bool, enable_deletion: bool):
"""执行双向同步任务"""
try:
print("🔄 开始执行双向同步: {}{}".format(platform_a, platform_b))
print(" • 平台A: {}/{}".format(platform_a_org, platform_a_repo))
print(" • 平台B: {}/{}".format(platform_b_org, platform_b_repo))
print(" • 冲突策略: {}".format(conflict_strategy))
print(" • 里程碑同步: {}".format("启用" if sync_milestones else "禁用"))
print(" • 评论同步: {}".format("启用" if sync_comments else "禁用"))
print(" • Issue删除同步: {}".format("启用" if enable_deletion else "禁用"))
# 检查双向同步方法支持的参数
import inspect
sig = inspect.signature(bidirectional_method)
# 构建参数字典
kwargs = {}
if 'conflict_strategy' in sig.parameters:
kwargs['conflict_strategy'] = conflict_strategy
if 'sync_milestones' in sig.parameters:
kwargs['sync_milestones'] = sync_milestones
if 'sync_comments' in sig.parameters:
kwargs['sync_comments'] = sync_comments
if 'enable_deletion' in sig.parameters:
kwargs['enable_deletion'] = enable_deletion
# 根据方法名和平台顺序调用相应的双向同步方法
method_name = bidirectional_method.__name__
if method_name == 'bidirectional_sync_gitlink_github':
# 确定GitLink和GitHub的顺序
if platform_a == 'gitlink':
result = bidirectional_method(
platform_a_org, platform_a_repo, # GitLink
platform_b_org, platform_b_repo, # GitHub
**kwargs
)
else: # GitHub是平台A
result = bidirectional_method(
platform_b_org, platform_b_repo, # GitLink
platform_a_org, platform_a_repo, # GitHub
**kwargs
)
elif method_name == 'bidirectional_sync_gitlink_gitee':
# 确定GitLink和Gitee的顺序
if platform_a == 'gitlink':
result = bidirectional_method(
platform_a_org, platform_a_repo, # GitLink
platform_b_org, platform_b_repo, # Gitee
**kwargs
)
else: # Gitee是平台A
result = bidirectional_method(
platform_b_org, platform_b_repo, # GitLink
platform_a_org, platform_a_repo, # Gitee
**kwargs
)
elif method_name == 'bidirectional_sync_github_gitee':
# 确定GitHub和Gitee的顺序
if platform_a == 'github':
result = bidirectional_method(
platform_a_org, platform_a_repo, # GitHub
platform_b_org, platform_b_repo, # Gitee
**kwargs
)
else: # Gitee是平台A
result = bidirectional_method(
platform_b_org, platform_b_repo, # GitHub
platform_a_org, platform_a_repo, # Gitee
**kwargs
)
else:
print("❌ 未知的双向同步方法: {}".format(method_name))
return
if result and isinstance(result, dict):
print("✅ 双向同步完成!")
print("📊 双向同步统计:")
# 输出各方向的统计
for direction_key in result:
if '_to_' in direction_key and isinstance(result[direction_key], dict):
direction_stats = result[direction_key]
direction_name = direction_key.replace('_', '').title()
print(" 📤 {}:".format(direction_name))
print(" • 新建: {}".format(direction_stats.get('created', 0)))
print(" • 更新: {}".format(direction_stats.get('updated', 0)))
print(" • 跳过: {}".format(direction_stats.get('skipped', 0)))
print(" • 失败: {}".format(direction_stats.get('failed', 0)))
# 输出总体统计
print(" 🔄 总体统计:")
print(" • 处理Issue总数: {}".format(result.get('total_processed', 0)))
print(" • 解决冲突: {}".format(result.get('conflicts_resolved', 0)))
# 输出里程碑同步结果
if result.get('milestone_sync_result'):
milestone_result = result['milestone_sync_result']
print(" 🏁 里程碑同步统计:")
for key, value in milestone_result.items():
if isinstance(value, dict):
created_count = sum(v for k, v in value.items() if 'created' in k and isinstance(v, int))
if created_count > 0:
direction_name = key.replace('_', '').title()
print("{}: {}".format(direction_name, created_count))
else:
print("❌ 双向同步失败")
except Exception as e:
print("💥 双向同步任务执行异常: {}".format(str(e)))
@app.post("/webhook")
async def webhook_endpoint(request: Request):
"""Webhook接收端点 - 自动同步Gitee和GitLink"""
try:
if not DEPENDENCIES_AVAILABLE or not webhook_handler:
return {
"success": False,
"message": "Webhook服务不可用",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
# 获取请求头
headers = dict(request.headers)
# 获取请求体
webhook_data = await request.json()
# 处理webhook
result = webhook_handler.process_webhook(webhook_data, headers)
return result
except Exception as e:
error_msg = f"Webhook处理异常: {str(e)}"
print(f"{error_msg}")
return {
"success": False,
"message": error_msg,
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
@app.get("/webhook/status")
async def webhook_status():
"""获取Webhook服务状态"""
return {
"success": True,
"data": {
"webhook_available": DEPENDENCIES_AVAILABLE and webhook_handler is not None,
"supported_platforms": ["gitee", "gitlink"],
"repo_config": webhook_handler.repo_config if webhook_handler else None,
"loop_detection": "启用 (5分钟窗口)" if webhook_handler else "不可用",
"sync_api_url": webhook_handler.sync_api_url if webhook_handler else None
},
"message": "Webhook服务状态获取成功",
"timestamp": time.strftime('%Y-%m-%d %H:%M:%S')
}
if __name__ == '__main__':
print("🎯 启动独立的Issue同步服务...")
print("📖 API文档: http://localhost:8001/docs")
print("🔍 服务状态: http://localhost:8001/status")
print("=" * 50)
# 修复uvicorn启动配置 - 使用导入字符串
uvicorn.run(
"issue_sync_web:app", # 使用导入字符串而不是直接传递app对象
host='0.0.0.0',
port=8001,
reload=True,
debug=True
)