Olá pessoal,
Como muitos ja sabem, eu trabalho muito usando git e Azure Devops ou Github nos projetos que participo e quanto maior o time, maior a dificuldade de manter padrões, seja de estilo de codigo, nomeação de arquivos ou variáveis e até mesmo as mensagens dos commits.
Com o Git, nós podemos criar ramificações de desenvolvimento (chamados Git Branches), registrar modificações e ter um controle absoluto sobre as versões. Entretanto, é possível automatizar esse processo. A automação do Git funciona no nível dos programas e da implementação. É para isso que os Hooks são utilizados.
Git Hooks são shell scripts executados automaticamente antes ou depois que o Git execute um comando importante, como “Commit” ou “Push”. Para um Hook funcionar, é necessário que o script tenha permissões de execução no sistema Unix. Usando esses scripts, nós podemos automatizar algumas ações.
No exemplo de hoje vamos utilizar o hook commit-msg. Este hook é invocado pelo git-commit e git-merge, e pode ser ignorado com a opção –no-verify. É necessário um único parâmetro, o nome do arquivo que contém a mensagem de log de confirmação proposta. Caso o status seja diferente de zero, o commit será abortado. Infelizmente o Azure DevOps nao suporta hooks no lado do servidor, então vamos criar client hooks que podem ocorrer antes, durante e depois de um commit ser enviado.
Para testar meus hooks, primeiro criei uma pasta para o repositório com o comando New-Item -Path E:\Sources\ -Name test -ItemType Directory
e depois usei o comando git init
para inicializar o repositorio localmente. Dentro dessa pasta test, haverá uma pasta chamada .git oculta, que tem todos os arquivos de configuração do seu repositório e dentro dela haverá uma pasta chamada hooks, onde você encontrará arquivos de sample com exemplos de hooks para voce começar.
No windows, como não é possível executar scripts powershell sem extensão .ps1, precisamos fazer um workaround. Vamos criar um arquivo chamado commit-msg sem extensão que terá o seguinte conteúdo:
#!/bin/sh
echo "======================================="
echo "Checks that name of commit is in correct form: <type>(scope): <description>"
exec powershell.exe -NoProfile -ExecutionPolicy Bypass -File ".\.githooks\commit-msg.ps1" $1
exit
Caso esteja no linux, basta instalar o powershell e usar #!/usr/bin/env pwsh
na primeira linha para informar o interpretador do script.
No meu caso, criei uma pasta na raiz do repositório chamada .githooks para armazenar os scripts. Esse script irá dizer ao git para invocar o script powershell no caminho informado onde $1 é o argumento contendo a mensagem do commit.
Nosso script para validação irá usar Conventional Commits, que é um padrão bem conhecido e utilizado em grandes times que também permite utilizar ferramentas como o gitversion para versionamento semântico automatizado. Para validar a mensagem, podemos utilizar a seguinte expressão regular: ^(feat|fix|ci|chore|docs|test|style|refactor)(\(.+?\))?: .{1,}$
que irá dividir a mensagem em 3 grupos, tipo, escopo e mensagem.
Caso a expressão regular não seja verdadeira, vamos retornar um código de saida 1, caso contrario, a saida será 0.
[CmdletBinding()]
param (
$commitPath
)
$ErrorActionPreference = "stop"
$commitMsg = Get-Content $commitPath -TotalCount 1
if ($commitMsg -notmatch '^(feat|fix|ci|chore|docs|test|style|refactor)(\(.+?\))?: .{1,}$') {
Write-Information -MessageData "commit isn't in correct format: '<type>(scope): <description>'" -InformationAction Continue
Write-Information -MessageData "commit message: $commitMsg" -InformationAction Continue
Write-Information -MessageData "please ensure your commit message complies" -InformationAction Continue
Write-Information -MessageData "with the conventional commit guidelines" -InformationAction Continue
Write-Information -MessageData "refer to https://www.conventionalcommits.org/en/v1.0.0/#summary for more information" -InformationAction Continue
Write-Information -MessageData "=======================================" -InformationAction Continue
exit 1
}
else {
Write-Information -MessageData "commit message complies with conventional commit messages" -InformationAction Continue
Write-Information -MessageData "=======================================" -InformationAction Continue
exit 0
}
Feito isso podemos testar nosso hook com uma mensagem de commit incorreta, e com uma mensagem seguindo o padrão.
Conforme observado, utilizando essa técnica é possível rejeitar mensagens de commit que não sigam um padrão definido e uma série de outras rotinas, como por exemplo utilizar o hook pre-commit para executar terraform fmt -recursive
e terraform validate
em um repositório que contém código terraform.
Dúvidas? Sugestões? Comente!
Até a próxima!