Гейт ищет гонки, переписанные шаги схемы и девять новых классов дефектов
- включены noctx, contextcheck и bodyclose (отмена доходит до внешнего вызова, контекст приезжает сверху, тело ответа закрывается), nilerr, rowserrcheck и sqlclosecheck (отказ не теряется молча), testifylint и nolintlint (форма утверждения и форма подавления), плюс errcheck check-type-assertions: непроверенное приведение типа паникует, и check-blank его не видит - заведён шаг tests: go test -race, потому что «результат пишет только держатель захвата» — утверждение об одновременности. Без компилятора C шаг гоняет тесты без детектора и краснеет кодом 3 после них: гонки не повод отнимать у гейта сами тесты - заведён шаг migrations: у файла шага схемы допустим один статус — A. Баз диффа две, BASE и HEAD: первая отвечает на «уже уехал» настолько, насколько свежа origin/master, вторая ловит правку закоммиченного шага независимо от неё. Каталог берётся из docs/.docs.json, пустой каталог роняет шаг - единственное подавление — noctx на httptest.NewRequest в проверках: за фикстурой запроса внешнего собеседника нет. Граница проверена мутацией — http.Get и exec.Command из проверки правилу по-прежнему подсудны
This commit is contained in:
+78
-1
@@ -33,17 +33,94 @@ tasks:
|
||||
echo "gofmt: файлы выше не отформатированы"
|
||||
exit 1
|
||||
fi
|
||||
- go test ./...
|
||||
- task: tests
|
||||
- golangci-lint run
|
||||
- task: shell
|
||||
- task: dockerfile
|
||||
- task: go-version
|
||||
- task: migrations
|
||||
- task: docs
|
||||
- task: tasks
|
||||
- task: openspec
|
||||
# Последним: единственный шаг, которому нужна сеть, и самый долгий.
|
||||
- task: vulns
|
||||
|
||||
tests:
|
||||
desc: 'Тесты с детектором гонок'
|
||||
cmds:
|
||||
# Гонки ищет детектор, а не чтение кода: у сервиса три воркера ходят в одну
|
||||
# очередь, и «результат пишет только держатель захвата» — утверждение о
|
||||
# одновременном доступе. Детектору нужен CGO и компилятор C; сборка
|
||||
# приложения по-прежнему обходится без них (CLAUDE.md, «Стек»), поэтому их
|
||||
# отсутствие — отказ окружения, код 3, а не отказ проверки.
|
||||
# Окружение проверяется **после** обычного прогона, а не вместо него:
|
||||
# отсутствие компилятора отнимает у гейта поиск гонок, но не должно
|
||||
# отнимать сами тесты. Порядок проверок — сперва компилятор: без него
|
||||
# совет «включи CGO_ENABLED=1» бесполезен.
|
||||
- |
|
||||
if ! command -v gcc >/dev/null 2>&1 && ! command -v clang >/dev/null 2>&1; then
|
||||
go test ./... || exit 1
|
||||
echo "тесты прошли, но гонки не искали: детектору нужен компилятор C"
|
||||
echo "ни gcc, ни clang не найдены в PATH; поставь: apt install gcc"
|
||||
exit 3
|
||||
fi
|
||||
if [ "$(go env CGO_ENABLED)" != "1" ]; then
|
||||
go test ./... || exit 1
|
||||
echo "тесты прошли, но гонки не искали: детектору нужен CGO"
|
||||
echo "CGO_ENABLED=$(go env CGO_ENABLED); включи: CGO_ENABLED=1 task gate"
|
||||
exit 3
|
||||
fi
|
||||
go test -race ./...
|
||||
|
||||
migrations:
|
||||
desc: 'Применённый шаг схемы не переписывается'
|
||||
cmds:
|
||||
# Инвариант CLAUDE.md (critical): хранилище считает применённое по имени
|
||||
# файла шага, поэтому изменить уехавший шаг нельзя — только добавить новый.
|
||||
# Компилятор этого не держит, и до этого шага не держало ничто.
|
||||
#
|
||||
# Судится каталог шагов против базы диффа: у файла шага допустим один
|
||||
# статус — `A`. Правка (`M`), удаление (`D`) и переименование (`R`) красят.
|
||||
# `migrations.go` под правило не подпадает: строка `Register` у нового шага
|
||||
# прибавляется именно там, и запрет на него запретил бы заведение шага.
|
||||
- |
|
||||
if ! git rev-parse --verify --quiet "{{.BASE}}" >/dev/null 2>&1; then
|
||||
echo "база диффа не найдена: {{.BASE}}"
|
||||
echo "задай свою: task migrations BASE=<rev>"
|
||||
exit 3
|
||||
fi
|
||||
# Каталог шагов берётся из docs/.docs.json — там он уже записан ключом
|
||||
# `migrations` для сверки документов. Свой литерал завёл бы факту второй
|
||||
# дом: каталог переехал бы, а один из двух стражей молча позеленел.
|
||||
dir=$(python3 -c 'import json,sys; print(json.load(open("docs/.docs.json"))["migrations"])' 2>/dev/null) || dir=""
|
||||
if [ -z "$dir" ] || [ ! -d "$dir" ]; then
|
||||
echo "каталог шагов схемы не найден: ключ migrations в docs/.docs.json → '$dir'"
|
||||
exit 3
|
||||
fi
|
||||
# Страж предмета: правило, потерявшее файлы, стало бы вечно зелёным от
|
||||
# одного переименования — тот же приём, что у правил `internal/archrules`.
|
||||
if [ -z "$(ls "$dir" | grep -E '^[0-9]{12}_.*\.go$')" ]; then
|
||||
echo "в $dir нет ни одного файла шага: правило потеряло предмет"
|
||||
echo "поправь шаблон имени в этом шаге либо ключ migrations в docs/.docs.json"
|
||||
exit 3
|
||||
fi
|
||||
# Баз две, и вторая обязательна. `{{.BASE}}` отвечает на «шаг уже уехал»
|
||||
# ровно настолько, насколько свеж `origin/master`: отставшая ссылка
|
||||
# читает весь каталог как добавленный, и правило молчит. `HEAD` ловит
|
||||
# правку закоммиченного шага в рабочем дереве независимо от ссылки.
|
||||
for base in {{.BASE}} HEAD; do
|
||||
touched=$(git diff --name-status "$base" -- "$dir" \
|
||||
| grep -E '[0-9]{12}_[^/]*\.go$' \
|
||||
| grep -vE '^A[[:space:]]' || true)
|
||||
if [ -n "$touched" ]; then
|
||||
echo "база $base:"
|
||||
echo "$touched"
|
||||
echo "применённый шаг схемы переписан: изменение схемы — только новым файлом шага"
|
||||
echo "(CLAUDE.md, «Инварианты», critical: хранилище считает применённое по имени файла)"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
shell:
|
||||
desc: 'shellcheck на скрипты оболочки'
|
||||
cmds:
|
||||
|
||||
Reference in New Issue
Block a user