Andrey Epifancev c9ac2d5238 refactor: очередь ядра и обработчики команд модуля jira (#87)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 22:15:42 +04:00

101 lines
4.7 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.

"""Проекты-метки в модуле jira: базовая JQL из меток, доски, миграция v3 → v4, проект по умолчанию."""
import logging
import re
from ...core import settings
from ...core.projects import ProjectError, label_error, create, labels, validate
log = logging.getLogger(__name__)
LEGACY_LABEL = "AWPCA"
LEGACY_NAME = "АРМ КА"
BOARD_TYPES = ("scrum", "kanban")
def base_jql(conn) -> str | None:
"""Общая JQL обновления: все метки проектов; без проектов — None."""
found = labels(conn)
if not found:
return None
key = settings.get(conn, "project_key") or "AURORA"
return f"project = {key} AND labels in ({', '.join(f'"{x}"' for x in found)})"
def boards(conn) -> list[dict]:
"""Доски проектов без повторов (порядок первого проекта). type — None, если тип неизвестен хотя бы у одного
проекта доски (агент тогда запросит его, record_board_types проставит всем); иначе первый известный."""
out: dict[int, str | None] = {}
unknown: set[int] = set()
for r in conn.execute("SELECT board_id, board_type FROM project WHERE board_id IS NOT NULL ORDER BY created_at, label"):
out.setdefault(r["board_id"], r["board_type"])
if r["board_type"] is None:
unknown.add(r["board_id"])
return [{"id": i, "type": None if i in unknown else t} for i, t in out.items()]
def record_board_types(conn, found) -> int:
"""Записать типы досок {"<id>": "scrum" | "kanban"} всем проектам с этой доской; прочее пропустить."""
if not isinstance(found, dict):
return 0
updated = 0
for raw, kind in found.items():
if kind not in BOARD_TYPES:
continue
try:
board = int(raw)
except (TypeError, ValueError):
continue
updated += conn.execute("UPDATE project SET board_type = ? WHERE board_id = ?", (kind, board)).rowcount
return updated
_LEGACY = re.compile(r"\blabels\s*(?:=\s*(?P<one>\S+)|in\s*\((?P<many>[^()]*)\))\s*$", re.IGNORECASE)
def parse_legacy_labels(jql) -> list[str] | None:
"""Метки из прежней base_jql (`labels = X` / `labels in (X, Y)` в конце); не разобрана — None."""
m = _LEGACY.search(jql) if isinstance(jql, str) else None
if not m:
return None
out: list[str] = []
for raw in ([m["one"]] if m["one"] is not None else m["many"].split(",")):
label = raw.strip().strip('"')
if label_error(label):
return None
if label.casefold() not in {x.casefold() for x in out}:
out.append(label)
return out or None
def ensure_legacy(conn, board_id: int | None) -> bool:
"""Завести AWPCA «АРМ КА» с доской, если проекта с меткой awpca (без учёта регистра) нет; True — заведён.
Неверная доска из конфига — проект без доски."""
if LEGACY_LABEL.casefold() in {x.casefold() for x in labels(conn)}:
return False
try:
validate(LEGACY_LABEL, LEGACY_NAME, board_id)
except ProjectError:
board_id = None
create(conn, LEGACY_LABEL, LEGACY_NAME, board_id)
return True
def migrate_v3(conn) -> None:
"""Миграция v3 → v4: проекты из прежней base_jql, доска — единственному проекту, очередь и журнал — на новую JQL."""
old = settings.get(conn, "base_jql")
found = parse_legacy_labels(old)
if found is None:
log.warning("миграция v4: base_jql не разобрана (%r) — проектов нет, заведите их POST /projects", old)
return
board = settings.get(conn, "board_id")
board = board if isinstance(board, int) and not isinstance(board, bool) and board > 0 else None
if board is not None and len(found) > 1:
log.warning("миграция v4: доска %s не отдана ни одному проекту — меток несколько: %s", board, ", ".join(found))
board = None
for label in found:
create(conn, label, LEGACY_NAME if label == LEGACY_LABEL else label, board)
new = base_jql(conn)
conn.execute("UPDATE sync_run SET query = ? WHERE query = ?", (new, old))
conn.execute("UPDATE command SET params = json_set(params, '$.jql', ?) WHERE type = 'refresh' "
"AND status IN ('queued', 'claimed') AND json_extract(params, '$.jql') = ?", (new, old))