Oie! Se você já usou bibliotecas, ou viu repositórios open-source, você já deve ter visto um arquivo chamado CHANGELOG.md. Até dá pra fazer ele manualmente, mas...
Você luta contra muitos fatores e perde muito tempo. Além disso, é muito simples fazer de forma automática. Só precisamos:
Definir um padrão para os nossos commits
Usar pacotes para auxiliar nesses padrões
Usar um pacote para gerar o CHANGELOG
Então, vamos começar a gerar nosso CHANGELOG.
Preparação
Na época que esse guia foi preparado, foram usadas as seguintes tecnologias:
Todo o código desse projeto está no GitHub, então, caso você se perca em qualquer parte, pode fazer uma comparação direta. Além disso, todos os passos desse artigo estão lá de forma resumida:
O padrão que vamos seguir para as mensagens é o conventional commit specification(especificação convencional de commit). Esse padrão é escrito da seguinte forma:
Arquivo, domínio, ou módulo que aquele commit se refere
descrição
✅
Uma descrição curta sobre o commit
corpo
❌
Uma descrição maior, caso não consiga explicar com clareza tudo o que tem no commit
rodapé
❌
Fechamento de tarefas e/ou informação sobre breaking changes
Lista de tipos permitidos
feat: Uma funcionalidade
fix: Um ajuste de erro/bug
docs: Modificação na documentação
style: Mudança de estilo (ponto, vírgula, indentação)
refactor: Mudança de código que não adiciona funcionalidade ou arruma um erro
perf: Mudança que altera performance
test: Novos testes ou correção de antigos
build: Mudanças que afetam o build ou dependências exeternas (gulp, npm)
ci: Mudanças na configuração da Integração Contínua (Travis, Circle)
chore: Outras mudanças que não são nos arquivos de src ou test
revert: Reversão de um commit
Exemplos de commit
feat(cadastro): adiciona integração com Gugou Sign-in
fix(pagamento): muda a chave do RecebaSeguro
A chave que estava sendo usada era de desenvolvimento,
mas acabou sendo enviada para produção
Fecha a tarefa #457
refactor(produto): remove o método #adicionarAoCarrinho
O método já tinha sido depreciado e agora foi removido
BREAKING CHANGE: o método públic #adicionarAoCarrinho foi removido
Facilitando a padronização
Apesar da padronização facilitar a automatização, ela pode ser muita coisa pra gravar de primeira. Então, para facilitar a aplicação desse padrão, nós vamos usar o Commitizen e o Commitlint.
Commitlint
O commitlint vai verificar se nossos commits estão seguindo o Conventional Commit Specification. Ele vai fazer isso com a ajuda do husky, que irá disparar o commitlint toda vez que for feito um commit.
1) Instale as dependências
# dentro do seu projeto
npm install--save-dev husky @commitlint/cli @commitlint/config-conventional
A configuração está pronta e já deve estar funcionando. Se quiser, pode fazer uma adição no seu projeto e commitar como teste para quebrar. Você deve receber um erro explicando o que está faltando no commit.
Commitizen
Agora que temos algo para verificar nossos commits, precisamos fazer eles de uma maneira mais fácil. Com o commitizen, nós vamos commitar usando o comando git cz, que vai fazer perguntas passo-a-passo até ter o commit final.
1) Instale e configure o commitizen
npm install--global commitizen
# dentro do seu projeto
commitizen init cz-conventional-changelog --save-dev--save-exact
2) Teste para ver se está funcionando
Faça uma pequena alteração, adicione ela com git add . e faça um git cz.
Automatizando o CHANGELOG
Agora que nós temos os commits seguindo um padrão, podemos gerar o nosso arquivo CHANGELOG. Os dois pacotes mais utilizados para fazer essa tarefa hoje, são o semantic-release e o standard-version. Vamos seguir com o standard-version pela facilidade do uso.
standard-version
Esse pacote vai ser responsável por analisar nossos commits, gerar uma nova versão pro projeto e gerar o CHANGELOG.
1) Instale o standard-version
npm install--save-dev standard-version
2) Altere seu package.json
{"scripts":{"release":"standard-version"}}
3) Faça seu primeiro release
Agora que tudo está configurado, commite essas alterações e execute o seguinte comando:
Uma BREAKING CHANGE representa um major (1.X.X) do SemVer;
Só aumenta um número por vez. 3 feats aumentam o mesmo que 1;
O maior número é que manda. Se tem feat, não importa o fix;
Só aparecem os commits com feat e fix;
Todos os links estão apontando para o repositório do GitHub;
Tirando os dois últimos pontos, o resto são regras do próprio SemVer (Semantic Versioning), que é quem dita as regras do versionamento (major.minor.patch).
Esses dois últimos pontos ganharam destaque porque eles são muito interessantes. Fazendo uma reflexão, parece que você teria que fazer uma solução própria caso quisesse exibir commits de outros tipos ou se quisesse usar o GitLab. Felizmente, o standard-version tem uma solução bem prática pra isso. Você só precisa passar um arquivo de configuração.
Configurando a geração do CHANGELOG
Podemos passar a configuração pro standard-version de diversas formas, mas vamos focar no .versionrc
Aqui nós estamos adicionando o tipo perf ao CHANGELOG.md, ao mesmo tempo que estamos também definindo os nomes das sessões em português. Por último, estamos adicionando o [skip ci] na mensagem de commit que é gerada pelo standard-version. Isso vai ser útil no futuro.
{"types":[{"type":"feat","section":"Funcionalidades"},{"type":"fix","section":"Errors Corrigidos"},{"type":"chore","hidden":true},{"type":"docs","hidden":true},{"type":"style","hidden":true},{"type":"refactor","hidden":true},{"type":"perf","section":"Melhorias de Performance"},{"type":"test","hidden":true}],"releaseCommitMessageFormat":"chore(release): {{currentTag}} [skip ci]"}
2) Altere o package.json (Opcional: GitLab)
Se quiser mesmo usar outro repositório, é bem provável que você só precise adicionar o repository.url no seu package.json. O standard-version usa essa URL para definir as URLs do CHANGELOG:
Se tiver problema nas URLs que foram geradas no seu CHANGELOG.md, você pode adicionar uma configuração customizada para o seguintes campos no seu .versionrc: commitUrlFormat, compareUrlFormat e issueUrlFormat.
Automatizando a automatização com integração contínua
O nosso CHANGELOG já é gerado graças ao standard-version, mas ainda precisamos rodar o script de forma manual. O ideal é que isso aconteça sempre que o código atinja a versão final / produção. Para isso, vamos usar o GitHub Actions como nossa ferramenta de integração contínua (CI - Continuous Integration).
No repositório do GitHub, na aba Ações/Actions, vamos criar um workflow de Node.js.
E esse é o arquivo que é gerado por padrão nesse workflow, mas não vamos usa-lo:
# nome do processoname:Node CI# o processo roda quando tiver um pushon:[push]jobs:build:# roda o build no ubunturuns-on:ubuntu-lateststrategy:# o processo vai executar uma vez para cada configuração do nodematrix:node-version:[8.x,10.x,12.x]steps:# esse passo pega uma cópia dos seu repositório-uses:actions/checkout@v1# esse passo instala a versão do node-name:Use Node.js ${{ matrix.node-version }}uses:actions/setup-node@v1with:node-version:${{ matrix.node-version }}# esse passo faz a instalação das dependências, roda o build e o teste-name:npm install, build, and testrun:|npm cinpm run build --if-presentnpm testenv:CI:true
Nós vamos usar esse arquivo como base para construir o nosso próprio. Se olhar bem, nós não precisamos realizar um teste, criar uma build ou muito menos rodar em várias versões do node, mas precisamos gerar o CHANGELOG e ele precisa de permissões para commitar e pushar no GitHub.
Além disso, tem um ponto que precisamos prestar muita atenção. Como o nosso processo de automatização gera um commit e roda a cada push, nós vamos criar um loop infinito. Felizmente, eu já passei 1 dia resolvendo isso, e depois de 50 commits disparados automaticamente, achei a solução.
Nos outros sistemas de integração contínua (CI) se fizermos um commit com skip ci - se lembra do .versionrc? - esse commit é automaticamente ignorado. Pena que não funciona assim no GitHub. Felizmente, a internet é um lugar maravilhoso e as pessoas conseguiram desenvolver uma solução para isso.
Juntando os fatores que precisávamos para gerar o CHANGELOG.md e aplicando essa solução que previne o loop, temos o seguinte arquivo:
.github/workflows/gerador-de-changelog.yml
name:Gerador de CHANGELOG# só executa no push de commit da branch masteron:push:branches:-masterjobs:build:# só deixa executar se o último commit não conter 'skip ci' na mensagemif:"!contains(github.event.head_commit.message,'skipci')"runs-on:ubuntu-lateststeps:-uses:actions/checkout@v1# configura o GITHUB_TOKEN# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/authenticating-with-the-github_token-name:Configura o GitHub tokenuses:fregante/setup-git-token@v1with:token:${{ secrets.GITHUB_TOKEN }}name:"Geradordechangelog"email:"changelog@users.noreply.github.com"# instala a versão 11.x do Node.js-name:Instala o Node.js 11.xuses:actions/setup-node@v1with:node-version:11.x# instala as dependências, vai para a master# executa o standard-version, e envia o commit e tag-name:Gera o CHANGELOGrun:|npm cigit checkout masternpm run releasegit push origin master --follow-tags
URL
![](https://github.com/<CONTA>/<REPOSITORIO>/workflows/<NOME_WORKFLOW>/badge.svg)
Exemplo do meu repositório:
![](https://github.com/klauskpm/changelog-cicd/workflows/Gerador%20de%20CHANGELOG/badge.svg)
Sendo klauskpm meu usuário, changelog-cicd o repositório que estou usando, e Gerador de CHANGELOG o nome do workflow, não o do arquivo, com %20 em vez de espaços.
Assim que sua badge será exibida no seu README.md:
Não deixe de me seguir caso queira receber mais artigos como esse, e compartilhar com seus colegas caso tenha ❤️. Não deixe de comentar se tiver algo que acha que eu deva mudar no artigo.