Executando verificação de segurança...
5

Padronizando os commits do seu repositório Seguindo Conventional Commits

Introdução

"add changes", "add", "commit", "push", quem nunca fez um commit com uma mensagem parecida ou até mesmo pior, eu já!

Entender o histórico de commits de um projeto é importantíssimo, por isso nosso papel é manter a legibilidade em todas as alterações enviadas para o git. Os commits devem contar a história de desenvolvimento da aplicação com o que foi feito em cada uma das entregas. Uma alteração? Uma nova feature? A correção de um bug? Tudo deve ser devidamente descrito.

Dessa forma, é mais fácil de acompanharmos todo o histórico e facilitar a manutenibilidade do projeto. Ninguém precisa (pelo menos não deveria) ter que adivinhar o que foi enviado junto a um commit. Uma mensagem bem escrita facilita entender uma nova implementação ou a correção de um bug inesperado.

Toda mensagem de commit deve ser curta, porém objetiva e assertiva, se precisarmos de informações adicionais, podemos adicioná-las no corpo do commit. É comum que esqueçamos de dar um commit seguindo boas práticas, por este motivo, algumas ferramentas foram desenvolvidas para nos ajudar no dia a dia.

Bora implementar?

Padronizando commits

Devemos seguir pela linha da padronização das mensagens de commits, facilitando tanto na hora da escrita, quanto da leitura. Pensando nisso, podemos trabalhar com o Conventional Commits.

O Conventional Commit traz a ideia de que devemos adicionar uma "flag" (sinalizador) com o que estamos enviando naquela alteração. Trazendo a primeira ideia de padronização de nossos commits, por exemplo: quando uma feature for enviada, adicionamos ao início da mensagem de commit a flag "feat", o commit poderia ficar assim:
"feat: cadastro de pessoas usuárias", ou poderíamos estar apenas adicionando um teste;
"test: validando cadastro com email invalido".

De forma resumida, toda alteração deve ter uma flag no início da mensagem, dizendo de forma explícita qual a principal função daquela modificação enviada.

Quais as flags e quando eu deveria utilizar cada uma delas? Confira aqui.

Trabalhando com Conventional Commits

A ideia do Conventional Commit é seguir a seguinte estrutura

<tipo>[escopo opcional]: <descrição>

[corpo opcional]

[rodapé opcional]

Um exemplo prático citado acima seria:

git commit -m "feat: cadastro de pessoas usuárias"

Podendo ainda adicionar o escopo da modificação:

git commit -m "feat: (api/users) cadastro de pessoas usuárias"

É importante sempre utilizar letras minúsculas, espaço após os dois pontos e não utilizar ponto final.

Commits Atômicos

Você conhece o commit bomba? Aquele commit com 10 arquivos novos e 5 modificados? Não é esse tipo de commit que queremos durante o desenvolvimento de nosso projeto. A expressão de commit atômico vem da ideia de termos commits na menor unidade de medida possível em uma alteração ou implementação. Por exemplo, ao criarmos um novo arquivo de conexão com o banco de dados e escrevermos uma função de leitura dos usuários pelo email, devemos realizar dois commits, um para cada modificação.

Arquivo de conexão com o banco de dados;
Função de leitura de dados de pessoa usuária pelo email.

Dessa forma evitamos commits do tipo "adiciona conexão com o banco e busca dados de usuário pelo email", o ideal é realizarmos um commit para cada modificação, aproveitando o conteúdo anterior, podemos já adicionar nosso conventional commit.

  • "feat: criando o arquivo de conexão com o banco de dados"
  • "feat: adiciona função de leitura de pessoas usuárias pelo email"

Muito mais legível né?!

Colocando em prática

Uau, já sabemos de tudo, agora vamos seguir essas padronização em nossos projetos!
Isso me lembra a promessa de que vou para a academia na segunda-feira. De nada adianta nos comprometermos com algo e não seguir, por isso vamos fazer o seguinte:

Iremos utilizar ferramentas para nos auxiliar a seguir nossos próprios combinados. Vamos impor regras que devemos sempre seguir o convencional commit em nossas alterações durante o desenvolvimento do projeto.

Commitlint

A primeira ferramenta a nos auxiliar é o CommitLint, o papel dele é garantir que nossas mensagens de commit irão seguir todas as regras definidas pelo Conventional Commit. Toda mensagem submetida será analisada e deverá seguir a estrutura padronizada.

Caso a mensagem não esteja na estrutura esperada, nosso commit será cancelado e o commitlint apresentará uma mensagem com o erro ocorrido, podendo ser por falta de seguir o padrão por completo, por não existir a flag especificada, entre outros.

Veja o exemplo a seguir retirado da documentação do Commitlint.


imagem da documentação do commitlint.

Commitizen

O Commitizen Irá nos gerar um CLI iterativo onde poderemos visualizar todas as flags definidas pelo Conventional Commit com uma breve descrição de quando cada uma delas deve ser utilizada, em uma espécie de sheat sheet. Dessa forma, não precisamos decorar todas as flags e lembrar onde cada uma se aplica.

Isso nos ajuda com a barreira de entrada que é decorar cada uma das flags e sua utilização, também nos poupando tempo para que não precise olhar na documentação a cada commit realizado, lembrando que iremos aplicar os commits atômicos.

commitizen
imagem da documentação do commitizen

Husky

Por fim, vamos trabalhar com o Husky, o Git nos fornece ganchos, uma espécie de gatilho que podemos acionar a partir de algumas ações. Como queremos que o CommitLint verifique nossas mensagens de commit, podemos usar o gancho commit-msg, que será executado ao tentarmos enviar uma mensagem de commit, iniciando todo o processo de lint do commit.

Podemos então criar um gancho para executar o commitlint todas as vezes que uma nova mensagem de commit for enviada, acionando todo o fluxo de verificação.

Colocando em prática

A título de exemplo todos os comandos serão executados utilizando o npm mas que funcionam de forma semelhante com o yarn.

Antes de começar a instalação das bibliotecas é importante que você tenha realizado os seguintes passos:

  1. Iniciado um projeto.
    $ npm init 
    
  2. Iniciado um repositório git local.
    $ git init
    

Instalando o Commitlint

# adicionando dependências
npm install -D @commitlint/{cli,config-conventional}

# configurando o commitlint
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

** Caso aconteça um erro ao executar o segundo comando, você pode criar um arquivo com o nome "commitlint.config.js" e colar o conteúdo a seguir dentro dele.

module.exports = { extends: ['@commitlint/config-conventional'] };

Rápido e prático ;)

Instalando o Husky

# adicionando dependência
npm install -D husky

# ativando ganchos (hooks)
npx husky install

Com o Husky instalado e os ganchos ativados, podemos adicionar o gatilho para a mensagem de commit.

npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'

Realizando o primeiro teste

Podemos verificar se nosso gancho está funcionando da maneira correta, acionando o commitlint ao enviar uma mensagem.

Adicione um arquivo para a árvore de modificações do git, podemos utilizar o arquivo de config do commitlint.

git add commitlint.config.js

Agora, podemos tentar realizar o commit dessa alteração.

git commit -m "isso deve falhar"

É esperado que um erro seja gerado, justamente pois não estamos seguindo a convenção definida. Agora faremos da maneira correta!

git commit -m "chore: adiciona arquivo de configuração do commitlint"

Seguimos a convenção, adicionamos uma flag (chore) e também uma mensagem curta e descritiva de nossa alteração. Parabéns!

Facilitando a vida com Commitzen

Como dito, não precisamos ficar relembrando todas as tags e quando utilizar cada uma delas, trouxemos o Commitzen para facilitar nossa vida.

# instalando dependências
npm install -D commitizen
# configurando commitzen

# utilizando npm
npx commitizen init cz-conventional-changelog --npm --dev --exact

# utilizando yarn
yarn commitizen init cz-conventional-changelog --yarn --dev --exact

Hora de testar!

Para executarmos o Commitzen precisamos chamar o executável com nome de git-cz utilizando o npx ou o yarn, uma maneira de tornarmos isso mais amigável é adicionando um script ao nosso package.json, vamos chamá-lo de commit mas qualquer nome pode ser utilizado.

// ...
"scripts": {
  "commit": "git-cz"
}
// ...

Para seguirmos com o teste vamos adicionar mais um arquivo as alterações do git, que tal o diretório de configurações do Husky?

git add .husky

Por fim, podemos então colocar o Commitzen para trabalhar.

npm run commit
# ou
yarn commit

Observe que um terminal interativo foi acionado, nele podemos encontrar todas as flags definidas pelo Conventional Commits.

terminal

  1. Percorra o menu utilizando as setas e selecione a que melhor descrever sua alteração pressionando enter.

  2. Qual o escopo dessa alteração? Aqui de maneira opcional, você pode colocar o escopo onde a alteração está acontecendo, um componente? um arquivo? Por exemplo: "husky"

  3. Adicione sua mensagem de commit, esta por sua vez, deve possuir no máximo 82 caracteres, suficiente para uma mensagem assertiva, lembrando que a flag do Conventional Commit já será adicionada e não contabilizada por esses 82 caracteres.

  4. Você também pode adicionar uma descrição mais completa no corpo do commit, esse é o lugar adequado, também é opcional.

  5. Existem alterações importantes? Aqui você deve responder com "Y/n" (sim ou não), está relacionado ao Semantic Versioning, não vamos abordá-lo aqui, por hora, vamos colocar "n".

  6. Essa alteração está relacionada a alguma issue do GitHub? Por hora vamos colocar "n".

E pronto, seu commit foi adicionado e seguiu todas as especificações de um bom commit!

img

chore(husky): diretorio de configuracoes do husky

  • chore: flag do Conventional Commits;
  • (husky): escopo onde a alterações ocorreu;
  • diretorio de configuracoes do husky: mensagem do commit;

Conclusão

Esse conjunto de ferramentas nos auxilia a escrevermos commits melhores não só por aparência mas também para termos um bom histórico de alterações em nossos repositórios.

No começo pode parecer algo massante e trabalhoso, mas com o tempo nos auxilia e nos gera produtividade e facilidade na leitura da história de vida do nosso projeto.

Dê uma chance a esta ideia, teste e me dê seu feedback :)

Carregando publicação patrocinada...
2

Estou usando o padrão a uns anos aqui na empresa, Gosto de algumas coisas, não curti outras. O mais legal foi que automatizamos o processo de versionamento, então sempre que tem um release, nossos script verifica se foram feitos apenas feat, fix, etc... Assim fazemos os versionamento com base nisso, seguindo o semantic version: X.Y.Z

3

Que massa Romulo, adoraria saber como funciona o processo, que tal o desafio de escrever um artigo sobre? Tenho certeza que poderia ajudar outras pessoas!

2
1

Otimo post, seguir um padrão de commits é algo que em seu projeto pessoal ou pensando em curto prazo não faz muito sentido, mas em longo prazo faz uma diferença enorme para rastrear alterações feitas no codigo.

Não é necessario seguir o padrão do Conventional Commits, você pode criar o seu proprio, porem eu aconselho fortemente a seguir o Conventional Commits por conta de ser uma das padronizações mais usadas nos projetos, e quando você foi ver um projeto open source provavelmente estara usando esse padrão de commits.

Sobre as ferramentas apresentadas, eu já dei uma olhada nelas, e só não gostei do fato de haver a necessidade de configurar a nivel de projeto com o node, eu trabalho na maioria dos meus projetos com java, e não gostaria de terque iniciar um projeto node somente para adicionar validação de commit, se alguem souber alguma outra solução parecida sem a necessidade de utilizar node adoraria conhecer.

1

Faz sentido sua provocação Andre, talvez uma ferramenta com o mesmo proposito mas que esteja mais vinculado ao git do que as tecnologias de desenvolvimento, sendo possível trabalhar com qualquer linguagem.

Não sei se existe, mas é algo a se pensar :)