Status checks: integrando CI como gate de merge

1. O que são Status Checks e por que usá-los como gate de merge

Status checks são notificações automáticas que provedores de CI (Integração Contínua) enviam para plataformas Git como GitHub, GitLab e Bitbucket, informando o estado de execução de jobs específicos. Cada check pode ter status como pending, success, failure, error ou cancelled. Quando configurados como gate de merge, esses checks determinam se um pull request (PR) pode ser mesclado ao branch de destino.

No GitHub, por exemplo, checks aparecem na parte inferior de um PR. Há dois tipos principais:

  • Checks obrigatórios: devem ser aprovados para que o merge seja liberado.
  • Checks opcionais: não bloqueiam o merge, mas servem como indicadores visuais.

Benefícios de usar status checks como gate de merge:

  • Qualidade garantida: código só entra no branch principal após passar por validações como testes, linting e build.
  • Prevenção de quebras: evita que código defeituoso ou incompleto seja integrado.
  • Rastreabilidade: cada commit fica associado a um histórico de checks, facilitando auditoria.

2. Configurando provedores de CI para expor status checks

GitHub Actions

No GitHub Actions, cada job pode expor status checks automaticamente. O campo conclusion define o resultado final. Exemplo de workflow:

name: CI Pipeline
on: [pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run Tests
        run: npm test
      - name: Run Lint
        run: npm run lint

Cada passo é um check individual. O status final do job é refletido no PR.

Jenkins

Para Jenkins com plugin GitHub, o commit status é atualizado via API. Exemplo de pipeline declarativa:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean install'
            }
        }
    }
    post {
        success {
            githubNotify(
                status: 'SUCCESS',
                description: 'Build passou',
                context: 'Jenkins/Build'
            )
        }
        failure {
            githubNotify(
                status: 'FAILURE',
                description: 'Build falhou',
                context: 'Jenkins/Build'
            )
        }
    }
}

CircleCI

No CircleCI, o status é enviado automaticamente com base no resultado dos jobs. Exemplo de .circleci/config.yml:

version: 2.1
jobs:
  test:
    docker:
      - image: cimg/node:20.0
    steps:
      - checkout
      - run: npm test
workflows:
  version: 2
  build_and_test:
    jobs:
      - test

3. Habilitando status checks como proteção de branch

A configuração de proteção de branch é feita nas configurações do repositório. No GitHub:

  1. Acesse Settings > Branches > Branch protection rules.
  2. Clique em Add rule e especifique o branch (ex: main).
  3. Marque a opção Require status checks to pass before merging.
  4. Na lista exibida, selecione os checks que devem ser obrigatórios.

Para repositórios privados, as mesmas regras se aplicam. A diferença é que repositórios públicos podem ter proteções mais restritivas, como exigir checks de colaboradores externos.

4. Comportamento do merge com status checks habilitados

Quando checks obrigatórios estão configurados:

  • O botão de merge fica desabilitado enquanto houver checks pendentes ou com falha.
  • Novos pushes disparam reexecução automática dos checks, atualizando o status.
  • Há diferenciação entre checks de CI (automáticos) e checks manuais (ex: "WIP" ou "Revisão necessária").

Exemplo visual no GitHub:

[✓] CI / build (pull_request) — success
[✓] CI / test (pull_request) — success
[✓] Lint check (pull_request) — success
[x] Security scan (pull_request) — failure

Neste caso, o merge está bloqueado até que o check de segurança seja aprovado.

5. Estratégias avançadas de status checks

Combinando múltiplos checks

É comum exigir que todos os checks de uma pipeline passem:

Checks obrigatórios:
- Build (Node.js)
- Testes unitários
- Testes de integração
- Análise de segurança (Snyk)
- Linting (ESLint)

Checks condicionais

Para ignorar checks em paths específicos (ex: documentação), use filtros no workflow:

on:
  pull_request:
    paths-ignore:
      - 'docs/**'
      - '*.md'

Timeouts e retry automático

Para evitar que checks lentos travem o fluxo, configure timeouts e retry:

jobs:
  test:
    timeout-minutes: 10
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run tests
        run: npm test
      - name: Retry on failure
        if: failure()
        run: npm test -- --retry 2

6. Tratamento de falhas e notificações

Reexecução manual ou automática

No GitHub, é possível reexecutar checks falhados clicando em Re-run jobs. Para reexecução automática, use:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - name: Run tests
        run: npm test
      - name: Retry if flaky
        if: failure()
        run: npm test -- --retry 3

Notificações para desenvolvedores

Integrações com Slack, e-mail ou webhooks podem ser configuradas:

name: Notify on failure
on: [pull_request]
jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Send Slack notification
        if: failure()
        uses: slackapi/slack-github-action@v1.24.0
        with:
          payload: '{"text":"Pipeline falhou no PR ${{ github.event.number }}"}'

Políticas de bypass

Administradores podem ter permissão para ignorar checks (ex: merges forçados). Isso deve ser usado com moderação e registrado em logs.

7. Monitoramento e auditoria de status checks

O histórico de checks pode ser consultado via API do GitHub:

GET /repos/{owner}/{repo}/commits/{ref}/statuses

Para auditoria, é possível extrair métricas como:

  • Taxa de aprovação: percentual de PRs que passam em todos os checks.
  • Tempo médio de execução: quanto tempo os checks levam para concluir.
  • Padrões de erro: checks que mais falham, indicando instabilidade.

Exemplo de consulta com curl:

curl -H "Authorization: token GITHUB_TOKEN" \
  https://api.github.com/repos/owner/repo/commits/abc123/statuses

8. Boas práticas e armadilhas comuns

Não tornar todos os checks obrigatórios

Equilíbrio entre rigidez e agilidade. Checks opcionais podem ser úteis para análises de performance ou cobertura de código.

Evitar checks muito lentos

Checks que demoram mais de 30 minutos podem travar o fluxo de merge. Considere paralelizar jobs ou usar cache.

Documentar a pipeline de CI

Mantenha um arquivo CONTRIBUTING.md com a lista de checks esperados, facilitando a vida de novos contribuidores.

Exemplo de documentação:

## Status Checks Obrigatórios
- Build (Node.js 20)
- Testes unitários (Jest)
- Linting (ESLint)
- Análise de segurança (Snyk)

## Como reexecutar checks falhos
1. Acesse o PR no GitHub.
2. Clique em "Checks" na aba inferior.
3. Selecione "Re-run failed jobs".

Armadilhas comuns:

  • Falsos positivos: checks que falham sem motivo real. Configure retry automático.
  • Dependência externa: se um serviço externo falha, todos os checks podem falhar. Use fallback ou mock.
  • Check único gigante: um único job que faz tudo. Prefira múltiplos checks pequenos e paralelos.

Seguindo essas práticas, a integração de CI como gate de merge se torna um aliado poderoso para manter a qualidade do código sem sacrificar a produtividade da equipe.

Referências