Nesta aula, vamos explorar três das ferramentas de Integração Contínua mais populares: GitHub Actions, GitLab CI e Jenkins. Cada uma possui características distintas que atendem a diferentes necessidades e ecossistemas. Compreender seus modelos de funcionamento, especialmente o conceito de trigger-based (acionamento por eventos), é fundamental para automatizar fluxos de trabalho de forma eficiente.

Além de apresentar um panorama, discutiremos critérios para escolher a ferramenta certa para seu projeto e veremos exemplos conceituais de pipelines. Ao final, você será capaz de avaliar qual ferramenta se alinha melhor com sua stack tecnológica e requisitos de equipe.

GitHub Actions, GitLab CI, Jenkins (panorama)

GitHub Actions é a solução nativa de CI/CD do GitHub, integrada diretamente aos repositórios. Os pipelines são definidos em arquivos YAML (.github/workflows/*.yml) e podem ser acionados por eventos como push, pull request, criação de issues, entre outros. Sua grande vantagem é a integração perfeita com o ecossistema GitHub e uma vasta marketplace de ações reutilizáveis.

GitLab CI é a ferramenta de CI/CD embutida no GitLab, também baseada em arquivos YAML (.gitlab-ci.yml). Ela oferece um pipeline como código robusto, com suporte a stages, jobs, artifacts e ambientes. O GitLab CI pode ser usado tanto na versão SaaS (gitlab.com) quanto self-hosted. Sua integração com o registro de containers e o Kubernetes é um diferencial.

Jenkins é o veterano entre as ferramentas de CI, sendo um servidor de automação open-source altamente extensível via plugins. Os pipelines podem ser definidos via interface web (freestyle) ou como código (Jenkinsfile, usando Declarative ou Scripted Pipeline). Jenkins requer mais esforço de configuração e manutenção, mas oferece flexibilidade quase ilimitada, sendo adequado para ambientes complexos e legados.

Trigger-based

O termo trigger-based refere-se à capacidade de iniciar pipelines automaticamente em resposta a eventos específicos. Todas as três ferramentas suportam esse modelo, mas com nuances.

No GitHub Actions, os triggers são definidos no campo on do workflow. Exemplos comuns: push, pull_request, schedule (cron), workflow_dispatch (manual). É possível filtrar branches, tags e paths. Exemplo de trigger para push na branch main:

on:
  push:
    branches: [main]

No GitLab CI, os triggers são configurados no .gitlab-ci.yml através de regras (rules) ou diretamente com only/except (deprecated). Exemplo: executar job apenas para tags:

job:
  script: echo "Hello"
  only:
    - tags

Jenkins suporta triggers via plugins (como o GitHub plugin) ou polling do SCM. O pipeline declarativo permite usar triggers diretamente:

pipeline {
    agent any
    triggers {
        pollSCM('* * * * *')
    }
    stages {
        stage('Build') {
            steps {
                echo 'Building...'
            }
        }
    }
}

Além de triggers automáticos, todas permitem execução manual (GitHub Actions: workflow_dispatch; GitLab: botão "Run pipeline"; Jenkins: “Build Now”).

Escolhendo

A escolha da ferramenta de CI depende de vários fatores. Se o seu repositório já está no GitHub, o GitHub Actions é a opção mais natural, com integração zero-config e marketplace rico. Para times que usam GitLab, o GitLab CI oferece uma experiência completa e integrada, incluindo registro de containers e deploy para Kubernetes. Jenkins é ideal para organizações que precisam de alta customização, suporte a múltiplos SCMs, ou que já possuem infraestrutura legada.

Considere também custos: GitHub Actions oferece minutos gratuitos para repositórios públicos e uma cota para privados; GitLab CI tem limites similares; Jenkins é gratuito, mas requer servidor próprio e manutenção. A curva de aprendizado é menor para GitHub Actions e GitLab CI, enquanto Jenkins exige conhecimento mais aprofundado. Para equipes pequenas ou startups, as soluções nativas geralmente são mais produtivas.

Exemplos conceituais

Vamos comparar um pipeline simples de build e teste para uma aplicação Node.js nas três ferramentas.

GitHub Actions:

name: Node.js CI
on: [push]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '18'
      - run: npm ci
      - run: npm test

GitLab CI:

stages:
  - build
  - test

build-job:
  stage: build
  script:
    - npm ci

test-job:
  stage: test
  script:
    - npm test

Jenkins (Declarative Pipeline):

pipeline {
    agent any
    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }
        stage('Build') {
            steps {
                sh 'npm ci'
            }
        }
        stage('Test') {
            steps {
                sh 'npm test'
            }
        }
    }
}

Perceba que a lógica é similar, mas a sintaxe e a forma de definir etapas variam. O GitHub Actions usa steps dentro de jobs; GitLab CI usa jobs com stages; Jenkins usa stages com steps.

Boas práticas

Ao implementar CI, mantenha os pipelines rápidos e confiáveis. Use cache para dependências, paralelize jobs quando possível, e evite stages muito longos. Versionar o pipeline como código (YAML ou Jenkinsfile) é essencial para rastreabilidade. Por fim, monitore a saúde dos pipelines e configure notificações para falhas.

Referências

Exercícios

  1. Crie um workflow do GitHub Actions que é acionado quando um pull request é aberto para a branch main e executa um job que imprime "PR aberto".

    ✓ Resposta:
    name: PR Check
    on:
      pull_request:
        branches: [main]
    jobs:
      check:
        runs-on: ubuntu-latest
        steps:
          - run: echo "PR aberto"
  2. No GitLab CI, escreva um pipeline com dois jobs: um na stage 'build' que executa 'make build' e outro na stage 'test' que executa 'make test'. O job de test deve depender do job de build.

    ✓ Resposta:
    stages:
      - build
      - test
    
    build-job:
      stage: build
      script:
        - make build
    
    test-job:
      stage: test
      script:
        - make test
      needs: [build-job]
  3. Em um Jenkins Declarative Pipeline, adicione um trigger para executar o pipeline a cada 5 minutos (pollSCM).

    ✓ Resposta:
    pipeline {
        agent any
        triggers {
            pollSCM('*/5 * * * *')
        }
        stages {
            stage('Hello') {
                steps {
                    echo 'Hello World'
                }
            }
        }
    }
  4. Explique a diferença entre um trigger baseado em push e um baseado em pull request no GitHub Actions. Dê um exemplo de quando usar cada um.

    ✓ Resposta:

    O trigger push executa o workflow quando commits são enviados para uma branch. É útil para executar testes e builds após cada alteração na branch principal. O trigger pull_request executa quando um PR é aberto, sincronizado ou reaberto. É ideal para validar alterações antes de mesclar, garantindo que o código proposto passe nos testes. Exemplo: usar push para branch develop para build contínuo, e pull_request para branch main para revisão antes do merge.

  5. Liste três critérios importantes ao escolher entre GitHub Actions, GitLab CI e Jenkins para um novo projeto.

    ✓ Resposta:
    1. Ecossistema do repositório: Se o código está no GitHub, GitHub Actions é a escolha mais integrada; se no GitLab, GitLab CI é nativo. Jenkins funciona com qualquer SCM, mas requer mais configuração.
    2. Curva de aprendizado e manutenção: GitHub Actions e GitLab CI são mais simples e gerenciados; Jenkins exige administração do servidor e conhecimento de plugins.
    3. Necessidades de customização: Para pipelines complexos e ambientes heterogêneos, Jenkins oferece flexibilidade máxima. Para fluxos padrão, as soluções nativas são suficientes.