CHANGELOGの悩みを一発解決!git-cliffの使い方からカスタマイズまで📚
はじめに
CHANGELOGを自動生成するツールは多種多様です。Conventional Commits
に対応したコミットメッセージから生成するもの、GitHub上でのリリースやタグ付けまで行うものなどがあります。
CHANGELOGを自動生成する際には、バージョンタグに対応したコミットメッセージを基にしてくれると便利です。コミットメッセージを適切に付けるだけで、後はツールにお任せできます。ただし、いくつかの懸念点が存在します。
懸念点 1: チキンエッグプロブレム
CHANGELOG自動生成ツールは便利ですが、一つの大きな問題があります。それは、Gitのタグとコミットメッセージを基にCHANGELOGを生成するため、タグを作成する前にはCHANGELOGが存在しないという点です。この状況は「チキンエッグプロブレム」に類似しています。具体的には、新しいバージョン(卵)がリリースされる際には、その詳細をCHANGELOG(鶏)で文書化する必要があります。しかし、その新しいバージョンはGitのタグで識別され、このタグがCHANGELOG生成をトリガーします。その結果、タグが付けられたコミットにはCHANGELOGが含まれないという問題が生じます。この問題は、実際の開発フローで混乱を招く可能性があります。
懸念点 2: 混乱するファイルを置きたくない
自動生成ツールにはNode.js製のものが多いようです。使用するにはpackage.jsonをプロジェクトに置く必要があります。私は主にPythonでの開発を行っているので、プロジェクトにpackage.jsonがあると不快です。Pythonのプロジェクトなのか、Node.jsのプロジェクトなのか、混乱しそうです。
懸念点 3: 不安要素
自動生成ツールには、タグ付けからGitHub上でのリリースまで行ってくれるものもあります。多機能で便利な一方で、内部で何をしているかわからないという不安があります。それならば、CHANGELOGの生成だけを行ってくれる方が良いと感じます。
求める機能
以上を踏まえて、自動生成ツールに求める機能は以下の通りです。
- Semantic Versioningに対応
- Conventional Commitsをカスタマイズしたものに対応
- CHANGELOGの生成以外は不要
Conventional Commitsは、コミットメッセージに一定のルールを導入することで、コミットの内容を明確にします。メッセージに接頭辞を付けることで、そのコミットが何を目的としているのかが一目瞭然となります。
# feat: 新機能の追加
# fix: バグの修正
注意点として、1つのコミットに複数の変更を含めることは非推奨です。例えば、新しい機能の追加とバグの修正は、それぞれ別のコミットとして扱うべきです。
git-cliffは、複数の変更を含むコミットメッセージを無視します。以下のようなコミットメッセージは避けるべきです。
# 非推奨: 複数の変更を1つのコミットで行っている
feat: 新機能の追加, fix: バグの修正
git-cliff チュートリアル
git-cliffは Rust製 のCHANGELOG 自動生成ツールです。
JINJA2 に似たテンプレートを使っているので、簡単にカスタマイズできます。そして一番のポイントは、タグ付け前のコミットを参照してCHANGELOGを生成できる所です。チキンエッグプロブレムも解決します。
インストール
インストールには色々な方法があります。
# with cargo
cargo install git-cliff
# with yarn
yarn add -D git-cliff
# with npm
npm install git-cliff --save-dev
# with pip
pip install git-cliff
設定ファイル
設定ファイルを作成します。
git cliff --init
cliff.toml
が作成されます。他には何もしないので、既存のプロジェクトでも安心して実行できます。
作成時のサンプルはこちらから見ることができます。
設定例
header
headerは、CHANGELOGのヘッダーをカスタマイズできます。
header = """
# Changelog\n
このプロジェクトに対するすべての重要な変更は、このファイルに文書化されます。\n
"""
同様にbodyやfooterもカスタマイズできます。
tag_pattern
デフォルトでは、タグの形式は v1.0.0
のようなものを検索して、そのタグの付いたコミットメッセージからCHANGELOGを作成します。接頭辞の v
が付かない 1.0.0
のような形式なら以下の修正をします。
tag_pattern = "v[0-9]*"
↓
tag_pattern = "[0-9]*"
commit_preprocessors
初期設定では Conventional Commits に基づいたコミットメッセージをもとに自動生成のプロセスを行います。
コミットメッセージが feat
から始まる通常の形式なら設定の必要はありません。
例えば 🆕 feat:
のように、絵文字とスペースが入っている場合でも、これを除去すれば Conventional Commits に合致します。
以下の設定により、読み込んだコミットメッセージをreplaceしてくれます。
commit_preprocessors = [
{ pattern = "[🆕🐛👻📖📐🧹🏃〽📥]\\s+", replace = "" },
]
skip_tags
正規表現でスキップするタグを指定します。このタグに含まれるコミットからの自動生成は行われません
ignore_tags
正規表現で無効化するタグを指定します。このタグに含まれるコミットは次のタグに含まれます。
その他の設定については公式ドキュメントを参考にしてください。
CHANGELOGの自動生成
まずはCHANGELOGの生成ルールをまとめておきます
- gitのtagから、設定の tag_pattern に合致しているものを抽出し、それ以前のコミットメッセージを精査する
-
tag_pattern = "v[0-9]*"
の場合、tag名がtest
等なら対象外となる
-
- コミットメッセージが Conventional Commits に当てはまるものを抽出する
言い換えると、必要な要件は以下の通りです。
- Conventional Commits に準拠したコミットメッセージを付けてcommitする
- tagを付けることで、そこまでのコミットがCHANGELOG自動生成の対象になる
- 逆に言うと、CHANGELOGに残したくないコミットメッセージは Conventional Commits に準拠しないものにする。
この条件でコミットとタグ付けをして、自動生成を行います、
基本の自動生成コマンド
git cliff
で自動生成を行います。このコマンドは実行ディレクトリの cliff.toml
と.git
を参照します。
> git cliff
# Changelog
このプロジェクトに対するすべての重要な変更は、このファイルに文書化されます。
## [unreleased]
### Features
- CHANGELOG.mdを作成
<!-- 中略 -->
## [0.2.0] - 2023-09-26
### Features
- Add cliff.toml
<!-- generated by git-cliff -->
自動生成と言いましたが、ログに出力されるだけでファイルは生成されません。実際に生成するには以下のようにします。
git cliff -o CHANGELOG.md
git cliff > CHANGELOG.md
タグ付けしていないコミットを反映させる
先程の例では、生成されたCHANGELOGに以下の記述があります。
## [unreleased]
### Features
- CHANGELOG.mdを作成
タグ付けされていないcommitは [unreleased]
となります。しかしタグを付けてから生成すると、タグが紐づいたコミットには新しいCHANGELOGが含まれていないことになります。
この問題を解決するために、最新バージョンのタグを仮に指定することができます。
> git cliff --tag 0.5.0
## [0.5.0] - 2023-09-26
### Features
- CHANGELOG.mdを作成
生成されたCHANGELOGをcommitしてから、手動でgit tag 0.5.0
等のコマンドでタグ付けすれば、タグとコミットが理想的に紐づきます。
git-cliffが勝手にタグ付けを行うことはありません。
Tips
コミットメッセージの修正
CHANGELOGを作成したものの、一貫性が欠けてしまった場合があります。
### Features
- Add find function
- Find関数の追加
- Text_normalizeを追加
今後はコミットメッセージに一定のルールを適用する予定ですが、過去のメッセージも修正したい場合、cliff.tomlのcommit_preprocessorsセクションで修正ルールを定義できます。
commit_preprocessors = [
{ pattern = "[🆕🐛👻📖📐🧹✨🏃〽📥]\\s+", replace = "" },
{ pattern = "add find function", replace = "**collection_util.find** を追加" },
{ pattern = "find関数の追加", replace = "" },
{ pattern = "text_normalizeを追加", replace = "**string_util.text_normalize** を追加" },
{ pattern = "add file_util.cat", replace = "**file_util.cat** を追加" },
]
特定のセクションを反映させたくない
例えばrefactor:
で始まるコミットメッセージをCHANGELOGに反映させたくない場合、cliff.tomlのcommit_parsersセクションで設定できます。
commit_parsers = [
{ message = "^refactor", group = "Refactor" },
↓
{ message = "^refactor", skip = true },
]
特定のタグを反映させたくない
特定のタグをCHANGELOGの生成から除外したい場合は、cliff.tomlのskip_tagsセクションで正規表現を用いて設定できます。
例えば、v1.0
からv1.2
までを除外したい場合、以下のように設定します。
skip_tags = "v1.[012].*"
まとめ
インストール
インストールはrust, python, nodejsなどに対応しています。
pip install git-cliff
設定ファイル
cliff.toml
は設定ファイルです。コマンドから作成できます。
CHANGELOGのデザインをカスタマイズ、tagのパターン、過去のコミットメッセージを変換するなど、様々な設定が可能です。
git cliff --init
コマンド
git cliff
コマンドは過去のコミットメッセージからCHAGELOGを作成し、標準出力に出します。タグ付けやコミットなどは行いません
ファイルに保存する場合は -o
オプションを使います。
git cliff -o CHANGELOG.md
--tag
オプションは、まだ付けていないtagを指定できます。これによりunreleased の箇所はタグ名に置き換えられます。
git cliff --tag 0.5.0
実際の活用例
実際のプロジェクトでは、実装やテストを行う 開発フェーズ と、リリースに向けての作業を行う 公開準備フェーズ に分かれます。
開発フェーズでは、コミットメッセージを適切に付けることが、読みやすいCHANGELOGを作成するためのポイントとなります。コミットメッセージの標準化についてはこちらを参考にしてください。
公開準備フェーズでは、実際にCHANGELOGを作成します。CIでのtestやドキュメントの自動作成を同時に行う工程についてはこちらを参考にしてください。
git-cliff はCHANGELOG生成のためだけでなく、プロジェクトの管理全体をスムーズにする強力なツールです。ぜひ活用して、効率的な開発ライフを送ってください。
Discussion