Changelog generation: criando CHANGELOG.md a partir de commits

1. Introdução à Geração Automática de Changelogs

Manter um changelog manual é uma tarefa ingrata. Em projetos com múltiplos contribuidores, o arquivo CHANGELOG.md frequentemente fica desatualizado, com entradas genéricas ou simplesmente inexistente. Automatizar sua geração a partir dos commits resolve esse problema, garantindo que cada release tenha um registro preciso e detalhado das mudanças.

Os benefícios são claros: economia de tempo, consistência entre releases, rastreabilidade total das alterações e documentação viva que evolui com o código. A diferença entre um changelog manual e um gerado por commits é a diferença entre um resumo subjetivo e um relatório objetivo baseado em dados.

O pré-requisito fundamental para essa automação funcionar é ter commits bem escritos, seguindo uma convenção padronizada. Sem isso, seu changelog será tão caótico quanto suas mensagens de commit.

2. Estrutura e Padrões de Commits para Changelogs Eficazes

A espinha dorsal de qualquer geração automatizada de changelog é a Convenção de Commits Semânticos (Conventional Commits). Esse padrão define uma estrutura clara para mensagens de commit:

<tipo>(<escopo opcional>): <descrição>

<corpo opcional>

<rodapé opcional>

Os tipos mais comuns mapeiam diretamente para seções do changelog:

  • feat: — Nova funcionalidade (entra em "Novas funcionalidades")
  • fix: — Correção de bug (entra em "Correções")
  • BREAKING CHANGE: — Mudança que quebra compatibilidade (entra em "Breaking Changes")
  • docs: — Documentação (geralmente omitida ou em seção separada)
  • refactor: — Refatoração (não aparece no changelog por padrão)
  • chore: — Tarefas de manutenção (ignorada)

Exemplo prático de commits bem formatados:

feat(api): adicionar endpoint de autenticação JWT
fix(ui): corrigir layout quebrado no Safari
BREAKING CHANGE: alterar formato de resposta da API de XML para JSON
docs: atualizar README com instruções de instalação

3. Ferramentas Nativas do Git para Extração de Commits

O Git oferece comandos poderosos para extrair e formatar commits. O git log é sua principal ferramenta:

git log --oneline --format="%s" v1.0.0..v2.0.0

Esse comando lista todos os commits entre duas tags. Para agrupar por tipo:

git log v1.0.0..v2.0.0 --grep="^feat" --format="- %s"
git log v1.0.0..v2.0.0 --grep="^fix" --format="- %s"

O git shortlog cria um resumo agrupado por autor:

git shortlog v1.0.0..v2.0.0 -sn

Para filtrar por data (útil quando não há tags):

git log --since="2024-01-01" --until="2024-03-31" --format="%s"

4. Scripts e Automação Manual com Shell

Você pode criar um script Bash simples para gerar um changelog básico. Aqui está um exemplo funcional:

#!/bin/bash

# changelog-generator.sh
# Uso: ./changelog-generator.sh v1.0.0 v2.0.0

FROM_TAG=$1
TO_TAG=$2

echo "# Changelog"
echo ""
echo "## [$TO_TAG] - $(date +%Y-%m-%d)"
echo ""

echo "### Novas funcionalidades"
echo ""
git log $FROM_TAG..$TO_TAG --grep="^feat" --format="- %s (%h)" | sed 's/^feat: //'
echo ""

echo "### Correções"
echo ""
git log $FROM_TAG..$TO_TAG --grep="^fix" --format="- %s (%h)" | sed 's/^fix: //'
echo ""

echo "### Breaking Changes"
echo ""
git log $FROM_TAG..$TO_TAG --grep="BREAKING CHANGE" --format="- %s (%h)"
echo ""

Execute com:

chmod +x changelog-generator.sh
./changelog-generator.sh v1.0.0 v2.0.0 > CHANGELOG.md

Para projetos sem tags, use --since:

git log --since="2024-01-01" --until="2024-06-01" --format="%s" > changelog_raw.txt

5. Ferramentas Populares de Terceiros

git-cliff

Ferramenta altamente configurável que usa templates Tera:

# Instalação
cargo install git-cliff

# Configuração básica
git cliff --init

# Geração
git cliff -o CHANGELOG.md

standard-version

Integrado com versionamento semântico:

npm install -g standard-version
standard-version --release-as minor

auto-changelog

Simples e direto, baseado em tags:

npm install -g auto-changelog
auto-changelog -p

6. Customização e Templates Avançados

Com git-cliff, você pode criar templates complexos. Exemplo de configuração cliff.toml:

[changelog]
header = "# Changelog\n\n"
body = """
{% if version %}\n## [{{ version }}] - {{ timestamp | date(format="%Y-%m-%d") }}{% endif %}\n
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.message }}{% if commit.author %} ({{ commit.author }}){% endif %}
{% endfor %}
{% endfor %}
"""

Para incluir links para issues e PRs, use expressões regulares no commit:

git log --format="- %s (fixes #%b)" | grep -E "#[0-9]+"

7. Integração com CI/CD e Fluxo de Trabalho

GitHub Actions

Crie um workflow .github/workflows/release.yml:

name: Generate Changelog

on:
  push:
    tags:
      - 'v*'

jobs:
  changelog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Generate changelog
        run: |
          git cliff --unreleased --strip all > CHANGELOG.md
          git add CHANGELOG.md
          git commit -m "docs: update changelog for ${{ github.ref_name }}"
          git push

GitLab CI

stages:
  - changelog

generate-changelog:
  stage: changelog
  script:
    - git cliff -o CHANGELOG.md
    - git add CHANGELOG.md
    - git commit -m "docs: update changelog"
    - git push origin HEAD:$CI_COMMIT_BRANCH
  only:
    - tags

Para validação de commits, use commitlint:

npm install -g @commitlint/cli @commitlint/config-conventional
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

8. Manutenção e Boas Práticas Contínuas

Nem todos os commits serão perfeitamente categorizados. Para lidar com commits não formatados:

# Capturar commits que não seguem o padrão
git log --format="%s" | grep -vE "^(feat|fix|docs|chore|refactor|BREAKING CHANGE)"

Estratégias para múltiplos contribuidores:

  1. Defina uma política clara no CONTRIBUTING.md
  2. Implemente hooks de validação com husky e commitlint
  3. Use squash merges para limpar o histórico antes de releases
  4. Revise manualmente o changelog gerado antes de publicar

O versionamento do próprio CHANGELOG.md é controverso. A recomendação é:

  • Nunca editar manualmente o arquivo gerado automaticamente
  • Adicionar entradas manuais apenas em seção separada ("Notas da release")
  • Versionar o template e a configuração, não o arquivo final

Se precisar de edição manual, crie um arquivo CHANGELOG_MANUAL.md que será mesclado ao gerado automaticamente.


Referências

  • Conventional Commits 1.0.0 — Especificação oficial do padrão de mensagens de commit que fundamenta a geração automatizada de changelogs
  • git-cliff Documentation — Documentação oficial da ferramenta de geração de changelogs altamente configurável com templates Tera
  • Keep a Changelog — Padrão recomendado para estrutura de arquivos CHANGELOG.md, com boas práticas de organização
  • standard-version GitHub Repository — Ferramenta de versionamento semântico que gera changelogs automaticamente a partir de commits convencionais
  • Git Log Documentation — Documentação oficial do Git sobre o comando git log, essencial para extração e formatação de commits
  • commitlint GitHub Repository — Ferramenta de validação de mensagens de commit baseada em regras configuráveis
  • semantic-release GitHub Repository — Sistema automatizado de versionamento e publicação que inclui geração de changelog