All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-frontend (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 11s
Deploy / deploy-caddy (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy / build-backend (push) Successful in 3m57s
Deploy Trade-In / test (push) Successful in 4m5s
Deploy / build-worker (push) Successful in 4m59s
Deploy Trade-In / build-backend (push) Successful in 1m53s
Deploy / deploy (push) Successful in 1m58s
Deploy / deploy-status (push) Successful in 1s
Deploy / perimeter-smoke (push) Successful in 11s
Deploy Trade-In / deploy (push) Successful in 2m27s
Deploy Trade-In / deploy-status (push) Successful in 1s
Deploy Trade-In / perimeter-smoke (push) Successful in 9s
71 lines
3.4 KiB
Python
71 lines
3.4 KiB
Python
"""pre-commit и uv.lock держат ОДНУ версию ruff (#2864).
|
||
|
||
Хук `ruff-pre-commit` пинился на v0.7.4, а CI и `uv run ruff format` брали ruff из
|
||
lock-файлов (0.15.12 в backend/, 0.15.20 в tradein-mvp/). Старый и новый ruff
|
||
по-разному форматируют длинные `assert ..., "сообщение"` — хук на каждом коммите
|
||
переписывал нетронутые строки, следующий `uv run ruff format` возвращал как было.
|
||
`ruff format --check` намеренно не в CI-гейте, поэтому дрейф нигде не краснел.
|
||
|
||
Гейт читает три источника истины и требует равенства. Красный на origin/main по
|
||
значению: rev v0.7.4 против 0.15.12 и 0.15.20. Бампить втроём: rev в
|
||
.pre-commit-config.yaml + `ruff==X` в обоих pyproject.toml + `uv lock`.
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import re
|
||
from pathlib import Path
|
||
|
||
КОРЕНЬ = Path(__file__).resolve().parents[2]
|
||
|
||
_REV = re.compile(
|
||
r"repo:\s*https://github\.com/astral-sh/ruff-pre-commit\s*\n\s*rev:\s*v?([\w.]+)",
|
||
)
|
||
_LOCK_RUFF = re.compile(r'^name = "ruff"\nversion = "([\w.]+)"', re.MULTILINE)
|
||
_PYPROJECT_RUFF = re.compile(r'"ruff([<>=!~]+[^"]*)"')
|
||
|
||
|
||
def _precommit_rev() -> str:
|
||
текст = (КОРЕНЬ / ".pre-commit-config.yaml").read_text(encoding="utf-8")
|
||
m = _REV.search(текст)
|
||
assert m, "в .pre-commit-config.yaml нет блока ruff-pre-commit с rev"
|
||
return m.group(1)
|
||
|
||
|
||
def _lock_version(lock: str) -> str:
|
||
m = _LOCK_RUFF.search((КОРЕНЬ / lock).read_text(encoding="utf-8"))
|
||
assert m, f"в {lock} нет пакета ruff"
|
||
return m.group(1)
|
||
|
||
|
||
def test_precommit_rev_matches_both_locks() -> None:
|
||
"""Головной: хук и оба lock'а — одна версия ruff."""
|
||
rev = _precommit_rev()
|
||
locks = {
|
||
"backend/uv.lock": _lock_version("backend/uv.lock"),
|
||
"tradein-mvp/uv.lock": _lock_version("tradein-mvp/uv.lock"),
|
||
}
|
||
расхождения = {k: v for k, v in locks.items() if v != rev}
|
||
assert not расхождения, (
|
||
f"pre-commit ruff rev=v{rev}, а в lock'ах {расхождения} — хук и "
|
||
"`uv run ruff format` будут форматировать по-разному (#2864)"
|
||
)
|
||
|
||
|
||
def test_pyproject_pins_exact_ruff() -> None:
|
||
"""Контроль от повторного дрейфа: `ruff==X` в обоих pyproject, X = rev.
|
||
|
||
С `>=` любой `uv lock --upgrade` молча уводит lock от хука — ровно так
|
||
и разъехались 0.7.4 / 0.15.12 / 0.15.20.
|
||
"""
|
||
rev = _precommit_rev()
|
||
for f in ("backend/pyproject.toml", "tradein-mvp/backend/pyproject.toml"):
|
||
m = _PYPROJECT_RUFF.search((КОРЕНЬ / f).read_text(encoding="utf-8"))
|
||
assert m, f"в {f} нет зависимости ruff"
|
||
assert m.group(1) == f"=={rev}", f"{f}: ruff{m.group(1)}, ожидался ruff=={rev}"
|
||
|
||
|
||
def test_gate_reads_real_values() -> None:
|
||
"""Контроль самого гейта: парсеры возвращают версии, а не падают на пустом."""
|
||
assert re.fullmatch(r"\d+\.\d+\.\d+", _precommit_rev())
|
||
assert re.fullmatch(r"\d+\.\d+\.\d+", _lock_version("backend/uv.lock"))
|