GitHub Actions と semantic-releaseを組み合わせて Node.js パッケージのリリースフローを整備する試み
はじめに
オープンソースとして公開しているとある複数のパッケージでリリースフローが整備されいないという問題があって,昨年末は少々頭を悩ませていました.
そこで今回は GitHub Actions と semantic-release を組み合わせて npm へのリリース作業*1を自動化する,という方針で上記の問題を解決できないか?ということを試してみようと思います.
実験台にしたパッケージは krdlab/daab-session *2です.
先に軽く結論を述べますと,ライブラリ系のリポジトリでは導入する価値ありだ (というかした方が良い) と思いました.master ブランチにマージするだけで必要なものが自動的にリリースされるようになります.
GitHub Actions の設定
ここは公式が用意してくれているものをそのまま設定します.この段階では publish 関連を設定せずに,ビルドとテストが成功することだけを確認します.
後ほど少しだけ修正します.
semantic release の設定
semantic-release は Angular Commit Message Conventions にしたがってコミットするとパッケージのバージョニングと公開を自動化してくれます.導入手順は以下の通りです.
- 対象 GitHub リポジトリの Settings にある Secrets へ GitHub と npm のアクセストークンを追加
- semantic-release と必要な plugin を
npm install
- Actions の設定で追加した
.github/workflows/nodejs.yml
に semantic-release 実行ステップを追加 package.json
にrelease
フィールドを追加
1. 対象 GitHub リポジトリの Settings にある Secrets へ GitHub と npm へのアクセストークンを追加
semantic-release が使うトークンとして以下の 2 つが必要になるので,発行 & 設定します.
- GitHub で Personal access token を発行
- repo 権限を与える
- これを
GH_TOKEN
として Secrets に登録する
- npm で Access Token を発行
- publish 権限を与える
- これを
NPM_TOKEN
として Secrets に登録する
2. semantic-release と必要な plugin を npm install
npm install --save-dev semantic-release @semantic-release/changelog @semantic-release/git
デフォルトでロードされるプラグインは以下の通りです.
https://semantic-release.gitbook.io/semantic-release/usage/plugins#default-plugins
Changelog を生成したい場合は @semantic-release/changelog が追加で必要になります.
また,更新された package.json や生成された CHANGELOG.md はデフォルトだと publish 先にしか含まれないため,リポジトリに反映するためには @semantic-release/git が必要です.
3. .github/workflows/nodejs.yml
に semantic-release 実行ステップを追加
.github/workflows/nodejs.yml
の steps
に以下を追加します.
- name: semantic-release if: matrix.node-version == '12.x' run: | npm run semantic-release env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GH_TOKEN }}
matrix build しているため if
でリリースフローが複数回実行されないように絞り込んでおきます.
semantic-release はデフォルト設定だと master ブランチのみを対象としかつ npm を対象とするため,上記の追加だけで「PR を master ブランチにマージすると publish」されるようになります.ちなみに master ブランチ以外で実行した場合は以下のようなメッセージが出力されます.
This test run was triggered on the branch feature/add-github-actions, while semantic-release is configured to only publish from master, therefore a new version won’t be published.
4. package.json
に release
フィールドを追加
package.json
に以下の設定を追加します.といっても plugins
のデフォルト値に changelog と git を追加しているだけです.
"release": { "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", "@semantic-release/changelog", "@semantic-release/npm", "@semantic-release/github", "@semantic-release/git" ] }
注意点としては,リポジトリに付いている既存のバージョンタグが v1.0.1
のように v
から始まる場合は問題ありませんが,そうでない場合は追加で tagFormat
の設定が必要だということです.
semantic-release のリリースステップや dry-run の出力をみると Git タグを基に次のバージョン値を決めていることが分かります.この時タグからバージョンを抽出するフォーマットが tagFormat
なのですが,このデフォルト値が v${version}
になっているため,これを既存のタグフォーマットにあわせて修正する必要があります.
例えば単純にバージョン値を Git タグとして付けている場合は以下のような設定を追加します.
"release": { "plugins": [ ... ], "tagFormat": "${version}" <--- これ }
補足をいくつか
- dry-run は
GH_TOKEN=<トークン値> npm run semantic-release -- --dry-run
のようにトークンを指定した方が良い- password の入力が不要になる (入力を求められるが空値で良くなる)
- exec プラグインを使って他のパッケージマネージャを対象にすることは可能らしい
- コミットメッセージ規約をサポートするツールもあわせて導入すると良いかも
おわりに
以上のような設定を施すことで「master ブランチへマージしたら Release note や ChangeLog が生成されて npm に publish される」という一連の作業が自動化されます.
実行してみて思ったのは「想像以上に楽だ……」ってことです.パッケージ数が多いとより嬉しいんじゃないかなと思います.
リリース手順は実施頻度が低ければ忘れやすく,頻度が高ければ面倒なものになってしまいます.自動化しておくことでいずれの場合についても負担を軽減できる*3と感じました.