増補改訂版の以下の記事をご利用ください。
概要
Changesets と GitHub Actions を使用し、monorepoに含まれる複数のnpmパッケージの更新履歴とバージョンの管理およびリリース作業を省力化する。
以下のリリースフローを構築する。
- ローカルでは開発の区切り毎に
$ pnpm changeset
でChangesetsの対話式CLIからバージョンアップ種別の選択とCHANGELOGの入力を行う- 一時ファイル(メタデータ入りの
CHANGELOG.md
の断片)が生成される
- 一時ファイル(メタデータ入りの
- 一時ファイルをソースと一緒にGitHubにPushする
- 一時ファイルがGitHubのmainブランチに到達すると Changesets Release Action が「その時点でリリース対象となるnpmパッケージを一括リリースするためのPR」を自動生成する
- PRの内容は「
CHANGESET.md
の更新」「package.json
のversion
フィールドのインクリメント」「一時ファイルの削除」 - PRをマージする前に別の一時ファイルを追加するとリリース用PRの内容は自動で更新される
- PRには全ての一時ファイルの内容がパッケージ毎に整理されて表示される
- PRの内容は「
- 任意のタイミングでリリース用PRをマージするとリリースされる
要件
- 単独または少人数による開発を想定
- pnpm Workspaceによるmonorepo環境
- npmパッケージのバージョンは個別管理とし、CommitやPRには紐付けない
- npmパッケージ間の相互依存はないものとする
-
CHANGELOG.md
の管理とpackage.json
上のバージョンのインクリメントはChangesetsに一任する - GitHub ActionsでChangesets Release Actionを使用してリリース用PRを自動生成する
- リリース用PRをマージしたら自動でnpmjs.comにデプロイする
- changeset-bot は扱わない
ベースとなる開発環境は以下の記事の通り。
構築
リポジトリ
Changesets
導入は開発環境構築記事のChangesetsの節を参照のこと。
当該記事における「アップデート対象パッケージの選択とサマリーの入力」を実施した後、生成された一時ファイルのMarkdownをそのままリポジトリにCommitする。
「CHANGELOG.mdの更新とバージョンのインクリメント」相当の手順はChangesets Release ActionがGitHub上で自動実行する。
Tips
概要に載せたスクリーンショットの通り、自動生成されるリリース用PRには「一時ファイルを処理したコミットへのリンク」が設置される。
そのため、個別の開発用ブランチ(いわゆるfeatureブランチ)からリリース用のブランチに直接マージするGitHub Flow的なブランチモデルとの親和性が高い。
開発用ブランチ毎に $ pnpm changeset
を実行することでCHANGELOGの項目とマージコミットが紐付く形になるため、後から「GitHub上で パッケージ名@バージョン
で検索 → PR → ソース/差分/Issue」と簡単に辿ることができる。
npm-scripts
pnpm publish
コマンドで自動実行される prepublishOnly
タスクで必要な処理が行われるように各npmパッケージの package.json
を設定する。
// 例
"scripts": {
"clean": "rimraf ./dist",
"test": "vitest run",
"coverage": "vitest run --coverage",
"tsc": "tsc -p .",
"build": "pnpm clean && pnpm tsc",
"prepublishOnly": "pnpm test && pnpm build"
}
GitHub
Secrets追加
npmjs.comにデプロイする際に必要なアクセストークンをGitHubのSecretsに追加する。
- npmjs.comにログインしユーザーメニューから「Access tokens」に移動
- 「Generate new token」ボタンから「Automation」トークンを作成する
- GitHubのリポジトリで
Settings -> Secrets -> Actions -> New repository secrets
と移動 - トークンを
NPM_TOKEN
として追加する
GitHub Actions
リポジトリのルートに .github/workflow
ディレクトリを作成して設定用のYAMLを配置する。
ファイル名・Workflow名・Job名は適宜変更のこと。
name: Changesets
# mainブランチに対するPush時に動作
on:
push:
branches:
- main
jobs:
changesets:
runs-on: ubuntu-latest
steps:
# [1] リポジトリをチェックアウト
- name: Checkout
uses: actions/checkout@v3
# [2] Node.js 16系をインストール
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
# [3] pnpm 7系をインストール
- name: Install pnpm
id: pnpm-install
uses: pnpm/action-setup@v2
with:
version: 7
# [4] pnpmのストアディレクトリを取得
# pnpmは依存関係の実体をnode_modulesではなく独自のストアで管理している
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "::set-output name=pnpm_cache_dir::$(pnpm store path)"
# [5] pnpmのストアディレクトリをキャッシュとして定義
# 一致するものがあれば復元される
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.pnpm_cache_dir }}
# キーは実行環境のOSとpnpm-lock.yamlのハッシュ
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
# ハッシュが一致するものがない場合はOSが一致するものを使用する(step6で更新される)
restore-keys: |
${{ runner.os }}-pnpm-store-
# [6] 依存関係のインストール
- name: Install dependencies
run: pnpm install
# [7] 都度指定しなくていいようにnpmのtokenを .npmrc に追記する
- name: Setup npmrc
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
cat << EOF > "$HOME/.npmrc"
//registry.npmjs.org/:_authToken=$NPM_TOKEN
EOF
# [8] Changesets Release Actionの設定
- name: Create release PR or publish to npm
id: changesets
uses: changesets/action@v1
with:
# リリース用のコマンドは `pnpm publish` の再帰実行とする
# npmjs.com上のバージョンとpackage.json内のバージョンを比較して更新があったもののみリリースされる
# デバッグ用にドライランにしたい場合は `pnpm -r publish --dry-run` とする
publish: pnpm -r publish
# GitHubのReleaseは自動生成しない(既定では自動生成される)
# (2022-08-01現在、有効にしても最新のChangesets Release Actionとpnpm7系の組み合わせでは正常にトリガされない)
createGithubReleases: false
env:
# GITHUB_TOKENは自動生成されるためなにもしなくても使用可能
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Linter
基本的な文法チェックには actionlint が便利。
動作テスト
環境変数やoutputsの処理などは nektos/act を使ってローカルでテストできる。
PRの生成などGitHubの機能を使用するものは、テスト用のブランチないしリポジトリを作成し、デプロイ系の動作をdry-runに設定して確認する。
実行
基本的に概要の通り。
実際に運用中のリポジトリにおける一連のフローをサンプルとして掲載する。
-
changsetコマンドを実行 ※画像
- この例ではPatchレベルのサマリを2件入力している
-
1で生成された一時ファイルをCommit/Push
- 他のファイルと一緒でも構わない
-
GitHub Actionsが2を処理してPRを生成する
- Step名
Create release PR or publish to npm
参照
- Step名
- 3で生成されたPR
-
4をマージするとGitHub Actionsが自動でnpmjs.comにデプロイする
- Step名
Create release PR or publish to npm
参照
- Step名
※各所のCodecov関連の記述はテスト用のため無視のこと
留意事項
- 本稿で行った設定では、経緯に関わらずnpmjs.comに公開されているバージョンより新しいバージョンが指定された
package.json
がChangeset Releace Actionの動作するリモートブランチに到達すると即座にリリースされる- 動作としてはリリース用PRがマージされた時と同じ
-
package.json
を手作業で編集する場合は予期しないリリースが行われないよう注意が必要 - 逆にこの仕様を利用して
$ pnpm changeset version
コマンドをローカルで実行する運用にすることも可能