This commit is contained in:
Raykov-MS 2026-03-05 12:28:30 +03:00
parent 206bb9fec0
commit 320cbbb5c3

53
main.py
View File

@ -475,7 +475,6 @@ class GiteaClient:
return [] return []
return data return data
storage = Storage(DB_PATH) storage = Storage(DB_PATH)
telegram_client = TelegramClient(TELEGRAM_BOT_TOKEN) telegram_client = TelegramClient(TELEGRAM_BOT_TOKEN)
gitea_client = GiteaClient(GITEA_BASE_URL, GITEA_TOKEN) gitea_client = GiteaClient(GITEA_BASE_URL, GITEA_TOKEN)
@ -574,6 +573,29 @@ def calculate_effective_approvals(reviews: list[dict[str, Any]]) -> int:
return sum(1 for _, state in latest_state_by_login.values() if state == "approved") return sum(1 for _, state in latest_state_by_login.values() if state == "approved")
def get_pr_author_login(
repo_full_name: str, pr_number: int, pull_request: dict[str, Any] | None = None
) -> str | None:
"""Логин создателя (автора) PR."""
if pull_request:
login = ((pull_request.get("user") or {}).get("login") or "").strip()
if login:
return login
rows = storage.get_assignments_for_pr(repo_full_name, pr_number)
return rows[0]["author_login"] if rows else None
async def get_pr_author_chat_id(
repo_full_name: str, pr_number: int, pull_request: dict[str, Any] | None = None
) -> int | None:
"""Chat_id создателя PR в Telegram (если зарегистрирован)."""
author_login = get_pr_author_login(repo_full_name, pr_number, pull_request)
if not author_login:
return None
user = storage.get_user_by_gitea_login(author_login)
return user.telegram_chat_id if user else None
async def get_pr_participant_chat_ids( async def get_pr_participant_chat_ids(
repo_full_name: str, repo_full_name: str,
pr_number: int, pr_number: int,
@ -913,7 +935,7 @@ async def handle_pull_request_comment(payload: dict[str, Any]) -> None:
async def handle_pr_reviewed(payload: dict[str, Any]) -> None: async def handle_pr_reviewed(payload: dict[str, Any]) -> None:
"""Изменение статуса ревью (approved / request changes) — уведомляем участников.""" """Изменение статуса ревью (approved / request changes) — уведомляем только создателя PR."""
pull_request = payload.get("pull_request") or {} pull_request = payload.get("pull_request") or {}
repository = payload.get("repository") or {} repository = payload.get("repository") or {}
review = payload.get("review") or {} review = payload.get("review") or {}
@ -937,15 +959,15 @@ async def handle_pr_reviewed(payload: dict[str, Any]) -> None:
msg = f"PR {repo_full_name}#{pr_number}: ревью {status_text} ({reviewer_login})." msg = f"PR {repo_full_name}#{pr_number}: ревью {status_text} ({reviewer_login})."
else: else:
msg = f"PR {repo_full_name}#{pr_number}: ревью {status_text}." msg = f"PR {repo_full_name}#{pr_number}: ревью {status_text}."
for chat_id in await get_pr_participant_chat_ids( author_chat_id = await get_pr_author_chat_id(repo_full_name, int(pr_number), pull_request)
repo_full_name, if author_chat_id is not None:
int(pr_number), await telegram_client.send_message(author_chat_id, msg)
pull_request=pull_request, else:
exclude_login=reviewer_login, log_warn(
): f"[notify] ревью для {repo_full_name}#{pr_number}: автор не зарегистрирован в боте."
await telegram_client.send_message(chat_id, msg) )
# Доп. нотификация, когда набран порог approve для merge. # Уведомление «можно мерджить» — только создателю PR.
if not gitea_client.enabled: if not gitea_client.enabled:
return return
reviews = await gitea_client.list_pull_request_reviews(repo_full_name, int(pr_number)) reviews = await gitea_client.list_pull_request_reviews(repo_full_name, int(pr_number))
@ -954,21 +976,14 @@ async def handle_pr_reviewed(payload: dict[str, Any]) -> None:
already_notified = storage.get_kv(merge_ready_key) == "1" already_notified = storage.get_kv(merge_ready_key) == "1"
if approvals_count >= APPROVALS_REQUIRED_FOR_MERGE: if approvals_count >= APPROVALS_REQUIRED_FOR_MERGE:
if not already_notified: if not already_notified and author_chat_id is not None:
merge_msg = ( merge_msg = (
f"PR {repo_full_name}#{pr_number} набрал {approvals_count} approve " f"PR {repo_full_name}#{pr_number} набрал {approvals_count} approve "
f"(порог {APPROVALS_REQUIRED_FOR_MERGE}) — можно мерджить." f"(порог {APPROVALS_REQUIRED_FOR_MERGE}) — можно мерджить."
) )
for chat_id in await get_pr_participant_chat_ids( await telegram_client.send_message(author_chat_id, merge_msg)
repo_full_name,
int(pr_number),
pull_request=pull_request,
):
await telegram_client.send_message(chat_id, merge_msg)
storage.set_kv(merge_ready_key, "1") storage.set_kv(merge_ready_key, "1")
else: else:
# Если approvals опустились ниже порога (например, после request changes),
# разрешаем повторную нотификацию при следующем достижении порога.
if already_notified: if already_notified:
storage.delete_kv(merge_ready_key) storage.delete_kv(merge_ready_key)