Skip to content

fix codecheck problem #5

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 24, 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
36 changes: 28 additions & 8 deletions app/api/endpoints/webhook.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
# 标准库
import asyncio
import re
import time
import traceback
import hmac
import hashlib
import logging

# 第三方库
from fastapi import APIRouter, Request, HTTPException, Header, status, BackgroundTasks

# 应用程序自定义模块
from app.config import settings, init_db_pool
from app.utils import git_api, gitee_tool
from app.utils.client import silicon_client
from app.utils import euler_maker_api as maker
import hmac
import hashlib
import logging

router = APIRouter()
logger = logging.getLogger(__name__)
MAX_RETRIES = 0
db_pool = init_db_pool()


def verify_signature(body: bytes, signature: str) -> bool:
"""Verify HMAC signature of webhook payload."""
try:
Expand Down Expand Up @@ -88,8 +92,16 @@ async def handle_webhook(
conn = db_pool.get_connection()
cursor = conn.cursor()
cursor.execute(
"INSERT INTO pending_requests (repo_url,source_url,pr_number,repo_name,pr_url,spec_content) VALUES (%s,%s,%s,%s,%s,%s)",
(pr_data["repo_url"],pr_data["source_url"],pr_data["pr_number"],pr_data["repo_name"],pr_data["pr_url"],spec_content)
"INSERT INTO pending_requests (repo_url, source_url, pr_number, repo_name, pr_url, spec_content) "
"VALUES (%s, %s, %s, %s, %s, %s)",
(
pr_data["repo_url"],
pr_data["source_url"],
pr_data["pr_number"],
pr_data["repo_name"],
pr_data["pr_url"],
spec_content
)
)
conn.commit()
return {"status": "处理已启动"}
Expand Down Expand Up @@ -157,7 +169,12 @@ async def handle_build_retries(pr_data: dict, current_spec: str, srcDir: str, bu
)
repair_job_id = maker.get_job_id(settings.os_repair_project, pr_data["repo_name"])
commit_url = f"{fork_url}/commit/{commit_sha}"
maker_url = f"https://eulermaker.compass-ci.openeuler.openatom.cn/package/build-record?osProject={settings.os_repair_project}&packageName={pr_data['repo_name']}&jobId={repair_job_id}"
maker_url = (
f"https://eulermaker.compass-ci.openeuler.openatom.cn/package/build-record?"
f"osProject={settings.os_repair_project}&"
f"packageName={pr_data['repo_name']}&"
f"jobId={repair_job_id}"
)

# 递归处理
await handle_build_retries(pr_data, new_spec, srcDir, new_build_id, retry_count + 1, commit_url, maker_url)
Expand Down Expand Up @@ -228,7 +245,10 @@ async def process_initial_repair(pr_data: dict, original_spec: str):

repair_job_id = maker.get_job_id(settings.os_repair_project, pr_data["repo_name"])
commit_url = f"{fork_url}/commit/{commit_sha}"
maker_url = f"https://eulermaker.compass-ci.openeuler.openatom.cn/package/build-record?osProject={settings.os_repair_project}&packageName={pr_data['repo_name']}&jobId={repair_job_id}"
maker_url = (f"https://eulermaker.compass-ci.openeuler.openatom.cn/package/build-record?"
f"osProject={settings.os_repair_project}&"
f"packageName={pr_data['repo_name']}&"
f"jobId={repair_job_id}")

await handle_build_retries(pr_data, fixed_spec, srcDir, repair_build_id, 0, commit_url, maker_url)
except Exception as e:
Expand Down
7 changes: 5 additions & 2 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import yaml
from mysql.connector import pooling


class Settings:
def __init__(self):
config_path_env = os.getenv("CONFIG_PATH")
Expand Down Expand Up @@ -44,7 +45,7 @@ def __init__(self):
self.password: str = config.get("PASSWORD")
self.database: str = config.get("DATABASE")
self.pool_size: int = config.get("POOL_SIZE")
#os.remove(config_path_env)
# os.remove(config_path_env)


settings = Settings()
Expand All @@ -57,9 +58,11 @@ def __init__(self):
"database": settings.database,
'charset': 'utf8mb4'
}


def init_db_pool():
return pooling.MySQLConnectionPool(
pool_name="request_pool",
pool_size=settings.pool_size,
**db_config
)
)
17 changes: 12 additions & 5 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
# 标准库
import logging
import asyncio

# 第三方库
from fastapi import FastAPI, HTTPException, Request, status

# 应用程序自定义模块
from app.api.endpoints import webhook
from app.config import settings
from app.utils.processor import RequestProcessor
import asyncio
import time

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

Expand All @@ -13,7 +18,8 @@
app.include_router(webhook.router, prefix="/api/v1", tags=["webhooks"])
processor = RequestProcessor()

@app.on_event ("startup")

@app.on_event("startup")
def startup_event():
"""
在应用程序启动时执行的事件处理函数。
Expand All @@ -22,8 +28,9 @@ def startup_event():
"""
# 延迟5秒后执行后台任务
loop = asyncio.get_running_loop()
loop.call_later(5, lambda: asyncio.create_task(processor.start()))

loop.call_later(5, lambda: asyncio.create_task(processor.start()))


@app.middleware("http")
async def log_requests(request: Request, call_next):
# 记录请求的基本信息
Expand Down
3 changes: 3 additions & 0 deletions app/utils/euler_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def get_privacy_version(self) -> str:

except (RequestException, json.JSONDecodeError) as e:
self._handle_request_exception(e, "获取隐私协议版本")
return ""

def authenticate(self, version: str) -> None:
"""进行用户认证并维护会话状态"""
Expand Down Expand Up @@ -166,6 +167,7 @@ def get_auth_code(self) -> str:

except (RequestException, IndexError) as e:
self._handle_request_exception(e, "获取授权码")
return ""

def get_access_token(self, code: str) -> str:
"""使用授权码获取访问令牌"""
Expand All @@ -184,6 +186,7 @@ def get_access_token(self, code: str) -> str:

except RequestException as e:
self._handle_request_exception(e, "获取访问令牌")
return ""

def execute_flow(self) -> str:
"""执行完整的OAuth流程"""
Expand Down
12 changes: 8 additions & 4 deletions app/utils/euler_maker_api.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
# 标准库
import asyncio
import logging
import time
import uuid

# 第三方库
import httpx
import requests
from typing import Any, Dict, List, Optional
from requests.exceptions import RequestException

# 应用程序自定义模块
from . import euler_api

# 常量定义
Expand Down Expand Up @@ -40,7 +44,7 @@ def _request_wrapper(
time.sleep(RETRY_DELAY * (attempt + 1))
else:
logger.info(f"最终请求失败: {url}")
return None
return None


def get_request_headers() -> Dict[str, str]:
Expand Down Expand Up @@ -267,6 +271,7 @@ def get_build_log(url: str) -> Optional[str]:
logger.error(f"Log fetch error: {str(e)}")
return None


async def get_build_status(
build_id: str,
max_retries: int = 10,
Expand All @@ -283,7 +288,7 @@ async def get_build_status(

for attempt in range(1, max_retries + 1):
try:
# 添加请求追踪ID
# 添加请求追踪ID
headers = get_request_headers() | {"X-Request-ID": uuid.uuid4().hex}

response = requests.post(
Expand All @@ -309,9 +314,8 @@ async def get_build_status(
except httpx.HTTPStatusError as e:
logger.error(f"HTTP error {e.response.status_code}: {e.response.text}")
if e.response.status_code == 404:
break # 立即终止不存在的请求
break # 立即终止不存在的请求
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")

return None

12 changes: 8 additions & 4 deletions app/utils/git_api.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
# 标准库
import os
import shutil
import stat
import subprocess
import logging
from abc import ABC, abstractmethod
from base64 import b64encode
from urllib.parse import urlparse

# 第三方库
import httpx

from app.config import settings
import requests
import logging

# 应用程序自定义模块
from app.config import settings
from app.utils.client import api_client


logger = logging.getLogger("git_api")


Expand Down Expand Up @@ -336,6 +339,7 @@ def update_spec_file(service, owner, repo, file_content, branch):
return clone_url, sha, branch
except Exception as e:
logger.info(f"提交失败: {str(e)}")
return "", "", ""


def comment_on_pr(repo_url, pr_num, comment):
Expand Down Expand Up @@ -405,7 +409,7 @@ def check_and_push(repo_url, new_content, pr_num):
["git", "rev-parse", "HEAD"], cwd=temp_dir, text=True).strip()
if os.path.exists(temp_dir):
shutil.rmtree(temp_dir, onerror=force_remove_readonly)
return f'{repo_url}.git', commit_sha, branch
return f'{repo_url}.git', commit_sha, branch


def force_remove_readonly(func, path, _):
Expand Down
20 changes: 13 additions & 7 deletions app/utils/gitee_tool.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# 标准库
import json
import logging
import os
import tarfile
import requests
import tempfile
from urllib.parse import urlparse, urlencode
from urllib.parse import urlparse

# 第三方库
import requests


GITEE_API = "https://gitee.com/api/v5"
logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -69,11 +73,13 @@ def download_gitee_file(raw_url, token=None):
_, ext = os.path.splitext(raw_url)
fd, path = tempfile.mkstemp(suffix=ext)

with os.fdopen(fd, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
if chunk:
f.write(chunk)

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)
return path


Expand Down
7 changes: 4 additions & 3 deletions app/utils/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,11 @@
# PURPOSE.
# See the Mulan PSL v2 for more details.
# ******************************************************************************/
import logging
import asyncio

import time
from app.config import settings, init_db_pool
from app.api.endpoints.webhook import process_initial_repair
import logging
import asyncio


REPAIR_STATUS_COMPLETED = "completed"
Expand All @@ -24,6 +23,8 @@
REPAIR_STATUS_PENDING = "pending"

logger = logging.getLogger(__name__)


class RequestProcessor:
def __init__(self):
"""
Expand Down
Loading