Passo a passo: Configurando pipeline CI/CD no GitHub Actions

Publicado em 2026-02-01 • leitura estimada • ~5 min

Configure pipelines completos: build, testes, deploy automático, secrets, matrix builds e deploy em produção com GitHub Actions.

O que é CI/CD e por que usar GitHub Actions

CI (Continuous Integration): automatiza build e testes a cada push/PR. Detecta problemas cedo.

CD (Continuous Deployment): automatiza deploy em produção após testes passarem.

GitHub Actions é a plataforma de CI/CD nativa do GitHub. Vantagens:

  • Integrado ao repositório (sem configuração externa)
  • Gratuito para repos públicos (2000 minutos/mês para privados)
  • Marketplace com milhares de actions prontas
  • Suporta Linux, Windows, macOS

Conceitos básicos

Estrutura de um workflow

  • Workflow: pipeline automatizado (arquivo YAML em .github/workflows/)
  • Job: conjunto de steps que rodam em um runner
  • Step: tarefa individual (rodar comando, usar action)
  • Runner: máquina virtual que executa os jobs
  • Action: comando reutilizável (ex: actions/checkout@v4)

Triggers (eventos que disparam workflows)

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  schedule:
	    - cron: '0 2 * * *'  # todo dia às 2h
  workflow_dispatch:      # manual via UI

Passo 1: Seu primeiro workflow

Criar arquivo de workflow

Crie .github/workflows/ci.yml no seu repositório:

name: CI Pipeline

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

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test

      - name: Build project
        run: npm run build

Commit e push. O workflow rodará automaticamente.

Passo 2: Workflow completo para Node.js

name: Node.js CI/CD

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

jobs:
  test:
    runs-on: ubuntu-latest

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

    steps:
      - uses: actions/checkout@v4

      - name: Setup 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: Run linter
        run: npm run lint

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

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: ./coverage/coverage-final.json
          fail_ci_if_error: true

  build:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
      - uses: actions/checkout@v4

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

      - name: Install dependencies
        run: npm ci

      - name: Build
        run: npm run build

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build
          path: dist/

Passo 3: Workflow para Python

name: Python CI

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest

    strategy:
      matrix:
        python-version: ['3.10', '3.11', '3.12']

    steps:
      - uses: actions/checkout@v4

      - name: Setup Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: 'pip'

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements.txt
          pip install pytest pytest-cov flake8

      - name: Lint with flake8
        run: |
          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
          flake8 . --count --max-line-length=127 --statistics

      - name: Run tests
        run: pytest --cov=./ --cov-report=xml

      - name: Upload coverage
        uses: codecov/codecov-action@v4
        with:
          file: ./coverage.xml

Passo 4: Workflow para Docker

name: Docker Build and Push

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

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=sha

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

Passo 5: Deploy automático (Vercel, Netlify, AWS)

Deploy para Vercel

name: Deploy to Vercel

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - 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 }}
          vercel-args: '--prod'

Deploy para AWS S3 + CloudFront

name: Deploy to AWS

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

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

      - name: Install and build
        run: |
          npm ci
          npm run build

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: us-east-1

      - name: Sync to S3
        run: |
          aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }} --delete

      - name: Invalidate CloudFront
        run: |
          aws cloudfront create-invalidation \
            --distribution-id ${{ secrets.CLOUDFRONT_DISTRIBUTION_ID }} \
            --paths "/*"

Passo 6: Gerenciar secrets

Adicionar secrets no GitHub

  1. Vá em Settings > Secrets and variables > Actions
  2. Clique em New repository secret
  3. Adicione nome e valor (ex: AWS_ACCESS_KEY_ID)

Usar secrets no workflow

steps:
  - name: Deploy
    env:
      API_KEY: ${{ secrets.API_KEY }}
      DATABASE_URL: ${{ secrets.DATABASE_URL }}
    run: |
      echo "Deploying with API key"
      ./deploy.sh

Passo 7: Matrix builds (testar múltiplas versões)

name: Multi-version Test

on: [push]

jobs:
  test:
    runs-on: ${{ matrix.os }}

    strategy:
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        node-version: [18, 20, 22]
        exclude:
          - os: macos-latest
            node-version: 18

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js ${{ matrix.node-version }} on ${{ matrix.os }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}

      - run: npm ci
      - run: npm test

Passo 8: Conditional steps e environments

Steps condicionais

steps:
  - name: Run only on main
    if: github.ref == 'refs/heads/main'
    run: echo "This is main branch"

  - name: Run only on PR
    if: github.event_name == 'pull_request'
    run: echo "This is a PR"

  - name: Run only on success
    if: success()
    run: echo "Previous steps succeeded"

  - name: Run even on failure
    if: always()
    run: echo "This always runs"

Environments (staging, production)

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.myapp.com

    steps:
      - uses: actions/checkout@v4
      - name: Deploy to staging
        run: ./deploy-staging.sh

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.com

    steps:
      - uses: actions/checkout@v4
      - name: Deploy to production
        run: ./deploy-production.sh

Passo 9: Reutilizar workflows (Composite Actions)

Criar action reutilizável (.github/actions/setup/action.yml)

name: 'Setup Project'
description: 'Install dependencies and cache'

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

    - name: Install dependencies
      shell: bash
      run: npm ci

Usar no workflow

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

Passo 10: Monitoramento e debugging

Ver logs detalhados

steps:
  - name: Debug info
    run: |
      echo "Event: ${{ github.event_name }}"
      echo "Ref: ${{ github.ref }}"
      echo "Actor: ${{ github.actor }}"
      echo "SHA: ${{ github.sha }}"

  - name: Enable debug logging
    run: echo "::debug::This is a debug message"

Adicionar status badge no README

![CI](https://github.com/seu-usuario/seu-repo/actions/workflows/ci.yml/badge.svg)

Boas práticas

1. Cache de dependências

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'  # Acelera installs

2. Fail fast em matrix builds

strategy:
  fail-fast: true  # Para todos os jobs se um falhar
  matrix:
    node-version: [18, 20, 22]

3. Timeout para evitar custos

jobs:
  test:
    runs-on: ubuntu-latest
	    timeout-minutes: 10  # Cancela após 10min

4. Concurrency (evitar deploys simultâneos)

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

5. CODEOWNERS para aprovar workflows

Crie .github/CODEOWNERS:

.github/workflows/* @seu-time

Troubleshooting comum

Erro: "No space left on device"

- name: Free disk space
  run: |
    sudo rm -rf /usr/share/dotnet
    sudo rm -rf /opt/ghc

Erro: "Permission denied" no deploy

Adicione permissões ao job:

jobs:
  deploy:
    permissions:
      contents: write
      packages: write

Workflow não dispara

  • Verifique se o arquivo está em .github/workflows/
  • Confira indentação YAML (use validador)
  • Confirme que o evento (push/PR) corresponde ao trigger

Conclusão

GitHub Actions simplifica CI/CD diretamente no repositório. Comece com workflows básicos (build + test), evolua para matrix builds, adicione deploy automático e monitore com badges. Com pipelines bem configurados, você detecta bugs cedo, garante qualidade e acelera entregas.

FAQ

GitHub Actions é gratuito?

Sim para repos públicos. Repos privados têm 2000 minutos gratuitos por mês (plano free).

Posso rodar workflows localmente?

Sim, use a ferramenta act (github.com/nektos/act) para testar workflows no Docker.

Como fazer rollback automático?

Use environments com protection rules. Se o deploy falhar, dispare outro workflow que faz rollback para versão anterior.

Qual a diferença entre CI e CD?

CI (Continuous Integration) roda build e testes. CD (Continuous Deployment) faz deploy automático em produção.

Como proteger secrets?

Nunca commite secrets no código. Use secrets do GitHub Actions. Para auditoria, ative logs de segurança.