Питання на співбесіді: Хуки, CI й автоматизація
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
14 питань
Хуки - виконувані скрипти, які Git запускає в певні моменти: перед комітом, після checkout, перед push. Лежать у .git/hooks/ (Git створює там приклади з суфіксом .sample) і мають бути виконуваними (chmod +x).
Клієнтські хуки, які використовують найчастіше:
| Хук | Коли | Типове використання |
|---|---|---|
pre-commit |
перед створенням коміту | форматування, лінтер, швидкі перевірки |
prepare-commit-msg |
перед відкриттям редактора повідомлення | підставити номер задачі з назви гілки |
commit-msg |
після введення повідомлення | перевірити формат (Conventional Commits) |
post-checkout |
після checkout/switch |
оновити залежності, очистити кеш |
pre-push |
перед відправкою на сервер | запустити тести |
Ненульовий код виходу скасовує операцію - так pre-commit може заборонити коміт:
#!/bin/sh
# .git/hooks/pre-commit
vendor/bin/pint --test || {
echo "Код не відформатовано. Запустіть vendor/bin/pint"
exit 1
}
Що отримують хуки:
commit-msg- шлях до файла з повідомленням коміту (першим аргументом);pre-push- назву й адресу віддаленого репозиторію в аргументах, а в стандартному вводі - рядки з посиланнями й SHA, які відправляються.
Важливі обмеження:
.git/hooksне потрапляє в репозиторій - хуки не поширюються командою автоматично (для цього -core.hooksPathчи інструменти на кшталт Husky і CaptainHook);- хуки легко обійти:
git commit --no-verify(чи-n) пропускаєpre-commitіcommit-msg,git push --no-verify-pre-push. Тому хуки - зручність для розробника, а гарантію дає CI; - хуки мають бути швидкими:
pre-commitна хвилину - і люди почнуть використовувати--no-verifyпостійно. Повний набір тестів - уpre-pushчи CI.
Каталог .git/ не версіонується, тож хуки, покладені в .git/hooks, живуть лише на вашій машині. Є кілька способів зробити їх спільними.
1. core.hooksPath - вбудований механізм Git:
mkdir .githooks
# покласти туди pre-commit, commit-msg... і зробити виконуваними
chmod +x .githooks/*
git config core.hooksPath .githooks
Хуки лежать у репозиторії й проходять рев'ю, але кожен розробник має один раз виконати git config. Його зручно додати в скрипт налаштування проєкту:
{
"scripts": {
"post-install-cmd": ["git config core.hooksPath .githooks || true"]
}
}
2. CaptainHook - для PHP-проєктів: конфігурація в captainhook.json, хуки встановлюються командою vendor/bin/captainhook install (або автоматично через Composer-плагін):
{
"pre-commit": {
"enabled": true,
"actions": [
{ "action": "vendor/bin/pint --test" },
{ "action": "vendor/bin/phpstan analyse --no-progress" }
]
}
}
3. GrumPHP - інший PHP-інструмент: набір готових задач (phpcs, phpstan, phpunit, перевірка повідомлень комітів), конфігурація в grumphp.yml, хуки ставить сам.
4. Husky - якщо в проєкті є Node: npx husky init створює каталог .husky/ і через скрипт prepare у package.json налаштовує core.hooksPath при кожному npm install. Часто разом з lint-staged, що запускає інструменти лише на змінених файлах.
Як обрати: PHP-бекенд без Node - CaptainHook чи GrumPHP; є фронтенд і npm install - Husky; мінімум залежностей - core.hooksPath.
Пам'ятайте: хуки - зручність, а не гарантія. Будь-хто може їх не встановити чи пропустити через --no-verify, тому ті самі перевірки обов'язково дублюються в CI.
Laravel Pint - форматувальник коду на основі PHP CS Fixer. Корисні режими:
vendor/bin/pint # виправити всі файли
vendor/bin/pint --test # лише перевірити, ненульовий код при помилках
vendor/bin/pint --dirty # лише файли з незакоміченими змінами
vendor/bin/pint --diff=main # лише файли, що відрізняються від гілки main
vendor/bin/pint --repair # виправити, але повернути ненульовий код, якщо було що виправляти
Простий pre-commit хук:
#!/bin/sh
files=$(git diff --cached --name-only --diff-filter=ACMR -- '*.php')
[ -z "$files" ] && exit 0
vendor/bin/pint $files
git add $files
git diff --cached- лише файли, додані в індекс (тобто ті, що потраплять у коміт);--diff-filter=ACMR- додані, скопійовані, змінені й перейменовані; видалені файли форматувати нема чого;git addпісля форматування - щоб виправлення потрапили в коміт.
Пастка частково доданих файлів: якщо у файлі частина змін додана в індекс (git add -p), а частина ні, то git add $files після Pint додасть у коміт і ті зміни, які ви навмисно не додавали. Варіанти:
- лише перевіряти, а не виправляти:
vendor/bin/pint --test $files- коміт блокується, розробник сам запускає Pint; - використати інструмент, що вміє працювати з частковим індексом (lint-staged ховає неіндексовані зміни на час перевірки).
--dirty у хуку - зручно, але він бере файли з будь-якими незакоміченими змінами, а не лише з індексу.
Що варто знати:
- форматування в хуку - зручність; в CI має бути
pint --test, щоб неформатований код не потрапив уmainчерез--no-verify; - конфігурація в
pint.json- однакова для хуку, CI й редактора; - великий одноразовий перехід на Pint краще зробити окремим комітом і додати його SHA у
.git-blame-ignore-revs, щобgit blameне показував форматування як автора всіх рядків.
GitHub Actions - вбудований у GitHub CI/CD. Робочі процеси (workflows) описуються в YAML у .github/workflows/ і запускаються на події: push, pull request, розклад, ручний запуск.
Основні поняття:
- workflow - файл з описом процесу;
- event (
on) - що запускає процес; - job - набір кроків, що виконується на окремій віртуальній машині (runner); jobs ідуть паралельно, якщо не вказано залежність
needs; - step - команда (
run) чи готова дія (uses) з Marketplace.
Мінімальний workflow для Laravel:
# .github/workflows/tests.yml
name: tests
on:
pull_request:
push:
branches: [main]
jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
coverage: none
- run: composer install --no-interaction --prefer-dist
- run: cp .env.example .env && php artisan key:generate
- run: vendor/bin/pint --test
- run: php artisan test --compact
Що відбувається: на кожен PR і push у main GitHub піднімає чисту машину з Ubuntu, завантажує код, встановлює PHP і залежності, перевіряє стиль і запускає тести. Результат видно в PR як перевірку - зелену чи червону.
Чому це важливо:
- те, що «працює в мене», перевіряється в чистому середовищі;
- хуки можна пропустити, а CI - ні, особливо з обов'язковими перевірками в захисті гілки;
- рецензент не витрачає час на код, який не проходить тести.
Корисно знати:
- для публічних репозиторіїв стандартні runner-и безкоштовні, для приватних є місячна квота хвилин;
- секрети (ключі API) - у Settings → Secrets і доступні як
${{ secrets.NAME }}; у PR з форків секрети за замовчуванням не передаються; shivammathur/setup-php- де-факто стандарт для PHP: версії, розширення, інструменти.
Dependabot - бот GitHub, що стежить за залежностями й сам відкриває pull request-и з оновленнями. Розробнику лишається переглянути зміни, дочекатися зеленого CI і злити.
Два режими:
- security updates - PR лише для залежностей з відомими вразливостями (на основі GitHub Advisory Database);
- version updates - регулярні PR з новими версіями за розкладом.
Конфігурація для Laravel-проєкту:
# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: composer
directory: /
schedule:
interval: weekly
groups:
laravel:
patterns: ["laravel/*"]
open-pull-requests-limit: 5
- package-ecosystem: npm
directory: /
schedule:
interval: weekly
- package-ecosystem: github-actions
directory: /
schedule:
interval: monthly
Що тут налаштовано:
- екосистеми: Composer, npm і навіть версії дій у workflow GitHub Actions;
groups- кілька оновлень в одному PR (усі пакетиlaravel/*разом), щоб не тонути в десятках дрібних PR;open-pull-requests-limit- скільки PR бот тримає відкритими одночасно;schedule- як часто перевіряти.
Чому це варто робити:
- маленькі регулярні оновлення простіші за одне велике раз на рік, коли накопичилися мажорні версії й breaking changes;
- вразливості закриваються швидко, а не після інциденту;
- оновлення проходять той самий процес, що й код: CI, рев'ю, історія.
Без доброго набору тестів Dependabot корисний наполовину: зелений CI має реально означати «оновлення нічого не зламало». Тому тести - передумова для сміливих оновлень.
Корисні опції: ignore - пропускати певні пакети чи мажорні версії, cooldown - не пропонувати версію одразу після публікації, а почекати кілька днів (захист від зламаних чи скомпрометованих релізів).
Докладніше в документації: GitHub: Dependabot version updates
Для повідомлень комітів є два хуки:
prepare-commit-msg- викликається до відкриття редактора; може підготувати чи доповнити текст;commit-msg- викликається після введення повідомлення; може перевірити його і заборонити коміт.
Обидва отримують шлях до файла з повідомленням першим аргументом.
Перевірка Conventional Commits у commit-msg:
#!/bin/sh
pattern='^(feat|fix|docs|refactor|test|chore|perf|ci|build)(\([a-z0-9-]+\))?!?: .{1,72}$'
if ! head -1 "$1" | grep -qE "$pattern"; then
echo "Повідомлення не відповідає Conventional Commits:"
echo " feat(vacancies): add CSV export"
exit 1
fi
Номер задачі з назви гілки в prepare-commit-msg:
#!/bin/sh
# гілка feature/ABC-123-csv-export -> префікс [ABC-123]
case "$2" in merge|squash|commit) exit 0 ;; esac # не чіпати merge, squash і --amend
ticket=$(git branch --show-current | grep -oE '[A-Z]+-[0-9]+')
[ -n "$ticket" ] && ! grep -q "$ticket" "$1" && sed -i.bak "1s/^/[$ticket] /" "$1" && rm -f "$1.bak"
Другий аргумент - джерело повідомлення (message при -m, merge, squash, commit при --amend чи -c), щоб не дописувати префікс у службові повідомлення.
Готові інструменти:
- commitlint (Node) - правила для Conventional Commits, часто разом з Husky;
- CaptainHook має вбудовані дії для перевірки повідомлень (довжина рядків, регулярні вирази, загальноприйняті правила оформлення повідомлень);
- GrumPHP - задача
git_commit_message.
Чому перевірка потрібна і в CI: хук локальний, і git commit --no-verify його пропускає. Якщо від формату залежать змінлог і версіонування, перевіряйте повідомлення ще й у CI - або заголовок PR, якщо зливаєте через squash: тоді саме він стає повідомленням коміту в main.
Тести, що працюють з базою, найкраще ганяти на тій самій СУБД, що й на продакшені: SQLite пропускає помилки, специфічні для PostgreSQL чи MySQL (суворіший GROUP BY, типи, регістр у LIKE).
Service containers - Docker-контейнери, які GitHub Actions піднімає поруч із job:
jobs:
tests:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18
env:
POSTGRES_DB: testing
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
ports: ["5432:5432"]
options: >-
--health-cmd pg_isready
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:8-alpine
ports: ["6379:6379"]
env:
DB_CONNECTION: pgsql
DB_HOST: 127.0.0.1
DB_DATABASE: testing
DB_USERNAME: app
DB_PASSWORD: secret
REDIS_HOST: 127.0.0.1
steps:
- uses: actions/checkout@v7
- uses: shivammathur/setup-php@v2
with:
php-version: '8.5'
extensions: pdo_pgsql, redis
- id: composer-cache
run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"
- uses: actions/cache@v6
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: composer-${{ hashFiles('composer.lock') }}
restore-keys: composer-
- run: composer install --no-interaction --prefer-dist
- run: php artisan test --parallel
Ключові моменти:
- healthcheck у
options- GitHub чекає, доки база стане здоровою, перш ніж запускати кроки. Без нього тести можуть стартувати раніше, ніж PostgreSQL готовий; - адреса: job працює прямо на runner-і, тому сервіси доступні як
127.0.0.1через опубліковані порти. Якщо job сам виконується в контейнері (container:), сервіси доступні за назвою (postgres), і порти публікувати не треба; - кеш Composer за хешем
composer.lock- залежності не завантажуються щоразу; кешується каталог завантажень Composer, а неvendor/; - змінні
envперекривають.env- конфігурація тестів без окремого файла.
Прискорення: --parallel для тестів, окремі jobs для стилю (Pint) і статичного аналізу (PHPStan), щоб вони йшли паралельно з тестами, і concurrency з cancel-in-progress: true - скасовувати застарілі запуски при новому push у ту саму гілку.
Докладніше в документації: GitHub Actions: service containers
actions/checkout за замовчуванням завантажує лише один коміт - той, що запустив workflow (fetch-depth: 1). Для збирання й тестів цього досить, і це швидко. Але все, що потребує історії, ламається.
Типові симптоми:
fatal: No names found, cannot describe anything. # git describe без тегів
fatal: ambiguous argument 'origin/main...HEAD' # немає гілки main
fatal: bad object ... # немає потрібного коміту
git describeчи визначення версії з тегів - тегів немає;git diff origin/main...HEAD,pint --diff=main, «запускати тести лише для змінених файлів» - немаєmainі спільного предка;- генерація змінлогу з повідомлень комітів - немає комітів;
git logдля дати останньої зміни файла - показує один коміт;- інструменти на кшталт SonarQube скаржаться на неповну історію для blame.
Варіанти виправлення:
- uses: actions/checkout@v7
with:
fetch-depth: 0 # уся історія, усі гілки й теги
0 - найпростіше, але у великому репозиторії checkout стає помітно повільнішим.
Точніше - догрузити лише потрібне:
- uses: actions/checkout@v7
- run: git fetch --no-tags --depth=50 origin main
- run: vendor/bin/pint --test --diff=origin/main
Або fetch-tags: true з невеликою глибиною, якщо потрібні лише теги.
Нюанс pull request-ів: для події pull_request checkout за замовчуванням бере тимчасовий коміт злиття PR з базовою гілкою (refs/pull/N/merge), а не останній коміт гілки PR. Тести перевіряють результат злиття, що добре, але git log покаже коміт злиття, якого немає в гілці. Якщо потрібна саме голова гілки - ref: ${{ github.event.pull_request.head.sha }}.
Правило: глибина історії в CI - свідомий вибір: мінімум для швидкості, а для кроків, яким потрібна історія, - явно догрузити рівно стільки, скільки треба.
Видалити секрет з історії складно, а після публікації - вже запізно: ключ треба вважати скомпрометованим. Тому головне - не дати йому потрапити в коміт. Захист будують у кілька шарів.
1. Структура проєкту:
- секрети лише в
.env, який у.gitignore; у репозиторії -.env.exampleз порожніми значеннями; - у коді - лише
config('services.stripe.secret'), ніяких ключів у тестах, сидерах і фікстурах; - для CI - секрети платформи (
${{ secrets.NAME }}), а не файли в репозиторії.
2. Локальна перевірка до коміту - сканер секретів у pre-commit:
#!/bin/sh
gitleaks git --pre-commit --staged --redact --verbose
gitleaks шукає за сотнями шаблонів (ключі AWS, Stripe, GitHub-токени, приватні ключі) і за ентропією рядків. Хибні спрацювання - через .gitleaksignore чи конфігурацію.
3. Захист на сервері - push protection на GitHub:
- для користувачів увімкнено за замовчуванням: GitHub блокує ваш push із розпізнаним секретом у публічні репозиторії;
- для репозиторіїв (потрібна GitHub Secret Protection) - вмикається адміністратором і блокує push із секретами у конкретний репозиторій, зокрема з командного рядка, через вебінтерфейс і API.
При блокуванні push GitHub показує, у якому файлі й коміті знайдено секрет. Обхід можливий із зазначенням причини (хибне спрацювання, тестовий ключ), і для захисту на рівні репозиторію він створює сповіщення й запис у журналі аудиту.
4. Сканування в CI - той самий gitleaks на кожен PR: ловить те, що пройшло повз локальний хук через --no-verify чи відсутність хука.
5. Мінімізація шкоди:
- ключі з мінімальними правами й обмеженим терміном дії;
- окремі ключі для розробки, staging і продакшену;
- план дій на випадок витоку: спочатку відкликати ключ, а вже потім чистити історію.
Чому шари: кожен окремо можна обійти - хук не встановлено, push protection не знає формату вашого внутрішнього токена. Разом вони ловлять переважну більшість випадків.
Коли Composer встановлює пакет з дистрибутива (--prefer-dist, поведінка за замовчуванням для стабільних версій), він завантажує ZIP-архів, який GitHub генерує через git archive. Атрибут export-ignore у .gitattributes виключає файли з цього архіву.
# .gitattributes пакета
/.github export-ignore
/tests export-ignore
/docs export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/phpunit.xml.dist export-ignore
/phpstan.neon.dist export-ignore
/pint.json export-ignore
/CHANGELOG.md export-ignore
Перевірити результат локально:
git archive HEAD | tar -t
Виключені файли в списку не з'являться.
Навіщо це:
- менший
vendor/у кожному проєкті, що використовує пакет: тести, документація й конфіги CI пакета там нікому не потрібні; - швидше встановлення і менші образи Docker;
- менше шуму для інструментів, що сканують
vendor/(автодоповнення IDE, статичний аналіз); - не публікувати зайве - внутрішні скрипти, фікстури з даними.
Що не можна виключати:
src/,composer.json, файли, на які посилається автозавантаження;LICENSE- ліцензія має йти разом з кодом;README.mdзазвичай лишають;- ресурси, потрібні пакету під час роботи: шаблони, конфіги, міграції, файли перекладів.
Помилка тут ламає пакет лише при встановленні з дистрибутива: локально в репозиторії все працює, тому варто перевіряти через git archive чи тестове встановлення в чистий проєкт.
Пов'язане: --prefer-source завантажує повний клон репозиторію, і export-ignore там не діє. Інший корисний атрибут - export-subst: підставляє дані коміту (наприклад, $Format:%H$) у файли при створенні архіву.
Ручний git bisect вимагає на кожному кроці перевірити код і сказати good чи bad. git bisect run робить це сам: на кожному кроці запускає скрипт і читає його код завершення.
git bisect start HEAD v2.3.0 # погана ревізія, потім добра
git bisect run php artisan test --compact --filter=VacancyExportTest
git bisect reset
На 1000 комітах це близько 10 запусків тесту замість ручного пошуку.
Як Git трактує код завершення:
| Код | Значення |
|---|---|
0 |
коміт добрий |
1-127, крім 125 |
коміт поганий |
125 |
коміт неможливо перевірити - пропустити (skip) |
інше (наприклад, 128 і більше) |
перервати bisect |
Скрипт для реальних умов - стара версія коду може потребувати іншої підготовки:
#!/bin/sh
# bisect.sh
composer install --no-interaction --quiet || exit 125 # не збирається - пропустити
php artisan migrate:fresh --env=testing --force --quiet || exit 125
php artisan test --compact --filter=VacancyExportTest
exit 125- коміт, на якому проєкт не збирається з не пов'язаних причин, не вважається «поганим» і не збиває пошук;- база - тестова (
--env=testing), щоб не зачепити робочу.
Тест, якого ще не було в історії: часто баг виявили сьогодні, а тест написали теж сьогодні - у старих комітах його немає. Рішення - тримати тест поза робочим деревом і копіювати його на кожному кроці:
cp /tmp/RegressionTest.php tests/Feature/RegressionTest.php
php artisan test --compact tests/Feature/RegressionTest.php
status=$?
rm tests/Feature/RegressionTest.php
exit $status
Корисні деталі:
git bisect start --first-parent- іти лише по комітах злиття основної гілки: знайти, який PR зламав, без заходу в проміжні коміти гілок;git bisect logіgit bisect replay- зберегти й повторити сесію;- терміни
good/badможна замінити (--term-old=fast --term-new=slow) - bisect підходить і для пошуку регресії продуктивності, не лише помилки.
Серверні хуки виконуються на сервері, що приймає push, і можуть відхилити його. На відміну від клієнтських, їх не можна пропустити через --no-verify - розробник їх не контролює.
Основні серверні хуки:
| Хук | Коли | Що може |
|---|---|---|
pre-receive |
один раз на весь push, до оновлення посилань | відхилити весь push |
update |
для кожного оновлюваного посилання окремо | відхилити окрему гілку чи тег |
post-receive |
після успішного оновлення | сповіщення, запуск деплою; відхилити вже не може |
pre-receive отримує на стандартний ввід рядки <старий SHA> <новий SHA> <посилання>:
#!/bin/sh
zero=0000000000000000000000000000000000000000
while read old new ref; do
# заборонити force push у main: старий коміт має бути предком нового
if [ "$ref" = "refs/heads/main" ] && [ "$old" != "$zero" ]; then
if ! git merge-base --is-ancestor "$old" "$new"; then
echo "Force push у main заборонено"
exit 1
fi
fi
done
Вивід хука повертається клієнту з префіксом remote:.
Де це доступно:
- власний сервер Git, GitLab self-managed, GitHub Enterprise Server - так;
- github.com - власні серверні хуки встановити не можна. Їхню роль виконують rulesets (заборона force push, обов'язкові підписи, обмеження на шляхи й розмір файлів) і push protection для секретів.
Серверні хуки проти CI:
| Серверний хук | CI | |
|---|---|---|
| коли | синхронно, під час push | асинхронно, після push |
| результат | push відхилено, коду на сервері немає | код уже на сервері, PR позначено червоним |
| час | секунди - інакше push «зависає» | хвилини, без обмежень |
| що перевіряти | політики: формат, заборонені файли, права, підписи | збирання, тести, аналіз |
Правило: у хуки - швидкі й безумовні політики, порушення яких не має з'явитися на сервері навіть у гілці (секрети, величезні бінарні файли, заборонені операції). Усе, що довге чи потребує середовища, - в CI. Хук, що запускає тести, робить кожен push хвилинним і ламає роботу всієї команди при збоях.
Якщо повідомлення комітів дотримуються Conventional Commits, з історії можна автоматично визначити, яким має бути наступний номер версії і що писати в змінлог.
Правила семантичного версіонування з комітів:
| Коміти з останнього релізу | Нова версія |
|---|---|
лише fix: |
патч: 1.4.2 → 1.4.3 |
є feat: |
мінорна: 1.4.2 → 1.5.0 |
feat!: чи футер BREAKING CHANGE: |
мажорна: 1.4.2 → 2.0.0 |
chore:, docs:, test: |
релізу не потребують |
release-please (від Google) працює через релізний pull request:
- після кожного злиття в
mainдія аналізує нові коміти; - відкриває чи оновлює PR «chore(main): release 1.5.0» зі зміненим
CHANGELOG.mdі номером версії; - команда зливає цей PR, коли хоче випустити реліз;
- дія створює тег
v1.5.0і GitHub Release з нотатками.
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: googleapis/release-please-action@v5
with:
release-type: php
semantic-release - альтернатива без проміжного PR: реліз публікується одразу після злиття. Більше автоматизації, менше контролю над моментом релізу.
Що потрібно для роботи:
- дисципліна повідомлень - перевірка в
commit-msgі в CI; при злитті через squash - перевірка заголовка PR, бо він стає повідомленням коміту; - осмислені коміти:
fix: typoв історіїmainпотрапить у змінлог; - права боту на запис і створення PR; якщо релізний PR має запускати CI, потрібен токен GitHub App чи PAT - події від стандартного
GITHUB_TOKENне запускають інші workflow.
Обмеження: змінлог з комітів - для розробників. Для користувачів продукту часто потрібні людські нотатки до релізу, і автоматичний текст - лише чернетка для них.
У великому проєкті з десятками залежностей бот, що відкриває окремий PR на кожне оновлення, швидко стає шумом, який команда ігнорує. Мета - щоб рутинні оновлення проходили без людей, а увагу отримували лише ризиковані.
Renovate - гнучкіша альтернатива Dependabot: підтримує більше екосистем, складні правила, групування, автозлиття й «панель залежностей» (Dependency Dashboard) - задачу зі списком усіх очікуваних оновлень.
{
"extends": ["config:recommended"],
"schedule": ["before 6am on monday"],
"minimumReleaseAge": "3 days",
"lockFileMaintenance": { "enabled": true },
"packageRules": [
{
"matchUpdateTypes": ["patch", "minor"],
"matchCurrentVersion": "!/^0/",
"automerge": true
},
{
"matchPackageNames": ["laravel/**", "livewire/**", "filament/**"],
"groupName": "Laravel ecosystem"
},
{
"matchDepTypes": ["require-dev"],
"groupName": "dev dependencies",
"automerge": true
},
{
"matchUpdateTypes": ["major"],
"dependencyDashboardApproval": true
}
]
}
Що тут відбувається:
- автозлиття патчів і мінорних версій стабільних пакетів - якщо CI зелений, PR вливається сам;
- групи - пов'язані пакети оновлюються разом (екосистема Laravel), а не десятком окремих PR;
- мажорні версії - лише після схвалення на панелі, бо вони потребують міграції коду;
minimumReleaseAge- не брати версію, опубліковану щойно: зламані й скомпрометовані релізи зазвичай відкликають за перші дні;lockFileMaintenance- періодично оновлює транзитивні залежності вcomposer.lock, які інакше застарівають непомітно;- розклад - PR з'являються в певний час, а не протягом усього тижня.
Передумови для автозлиття:
- тести, яким можна довіряти - інакше автозлиття постачає баги в
main; - обов'язкові перевірки в захисті гілки - бот не повинен мати змоги злити червоний PR;
- моніторинг після деплою - швидко помітити регресію й відкотити.
Dependabot чи Renovate: Dependabot вбудований у GitHub і простіший у налаштуванні (групи, cooldown, ігнорування є й у ньому); Renovate виграє на складних правилах, монорепозиторіях і поза GitHub (GitLab, Bitbucket).