GitHub Actions do zero: CI/CD para projetos PHP e Node.js

1. Fundamentos do GitHub Actions e CI/CD

GitHub Actions é a plataforma de automação nativa do GitHub que permite criar pipelines de integração contínua (CI) e entrega contínua (CD) diretamente no repositório. Os workflows são definidos em arquivos YAML dentro do diretório .github/workflows/ e respondem a eventos como push, pull_request ou workflow_dispatch.

Os três componentes essenciais são:

  • Eventos: gatilhos que disparam o workflow (push, PR, agendamento)
  • Jobs: etapas independentes ou sequenciais que rodam em runners
  • Steps: comandos individuais dentro de cada job

Para projetos PHP e Node.js, o GitHub Actions oferece actions oficiais que simplificam a configuração de ambiente, cache e execução de testes.

name: CI Pipeline
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Exemplo de comando
        run: echo "Workflow iniciado"

2. Configurando o ambiente de execução para PHP

A action shivammathur/setup-php é a mais utilizada para configurar PHP em runners Ubuntu. Ela permite instalar extensões específicas, configurar o php.ini e habilitar ferramentas como Composer e PHPUnit.

- name: Setup PHP
  uses: shivammathur/setup-php@v2
  with:
    php-version: '8.2'
    extensions: mbstring, pdo_mysql, gd
    tools: composer, phpunit

O cache de dependências do Composer reduz significativamente o tempo de execução. O GitHub Actions fornece uma action de cache genérica que pode ser configurada para armazenar o diretório vendor.

- name: Cache Composer dependencies
  uses: actions/cache@v3
  with:
    path: vendor
    key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
    restore-keys: |
      ${{ runner.os }}-composer-

3. Pipeline de CI para projetos PHP

Um workflow completo de CI para PHP valida sintaxe, executa testes unitários e verifica padrões de código. O PHP_CodeSniffer garante que o código siga as regras PSR-12 ou padrões personalizados.

name: PHP CI

on:
  pull_request:
    branches: [main]

jobs:
  php-tests:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          coverage: xdebug

      - name: Cache Composer
        uses: actions/cache@v3
        with:
          path: vendor
          key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

      - name: Install dependencies
        run: composer install --no-progress --prefer-dist

      - name: PHP Syntax Check
        run: find . -name "*.php" -not -path "./vendor/*" -exec php -l {} \;

      - name: PHP CodeSniffer
        run: vendor/bin/phpcs --standard=PSR12 src/

      - name: Run PHPUnit
        run: vendor/bin/phpunit --coverage-text

4. Configurando o ambiente de execução para Node.js

A action actions/setup-node gerencia versões do Node.js e npm. Para projetos Node.js, o comando npm ci é preferível ao npm install em pipelines, pois instala exatamente as versões do package-lock.json e falha se o lockfile estiver desatualizado.

- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'

O cache automático do setup-node armazena ~/.npm e node_modules, mas para maior controle, pode-se usar a action actions/cache diretamente.

- name: Cache node_modules
  uses: actions/cache@v3
  with:
    path: node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

5. Pipeline de CI para projetos Node.js

Um pipeline típico para Node.js inclui linting com ESLint, formatação com Prettier e execução de testes com Jest. O build de produção pode ser verificado sem ser publicado.

name: Node.js CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  node-tests:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [18, 20]

    steps:
      - uses: actions/checkout@v4

      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: ESLint
        run: npx eslint src/ --max-warnings 0

      - name: Prettier Check
        run: npx prettier --check src/

      - name: Run tests
        run: npm test -- --coverage

      - name: Build production
        run: npm run build

6. Deploy automatizado (CD) para ambos os ecossistemas

O deploy contínuo pode ser feito via SSH utilizando ações como appleboy/scp-action para transferência de arquivos e appleboy/ssh-action para execução remota. É fundamental armazenar credenciais como Secrets do GitHub.

- name: Deploy via SSH
  uses: appleboy/ssh-action@v1.0.3
  with:
    host: ${{ secrets.DEPLOY_HOST }}
    username: ${{ secrets.DEPLOY_USER }}
    key: ${{ secrets.DEPLOY_KEY }}
    script: |
      cd /var/www/projeto
      git pull origin main
      composer install --no-dev --optimize-autoloader
      php artisan migrate --force

Para Node.js em serviços cloud como Vercel ou Heroku, existem actions oficiais simplificadas.

- name: Deploy to Vercel
  uses: amondnet/vercel-action@v25
  with:
    vercel-token: ${{ secrets.VERCEL_TOKEN }}
    vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
    vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}

7. Otimização, boas práticas e troubleshooting

Matrix builds permitem testar múltiplas versões de runtime em paralelo, garantindo compatibilidade. Exemplo para PHP:

strategy:
  matrix:
    php: [8.1, 8.2, 8.3]

Notificações de falha podem ser enviadas para Slack ou Discord usando ações dedicadas:

- name: Notify Slack
  if: failure()
  uses: slackapi/slack-github-action@v1.24.0
  with:
    payload: |
      {"text":"Pipeline falhou em ${{ github.repository }}"}
  env:
    SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

Debug de workflows: ative a depuração definindo ACTIONS_STEP_DEBUG=true como secret do repositório. Para reexecutar jobs falhos, use o botão "Re-run jobs" na interface do GitHub Actions.

Boas práticas finais:

  • Sempre use actions/checkout@v4 como primeiro step
  • Prefira npm ci em vez de npm install em pipelines
  • Utilize composer install --no-interaction --prefer-dist para PHP
  • Versionamento semântico de actions (pin em versões específicas)
  • Separe jobs de CI e CD em workflows distintos

Referências