feat: хуки переносимы за пределы python, строгий формат TODO(#N) #10
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/hooks-8-9"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Закрывает #8 и #9. Оба дефекта нашлись при раскатке общих хуков на репозитории jamzap: часть хуков молча не работала, часть падала на том, что нарушением не является.
no-broken-repo-paths: служебные каталоги больше не ссылки (#9).git/содержимым репозитория не является ни в одном репозитории, но существует всегда — поэтому упоминание рантайм-файла.git/config.lockв комментарии про конкурентный доступ считалось висячей ссылкой. Гейт падал на коде, который чинить не нужно, а обойти это можно было толькоexclude-ом на весь файл.Для остального спрашиваем сам git: путь под
.gitignore— артефакт (node_modules/,dist/,.venv/), и его отсутствие нарушением не является. Своего списка имён не держим: у каждого потребителя он свой и уже описан в его.gitignore.no-issue-refs-in-comments: работает вне python (#8)Хук искал комментарий только по символу
#, а в определении нёсtypes: [python]. В TS-репозитории он не находил ни одного комментария и молча проходил — это хуже отсутствия хука: конфиг заявляет гейт, которого нет.//и/* */для C-подобных,#для остальных;typesснят — скоуп задаёт потребитель черезfiles:, как уno-broken-repo-paths;.tsсимвол#начинает приватное поле класса (#count);"https://example.com"не выглядит началом//-комментария;todo-needs-issue: только голый номер (#8)Внутренний
[^)]*пропускал что угодно перед номером, поэтомуTODO(jamzap/backend#402)проходил наравне сTODO(#402). Формат теперь строгий:TODO(#N), несколько ссылок через запятую —TODO(#12, #34).TODO живёт внутри своего репозитория, кросс-проектных не заводим: зависимость от чужой задачи оформляется своей issue, а она уже ссылается на чужую — так связь видна в трекере, а не только в комментарии.
Исключение для TODO внутри
no-issue-refs-in-commentsсужено до того же формата, чтобы оба хука говорили о префиксе одно и то же. Оговорка: кросс-проектную формуTODO(ns/proj#N)самno-issue-refs-in-commentsне ловит — там#Nстоит вплотную к букве и под#NNNне подпадает. РасширятьISSUE_REF_REне стал: это вышло бы за рамки задачи и потянуло ложные срабатывания на URL-фрагментах. Формат ловитtodo-needs-issue.Обратная совместимость
У потребителей с префиксами обновление
rev:покрасит TODO на первом же касании файла. Это ожидаемо и лечится переписыванием пунктуации; в jamzap уже сделано (jamzap/mobile#158— 11 TODO приведены, кросс-реповые заменены зеркальными задачами).Версия поднята до
0.11.0.Проверки
bash fixtures/run_smoke.sh— все кейсы зелёные. Добавлено семь: TS-комментарии (чистый,//-нарушитель, блочный многострочный), сузившееся исключение TODO, служебные каталоги, служебные каталоги плюс настоящая висячая ссылка, строгий формат TODO (префикс отвергается, запятая принимается).Каждая правка проверена мутацией — снятие любой роняет свой кейс:
.gitbroken_paths_service_paths_okbroken_paths_service_paths_ok#-синтаксисissue_refs_good_tsTODO_REissue_refs_loose_todo_failКейс на служебные каталоги строит временное репо, а не использует обычную fixture: в linked worktree
.git— файл, а не каталог, и проверка проходила бы независимо от правки. Первая версия этого кейса именно так и обманывала — поймал при мутационной проверке.Отдельно проверено, что отсечка служебных каталогов не глушит хук целиком: файл с теми же путями плюс настоящая висячая ссылка по-прежнему падает.
Итерация 2 — правки по ревью
Оба блокера закрыты, плюс четыре замечания, которые дешевле починить, чем откладывать.
B1 — манифест не был покрыт. Smoke зовёт скрипты напрямую, минуя фильтр
typespre-commit'а, а регуляркуtodo-needs-issueдублировал литералом. Откат обеих правок в.pre-commit-hooks.yamlоставлял набор зелёным — то есть несущая часть фикса #8 регрессировала бы незаметно. Теперьhook_fieldчитает поля из манифеста (только stdlib, в CI нет PyYAML), а отсутствиеtypesуno-issue-refs-in-commentsстережёт отдельный кейс.Побочно вскрылось неприятное:
fixtures/todo/prefixed.pyматчился по слову-маркеру в собственном докстринге, а не по проверяемой строке — кейс проходил бы при любой регулярке. Докстринг переформулирован; после этого откатentry:кейс роняет.B2 — два базиса для одного пути.
git check-ignoreнаследовал cwd процесса, а существование пути проверялось от_REPO_ROOT. При запуске из подкаталога настоящая висячая ссылка тихо пропадала, а легально игнорируемый артефакт наоборот флагался. Под самим pre-commit cwd всегда корень, поэтому в бою не стреляло — но контракт «резолв от git-корня, а не от cwd» в репозитории уже зафиксирован кейсомbroken_paths_bad_from_subdir_fail, и правка #9 его частично отменяла. Добавлен кейс с.gitignoreв подкаталоге: мутация ловится.Взято из замечаний:
.css/.scss/.lessубраны изSLASH_SUFFIXES. Hex-цвет в комментарии (// раньше был #336699) неотличим от ссылки на задачу, а стили в #8 и не входили: новый класс ложняков не нужен.LC_ALL=Cпадение декодирования глушило хук в тихий проход.v0.4.0,v0.7.0,v0.9.0). Дописана оговорка про0.xи прямое следствие для потребителя — бамп minor может покрасить код, обновлятьrev:стоит отдельным PR.rev:в README и в примере подтянуты к текущей версии; комментарий в smoke указывал не на тот путь.Вынесено в #11: построчный разбор комментариев (многострочный шаблонный литерал, второй комментарий в строке, апостроф в JSX), непокрытая обработка строковых литералов,
#-режим для разметки, зависимость вердикта от.git/info/exclude, асимметрия пробелов вTODO. Чинить их стоит не по одному, а переиспользованием машины состояний изno-broken-repo-paths— сейчас логика дублирована в двух скриптах с разной зрелостью.Мутационная проверка после правок — каждая роняет свой кейс:
types: [python]в манифестmanifest_no_issue_refs_has_no_typesentry:уtodo-needs-issuetodo_needs_issue_prefixed_matchcheck-ignoreв cwd процессаbroken_paths_ignore_asked_from_repo_root_fail.gitbroken_paths_service_paths_okbroken_paths_service_paths_ok#-синтаксисissue_refs_good_ts/*и перенос блокаissue_refs_block_multiline_ts_failTODO_REissue_refs_loose_todo_failbash fixtures/run_smoke.sh— зелёный.Ограничение ревью, которое стоит знать: у ревьюера не было доступа к телам #8 и #9 (в его окружении нет forgejo-MCP), он сверялся с описанием PR и коммита. Пункты приёмки из тел issue я перечитал сам — расхождений с реализацией нет.