Developer Tools

GitHub Actions CI/CD: Criando Workflows de Build, Teste e Deploy do Zero

Aprenda a configurar o GitHub Actions para integração e entrega contínua. Abrange triggers, jobs, matrizes, secrets, caching, Docker e exemplos reais de workflows.

10 min de leitura

Colaboração de código no GitHub em tela

O GitHub Actions transforma cada push, pull request e merge em um pipeline automatizado — executando testes, gerando artefatos, verificando vulnerabilidades e fazendo deploy em produção. É a plataforma de CI/CD que vive direto dentro do seu repositório, sem nenhuma infraestrutura para gerenciar.

Como o GitHub Actions funciona

Cada workflow é um arquivo YAML dentro de .github/workflows/. Quando um evento de trigger é disparado, o GitHub sobe uma máquina virtual nova, executa os seus jobs e reporta os resultados — tudo em questão de segundos.

Push para main
  ↓
Workflow disparado
  ↓
Job: Build & Test (ubuntu-latest)
  ├── Passo 1: Checkout do código
  ├── Passo 2: Instalar Node.js
  ├── Passo 3: npm ci
  ├── Passo 4: npm test
  └── Passo 5: npm run build
  ↓
✅ Todas as verificações passaram

Seu primeiro workflow

Crie .github/workflows/ci.yml:

name: CI

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

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci
      - run: npm test
      - run: npm run build

É só isso. A partir de agora, cada push para main e cada PR executará sua suíte de testes automaticamente.

Triggers: quando os workflows são executados

Eventos de código

on:
  push:
    branches: [main, develop]
    paths: ['src/**', 'package.json']  # Só executa quando esses arquivos mudam
  pull_request:
    types: [opened, synchronize]

Agendado (cron)

on:
  schedule:
    - cron: '0 6 * * 1'  # Toda segunda-feira às 6:00 UTC

Acionamento manual

on:
  workflow_dispatch:
    inputs:
      environment:
        description: 'Destino do deploy'
        required: true
        type: choice
        options: [staging, production]

Isso adiciona um botão "Run workflow" na interface do GitHub onde você pode selecionar parâmetros.

Workflows reutilizáveis

on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: '20'

Chame-o a partir de outro workflow com uses: ./.github/workflows/reusable.yml.

Jobs e steps

Jobs em paralelo

Por padrão, os jobs são executados em paralelo:

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]  # Aguarda os dois passarem
    steps:
      - uses: actions/checkout@v4
      - run: npm run build

Estratégia de matriz — teste em múltiplas versões

Execute o mesmo job em diversas configurações:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
      fail-fast: false
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

Isso cria 6 jobs paralelos (3 versões × 2 sistemas operacionais).

Secrets e variáveis de ambiente

Usando secrets

Armazene valores sensíveis em Settings → Secrets and variables → Actions:

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
    run: ./deploy.sh

Os secrets são ocultados nos logs e nunca são expostos em forks.

Variáveis de ambiente

# Nível do workflow
env:
  NODE_ENV: production

jobs:
  build:
    # Nível do job
    env:
      CI: true
    steps:
      - name: Build
        # Nível do step
        env:
          VITE_API_URL: https://api.example.com
        run: npm run build

Caching para builds mais rápidos

Sem caching, cada execução baixa todas as dependências do zero. O caching reduz o tempo de build em 50-80%:

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: npm  # Caching nativo de npm

# Ou caching manual para outras ferramentas
- uses: actions/cache@v4
  with:
    path: ~/.cache/pip
    key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
    restore-keys: |
      ${{ runner.os }}-pip-

Artefatos: compartilhando dados entre jobs

Faça upload dos resultados de build em um job e baixe em outro:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - run: ./deploy.sh

Exemplos reais de workflows

Build e push de Docker

name: Docker

on:
  push:
    tags: ['v*']

permissions:
  packages: write

jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Deploy para Cloudflare Pages

name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: npm
      - run: npm ci && npm run build
      - uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          command: pages deploy dist --project-name=my-site

Release com changelog

name: Release

on:
  push:
    tags: ['v*.*.*']

permissions:
  contents: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Gerar changelog
        run: |
          git log $(git describe --tags --abbrev=0 HEAD^)..HEAD \
            --pretty=format:"- %s" > CHANGELOG.md
      - uses: softprops/action-gh-release@v2
        with:
          body_path: CHANGELOG.md
          generate_release_notes: true

Execução condicional

Controle quando steps e jobs são executados:

steps:
  - name: Deploy para produção
    if: github.ref == 'refs/heads/main'
    run: ./deploy-prod.sh

  - name: Deploy para staging
    if: github.event_name == 'pull_request'
    run: ./deploy-staging.sh

  - name: Notificar em caso de falha
    if: failure()
    run: curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d '{"text":"Build falhou!"}'

Boas práticas de segurança

1. Fixe as versões das actions por SHA

# ❌ Tag mutável — pode ser comprometida
- uses: actions/checkout@v4

# ✅ Fixado ao SHA exato do commit
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11

2. Use permissões mínimas necessárias

permissions:
  contents: read    # Apenas o necessário
  packages: write

3. Nunca exiba secrets com echo

# ❌ NUNCA faça isso
- run: echo ${{ secrets.API_KEY }}

# ✅ Use variáveis de ambiente
- env:
    API_KEY: ${{ secrets.API_KEY }}
  run: ./script-that-uses-api-key.sh

4. Limite permissões para PRs de forks

on:
  pull_request_target:  # Executa no contexto da branch base
    types: [opened, synchronize]

Depurando workflows com falha

  1. Verifique os logs — Clique em qualquer step com falha para ver a saída completa
  2. Ative logs de depuração — Defina o secret ACTIONS_STEP_DEBUG como true
  3. Use act localmente — Execute workflows na sua máquina com nektos/act
  4. Acesse o runner via SSH — Use mxschmitt/action-tmate para depuração interativa

Crie workflows visualmente

Não quer escrever YAML na mão? Use nosso GitHub Actions Generator para criar workflows visualmente com templates para Node.js, Python, Docker, deploys e muito mais — e baixe um YAML pronto para produção.

Conclusão

O GitHub Actions oferece CI/CD que vive dentro do seu repositório:

  1. Comece simples — Um arquivo de workflow com build + test
  2. Adicione caching — Reduza o tempo de build com actions/cache ou caching nativo da linguagem
  3. Use matriz — Teste em múltiplas versões e sistemas operacionais
  4. Proteja os secrets — Nunca os deixe hardcoded, use sempre secrets criptografados
  5. Automatize tudo — Releases, deploys, verificações de segurança, tarefas agendadas

O melhor pipeline de CI/CD é aquele que roda a cada commit sem que você precise pensar nisso. Configure uma vez e deixe o GitHub cuidar do resto.