02. Первый pull request¶
Пройди этот сценарий от начала до конца один раз, даже если изменение символическое. Цель — убедиться, что у тебя работает весь конвейер: линт → тесты → коммит → push → PR → merge.
Шаг 1. Обнови локальную копию¶
Зайди в клон сервис-репо, с которым будешь работать (у каждого сервиса —
свой репозиторий), и обнови main:
Если git pull ругается на несовпадение истории — не делай merge main
на лету, разберись отдельно (скорее всего, у тебя остались локальные
коммиты, не попавшие в upstream).
Шаг 2. Создай ветку¶
Имя ветки следует формату <type>/<short-description>:
Префиксы: feat/, fix/, chore/, refactor/, docs/, test/. Подробнее —
в conventions/commits-and-prs.md.
Шаг 3. Прогоняй тесты локально ДО правок¶
Ты уже в клоне сервис-репо из шага 1. Прогоняй тесты:
Это baseline. Если тесты упали ещё до твоих изменений — не правь код, а иди
в backend-канал выяснять, что сломано в main. Работать поверх красного
main смысла нет.
Шаг 4. Внеси изменения¶
Правь код в редакторе. Держи изменения сфокусированными: один PR = одна логическая правка. Если по ходу ты заметил «ещё надо починить вон то» — запиши задачу отдельно, не тащи в этот же PR.
Руководствуйся правилами:
conventions/go-style.md— именование, обработка ошибок, контекст.conventions/project-layout.md— в какую папку класть новый файл.- Для new-пакета / нового endpoint / новой миграции — смотри
соответствующий рецепт в
how-to/.
Шаг 5. Прогоняй линт и тесты¶
Если линт ругается:
- Читай сообщение целиком —
golangci-lintдаёт путь, строку и имя проверки. - Не выключай проверку через
//nolintбез комментария объяснения. - Типовые замечания (unused imports, shadowed err, errcheck) — это всегда правка кода, а не подавление линтера.
- Запусти
gofmt -l .— если что-то вывело, отформатируй.
Если тесты падают:
- Запусти конкретный тест для быстрого цикла:
go test -race -count=1 -run TestName ./internal/service/.... - Добавь
-vдля подробного вывода. - Если тест зависит от Postgres/Kafka через testcontainers — убедись, что
Docker запущен (
docker psне должен ругаться). - Зависший тест — см.
troubleshooting/test-hangs.md.
Шаг 6. Покрой новый код тестами¶
Любое новое поведение в internal/service/ должно иметь test. Правила:
- Новая ветка в service = минимум один happy-path тест и один error-path.
- Новая миграция = тест, который её применяет в testcontainers-Postgres и проверяет схему.
- Новый HTTP-endpoint = handler-тест через
httptest.NewRecorder. - Новый Kafka-handler = тест через
gochannelsubscriber/publisher.
Подробнее — в conventions/testing.md.
Шаг 7. Проверь по чеклисту автора PR¶
Пробеги глазами checklists/pr-author.md до
того, как запушишь ветку. Там собрано всё, что ревьюер спросит в первую
очередь: env-файлы, миграции с advisory_xact_lock, PII в логах, обёртка
ошибок через %w и т.д.
Шаг 8. Коммит¶
git add -p # добавляй интерактивно, по хункам
git status # убедись, что ничего лишнего
git commit -m "feat(user): add handbook link to readme"
Формат сообщения — Conventional Commits:
Примеры:
feat(review): add SSE throttle for histogram updates
fix(user): close refresh-token tx on rollback
chore(media): bump pgx to v5.7.2
docs(handbook): document outbox publisher pattern
Нет --no-verify. Нет секретов в сообщении и в изменениях (проверь git diff
глазами ещё раз).
Шаг 9. Push и открытие PR¶
Открой PR в UI git-хостинга. Описание PR должно отвечать на три вопроса:
- Цель. Зачем это изменение? (1–3 строки.)
- Что сделано. Короткий список ключевых правок. Не пересказывай diff.
- Как тестировать. Команды / шаги, по которым ревьюер проверит.
Пример:
## Цель
Добавляем ссылку на handbook из README, чтобы новички быстрее находили guide.
## Что сделано
- Добавлена секция «Documentation» в README.md.
- Обновлён onboarding-текст в CONTRIBUTING.md.
## Как тестировать
- `make lint && make test`
- Открыть README в preview, убедиться, что ссылка ведёт на handbook.
Если PR трогает > 400 изменённых строк — декомпозируй на несколько. Гигантские PR плохо ревьюятся и чаще содержат баги.
Шаг 10. Code review¶
- Минимум один approve. Для security-sensitive областей (auth, crypto, миграции, внешние клиенты с секретами) — два approve.
- Отвечай на каждый комментарий. Либо правь код, либо объясняй, почему не правишь. «ok» без правки — плохой сигнал.
- Никаких force-push после того, как ревьюер начал смотреть: пуш новые коммиты поверх. Squash произойдёт при merge.
Шаг 11. Merge¶
По умолчанию — squash merge. Финальное сообщение совпадает с заголовком PR, поэтому заголовок должен читаться как commit-message.
После merge:
- Удали ветку (UI предложит кнопку).
- У себя локально переключись на main и подтяни:
Готово — ты прошёл полный цикл. Дальше всё то же самое, только быстрее.