Introdução

Todo desenvolvedor, gerente de projetos ou interessados necessita de uma informação útil de acompanhamento. Desde as informações mais técnicas até as informações mais úteis aos interessados devem ser consideradas. Quando se faz isso com método, fica muito mais fácil para todos entenderem o que se passa.

Para que isso fique inteligível a todos vamos inserir alguns conceitos básicos de organização de repositórios nas seções abaixo.

Commits Convencionais

Os commits convencionais são modelos de commits para o seu repositório a fim de poder utilizá-los depois. Descrevendo como um programados são tags que representam determinadas ações. O objetivo de padronização é poder utilizá-las em em outros lugares para melhorar a comunicação. Vamos colocar abaixo algumas coisas relacionadas aos commits convencionais:

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

[corpo opcional]

[rodapé opcional]

Basicamente acima está descrito um commit convencional. Mas qual é a utilidade prática disso? Vamos por partes:

O primeiro item obrigatório que precisamos explicar é o tipo. Basicamente o tipo de commit é uma tag para que você possa utilizá-lo posteriormente. Há algumas convenções:

  1. O primeiro tipo que falaremos é um feat (que provém de feature). Isso é o descritor de uma funcionalidade no seu software. É um commit bastante comum e que pode ser relacionado frequentemente. Por exemplo, queremos que todas as features que foram agregadas ao software apareçam no changelog.
  2. O segundo tipo que abordaremos é o tipo fix (fixture) que é basicamente uma correção de algum problema no código. Também cai numa praticidade onde queremos que as correções apareçam em determinados documentos próprios para isso.
  3. Outros tipos de commits
    1. docs - relativos a documentação
    2. style - relativos a estilos
    3. CI - integração contínua, automação de deploy, etc.
    4. revert - retorno ao commit anterior
    5. chore - núcleo do sistema
    6. perf - melhora de performance do código
    7. test - testes unitários, automatizados, etc.
    8. build - mudanças que afetam o sistema de construção ou dependências externas
    9. refactor - refatoração do código

Lembre-se de que as tags de tipo podem ser personalizadas e devem refletir a organização do código como um todo. Não é muito difícil entender o porquê.

Você pode consultar mais sobre commits convencionais no site https://www.conventionalcommits.org/pt-br/v1.0.0/

Versionamento Semântico

O versionamento semântico é um processo de versionamento de código definido da forma abaixo:

MAJOR.MINOR.PATCH

Onde cada um desses conjuntos significam:

  • Major - Quando você faz mudanças que tornam partes do código incompatíveis com a versão anterior
  • Minor - Quando se adiciona funcionalidades mantendo a compatibilidade
  • Patch - Quando se efetua correções no código mantendo compatibilidade

As motivações do versionamento semântico podem ser vistas no site https://semver.org/lang/pt-BR/

Standard Version

Embora o standard version esteja em modo deprecated, eu ainda utilizo em alguns projetos. Utilizo com um pacote do Node para adicionar itens ao changelog. Esse é um passo onde ele lê os commits pelo tipo e adiciona ao changelog. O substituto do standard-version é o commit-and-tag-version.


Entendendo o fluxo no github - Início da Parte Prática

Vamos supor que você faça parte de um time que mexe em uma funcionalidade do software. Esse software pode possuir outros times fazendo alterações. Dentro de um fluxo normal com github não é sensato você mexer na branch principal. O que costuma acontecer é mexer em uma branch separada e ao terminar o trabalho solicitar uma pull request para a branch principal sendo aprovada por alguém que possua esses recursos.

A imagem abaixo foi retirada de um site https://nvie.com/posts/a-successful-git-branching-model/ e num outro momento vou fazer uma outra abordagem sobre os comentários dele.
Acontece que a cada release, que ganha uma tag no git, você precisa consolidar algumas informações. Geralmente as pessoas querem entender as mudanças, querem saber o que está naquele release, etc. Fazer isso de forma manual não é viável. Se somente isso não bastasse, a possibilidade de erros é gigantesca. Não vou entrar no problema de organização de commits e prevenção de conflitos.

Agora vamos brincar de versionamento. Você é o gerente do produto e precisa organizar as informações e orientar as pessoas a fazerem as coisas de forma que consiga fazer as coisas direito.

Todos os desenvolvedores precisarão das seguintes ferramentas:

  1. NodeJS
  2. Yarn (eu utilizo o yarn para gerenciar pacotes node)

Vamos começar a brincadeira.

Prática

Para iniciar a prática vamos ao projeto:

yarn init

Digite um comando acima dentro de um repositório git inicializado. Eu prefiro iniciar o meu somente com um arquivo readme. Se você utilizar a opção -y, o yarn utilizará as opções padrões em todos os campos.

Logo depois, é necessário fazer a instalação do commitlint.

## Instalação do commitlint
yarn add -D @commitlint/{cli,config-conventional}
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

Essa opção utiliza as opções convencionais de commit. Depois de muito tempo gostando de customizar as coisas eu prefiro a opção padrão. Isso te salva tempo de desenvolvimento e comunicação. Mas... se você quiser entender como customizar entre no site do commitlint que lá você encontra como customizar as opções dos seus commits convencionais.

O próximo pacote é o husky. Ele oferece recursos para acionar gatilhos em determinada fazer do commit.

## instalação husky
yarn add -D husky
npx husky init 
rm -rf .husky/pre-commit
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg	

Aqui ele dispara o commitlint antes do commit ser realizado e valida as configurações de acordo com os commits convencionais.

O próximo passo é o commitzen. É um pacote npm para linha de comando que deixa as coisas mais fáceis na hora de fazer o commit. Porém, isso muda um pouco o fluxo do processo.

## commitzen
yarn add -D commitizen
yarn commitizen init cz-conventional-changelog --yarn --dev --exact

O próximo passo eu estou instalando o standard-version. Ele está em modo deprecated, mas eu ainda o utilizo em alguns projetos. Mais a frente vou migrar para o release-it, mas por enquanto o pacote me atende.

## Standard - Version
yarn add -D standard-version

## Atualiza o package.json de uma só vez
jq '.scripts += {
  "prepare": "husky",
  "commit": "git-cz",
  "release": "standard-version",
  "release:major": "standard-version --release-as major",
  "release:minor": "standard-version --release-as minor",
  "release:patch": "standard-version --release-as patch"
}' package.json > package.json.tmp && mv package.json.tmp package.json

A segunda parte, que atualiza o package.json, utiliza o pacote jq. Estou utilizando o linux Fedora, mas você pode incluir as linhas no package.json manualmente.

Para versionar o changelog somente com os commits que queremos que apareça você precisará dizer ao pacote o que quer.

# Versionamento Changelog
cat <<EOF > .versionrc
{
  "types": [
    { "type": "feat", "section": "Funcionalidades" },
    { "type": "fix", "section": "Bugs" },
    { "type": "chore", "hidden": true },
    { "type": "docs", "hidden": true },
    { "type": "style", "hidden": true },
    { "type": "refactor", "hidden": true },
    { "type": "perf", "hidden": true },
    { "type": "test", "hidden": true },
    { "type": "build", "hidden": true }
  ] 
}
EOF

Neste caso queremos apenas os commits com as tags feat e fix para o commit . Para inicializar o changelog no primeiro release você pode executar o comando abaixo:

yarn release --first-release

Siga as instruções do terminal.

Para terminar as configurações, execute esse último trecho de código:

## Create .Gitignore
cat <<EOF > .gitignore
node_modules
EOF

Isso cria um .gitignore para não subir os pacotes instalados do node no seu repositório.

Lá em cima eu disse que o fluxo mudaria. O novo fluxo, por conta do commitizen, fica assim:

# Primeiro passo - Adicionar arquivos 
git add . 

# Segundo passo - Commitizen (as configurações do commit aparecerão no terminal)
yarn commit 

# Terceiro passo - supondo que se queira enviar o commit para o servidor. 
git push

Pronto.