.
This commit is contained in:
parent
3dcf947c68
commit
bbac9918e1
@ -44,6 +44,8 @@ python -m uvicorn main:app --host 0.0.0.0 --port 8080 --reload --env-file .env
|
||||
- `AUTO_ASSIGNED_LABEL` - необязательно, по умолчанию `auto-assigned`
|
||||
- `AUTO_ASSIGN_REVIEWERS_COUNT` - необязательно, по умолчанию `2` (сколько ревьюеров назначать автоматически)
|
||||
- `AUTO_ASSIGN_EXCLUDED_AUTHORS` - необязательно, CSV логинов Gitea; для этих авторов автоназначение и auto-label на `PR opened` не выполняются
|
||||
- `BACKEND_USERS` - необязательно, CSV логинов Gitea backend-команды; если автор PR входит в этот список, ревьюеры выбираются только из этого же списка
|
||||
- `FRONTEND_USERS` - необязательно, CSV логинов Gitea frontend-команды; если автор PR входит в этот список, ревьюеры выбираются только из этого же списка
|
||||
- `APPROVALS_REQUIRED_FOR_MERGE` - необязательно, по умолчанию `2` (порог approve для сообщения "можно мерджить")
|
||||
- `NOTIFY_ON_WEEKENDS` - необязательно, по умолчанию `true`; если `false`, бот не отправляет ЛС в субботу и воскресенье (МСК)
|
||||
- `ALLOW_SELF_ASSIGN` - необязательно, по умолчанию `false` (для локального теста можно `true`)
|
||||
@ -52,6 +54,8 @@ python -m uvicorn main:app --host 0.0.0.0 --port 8080 --reload --env-file .env
|
||||
- `GITEA_COUNT_REPOS` - необязательно, CSV репозиториев `org/repo` для расчета нагрузки (исторический счетчик назначений)
|
||||
- `BOT_DB_PATH` - необязательно, по умолчанию `botreviewer.sqlite3`
|
||||
|
||||
Если автор PR не входит ни в `BACKEND_USERS`, ни в `FRONTEND_USERS`, бот использует общий пул доступных пользователей (как раньше).
|
||||
|
||||
## Webhook-эндпоинты
|
||||
|
||||
- Обновления Telegram: `POST /telegram/webhook`
|
||||
|
||||
41
main.py
41
main.py
@ -51,6 +51,16 @@ AUTO_ASSIGN_EXCLUDED_AUTHORS = {
|
||||
for v in os.getenv("AUTO_ASSIGN_EXCLUDED_AUTHORS", "").split(",")
|
||||
if v.strip()
|
||||
}
|
||||
BACKEND_USERS = {
|
||||
v.strip().lower()
|
||||
for v in os.getenv("BACKEND_USERS", "").split(",")
|
||||
if v.strip()
|
||||
}
|
||||
FRONTEND_USERS = {
|
||||
v.strip().lower()
|
||||
for v in os.getenv("FRONTEND_USERS", "").split(",")
|
||||
if v.strip()
|
||||
}
|
||||
NOTIFY_ON_WEEKENDS = os.getenv("NOTIFY_ON_WEEKENDS", "true").lower() == "true"
|
||||
MSK_TZ = timezone(timedelta(hours=3))
|
||||
|
||||
@ -529,6 +539,23 @@ def choose_reviewer(candidates: list[RegisteredUser]) -> RegisteredUser:
|
||||
return random.choice(candidates)
|
||||
|
||||
|
||||
def get_reviewer_group_for_author(author_login: str) -> tuple[set[str] | None, str]:
|
||||
author_login_norm = author_login.strip().lower()
|
||||
if author_login_norm in BACKEND_USERS:
|
||||
return BACKEND_USERS, "backend"
|
||||
if author_login_norm in FRONTEND_USERS:
|
||||
return FRONTEND_USERS, "frontend"
|
||||
return None, ""
|
||||
|
||||
|
||||
def filter_candidates_by_author_group(author_login: str, candidates: list[RegisteredUser]) -> tuple[list[RegisteredUser], str]:
|
||||
configured_group, group_name = get_reviewer_group_for_author(author_login)
|
||||
if configured_group is None:
|
||||
return candidates, ""
|
||||
filtered = [candidate for candidate in candidates if candidate.gitea_login.strip().lower() in configured_group]
|
||||
return filtered, group_name
|
||||
|
||||
|
||||
async def build_reviewer_load_counts(candidates: list[RegisteredUser], current_repo_full_name: str) -> dict[str, int]:
|
||||
_ = current_repo_full_name
|
||||
return {
|
||||
@ -835,13 +862,20 @@ async def handle_pr_opened(payload: dict[str, Any]) -> None:
|
||||
log_warn("[gitea] Клиент не настроен, автоназначение пропущено.")
|
||||
return
|
||||
|
||||
candidates = storage.get_available_candidates(
|
||||
all_candidates = storage.get_available_candidates(
|
||||
author_login=author_login,
|
||||
today=msk_now().date(),
|
||||
allow_self_assign=ALLOW_SELF_ASSIGN,
|
||||
)
|
||||
candidates, assigned_group_name = filter_candidates_by_author_group(author_login, all_candidates)
|
||||
if not candidates:
|
||||
log_warn(f"[assign] Нет доступных кандидатов для {repo_full_name}#{pr_number}.")
|
||||
if assigned_group_name:
|
||||
log_warn(
|
||||
f"[assign] Нет доступных кандидатов для группы '{assigned_group_name}' "
|
||||
f"({repo_full_name}#{pr_number}, author={author_login})."
|
||||
)
|
||||
else:
|
||||
log_warn(f"[assign] Нет доступных кандидатов для {repo_full_name}#{pr_number}.")
|
||||
return
|
||||
|
||||
selected_reviewers, counts = await choose_reviewers_with_remote_load(
|
||||
@ -856,7 +890,8 @@ async def handle_pr_opened(payload: dict[str, Any]) -> None:
|
||||
|
||||
log_info(
|
||||
f"[assign] Автоназначение для {repo_full_name}#{pr_number}. "
|
||||
f"Кандидаты={len(candidates)}, выбраны={selected_logins}, нагрузки={dict(counts)}"
|
||||
f"Кандидаты={len(candidates)} из {len(all_candidates)}, "
|
||||
f"группа={assigned_group_name or 'all'}, выбраны={selected_logins}, нагрузки={dict(counts)}"
|
||||
)
|
||||
await gitea_client.assign_reviewers(repo_full_name, int(pr_number), selected_logins)
|
||||
await gitea_client.add_label(repo_full_name, int(pr_number), AUTO_ASSIGNED_LABEL)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user