semantic-release を使って Node パッケージのリリースワークフローを自動化する
これはなに
semantic-release の基礎知識と、これを用いて Node パッケージのリリースワークフローを自動化する方法をまとめたものです。
現代のソフトウェアパッケージにおけるリリースフローには、バージョン番号の管理、変更履歴の記録、リリースノートの作成、各種共有レジストリーへの公開など、多くの手順が要求されます。これらの手順を自動化することでソフトウェア開発者はリリースに費やす時間を短縮し、ヒューマンエラーの削減が期待できます。
semantic-release とは
ソフトウェアパッケージのリリースフローを自動化するための OSS ツールです。Semantic Versioning(SemVer2)に準拠した次期バージョン番号の決定、リリースノートの作成、npmjs といった共有レジストリーへの公開[1]といったリリースワークフローを包括的に自動化します。
次期バージョン番号の自動決定
semantic-release の最大の特徴は、それまで蓄積されたコミットメッセージの内容から次期バージョン番号を自動的に選定する点にあります。semantic-release は、Conventional Commits などに代表されるコミットメッセージ規約に基づいてコードベースの変更内容を解析し、それに応じた次期バージョン番号を決定してリリースワークフローを進めます(コミットメッセージの内容次第でリリースを見送る判断もします)。
この仕様は一貫したバージョン番号の管理を実現するのと同時に、コミットの粒度やそれを表すコミットメッセージに対して一定の規約を開発者に課すことで、コードベースの変更履歴を明確なものに保つ効果も期待できます。
用途ごとに提供されるプラグイン
semantic-release はプラグインシステムを採用しており、リリースワークフローの各ステップに特化したプラグインを提供しています。以下は主要なプラグインの一覧ですが、そのうちいくつかは semantic-release 本体に標準でバンドルされています。
プラグイン名 | 説明 | 標準バンドル |
---|---|---|
commit-analyzer | 蓄積されたコミットメッセージを解析し、SemVer2 に準拠した次期バージョン番号を決定する。 | ✅ |
release-notes-generator | Release Notes を生成する。 | ✅ |
npm | npmパッケージのバージョン更新およびリリース処理を実行する。package.json の version フィールドの更新作業も担う。 |
✅ |
github | Github Release や Comment を生成する。 | ✅ |
changelog |
CHANGELOG.md を生成する。 |
- |
git | リリースフローで発生した差分を Git リポジトリにコミットする。 例: package.json の version フィールドの更新。 CHANGELOG.md の更新。 |
- |
exec | 任意のコマンドを実行する。 | - |
この他にも多くのプラグインが提供されており、ユースケースに応じて適切なプラグインを選択することでリリースワークフローを柔軟にカスタマイズできます。
次期バージョン番号の決定ロジック
先述した @semantic-release/commit-analyzer
というプラグインがコミット履歴を解析し、Conventional Commits に準拠したコミットメッセージに含まれる type
フィールドに基づいて次期バージョン番号を決定します。
<type>[optional scope]: <description>
│ │ │
│ │ └─ コミットの内容を簡潔に記述
│ │
│ └─ コミットの影響範囲を指定するスコープ(省略可)
│
└─ コミットの種類を指定するタイプ
type | 解析内容 |
---|---|
feat |
新機能が追加されたとみなし、マイナーアップデートと判断される。 |
fix |
バグの修正パッチが適用されたとみなし、パッチアップデートと判断される。 |
perf |
パフォーマンスチューニングがされたとみなし、パッチアップデートと判断される。 |
この他にも refactor
、 test
など様々な type がありますが、原則として上記以3つ以外の type はアップデートの対象となりません。refactor
はバグの修正や機能の追加を含まないコードのリファクタリングを表し、test
はそのソフトウェアの開発生産性向上を目的としたテストコードの追加や変更を表すものです。つまり上記3つ以外はソフトウェアのユーザーに影響を与えるものではないため、アップデートして公開するに値しないというわけです。
また、メジャーアップデートは以下の特定のキーワードによって判断されます。
キーワード | 解析内容 |
---|---|
BREAKING CHANGE |
コミットメッセージのフッター部分に BREAKING CHANGE を含めると破壊的変更(= 重大な変更)が入ったとみなされ、メジャーアップデートと判断される。 |
! |
type/scope の直後に ! が入ると BREAKING CHANGE のエイリアスとして機能する(メジャーアップデートと判断される)。 |
initial commit |
v1.0.0 として処理される。 |
feat: add new feature
BREAKING CHANGE: this is a breaking change
feat!: add new feature
feat(api)!: add new feature
セットアップ
ここでは以下の要件を満たすセットアップをご紹介します。
- Node.js パッケージのリリースフローを自動化する
-
package.json
のversion
フィールドを次期バージョン番号で更新する - npmjs に Node パッケージを公開する
-
npm dist-tag
コマンドを実行して npmjs で公開するパッケージにタグを追加する
-
- Changelog ファイルおよび GitHub の Release Notes を生成する
インストール
npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git
semantic-release 本体(および標準バンドルされたプラグイン)に加えて Changelog ファイルを生成する @semantic-release/changelog
と、リリースフローで更新される package.json
や CHANGELOG.md
の差分を Git リポジトリにコミットする @semantic-release/git
をインストールします。
設定ファイルの作成
リポジトリーのルート直下に release.config.js
という名前で設定ファイルを作成します。
export default {
plugins: [
// 1. コミット履歴から次期バージョン番号を算出する。
"@semantic-release/commit-analyzer",
// 2. リリースノートのためのコンテンツ(テキスト)を生成する。
"@semantic-release/release-notes-generator",
// 3. "2" で生成されたリリースノート用コンテンツを Changelog ファイルに記述する。
'@semantic-release/changelog',
// 4-a. package.json の version フィールドを次期バージョン番号で更新する。
// 4-b. npmjs にパッケージを公開する。
// 4-c. npm dist-tag コマンドを実行して npmjs で公開するパッケージにタグを追加する。
'@semantic-release/npm',
// 5. リリースフローで発生したアセットの更新差分をリポジトリにコミットする。
[
'@semantic-release/git',
{
assets: ['CHANGELOG.md', 'package.json', 'package-lock.json'],
},
],
// 6. "2" で生成されたリリースノート用コンテンツを用いて GitHub Release を追加する。
'@semantic-release/github',
],
};
plugins
フィールドにリリースワークフローの各ステップに対応するプラグインを指定することで、semantic-release はそれらを指定された順序で実行します。この他にもさまざまな設定フィールドが提供されていますが、基本的に plugins
以外はデフォルト値のままで問題ありません。
!
エイリアスの有効化
メジャーアップデートを示すために !
エイリアスを使用したいところですが、残念ながらデフォルト設定の commit-analyzer
は !
エイリアスを認識しません。これは commit-analyzer
ならびに release-notes-generator
のプリセット初期値が angular
という Angular Commit Guidelines に準拠したものに設定されているためです。!
エイリアスは Conventional Commits の仕様なので[2]、これを認識させるには双方プラグインのプリセットを conventionalcommits
に変更する必要があります。
このプリセットはオプション扱いなので、別途インストールします。
npm install --save-dev conventional-changelog-conventionalcommits
次に release.config.js
を以下のように修正します。
export default {
plugins: [
- "@semantic-release/commit-analyzer",
+ [
+ "@semantic-release/commit-analyzer",
+ { preset: "conventionalcommits" },
+ ],
- "@semantic-release/release-notes-generator",
+ [
+ "@semantic-release/release-notes-generator",
+ { preset: "conventionalcommits" },
+ ],
// ...
],
};
これで semantic-release に !
エイリアスを含むコミットメッセージをメジャーアップデートとして認識させられます。
参考文献
- semantic-release breaking-change using ! (exclamation mark) · Issue #2339 · semantic-release/semantic-release
- "BREAKING CHANGE:" and "!" after type not properly triggering major release · Issue #231 · semantic-release/commit-analyzer
環境変数の設定
先述した設定で semantic-release を実行するためには、以下の環境変数を設定する必要があります。
環境変数名 | 説明 |
---|---|
NPM_TOKEN |
npmjs に Node パッケージを公開するための npm アクセストークン。 詳細: About access tokens | npm Docs |
GITHUB_TOKEN |
GitHub リポジトリーに更新差分をコミットしたり Release Notes を追加するための GitHub アクセストークン。 |
npm scripts の追加
package.json
に以下の npm scripts を追加します。
{
"scripts": {
"release": "semantic-release"
}
}
シンプルに semantic-release
コマンドを実行するだけで同階層ディレクトリーにある release.config.js
を読み込み、リリースワークフローが実行されます。
GitHub Actions の設定
semantic-release は CI/CD ツールとして使用することを想定されているため、ここでは GitHub Actions を使用してリリースワークフローを自動化する方法を紹介します。
name: Release
on:
push:
branches:
- main
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup node.js
uses: actions/setup-node@v4
- name: Install dependencies
run: npm install
- name: Release
run: npm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# あらかじめリポジトリーの secrets に NPM_TOKEN という名前で npm アクセストークンを登録しておく
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
ここでは例として main
ブランチに push されるとリリースワークフローが実行されるように設定しています。npm scripts に追加した release
コマンドを実行するステップを定義し、その際に環境変数として GitHub アクセストークンと npm アクセストークンを渡しています。これでリリースワークフローが自動化されます。
まとめ
ソフトウェアパッケージのリリースワークフローを自動化するツールは他にもいくつか存在しますが、semantic-release はその中でも特に「自動化」に重点を置いたツールです。Conventional Commits に準拠したコミットメッセージを使って次期バージョン番号を自動決定するという特徴は、ソフトウェアのリリースフローを一貫性のあるものに保つという点で非常に有用です。エコシステムもなかなか充実しており、本稿で紹介したプラグイン以外にも monorepo での利用をサポートする semantic-release-monorepo などが提供されています。
参考文献
-
プラグインを組み合わせることで Docker Hub や GitHub Packages などさまざまなレジストリーにも対応できます。 ↩︎
-
Conventional Commits は Angular Commit Guidelines を拡張したものです。 ↩︎
Discussion