Skip to content

fix problem and optimization #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 32 additions & 8 deletions app/api/endpoints/webhook.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def extract_pr_data(data: dict) -> dict:
if note not in [cmd.strip().lower() for cmd in settings.accept_cmds]:
raise ValueError("Unsupported command")

# Check for ci_failed label
labels = data.get("pull_request", {}).get("labels", [])
logger.info(f"labels is {labels}")
if not any(label.get("name") == "ci_failed" for label in labels):
raise ValueError("PR does not have ci_failed label")

pull_request = data.get("pull_request", {})
project = data.get("project", {})

Expand Down Expand Up @@ -162,6 +168,11 @@ async def handle_build_retries(pr_data: dict, current_spec: str, srcDir: str, bu
commit_url: str,
maker_url: str):
"""处理构建重试逻辑"""
old_version, new_version = git_api.get_upgrade_versions(
pr_data["repo_url"],
pr_data["pr_number"],
f'{pr_data["repo_name"]}.spec'
)
try:
build_status = await wait_for_build_completion(build_id)
logger.info(f'the build result is {build_status}')
Expand Down Expand Up @@ -211,11 +222,20 @@ async def handle_build_retries(pr_data: dict, current_spec: str, srcDir: str, bu

else:
# 达到最大重试次数
comment = settings.fix_failure_comment.format(max_retries=MAX_RETRIES, commit_url=commit_url,
maker_url=maker_url)
logger.info(f"old_version is {old_version}, new_version is {new_version}")
comment = settings.fix_failure_comment.format(
package=pr_data["repo_name"],
old_version=old_version,
new_version=new_version,
commit_url=commit_url,
maker_url=maker_url,
)
issue_url = await analyze_error_and_create_issue(pr_data, old_version, new_version)
if issue_url:
comment += (f"\n升级后,发现缺少依赖包情况,openEuler-AutoRepair已经提出Issue,请留意处理进度.\n"
f"Issue链接:{issue_url}。")
git_api.comment_on_pr(pr_data["repo_url"], pr_data["pr_number"], comment)
logger.error(f"PR #{pr_data['pr_number']} 构建失败,已达最大重试次数")
await analyze_error_and_create_issue(pr_data)

except Exception as e:
logger.error(f"处理重试时发生异常: {e}")
Expand Down Expand Up @@ -287,8 +307,8 @@ async def process_initial_repair(pr_data: dict, original_spec: str):
git_api.comment_on_pr(pr_data["repo_url"], pr_data["pr_number"], comment)


async def analyze_error_and_create_issue(pr_data: dict):
"""分析错误并创建问题"""
async def analyze_error_and_create_issue(pr_data: dict, old_version, new_version):
"""分析错误并创建Issue"""
# 分析错误日志
try:
# Get build log
Expand All @@ -312,8 +332,12 @@ async def analyze_error_and_create_issue(pr_data: dict):
chat = silicon_client.SiliconFlowChat(settings.silicon_token)
title, content = chat.analyze_missing_package(warnings)
if title and content:
git_api.create_issue(pr_data["repo_url"], title, content)

issue_url = git_api.create_issue(pr_data["repo_url"], title, settings.missing_package_comment.format(
old_version=old_version,
new_version=new_version,
missing_packages=content))
return issue_url
return ""
except Exception as e:
logger.error(f"获取构建日志失败: {e}")
return
return ""
1 change: 1 addition & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def __init__(self):
self.system_prompt: str = config.get("SYSTEM_PROMPT")
self.user_prompt: str = config.get("USER_PROMPT")
self.analyze_system_prompt: str = config.get("ANALYZE_SYSTEM_PROMPT")
self.missing_package_comment: str = config.get("MISSING_PACKAGE_COMMENT")
self.ai_model: str = config.get("AI_MODEL")
self.model_max_tokens: int = config.get("MODEL_MAX_TOKENS")
self.model_temperature: float = config.get("MODEL_TEMPERATURE")
Expand Down
57 changes: 56 additions & 1 deletion app/utils/git_api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# 标准库
import os
import re
import shutil
import stat
import subprocess
Expand Down Expand Up @@ -42,6 +43,10 @@ def get_spec_content(self, owner, repo, pr_number, file_path, token=None):
def create_issue(self, owner, repo, title, content):
pass

@abstractmethod
def get_upgrade_versions(self, owner, repo, pr_number, file_path, token=None):
pass


# 平台具体实现层
class GiteeForkService(ForkServiceInterface):
Expand Down Expand Up @@ -172,13 +177,49 @@ async def get_spec_content(self, owner, repo, pr_number, file_path, token=None):
logger.error(f"Unexpected error: {str(e)}")
return None

def get_upgrade_versions(self, owner, repo, pr_number, file_path, token=None) -> tuple:
try:
headers = {
"Authorization": f"token {token}"
}
# 异步获取PR文件列表
files_resp = self.client.get(f"/repos/{owner}/{repo}/pulls/{pr_number}/files")
files_resp.raise_for_status()
files = files_resp.json()

# 查找目标文件
target_file = next((f for f in files if f["filename"] == file_path), None)
if not target_file:
logger.warning(f"File {file_path} not found in PR #{pr_number}")
return "", ""

diff = target_file['patch']['diff']
version_pattern = re.compile(r'([+-])\s*Version:\s*([\w.]+)')
matches = version_pattern.findall(diff)

old_version = None
new_version = None
for sign, version in matches:
if sign == '-':
old_version = version
elif sign == '+':
new_version = version
return old_version, new_version

except httpx.HTTPStatusError as e:
logger.error(f"Gitee API error: {e.response.status_code} {e.response.text}")
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
return "", ""

def create_issue(self, owner, repo, title, content):
data = {
"repo": repo,
"title": title,
"body": content
}
response = self.client.post(f"/repos/{owner}/issues", data)
return response.json().get('html_url', "")


class GitHubForkService(ForkServiceInterface):
Expand Down Expand Up @@ -211,6 +252,9 @@ def get_spec_content(self, owner, repo, pr_number, file_path, token=None):
def create_issue(self, owner, repo, title, content):
pass

def get_upgrade_versions(self, owner, repo, pr_number, file_path, token=None):
pass


class GitCodeForkService(ForkServiceInterface):
def __init__(self, token):
Expand Down Expand Up @@ -248,6 +292,9 @@ def get_spec_content(self, owner, repo, pr_number, file_path, token=None):
def create_issue(self, owner, repo, title, content):
pass

def get_upgrade_versions(self, owner, repo, pr_number, file_path, token=None):
pass


# 工厂层
class ForkServiceFactory:
Expand Down Expand Up @@ -360,14 +407,16 @@ def create_issue(repo_url, title, content):
platform, token, owner, repo = parse_repo_url(repo_url)
service = ForkServiceFactory.get_service(platform, token)
try:
service.create_issue(
issue_url = service.create_issue(
owner=owner,
repo=repo,
title=title,
content=content,
)
return issue_url
except Exception as e:
logger.info(f"创建失败: {str(e)}")
return ""


async def get_spec_content(repo_url, pr_number, file_path):
Expand All @@ -376,6 +425,12 @@ async def get_spec_content(repo_url, pr_number, file_path):
return await service.get_spec_content(owner, repo, pr_number, file_path, token)


def get_upgrade_versions(repo_url, pr_number, file_path):
platform, token, owner, repo = parse_repo_url(repo_url)
service = ForkServiceFactory.get_service(platform, token)
return service.get_upgrade_versions(owner, repo, pr_number, file_path, token)


def check_and_push(repo_url, new_content, pr_num):
logger.info(f'repo_url is {repo_url}')
platform, token, owner, repo = parse_repo_url(repo_url)
Expand Down
11 changes: 4 additions & 7 deletions app/utils/gitee_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,10 @@ def download_gitee_file(raw_url, token=None):
_, ext = os.path.splitext(raw_url)
fd, path = tempfile.mkstemp(suffix=ext)

try:
with os.fdopen(fd, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)
finally:
os.remove(path)
with os.fdopen(fd, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
Comment on lines +76 to +77
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

添加注释

if chunk:
f.write(chunk)
return path


Expand Down
Loading