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