前置き
導入のきっかけ
Node.jsパッケージのリリース作業を何度も手動で実施しているうちに「この手順を自動化できないだろうか」と思うようになりました。
手順はバージョンを書き替えて、Gitにタグを付けて、リリースノートを書いて、npm login
して、npm publish
して...。
少し面倒なので、プログラマの3大美徳の一つ"怠惰"の実現を図ります。
記事を書くことにした理由
調査したところrelease-it
によって自動化が実現できることはわかりました。
公式ドキュメントも豊富でした。
更新も頻繁に行われており、安心して使うことができそうでした。
しかし実際に導入しようとすると、詰まるポイントがいくつかあり苦戦しました。
日本語ドキュメントも少ない状況でした。
私が実施したことの紹介が何かの役に立つのではと思い、記事を書いていきます。
この記事で紹介すること
- release-itの紹介
- リリース自動化の設定例
- npmjs.comのアクセストークンの取得方法
- release-itの設定例
- GitHub Actionsの設定例
- 実際に作ったサンプルの紹介
この記事で紹介しないこと
- release-itの詳細な解説
- 自分が試したことだけを記載する
- 自分が試していないことは主要機能であっても記載しない
-
package.json
の書き方 - npmの解説、npmコマンドの使い方
- GitHub Actionsの解説
バージョン情報
- release-it: 14.4.1
- release-it conventional-changelog: 2.0.1
注意点
(当然のことですが) 公開してはならない情報をうっかり公開しないように注意してください。
公開から72時間以内であれば簡単に npm unpublish <package_name> --force
で取り下げられるようですが、72時間を超えるといろいろ制約があるようです。
npm Unpublish Policy (公式ドキュメント)
release-itとは
従来のnpmコマンドによって実施していたリリース作業を自動化するためのツールです。
npm publish
だけでなく、同時に行うであろう操作や修正もサポートしています。
release-itによって自動化できることは主に以下です。
詳細な情報や正確な情報は公式を参照してください。
- 公開時の事前スクリプト実行
- バージョンアップ (
package.json
に記載されているバージョンの更新) - npm registryへの登録 (npmjs.comやその他プライベートregistryなどへの登録)
- Gitタグの付与
- GitHub Releaseの生成
-
CHANGELOG.md
の生成
Access Tokenの取得と設定
自動化を実現するためにはnpmアカウントの手動入力を省略する必要があります。
ここではnpm registryからトークンを取得し、GitHubに設定するところまで進めます。
npmリポジトリ側の操作
前提
npmのアカウントが作成済みであること。
手順
- npmjs.comにアクセスする
-
Access Tokens
->Generate New Token
を順に押下する -
Publish
->Generate token
を順に押下する - 生成されたトークンを控えておく
GitHub側の操作
前提
GitHubにリポジトリが作られていること。
手順
- GitHubのリポジトリにアクセスする
-
Settings
->Secrets
->New repository secret
を順に押下する - 以下を入力して
Add secret
を押下する
- Name:
NPM_TOKEN
(名称は任意。後述のGitHub Actionsで使用する) - Value: 先ほど取得したトークン
release-itの設定例
module.exports = {
"npm": {
"publish": true
},
"github": {
"release": true
},
"git": {
"requireCleanWorkingDir": false,
"addFiles": ["package.json", "CHANGELOG.md"],
"commitMessage": "chore: release ${version}"
},
"plugins": {
"@release-it/conventional-changelog": {
"preset": "angular",
"infile": "CHANGELOG.md"
}
}
}
設定ファイルは json
や yaml
でも書けますが、ここでは js
を採用します。
公式ドキュメント
npm.publish
true
の場合、パッケージが自動的に公開されます。
前述のトークンの設定が事前に必要です。
公開しない場合はfalse
を設定してください。
成功すると以下のようにregistryに登録されたことが確認できます。
ljourm-sample-release-it (npmjs.com)
github.release
true
の場合、GitHubのReleaseが生成されるようになります。
実際に生成されたRelease
git.requireCleanWorkingDir
後述の手順で.npmrc
を一時的に作るため、git差分が発生してエラーとなりました。
これを回避するためにfalse
を設定します。
git.addFiles
git.commitMessage
以下の更新がコミットされるようになります。
-
package.json
(自動でバージョンが更新される) CHANGELOG.md
デフォルトでgit push
まで実行されます。
実際にpushされたコミット
plugins.@release-it/conventional-changelog
せっかくなのでCHANGELOG.md
の更新まで実行したいと思い、公式のプラグインを導入しました。
@release-it/conventional-changelog (GitHub)
前回リリース以降のコミットメッセージのうち、条件に合ったものがCHANGELOG.md
に追記されます。
そしてそれがGitHubのリリースにも反映されます。
CHANGELOG.md
の記述ルールには複数の選択肢が用意されています。
選択肢一覧
"preset": "angular"
ここではangular
を採用しました。
コミットメッセージのルールはプロジェクトの事情に合わせればいいと思いますがが、type
をプレフィックスに採用するのは多くのプロジェクトに合うのではと思っています。
一方でscope
は必須でないと思ったので今回のサンプルでは省略しています。
Angular Commit Message Format (GitHub)
僕が考える最強のコミットメッセージの書き方 Prefixをつける (Qiita)
全てのコミットがCHANGELOG.md
に反映されるのではなく、feat
fix
perf
のみが反映されるとのことでした。
Angular Convention type (GitHub)
なお、柔軟にCHANGELOG.md
の内容を変えていくこともできるようです。
詳細は公式を参照ください。
公式ドキュメント config (GitHub)
CHANGELOG.md
の自動生成を上手く運用できるのか
ほとんど運用していない状態でこの記事を書いています。
CHANGELOG.md
の生成を自動化しましたが、コミットメッセージを正確に書いてもらない場合もありそうで、CHANGELOG.md
も不正確な状態になるのではと懸念しています。
今回はとりあえず導入してみて、しばらく様子を見てみたいと考えています。
GitHub Actionsの設定例
name: auto-release
on:
push:
branches:
- master
jobs:
auto-release:
runs-on: ubuntu-latest
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_IT_VERSION: 14.4.1
RELEASE_IT_CHANGELOG_VERSION: 2.0.1
steps:
- uses: actions/checkout@v2
with:
# ポイント1
fetch-depth: 0
- uses: actions/setup-node@v2
- name: Set releaser settings
run: |
git config --global user.name release-bot
git config --global user.email release-bot@example.com
- name: Set .npmrc
# ポイント2
run: echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc
- name: Major release
id: major
run: npx --package release-it@${RELEASE_IT_VERSION} --package @release-it/conventional-changelog@${RELEASE_IT_CHANGELOG_VERSION} release-it major --ci
if: contains(toJSON(github.event.commits.*.message), 'bump up version major')
- name: Minor release
id: minor
run: npx --package release-it@${RELEASE_IT_VERSION} --package @release-it/conventional-changelog@${RELEASE_IT_CHANGELOG_VERSION} release-it minor --ci
if: steps.major.conclusion == 'skipped' && contains(toJSON(github.event.commits.*.message), 'bump up version minor')
- name: Patch release
# ポイント3
run: npx --package release-it@${RELEASE_IT_VERSION} --package @release-it/conventional-changelog@${RELEASE_IT_CHANGELOG_VERSION} release-it patch --ci
# ポイント4
if: "!(steps.major.conclusion == 'success' || steps.minor.conclusion == 'success')"
ポイント1 fetch-depth: 0
CHANGELOG.md
に最新コミットしか反映されない問題の対策です。
# `fetch-depth: 0`が付いていない場合
git commit -m "feat: change 1" # これは反映されない
git commit -m "feat: change 2" # 最新のコミットメッセージのみ反映される
git push origin master
actions/checkout@v2
はデフォルトでGitの履歴を取らない (git log
で何も返ってこない)ことが原因とのことでした。
対策として fetch-depth: 0
を付けてGitの履歴を取得可能にします。
公式ドキュメント
ポイント2 .npmrc
手動でnpmコマンドを実行してリリースする場合、以下の手順になると思います。
$ npm login # ユーザ情報を対話式で入力する。これが自動化で問題となる。
$ npm publish
事前に登録したNPM_TOKEN
をここで使用します。
ポイント3 release-it patch --ci
ここではpatch
について解説しますが、majar
やminor
も基本的に同じです。
利用したいパッケージは通常package.json
内のdevDependencies
に追加すると思いますが、
今回はリリースでしか使用しないパッケージを開発環境に導入したくなかったため npx
による解決を採りました。
また、今回必要となるパッケージは二つあったため、-p
または--package
を使用します。
読みやすいように改行したものを以下に記載します。
npx \
--package release-it@${RELEASE_IT_VERSION} \ # 使用するパッケージ その1
--package @release-it/conventional-changelog@${RELEASE_IT_CHANGELOG_VERSION} \ # 使用するパッケージ その2
release-it patch --ci # 実行するコマンド。
ポイント4 if
コミットメッセージによってバージョンアップの対象を制御します。
これは後述の"参考にした記事"と同じ設定です。
- コミットメッセージに
bump up version major
が含まれていた時- -> Major version up (e.g.
1.0.0
->2.0.0
)
- -> Major version up (e.g.
- コミットメッセージに
bump up version minor
が含まれていた時- -> Minor version up (e.g.
1.0.0
->1.1.0
)
- -> Minor version up (e.g.
- 上記に該当しない場合
- -> Patch version up (e.g.
1.0.0
->1.0.1
)
- -> Patch version up (e.g.
GitHub Actionsの実行
ここまでの設定が完了した状態でmasterブランチに変更が入るとGitHub Actionsが実行されます。
実行されたAction
完了すると公開されたことが確認できるようになります。
実際にリリースされたパッケージ
1回のバージョンアップに複数のPull Requestをまとめたい場合
ここからは設定でなく運用テクニックの紹介です。
運用していると、例えばメジャーバージョンアップする時に「AとBとCを同時にリリースしたい」といったケースが発生すると思います。
そのような場合はバージョンアップ用の集約ブランチを作り、そこに各Pull Requestをマージし、最後に集約ブランチをmasterブランチにマージするのがよいと思います。
実際にシミュレーションしてみる
サンプルとして作成したリポジトリで実施してみました。
状況
マイナーバージョンアップを予定している。
その際に#2、#3、#5を同時にリリースしたい。
手順
- 集約ブランチ #4 を作る。
- 差分がないブランチからPull Requestを作ることはできないため、空コミットを作ってからPull Requestを作成する。
- e.g.
git commit --allow-empty -m "bump up version minor"
- 各修正のマージ先をmasterブランチでなく集約ブランチに変更してからマージする。
- 集約ブランチをmasterブランチにマージする。
この操作により複数のPull Requestを一つのリリースにまとめることができました。
release-itによって生成されたコミット
参考にした記事
GitHub Actionsとrelease-it npmでリリース作業を自動化する
こちらの記事がとても参考になりました。
上述のコミットメッセージによるMajor、Minor、Patchの切替もこちらを元にしています。
また、本記事と目指している方向が少し違うので、そういった意味でも参考になると思います。