Пошук уроків, статей та іншого контенту
Інтегруємо Git із CI/CD, запускаємо перевірки для гілок і pull request та керуємо автоматичними збірками.
Git у CI/CD є джерелом подій, які запускають автоматизацію:
push — зміни надіслано до віддаленої гілки;
pull request — запропоновано об’єднати одну гілку з іншою;
tag — створено тег, наприклад v1.4.0;
manual dispatch — запуск виконано вручну.
CI-система отримує код із Git-репозиторію, перевіряє його та створює артефакти. Результат перевірок повертається до pull request як статус:
успішно — зміни можна об’єднувати;
помилка — pull request потребує виправлення;
виконання триває — остаточний статус ще не визначено.
CD використовує перевірений результат CI для автоматичного розгортання або публікації.
Типовий pipeline має запускатися в кількох режимах:
Для кожного pull request — щоб перевірити зміни до злиття.
Для push у захищені гілки — щоб перевірити фактичний стан репозиторію після злиття.
Для тегів — щоб створити релізну збірку.
Вручну — для повторного запуску або спеціальних операцій.
Перевірка pull request і перевірка після злиття не є повністю взаємозамінними. Під час pull request перевіряється запропонований набір змін, а після
pushmainGitHub Actions зберігає конфігурацію workflow у каталозі .github/workflows. Нижче наведено pipeline для Node.js-проєкту:
запускається для pull request у main;
запускається після push у main;
запускається для тегів версії;
використовує однакову версію Node.js;
виконує перевірки;
створює production-збірку;
зберігає збірку як артефакт;
скасовує застарілий запуск для тієї самої гілки або pull request.
name: CI
on:
pull_request:
branches:
- main
push:
branches:
- main
tags:
- "v*"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
verify:
name: Перевірка
runs-on: ubuntu-latest
steps:
- name: Отримати код
uses: actions/checkout@v4
- name: Налаштувати Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Встановити залежності
run: npm ci
- name: Запустити lint
run: npm run lint
- name: Запустити тести
run: npm test
build:
name: Збірка
needs: verify
runs-on: ubuntu-latest
steps:
- name: Отримати код
uses: actions/checkout@v4
- name: Налаштувати Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Встановити залежності
run: npm ci
- name: Створити production-збірку
run: npm run build
- name: Зберегти артефакт збірки
uses: actions/upload-artifact@v4
with:
name: application-build
path: dist/
if-no-files-found: errorТакий workflow очікує, що package.json містить відповідні скрипти:
{
"scripts": {
"lint": "eslint .",
"test": "node --test",
"build": "mkdir -p dist && cp -r src/* dist/"
}
}Команда npm ci встановлює залежності за lock-файлом. На CI краще використовувати саме її, а не npm install, оскільки вона призначена для відтворюваних встановлень і завершується з помилкою, якщо package-lock.json не відповідає package.json.
У прикладі є дві job:
jobs:
verify:
...
build:
needs: verify
...Без needs GitHub Actions міг би запускати job паралельно. Властивість:
needs: verifyозначає, що build почнеться лише після успішного завершення verify.
Якщо lint або тести завершуються з ненульовим кодом:
job verify стає невдалою;
job build не запускається;
pull request отримує негативний статус;
злиття можна заборонити правилом захисту гілки.
Це створює чітку межу між перевіркою коду та створенням артефакту.
Фрагмент:
on:
pull_request:
branches:
- mainозначає, що workflow запускатиметься для pull request, цільовою гілкою якого є main.
Наприклад:
feature/login → main — workflow запускається;
bugfix/header → develop — цей workflow не запускається;
main → main — зазвичай такий pull request не створюють.
Під час події pull_request GitHub Actions перевіряє спеціальне посилання, яке представляє стан запропонованих змін. Це дає змогу перевірити pull request до його злиття.
Для перевірок pull request потрібно обережно працювати з секретами. Не слід без потреби передавати секретні значення workflow, який запускається для коду з потенційно ненадійної гілки або з pull request із зовнішнього fork-репозиторію.
У цьому workflow:
push:
branches:
- main
tags:
- "v*"є два типи запуску:
push у main;
push тегів, назви яких починаються з v.
Приклади тегів, що відповідають шаблону:
v1.0.0;
v2.3.1;
v10.0.0-rc.1.
Теги з іншими назвами, наприклад release-1, цей workflow не запускають.
Запуск після push у main важливий, навіть якщо всі зміни вже перевірялися в pull request. Він перевіряє саме результат, який опинився в основній гілці.
Під час активної розробки одна гілка може отримати кілька push поспіль. Без додаткового налаштування CI запустить окремий pipeline для кожного push.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueЦя конфігурація:
групує запуски за workflow і Git-посиланням;
скасовує старий запуск, якщо з’явився новіший;
економить ресурси;
не дозволяє застарілому результату стати останнім статусом для гілки.
Скасування безпечне для звичайних перевірок і збірок. Для операцій, які вже змінюють зовнішню систему, потрібно окремо продумати, чи можна їх переривати.
Рекомендується явно задавати мінімальні дозволи:
permissions:
contents: readЦе дозволяє workflow читати вміст репозиторію, але не дає йому права змінювати код або керувати іншими ресурсами.
Принцип мінімальних дозволів особливо важливий для CI:
стороння залежність може містити вразливий код;
помилка в script може виконати небажану команду;
pull request може містити змінені конфігурації pipeline.
Дозволи потрібно розширювати лише тоді, коли конкретний крок справді цього потребує.
Самого workflow недостатньо. Правила репозиторію мають вимагати успішного завершення перевірок перед злиттям pull request.
Для main зазвичай налаштовують:
заборону прямого push;
обов’язковий pull request;
щонайменше один review;
обов’язкові статуси CI;
заборону злиття, якщо перевірки не пройшли;
актуальність гілки pull request перед злиттям.
Назви обов’язкових статусів мають відповідати job або перевірці, яку створює workflow. Якщо перейменувати job verify, правило захисту може потребувати оновлення.
Захист гілки перетворює CI з рекомендації на механізм контролю: зміни не потрапляють у main, доки не пройдуть визначені перевірки.
Артефакт — це результат роботи pipeline, який можна завантажити або передати наступному етапу.
У прикладі артефактом є каталог dist/:
- name: Зберегти артефакт збірки
uses: actions/upload-artifact@v4
with:
name: application-build
path: dist/
if-no-files-found: errorПараметр if-no-files-found: error не дозволяє pipeline завершитися успішно, якщо збірка не створила очікувані файли.
Артефакт корисний тому, що наступний етап може використовувати вже перевірений результат, а не збирати код повторно. Це зменшує ризик, що між перевіркою та розгортанням буде отримано інший результат.
Іноді збірка потрібна для всіх pull request, а публікація — лише для тегів. Для цього використовують умову if:
publish:
name: Публікація
needs: build
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
steps:
- name: Отримати артефакт
uses: actions/download-artifact@v4
with:
name: application-build
path: dist
- name: Перевірити вміст збірки
run: find dist -type f -printУ такій конфігурації job publish запускається лише для тегів версії. Для pull request вона пропускається, хоча verify і build продовжують виконуватися.
Умови варто застосовувати до окремих етапів, а не приховувати ними помилки. Основні перевірки повинні запускатися для кожної зміни.
За замовчуванням actions/checkout отримує код репозиторію. Для деяких операцій потрібна історія Git або теги. Наприклад, якщо версію визначають за тегом, можна отримати повну історію:
- name: Отримати повну історію Git
uses: actions/checkout@v4
with:
fetch-depth: 0Значення fetch-depth: 0 завантажує всю історію та теги. Це повільніше й потребує більше місця, тому його не слід вмикати без потреби.
Для звичайного lint, тестів і збірки достатньо стандартного checkout із неповною історією.
CI має давати однаковий результат для однакового стану Git. Для цього:
фіксуйте версію Node.js;
зберігайте lock-файл у репозиторії;
використовуйте npm ci;
не покладайтеся на локально встановлені залежності;
не записуйте секрети в репозиторій;
перевіряйте код у чистому середовищі;
не змінюйте файли в процесі перевірки без контролю результату.
Важливо також зафіксувати версії action. Наприклад:
uses: actions/checkout@v4Це краще, ніж використовувати невизначене або змінне посилання, оскільки поведінка pipeline не повинна несподівано змінюватися через оновлення залежності workflow.
Розглянемо послідовність для гілки feature/search:
Розробник створює гілку від main.
Виконує локальні lint і тести.
Надсилає гілку до Git-репозиторію.
Створює pull request у main.
CI запускає verify і build.
Якщо перевірки неуспішні, розробник виправляє код і надсилає новий commit.
Старий запуск може бути скасований через concurrency.
Після успішних перевірок і review pull request зливається.
push у main запускає pipeline повторно.
Для тега v1.0.0 додатковий етап може створити релізну або публічну збірку.
Цей процес відокремлює розробку у feature-гілках від змін, які вважаються готовими.
mainЯкщо workflow запускається тільки після push у main, помилки в pull request виявляються запізно.
Виправлення: додайте подію pull_request для цільової гілки.
npm install замість npm cinpm install може оновити lock-файл або встановити інший набір версій.
Виправлення: зберігайте package-lock.json і використовуйте npm ci.
Якщо build не має needs: verify, вона може створити артефакт для коду, який не пройшов тести.
Виправлення: задайте залежність між job через needs.
Навіть якісний CI не захищає main, якщо розробники можуть надсилати туди код напряму.
Виправлення: увімкніть захист гілки та вимагайте pull request.
Без lock-файла різні запуски можуть отримати різні версії залежностей.
Виправлення: додайте lock-файл до Git і не ігноруйте його.
Наступний етап очікує dist/, але збірка створює інший каталог або нічого не створює.
Виправлення: перевіряйте шлях path і використовуйте if-no-files-found: error.
Кілька запусків для однієї гілки можуть завершитися в непередбаченому порядку.
Виправлення: налаштуйте concurrency для перевірок і збірок.
Workflow отримує права запису, хоча йому потрібно лише читати код.
Виправлення: починайте з permissions: contents: read і додавайте інші дозволи лише за потреби.
Git події запускають CI/CD: push, pull_request, теги та ручний запуск.
Перевірки pull request потрібно виконувати до злиття в основну гілку.
Перевірка push у main підтверджує фактичний стан після злиття.
needs задає порядок виконання job.
concurrency скасовує застарілі запуски.
npm ci і lock-файл допомагають отримати відтворюваний результат.
Артефакт збірки можна зберегти й використати на наступному етапі.
Захист гілки не дозволяє об’єднати зміни, доки обов’язкові перевірки не завершаться успішно.
Мінімальні дозволи workflow зменшують наслідки помилок і вразливостей.