Open14

monorepo の CHANGELOG 生成について調べてみる

前提

  • monorepo 構成で複数の package を lerna で管理している
  • 今まで fixed mode で管理していたが最近 independent mode に変更した[1]
  • fixed mode では CHANGELOG は repository 単位で良かったが independent mode に変更したので CHANGELOG を package 毎に生成し、管理したい
    • fixed mode のときは lerna-changelog を使って PR の label をもとに CHANGELOG を生成していた

Refs

脚注
  1. independent mode に移行した理由はここでは触れない ↩︎

検討するツール

  • lerna
    • 今まで使っているので導入コストはない
  • changesets
    • graphql-code-generator などで使われているっぽい

観点

  • package 毎に CHANGELOG を生成できるか?
  • 運用コスト
    • commit 規則が必要になったりしないか?
      一部のエンジニアだけが作業するなら運用できなくもないが、しばしば Backend メインのエンジニアなども触ることがあるためなるべく新しい規約は導入したくない
    • リリースオペレーションが複雑になったりしないか?
  • tool 自体がメンテナンスされているか?

lerna のリリースフロー(&CHANGELOG 生成)について調べてみる

セットアップ

大まかに書く

  1. yarn add -D lerna で lerna を追加する
  2. yarn lerna init を実行
    ここで lerna.json が生成されるので、対象となる packages の directory の指定や mode の指定を行う
  3. yarn lerna ls を実行し対象の packages が表示されたら多分大丈夫

変更履歴の積み方

lerna-changelog は PR にラベルをつけることで CHANGELOG を生成していたが、lerna cli では convensional commit という命名規則に則って commit を作ることで git の commit log から CHANGELOG を生成し、version を決定する[1]。デフォルトでは angular の preset に従うが、指定することも可能っぽい[2]

convensional commit に関する詳細は https://www.conventionalcommits.org/en/v1.0.0/ を参照。
いくつか例を上げると以下のような commit の命名を行う

  • feat(api): allow users to edit their name
  • fix(bar): fix log formmat
  • docs: fix typo

リリースの流れ

lerna version コマンドに --conventional-commits オプションを渡すと、conventional rule に従って version の bump up と CHANGELOG の生成を行った上でタグを打ち push してくれる。
ちなみに --no-git-tag-version オプションを渡すとタグは打たずに version の bump up と CHANGELOG の生成のみを行う。

実際に手を動かして試してみる

適当な branch を切って空のファイルを追加した commit を積み、CHANGELOG の生成(version の bump up)を試す。

conventional commit rule に従わなかったとき

+ ## [0.1.1](https://github.com/NotFounds/monorepo-exp/compare/bar@0.1.0...bar@0.1.1) (2022-04-12)
+ 
+ **Note:** Version bump only for package bar

conventioal commit rule に従わずに、PR のタイトルを convensional rule にして squash merge したとき

+ # [0.2.0](https://github.com/NotFounds/monorepo-exp/compare/foo@0.1.0...foo@0.2.0) (2022-04-12)
+ 
+ ### Features
+ 
+ * **foo:** Add file aaa and bbb ([#3](https://github.com/NotFounds/monorepo-exp/issues/3)) ([406d873](https://github.com/NotFounds/monorepo-exp/commit/406d8737956840dbf494b1b32004ed7a54b45d0b))
脚注
  1. https://github.com/lerna/lerna/tree/main/commands/version#--conventional-commits ↩︎

  2. https://github.com/lerna/lerna/tree/main/commands/version#--changelog-preset ↩︎

changesets のリリースフロー(&CHANGELOG 生成)について調べてみる

セットアップ

こちらも大まかに書く。詳細は https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md

  1. yarn add -D @changesets/cli で changesets cli を追加する
  2. yarn changeset init を実行
    ここで .changesets/ が作られ、中に config.json が生成される
  3. yarn changeset を実行し、インタラクティブなプロンプトに対象の packages が表示されていれば多分大丈夫

変更履歴の積み方

yarn changeset add もしくは yarn changeset を実行するとインタラクティブなプロンプトで変更履歴を追加したい package の選択と description の記述ができる。変更履歴は .changesets/ 以下に適当な名前のファイルとして管理される。

基本的には PR 毎に changeset も一緒に積んでいく形になると思っている。

リリースの流れ

yarn changeset version コマンドを実行すると .changesets 以下に溜められた変更履歴をもとに version の bump up と CHANGELOG 生成が行われる。
その際に .changesets 以下に溜められていた変更履歴は消されるっぽい。
また、これらの変更は git に staging, commit されないので注意が必要。

npm に publish する場合は予め npm token などの設定を行った上で yarn changeset publish を実行すると、タグを打ち npm に publish してくれる。
git のタグだけ打ちたい場合は yarn changeset tag

publish tag どちらのコマンドも git のタグは push してくれないので git push --follow-tags を自分で実行する必要がある。

観点に沿って比較

観点 \ 選択肢 lerna changesets
package 毎に CHANGELOG を生成できるか?
commit 規則が必要になったりしないか? 必要 不必要
リリースオペレーションが複雑になったりしないか? commit の命名規則をしっかりしておけばリリースはシンプル lerna に比べてリリース時に必要なオペレーションは多い認識
tool 自体がメンテナンスされているか?(master の最終更新) 2021/06 [1][2] 2022/04
脚注
  1. Lerna is largely unmaintained · Issue #2703 · lerna/lerna ↩︎

  2. Is this project dead? · Issue #3062 · lerna/lerna ↩︎

所感

  • lerna
    • convensional commit のルールに従ってさえいれば CHANGELOG は勝手に作られるので記録漏れはなさそう
    • commit 単位で CHANGELOG を積むことができるが、我々は普段 PR 単位で CHANGELOG を積んでいるためここの相性が悪い
      • PR merge 時に Squash Merge にすることも考えられるが GUI 上でメッセージを編集する必要がありそう?
  • changesets
    • PR に対して CHANGELOG を必ず積むようにチェックする仕組みを用意できれば記録漏れはなくせそう
    • lerna と比較するとリリース時のオペレーションが複雑なのでスクリプトなり自動化しておく必要はありそう
    • ファイルとして変更が記録されるのでそれに対するレビューも行いやすそう

一旦 changesets を導入する方針でスクリプト/運用tips 周りを調べてみる

事例1 - changesets/changesets

changesets 自体も changesets を利用している。
package.json を見てみても特殊なことはしていない。

直近の Release Tag に紐づく PR を見てみると先頭に以下のような説明があった。

This PR was opened by the Changesets release GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated.

この PR は Changesets の GitHub Actions によって自動生成されたっぽい。
ドキュメント にあるとおり、基本的には GitHub Actions を利用して運用するのが良さそう。

https://github.com/changesets/changesets/blob/980721dab5df7938a783306a6368f83f1a94c18d/.github/workflows/changeset-version.yml

既存プロジェクトへの changesets の導入

現在 lerna を持ちているプロジェクトを changesets に移行する。

まずは https://github.com/changesets/changesets/blob/main/docs/intro-to-using-changesets.md の手順に従う。

yarn changeset init を実行すると以下のファイルが作られる。

$ tree .changeset
.changeset
├── README.md
└── config.json

0 directories, 2 files

ここで .changeset/config.json を覗いてみる。
baseBranch が main になっているので master に置き換える。(ここは project による)
cf. https://github.com/changesets/changesets/blob/main/docs/config-file-options.md#basebranch-git-branch-name

{
  "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [],
  "access": "restricted",
- "baseBranch": "main",
+ "baseBranch": "master",
  "updateInternalDependencies": "patch",
  "ignore": []
}

導入の手順書にもどり、yarn changeset を実行するとインタラクティブにプロジェクトを選択するプロンプトが出てくる。
Space で選択し、Enter で決定する。

ここでは すべての package を選択し、semver は patch として変更内容を記述する。
例: Generate independently changelogs

yarn changeset status を実行すると以下のように更新対象の package と、それぞれ major/minor/patch どれが上がるか表示される。

$ yarn changeset status
yarn run v1.22.18
🦋  info Packages to be bumped at patch:
🦋  info
🦋  - パッケージA
🦋  - パッケージB
🦋  ---
🦋  info NO packages to be bumped at minor
🦋  ---
🦋  info NO packages to be bumped at major
✨  Done in 1.02s.

yarn changeset version を実行することで各 package の version の bump と CHANGELOG 生成が行われる。(この時点では tag は打たれない)

CHANGELOG のフォーマット変更

changesets のデフォルトの設定では、積んだ changesets の変更点が plane text として出力されるだけである。

以下のような plugin を利用することで CHANGELOG にコミットハッシュや GitHub の Pull Request の Link や Auther などの情報を追記することができる。

自分で script を書くことでより細かく formatting できるが、ここでは changelog-github を用いる。
まず、以下のコマンドを実行し、project に plugin を追加する。

$ yarn add -W -D @changesets/changelog-github

次に以下のように .changeset/config.json を修正し、format の方法を変更する。

{
  "$schema": "https://unpkg.com/@changesets/config@2.0.0/schema.json",
- "changelog": "@changesets/cli/changelog",
+ "changelog": "@changesets/changelog-github",
  "commit": false,
  "fixed": [],
  "linked": [],
  "access": "restricted",
  "baseBranch": "master",
  "updateInternalDependencies": "patch",
  "ignore": []
}

この plugin は yarn changeset version を実行時に GitHub の Pull Request を探しに行くため、GitHub の Parsonal Access Token(PAT) が必要になる。
GitHub の PAT は ここ から取得することができ、以下のように利用する。

$ GITHUB_TOKEN="<GitHub の PAT>" yarn changeset version

ref

https://github.com/changesets/changesets/blob/main/docs/modifying-changelog-format.md
ログインするとコメントできます