CI/CD для PHP проектов: GitHub Actions
Современная веб-разработка немыслима без автоматизации. Ручной запуск тестов, проверка стиля кода и деплой на сервер отнимают время и чреваты ошибками. Решение — CI/CD (Continuous Integration / Continuous Deployment). В этой статье мы разберем, как настроить полноценный пайплайн для PHP-проектов с помощью GitHub Actions. Вы узнаете, как автоматически тестировать код, проверять его качество и разворачивать на production-сервере при каждом пуше в репозиторий.
Что такое CI/CD и зачем это PHP-разработчику?
Continuous Integration (CI) — это практика, при которой каждый коммит автоматически проверяется: запускаются юнит-тесты, линтеры, проверки безопасности. Continuous Deployment (CD) — следующий шаг, когда успешно прошедший CI код автоматически разворачивается на сервере (staging или production).
Для PHP это особенно актуально: язык динамический, ошибки типизации и синтаксиса часто выявляются только в рантайме. GitHub Actions позволяет настроить пайплайн, который:
- Запускает PHPUnit тесты в разных версиях PHP (7.4, 8.0, 8.1, 8.2).
- Проверяет код с помощью PHP_CodeSniffer или PHPStan.
- Выполняет деплой на сервер через SSH или Docker.
Создание workflow в GitHub Actions
Для начала создайте в корне вашего PHP-проекта директорию .github/workflows. Внутри создайте файл, например ci.yml. Это и будет ваш пайплайн.
Рассмотрим базовый пример для CI. Он будет запускаться при каждом пуше в ветку main или при создании Pull Request.
name: PHP CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['7.4', '8.0', '8.1', '8.2']
steps:
- uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}
tools: composer, phpunit
- name: Validate composer.json and composer.lock
run: composer validate --strict
- name: Cache Composer packages
id: composer-cache
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-
- name: Install dependencies
run: composer install --prefer-dist --no-progress
- name: Run PHPUnit tests
run: phpunit --configuration phpunit.xml
Разбор ключевых моментов:
- Matrix strategy — позволяет запускать тесты на нескольких версиях PHP одновременно. Это гарантирует совместимость кода.
- shivammathur/setup-php — популярный action для настройки PHP окружения. Он устанавливает нужную версию, Composer и PHPUnit.
- Кэширование vendor — ускоряет последующие запуски, не загружая зависимости заново.
- composer validate — проверяет корректность composer.json.
Добавляем статический анализ и линтинг
Тесты — это хорошо, но без контроля качества кода не обойтись. Добавим в тот же workflow (или создадим отдельный job) проверку с помощью PHPStan и PHP_CodeSniffer.
- name: Run PHPStan
run: vendor/bin/phpstan analyse src tests --level=max
- name: Run PHP_CodeSniffer
run: vendor/bin/phpcs --standard=PSR2 src tests
Эти шаги можно добавить после установки зависимостей. PHPStan с уровнем max найдет потенциальные ошибки типов, а PHP_CodeSniffer со стандартом PSR-2 (или PSR-12) обеспечит единообразный стиль кода. Если хотя бы один шаг завершится ошибкой, весь workflow будет считаться проваленным, и Pull Request не будет принят.
Совет: для локальной разработки установите эти инструменты как dev-зависимости в composer.json:
composer require --dev phpstan/phpstan squizlabs/php_codesniffer
Настройка Continuous Deployment (деплой на сервер)
После того, как тесты пройдены, можно автоматически развернуть код на сервере. Рассмотрим два популярных подхода: через SSH (классический) и через Docker Hub.
Вариант 1: Деплой через SSH
Для этого понадобится добавить секреты (Secrets) в GitHub: SSH_PRIVATE_KEY, REMOTE_HOST, REMOTE_USER, REMOTE_PATH.
deploy:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Deploy to Server
uses: easingthemes/ssh-deploy@v2
env:
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
ARGS: "-rltgoDzvO --delete"
SOURCE: "."
REMOTE_HOST: ${{ secrets.REMOTE_HOST }}
REMOTE_USER: ${{ secrets.REMOTE_USER }}
TARGET: ${{ secrets.REMOTE_PATH }}
Обратите внимание на needs: build — job деплоя запустится только после успешного завершения job с тестами. Флаг --delete удаляет файлы на сервере, которых нет в репозитории.
Вариант 2: Docker-образ
Если ваш PHP-проект работает в контейнерах, можно собрать образ и отправить его в Docker Hub, а затем на сервере выполнить docker pull и перезапустить контейнер.
docker-build:
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Log in to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: yourusername