Projeto final: configurando um fluxo completo com hooks, CI e proteção de branches

1. Visão geral do fluxo de trabalho

1.1. Objetivos do projeto final: integridade, automação e colaboração

Este projeto final consolida todos os conceitos essenciais do Git em um fluxo de trabalho profissional. O objetivo é criar um ambiente onde cada commit, push e merge seja validado automaticamente, garantindo que o código mantenha qualidade, segurança e consistência. A integração entre hooks locais, CI (Integração Contínua) e proteção de branches forma uma barreira contra erros humanos e acelera a colaboração em equipe.

1.2. Estrutura do repositório exemplo

Vamos considerar um repositório com a seguinte estrutura de branches:

main              # branch de produção, protegida contra pushes diretos
release/v1.0      # branch de release, protegida, com CI obrigatório
feature/*         # branches de desenvolvimento, sem proteção
hotfix/*          # correções urgentes baseadas em main

1.3. Ferramentas envolvidas

  • Git hooks locais: scripts executados automaticamente em eventos como commit e push
  • GitHub Actions: serviço de CI integrado ao repositório remoto
  • Proteção de branches: regras configuradas no GitHub para bloquear operações inseguras

2. Configuração de hooks locais para qualidade de código

2.1. Hook pre-commit: lint automático e verificação de formatação

Crie o arquivo .git/hooks/pre-commit com o seguinte conteúdo:

#!/bin/bash
echo "Executando lint e formatação..."
npx eslint . --fix
npx prettier --check .
if [ $? -ne 0 ]; then
    echo "Erro: Código não está formatado corretamente. Execute 'npx prettier --write .'"
    exit 1
fi

Torne o hook executável:

chmod +x .git/hooks/pre-commit

2.2. Hook commit-msg: validação de padrão de mensagens (conventional commits)

Crie .git/hooks/commit-msg:

#!/bin/bash
COMMIT_MSG=$(cat "$1")
PATTERN="^(feat|fix|docs|style|refactor|test|chore)(\([a-z]+\))?: .{1,50}"
if ! [[ "$COMMIT_MSG" =~ $PATTERN ]]; then
    echo "Erro: Mensagem de commit não segue o padrão conventional commits."
    echo "Exemplo válido: feat(login): adiciona autenticação por token"
    exit 1
fi

2.3. Hook pre-push: execução de testes rápidos antes do envio ao remoto

Crie .git/hooks/pre-push:

#!/bin/bash
echo "Executando testes antes do push..."
npm test -- --bail
if [ $? -ne 0 ]; then
    echo "Erro: Testes falharam. Corrija antes de fazer push."
    exit 1
fi

3. Implementação de CI com GitHub Actions

3.1. Pipeline básico: instalação de dependências e execução de testes

Crie .github/workflows/ci.yml:

name: CI Pipeline

on:
  push:
    branches: [ main, release/*, feature/* ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '18'
      - run: npm ci
      - run: npm test

3.2. Validação de lint e análise estática em cada push

Adicione ao mesmo arquivo ci.yml:

  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npx eslint .
      - run: npx prettier --check .

3.3. Jobs condicionais: build e deploy apenas para branches protegidas

  build-and-deploy:
    needs: [test, lint]
    if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - run: npm run build
      - run: echo "Deploy simulado para produção"

4. Proteção de branches no repositório remoto

4.1. Configuração de regras de proteção para main e release

No GitHub, vá para Settings > Branches > Add rule e configure:

Branch name pattern: main
- [x] Require a pull request before merging
- [x] Require approvals (1)
- [x] Dismiss stale pull request approvals when new commits are pushed
- [x] Require status checks to pass before merging
- [x] Require branches to be up to date
- [x] Include administrators

Repita para release/*.

4.2. Exigência de pull requests com revisão obrigatória

As mesmas regras garantem que nenhum código seja mesclado sem revisão de pelo menos um colega.

4.3. Bloqueio de pushes diretos e exigência de status checks (CI)

Marque também:

- [x] Restrict who can push to matching branches
- [x] Allow force pushes (apenas para administradores, com cautela)

5. Integração entre hooks locais, CI e proteção de branches

5.1. Sincronizando validações locais com as do CI

Mantenha os mesmos scripts de lint e teste tanto nos hooks quanto no CI. Use arquivos de configuração compartilhados (.eslintrc.json, .prettierrc). Assim, o que falha no hook local também falhará no CI.

5.2. Uso de git-secrets ou hooks customizados para segurança

Instale git-secrets e configure-o:

git secrets --install
git secrets --register-aws
git secrets --add 'api_key|password|token'

Adicione ao pre-commit:

git secrets --scan
if [ $? -ne 0 ]; then
    echo "Erro: Possível segredo encontrado no código."
    exit 1
fi

5.3. Exemplo prático: fluxo completo de uma feature até o merge

  1. Crie uma branch feature/nova-funcionalidade a partir de main
  2. Faça commits com mensagens padronizadas (validadas pelo hook commit-msg)
  3. O hook pre-commit executa lint automaticamente
  4. Ao fazer push, o hook pre-push executa testes
  5. O CI roda lint e testes novamente no remoto
  6. Abra um Pull Request para main
  7. A proteção de branches exige revisão e status checks aprovados
  8. Após aprovação, o merge é realizado

6. Boas práticas e troubleshooting

6.1. Gerenciamento de hooks compartilhados via core.hooksPath ou template

Configure um diretório central de hooks:

git config --global core.hooksPath ~/.git-hooks

Crie ~/.git-hooks/pre-commit com os scripts desejados. Assim, todos os repositórios usam os mesmos hooks.

6.2. Como pular hooks temporariamente (com cautela) e depurar falhas

Para pular hooks em situações excepcionais:

git commit --no-verify -m "fix: correção emergencial"
git push --no-verify

Para depurar, adicione set -x no início do script hook e execute manualmente:

bash .git/hooks/pre-commit

6.3. Atualização das regras de proteção e CI conforme a equipe cresce

  • Revise periodicamente as regras de proteção
  • Adicione novos status checks (ex: cobertura de testes mínima)
  • Considere usar CODEOWNERS para revisão automática

7. Conclusão e próximos passos

7.1. Recapitulação dos benefícios do fluxo completo

Com hooks locais, CI e proteção de branches, você obtém:
- Código sempre formatado e sem erros básicos
- Mensagens de commit padronizadas
- Testes executados antes de qualquer merge
- Segurança contra pushes diretos e vazamento de segredos

7.2. Extensões possíveis: integração com code review automatizado

Futuras melhorias incluem:
- SonarQube para análise estática aprofundada
- GitHub CodeQL para segurança
- Deploy automático após merge em main

7.3. Referência aos artigos vizinhos sobre reescrita de histórico e migração

Este projeto final é a culminação de conceitos como reescrita de histórico com rebase interativo e migração de repositórios, que permitem manter o histórico limpo e organizado.

Referências