- 自分が使っている config 系(eslint, textlint, renovate...)をモノレポ構成で管理したかった。
- 自分しか使わない想定で npm Registry ではなく GitHub Packages を使いたい。
- リリース作業をやんわり自動化したい。(自動生成ツール使ってみたい)
リリース自動化ツール比較記事: CHANGELOG 生成系について調べてみた - くらげになりたい。
コミット方法に Emoji Prefix を使っている。Emoji Prefix は✨ feat: なんか追加
のように先頭に絵文字をつける文化圏の記法。認知負荷が低いため個人的には推している。ただ、Conventional Commitsの形式にならないため、Conventional Commits を前提としたツールチェインを利用できない。(e.g. Release Please, conventional-changelogなどのツールはコミットベースで CHANGELOG を自動生成する)
pnpm が推している1のでchangesets/changesetsを選定。
Changesets の特徴
- 手動/PR でリリースを自動化できるツール。
- 対話型 CLI で
CHANGELOG.md
の追記とpackage.json
のバージョンのインクリメントを行う。 - 標準で pnpm の Workspace に対応しておりインストールするだけで設定不要で使用できる。
- 他の自動リリースツールより手動の手順が多いけれども、その分柔軟性も高い。
- pnpm Workspace を使ったモノレポ構成
- レジストリは GitHub Packages
- パッケージ間の相互依存はないものとする
CHANGELOG.md
の管理とpackage.json
上のバージョンのインクリメントは Changesets に一任する- リリースフローを GitHub Actions で自動化
pnpm init
pnpm add -D @changesets/cli @changesets/changelog-github
pnpm changeset init
プロジェクトの初期化。.changeset/
にconfig.json
とREADME.md
が出力される。
package.json
の設定例
{
"name": "configs",
"version": "1.0.0",
"description": "x7ddf74479jn5 configs",
"scripts": {
"ci:version": "changeset version",
"ci:publish": "changeset publish",
"lint": "eslint --fix **/*.{ts,d.ts,js,cjs,mjs}",
"prettier": "prettier --write --ignore-unknown **/*",
"prepare": "simple-git-hooks"
},
"author": "x7ddf74479jn5 <[email protected]> (https://github.com/x7ddf74479jn5)",
"license": "MIT",
"private": "true",
"homepage": "https://github.com/x7ddf74479jn5/configs",
"repository": {
"type": "git",
"url": "https://github.com/x7ddf74479jn5/configs.git"
},
"bugs": {
"url": "https://github.com/x7ddf74479jn5/configs/issues"
},
"devDependencies": {
"@changesets/changelog-github": "0.4.8",
"@changesets/cli": "2.26.1",
"lint-staged": "13.2.0",
"prettier": "2.8.7",
"simple-git-hooks": "2.8.1",
"typescript": "5.0.3"
},
"simple-git-hooks": {
"pre-commit": "pnpm exec lint-staged --concurrent false -c lint-staged.mjs"
}
}
config.json
を以下のように編集。
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": ["@changesets/changelog-github", { "repo": "x7ddf74479jn5/configs" }], // [1]
"commit": false,
"fixed": [],
"linked": [],
"access": "public", // [2]
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
"changelog": "@changesets/changelog-github"
にオプションを設定することで author name や commit hash がリリースノートに含まれるようになる。repo
はプロジェクトルートを設定する。- private にする場合は
restricted
を設定。
最終的なディレクトリツリーの例(関係ないものは省略)
.
├── .changeset
│ ├── README.md
│ └── config.json
├── .github
│ └── workflows
│ └── release.yaml
├── .gitignore
├── package.json
├── packages
│ ├── module-a
│ │ ├── CHANGELOG.md
│ │ └── package.json
│ └── module-b
│ ├── CHANGELOG.md
│ └── package.json
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
pnpm-workspace.yaml
packages:
- "packages/*"
パッケージ側のpackage.json
の例
packages/module-a
{
"name": "@x7ddf74479jn5/module-a", // [1]
"version": "1.0.0",
"description": "module-a",
"main": "index.js",
"keywords": ["module-a"],
"author": "x7ddf74479jn5 <[email protected]> (https://github.com/x7ddf74479jn5)",
"license": "MIT",
"homepage": "https://github.com/x7ddf74479jn5/configs/tree/main/packages/module-a#readme",
"repository": {
"type": "git",
"url": "https://github.com/x7ddf74479jn5/config.git",
"directory": "packages/module-a"
},
"bugs": {
"url": "https://github.com/x7ddf74479jn5/config/issues"
}
}
- Github Packages の命名規則で**@<user-name/package-name>**の形式にする必要がある。
pnpm changeset
- アップデートするパッケージを選択
- メジャーアップデートするパッケージを選択
- マイナーアップデートするパッケージを選択
- サマリーを記述
- 確認
正常に終了すると.changeset/
中にランダムなファイル名(random-name.md)で CHANGELOG の断片が吐き出される。この Markdown には対象サブプロジェクトとバージョンアップの種別を示すメタデータ、および CHANGELOG.md
に追記される内容(=入力したサマリー)が記録されている。サマリーを複数入力する場合やパッケージ毎に異なるサマリーを入力する場合は pnpm changeset
を複数回実行する。
---
"@x7ddf74479jn5/module-a": minor
---
✨ feat: なんか追加
次のコマンドで CHANGELOG に統合される。
pnpm changeset version
# @x7ddf74479jn5/module-a
## 1.1.0
### Minor Changes
- [`14e046d`](https://github.com/x7ddf74479jn5/configs/commit/14e046d26ec2974acd4530c877f56c2df3adc724) Thanks [@x7ddf74479jn5](https://github.com/x7ddf74479jn5)! - ✨ feat: なんか追加
コードと.changeset/*
に生成されるマークダウンをまとめてコミット。
GitHub の PAT を取得の上、.npmrc
にレジストリ(npm.pkg.github.com
)の設定とともに記述する。.gitignore
に.npmrc
を追記する。
//npm.pkg.github.com/:_authToken=gh......................OU
@x7ddf74479jn5:registry=https://npm.pkg.github.com/ // [1]
- @:registry=https://npm.pkg.github.comの形式。
注意する点として、private なパッケージにする場合、利用側の.npmrc
もこの記述をしないと権限で弾かれる。
続いて、次のコマンドでパッケージの公開を行う。
pnpm changeset publish
これにより、現在 GitHub Packages に掲載されているバージョンよりも遅いバージョンの各パッケージでnpm publish
が実行される。
2.2.1 GitHub Actions でChangesets Release Actionを使用してリリース用 PR を自動生成する
name: Release
on:
push:
branches:
- main
concurrency: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
shell: bash
jobs:
release:
runs-on: ubuntu-latest
// [1]: write権限が必要
permissions:
packages: write
contents: write
pull-requests: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 18
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
- name: Get pnpm store directory
id: pnpm-cache
run: |
echo "PNPM_CACHE_DIR=$(pnpm store path)" >> $GITHUB_OUTPUT
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ steps.pnpm-cache.outputs.PNPM_CACHE_DIR }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
run: pnpm install
// [2]
- name: Setup npmrc
env:
NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
cat << EOF > "$HOME/.npmrc"
//npm.pkg.github.com/:_authToken=$NPM_TOKEN
@x7ddf74479jn5:registry=https://npm.pkg.github.com/
EOF
- name: Create release PR or publish to GitHub Packages
id: changesets
uses: changesets/action@v1
with:
version: pnpm ci:version // [3]: CHANGELOG.md生成
publish: pnpm ci:publish // [4]: リリース用PR作成
title: '[ci] release'
commit: '[ci] release'
createGithubReleases: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.GITHUB_TOKEN }} // [5]: 必須
- GitHub Packages に公開、リリースノートの自動作成、リリース PR に write 権限が必要。
@<github-username>:registry=https://npm.pkg.github.com/
の形式でレジストリの向き先を GitHub Packages に変える。changesets/action
は.npmrc
を自動生成するが、すでにある.npmrc
を検知するとそれを活用する。- 対応する npm script は
changeset version
- 対応する npm script は
changeset release
- npm Registry ではなく Github Packages を使用する場合でも publish するなら
NPM_TOKEN
を環境変数に設定する。
.npmrc
に各パッケージ共通のレジストリ設定を書く方法でやっているが、各パッケージのpackage.json
で以下のように書いても OK。
// ...
"publishConfig": {
"registry": "https://npm.pkg.github.com"
},
// ...
上記のアクションでリリース用の PR が作成される。
CI 実行した場合**[ci] release**のタイトルで PR が作成されているので、確認して問題なければマージする。成果物として次のものが自動実行される。
- リリースノートの生成
- タグ付け
- パッケージのデプロイ
Changesets に変更がないか PR でメンションしてくれる。
- GitHub Packages の npm registry を利用してパッケージを公開してみた| SHIFT Group 技術ブログ| note
- 【2023Q1】pnpm+Changesets+GitHub Actions で monorepo 内の npm パッケージのリリースと Codecov 連携を自動化する - Qiita
- GitHub Packages を使って自作ライブラリを管理しよう|エンジニアファースト
- changesets/changesets: 🦋 A way to manage your versioning and changelogs with a focus on monorepos
- pnpm と Changesets を組み合わせて使用する | pnpm