Início Tecnologia Sua primeira linha de defesa para o código limpo é pré-compromisso: como...

Sua primeira linha de defesa para o código limpo é pré-compromisso: como configurá-lo

12
0

 

Já acidentalmente empurra segredos para um repositório? Ou talvez você tenha pressionado o código não formatado, apenas para criar uma confirmação de “linha” de acompanhamento? Todos nós já estivemos lá. Esses pequenos erros podem levar a pipelines de CI/CD com falha e atrasos frustrantes, tudo por causa de cheques que poderiam ter sido executados localmente.

Os ganchos git são uma ferramenta poderosa para evitar esses problemas executando scripts antes de você se comprometer ou empurrar. No entanto, compartilhar e padronizar esses ganchos em uma equipe ou projeto pode ser um desafio.

É aqui que entra o pré-compromisso. O pré-compromisso é uma estrutura fácil de usar para gerenciar e compartilhar ganchos git de várias línguas, ajudando você a capturar problemas antes mesmo de deixar sua estação de trabalho.

Introdução: a configuração certa

Antes de aproveitar o poder do pré-compromisso, você precisa instalá-lo e configurá-lo para seus projetos.

Instalação

Você tem várias maneiras de instalar pré-compromisso:

brew install pre-commit
  • Python/pip (plataforma cruzada):
pip install pre-commit

Configuração específica do projeto (a maneira padrão)

Esta é a abordagem mais comum para permitir o pré-compromisso em um projeto específico:

  1. Crie um arquivo de configuração: Na raiz do seu repositório, crie um arquivo nomeado .pre-commit-config.yaml. Este arquivo definirá o pré-compromisso dos ganchos deve ser executado. (Abordaremos como preencher esse arquivo na próxima seção).
  2. Instalar ganchos: navegue até o diretório raiz do seu repositório em seu terminal e execute:
pre-commit install
  1. Este comando instala os focos git no seu repositório .git/hooks diretório. A partir de agora, o pré-compromisso executará automaticamente suas verificações antes de cada compromisso que você faz neste repositório específico.

Configuração global (o método “Defina e esqueça”)

Se você frequentemente iniciar novos projetos ou repositórios de clone e deseja que o pré-compromisso seja ativo por padrão (se existir uma configuração), poderá configurá-lo globalmente. Este método utiliza o Git’s init.templateDir recurso.

  1. Um arquivo de configuração: todo o seu repositório deve ter um .pre-commit-config.yaml. Este arquivo definirá os ganchos que o pré-compromisso deve executar. O melhor seria usar um repositório de modelo com um arquivo mínimo de pré-compromisso.
  2. Configure o diretório de modelos do Git: diga ao Git para usar um diretório específico como um modelo para novos repositórios:
git config --global init.templateDir ~/.git-template

(Você pode escolher um diretório diferente, se preferir, apenas certifique -se de que seja consistente na próxima etapa.)

3. Inicialize o pré-compromisso no diretório de modelos: execute o seguinte comando:

pre-commit init-templatedir ~/.git-template

(Se você escolheu um diretório diferente na etapa anterior, substitua ~/.git-template de acordo.)

Isso tem um grande benefício: com esta configuração global, qualquer novo repositório que você inicialize (git init) ou um clone terá automaticamente o gancho de pré-compromisso instalado. Se um repositório não tiver um .pre-commit-config.yaml Arquivo, o pré-compromisso simplesmente não fará nada, por isso é seguro ativar globalmente.

No entanto, eu gosto de dar um passo adiante adicionando um gancho padrão ~/.git-template/hooks/pre-commit isso falharia sistematicamente se um repositório não tivesse um .pre-commit-config.yaml. Aqui está o conteúdo do gancho.

#!/usr/bin/env bash
if [ -f .pre-commit-config.yaml ]; then
    echo 'pre-commit configuration detected, but `pre-commit install` was never run' 1>&2
    exit 1
fi

Construindo sua configuração (.Pre-Commit-Config.yaml)

O coração da pré-compromisso é o .pre-commit-config.yaml arquivo. Este arquivo, colocado na raiz do seu repositório, informa ao pré-compromisso que verifica a execução. Aqui está um pequeno exemplo dessa configuração.

# 
repos:
  # Lint all yam files
  - repo: 
    rev: v1.29.0
    hooks:
      - id: yamllint
  # Runs Ansible lint
  - repo: 
    rev: v24.7.0
    hooks:
      - id: ansible-lint
        args:
          - "ansible"
        additional_dependencies:
          - ansible

Estrutura central explicada

Uma configuração típica envolve uma lista de repositórios, cada um com ganchos específicos:

  • repos: Esta é uma chave de nível superior que leva uma lista de mapeamentos de repositório. Cada item da lista especifica um repositório Git que contém ganchos de pré-compromisso.
  • repo: O URL do repositório que hospeda os ganchos (por exemplo, ). Esta é uma maneira muito boa de gerenciar dependências. Quando você souber mais sobre a ferramenta, pode ir ao repositório.
  • rev: Ele especifica a versão dos ganchos para usar, fixando em uma tag git, sha ou ramificação. Mas é aconselhado sempre usar uma tag ou sha específica (não um ramo como master) para garantir que seu revestimento não quebre inesperadamente quando o repositório remoto atualiza.
  • hooks: Uma lista em cada repo entrada. Cada item aqui define um gancho específico para usar nesse repositório.
  • id: O identificador único do gancho (por exemplo, trailing-whitespaceAssim, check-yaml). Você pode encontrar IDs de gancho disponíveis na documentação do repositório do gancho. ou simplesmente o .pre-commit-hooks.yaml na raiz do repo.

Uma configuração prática de iniciantes

Aqui está um básico .pre-commit-config.yaml para você começar. Para este exemplo, aconselho você a ir ao Github e dar uma olhada Pré-compromisso/pré-compromisso gancho/blob/main/.pre-comcomit-hooks.yaml. Esta é a lista de ganchos simples que o pre-commit a equipe implementou e onde você pode encontrar o id de cada um dos ganchos relevantes que você pode usar.

Eu diria trailing-whitespace e end-of-file-fixer são realmente úteis, portanto, a configuração ficaria assim.

repos:
-   repo: 
    rev: v4.6.0  # Check for the latest stable version on the pre-commit-hooks repo!
    hooks:
    -   id: trailing-whitespace
    -   id: end-of-file-fixer
# Add other repositories and their specific hooks below
# -   repo: ...
#     rev: ...
#     hooks:
#     -   id: ...

Nota: As versões para ganchos mudam com o tempo. É uma boa prática ocasionalmente verificar o pre-commit-hooks repositório (ou qualquer outro repositório de gancho que você usa) para a última tag de versão estável e atualize seu rev de acordo. Ou tenha automação em vigor, como reforma ou dependente, para atualizá -los regularmente.

Você pode encontrar uma grande lista de ganchos pré-existentes no Site pré-comprometidoveja o que está lá e inicie a validação. Pela minha experiência, esta lista está longe de ser exaustiva; Em vez disso, prefiro verificar as ferramentas que gosto de usar um .pre-commit-hooks.yaml e veja se os ganchos estão disponíveis.

Bom saber ao usar pré-compromisso

Depois de se sentir confortável com o básico, o pré-compromisso oferece recursos mais avançados para ajustar o seu fluxo de trabalho.

Ganchos de corrida manualmente

Enquanto os ganchos são executados automaticamente em git commitvocê pode desencadeá -los manualmente em outros momentos:

  • Execute um gancho específico: para executar um único gancho (por exemplo, para testar sua configuração ou aplicar suas alterações sem cometer), use:
pre-commit run 

(Substituir com o ID real do seu arquivo de configuração.)

  • Execute todos os arquivos: para executar todos os ganchos configurados em todos os arquivos rastreados em seu repositório (não apenas alterações encenadas), use:
pre-commit run --all-files

Isso é útil para uma limpeza inicial ou ao adicionar novos ganchos a um projeto existente.

Criando seus próprios ganchos locais

Às vezes, você pode ter scripts ou cheques específicos do projeto que não fazem parte de um repositório público de gancho. O pré-compromisso permite definir ganchos “locais”.

  1. Escreva seu script: Crie seu script (por exemplo, um script de shell, script python) no seu repositório. Para este exemplo, digamos que você crie my_custom_script.sh.
  2. Defina em .pre-commit-config.yaml: Adicione uma entrada local de gancho à sua configuração:
# .pre-commit-config.yaml
-   repo: local
    hooks:
    -   id: my-custom-check
        name: My custom check
        entry: ./my_custom_script.sh # Path to your script
        language: script             # Or python, node, etc.
        files: \.(py)$               # Example: regex to run only on Python files
        # verbose: true              # Uncomment for more output
        # args: [--custom-arg]       # Optional arguments for your script

Isso diz ao pré-compromisso para correr my_custom_script.sh Para quaisquer mudanças no python (.py) arquivos. O language: script O tipo é muito flexível; Para ambientes específicos como Python ou Node, você pode especificá -los para gerenciar dependências, se necessário. Eu experimentei principalmente com bash ganchos.

Ainda assim, o pré-compromisso é muito inteligente em relação aos ambientes de trabalho, pois cria um ambiente de tempo de execução isolado para as ferramentas e dependências necessárias.

Infelizmente, nem todos os ganchos aproveitaram o recurso de dependência, e você pode ter que instalar as ferramentas para poder executar o gancho (estou pensando em Terraform, por exemplo)

Pré-compromisso em um ambiente de equipe e CI/CD

Enquanto o pré-compromisso brilha em máquinas de desenvolvedores individuais, seus benefícios se multiplicam quando integrados aos fluxos de trabalho da equipe e dos pipelines de CI/CD. Mesmo com ganchos pré-comprometidos instalados localmente, alguém pode se comprometer acidentalmente sem ganchos (por exemplo, usando git commit --no-verify) ou tenha uma configuração desatualizada do gancho. Seu pipeline CI/CD pode atuar como o melhor guardião.

Ao executar verificações de pré-compromisso no seu pipeline de CI, você garante que nenhum código que viole os padrões do seu projeto seja mesclado. O comando típico para isso é:

pre-commit run --all-files

Este comando verifica todos os arquivos no repositório, não apenas os alterados, garantindo validação abrangente.

Etapa conceitual do pipeline de IC (por exemplo, ações do github):

# Example for a GitHub Actions workflow
# ... (other steps like checkout, setup python/node, etc.)
- name: Install pre-commit and dependencies
  run: |
    pip install pre-commit
    # Install any other dependencies your hooks might need (e.g., linters)
    # This might be minimal if your hooks install their own dependencies (common).
- name: Run pre-commit checks
  run: pre-commit run --all-files

É bom ter um pipeline conceitual que funcione com qualquer sistema de IC, mas se você usar ações do GitHub, não precisará se preocupar; use a ação oficial.

jobs:
  pre-commit:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3
    - uses: actions/setup-python@v3
    - uses: pre-commit/[email protected]

Com a integração do IC, o loop é concluído e a mesma validação é aplicada em ambientes de desenvolvedor e no ambiente de IC. Se o pipeline falhar, corrija-o localmente executando pré-compromisso.

Conclusão

Percebendo lá tem Para ser uma maneira melhor do que as verificações manuais e os compromissos de “oops”, exploramos como é pre-commit transforma seu fluxo de trabalho de desenvolvimento.

Ao automatizar as verificações de tudo, desde erros de espaço em branco e detecção secreta até formatação e revestimento de código, o pré-compromisso atua como seu incansável guardião local da qualidade do código que pode até integrar “perfeitamente” em tubulações de CI/CD para servir como um portão de qualidade final.

fonte