- forbidigo с analyze-types запрещает в файлах проверок обращение к httptest.ResponseRecorder.Header и .HeaderMap: правило судит по типу приёмника, поэтому ловит и цепочку, и переменную, и индекс, и обход - класс стоил трёх зелёных гейтов при неработающем коде; правило записано строкой в перечне механизированного, прозой не дублируется - поправлены два утверждения «механизировано: ничего», разошедшиеся с включённым линтером и со сверкой шага схемы
68 lines
4.3 KiB
YAML
68 lines
4.3 KiB
YAML
version: "2"
|
||
|
||
linters:
|
||
default: standard
|
||
enable:
|
||
- errorlint
|
||
- forbidigo
|
||
settings:
|
||
forbidigo:
|
||
# Проверка ответа судит по **готовому ответу**, а не по изменяемому
|
||
# состоянию обработчика. `httptest` устроен зеркально настоящему серверу:
|
||
# `Header()` отдаёт живую карту, доступную и после записи ответа, а снимок,
|
||
# который получит клиент, лежит отдельно и читается через `Result()`.
|
||
# Проверка, читающая живую карту, зелена при неработающем коде — класс
|
||
# всплывал трижды (docs/review.md, записи 2026-08-10, 2026-08-11 и
|
||
# 2026-08-12) и трижды стоил зелёного гейта.
|
||
#
|
||
# Правило действует только в `*_test.go` — исключение ниже: в самом
|
||
# обработчике `Header()` и есть способ отдать заголовок.
|
||
#
|
||
# Судит оно **по типу приёмника**, а не по печатному тексту вызова
|
||
# (`analyze-types`), и в этом весь смысл: запрет на цепочку
|
||
# `w.Header().Get` обходится одной лишней строкой — `h := w.Header()`, —
|
||
# а также чтением по индексу карты и обходом `range`. По типу под правило
|
||
# попадают все эти формы разом. Записать его текстом нельзя ещё и потому,
|
||
# что `.Header` носят и запрос (`req.Header.Set` в проверках законен), и
|
||
# снимок ответа (`w.Result().Header` — как раз то, к чему правило ведёт).
|
||
#
|
||
# Приёмник назван поимённо: подставной сервер в проверках отдаёт заголовок
|
||
# через `w.Header().Set`, но у него приёмник — `http.ResponseWriter`, и под
|
||
# правило он не попадает.
|
||
#
|
||
# `HeaderMap` — тот же живой снимок прежним именем поля; правило второе,
|
||
# потому что о его устарелости говорит `staticcheck` (SA1019), а о том,
|
||
# почему по нему не судят ответ, — только это сообщение.
|
||
analyze-types: true
|
||
forbid:
|
||
- pattern: '^httptest\.ResponseRecorder\.Header$'
|
||
msg: 'проверка судит ответ по живой карте заголовков: читай w.Result().Header'
|
||
- pattern: '^httptest\.ResponseRecorder\.HeaderMap$'
|
||
msg: 'проверка судит ответ по живой карте заголовков: читай w.Result().Header'
|
||
errcheck:
|
||
# Без этого `_ = x.Close()` снимает замечание, и критерий «отказ не
|
||
# теряется молча» принимается реализацией, которая его теряет. Отказ,
|
||
# который решено не проверять, теперь объявляют ниже поимённо — заметно.
|
||
check-blank: true
|
||
exclude-functions:
|
||
# Закрытие через defer и лучшая-попытка уборки файла — осознанно без проверки
|
||
- (io.Closer).Close
|
||
- (*database/sql.DB).Close
|
||
- (*os.File).Close
|
||
- (io.ReadCloser).Close
|
||
- os.Remove
|
||
# Метод сам логирует ошибку отправки, вызывающему она не нужна
|
||
- (*git.vakhrushev.me/av/transcriber/internal/controller/tg.TelegramController).send
|
||
|
||
exclusions:
|
||
rules:
|
||
# `path-except` оставляет находки только в файлах проверок: в рабочем коде
|
||
# чтение своей карты заголовков законно.
|
||
- linters:
|
||
- forbidigo
|
||
path-except: '_test\.go$'
|
||
|
||
formatters:
|
||
enable:
|
||
- gofmt
|