5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

release-itとGitHub ActionsによってNode.jsパッケージのリリース作業を自動化する

Posted at

前置き

導入のきっかけ

Node.jsパッケージのリリース作業を何度も手動で実施しているうちに「この手順を自動化できないだろうか」と思うようになりました。
手順はバージョンを書き替えて、Gitにタグを付けて、リリースノートを書いて、npm loginして、npm publishして...。
少し面倒なので、プログラマの3大美徳の一つ"怠惰"の実現を図ります。

記事を書くことにした理由

調査したところrelease-itによって自動化が実現できることはわかりました。
公式ドキュメントも豊富でした。
更新も頻繁に行われており、安心して使うことができそうでした。

しかし実際に導入しようとすると、詰まるポイントがいくつかあり苦戦しました。
日本語ドキュメントも少ない状況でした。
私が実施したことの紹介が何かの役に立つのではと思い、記事を書いていきます。

この記事で紹介すること

この記事で紹介しないこと

  • 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とは

release-it (GitHub)

従来の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のアカウントが作成済みであること。

手順

  1. npmjs.comにアクセスする
  2. Access Tokens -> Generate New Tokenを順に押下する
  3. Publish -> Generate tokenを順に押下する
  4. 生成されたトークンを控えておく

GitHub側の操作

前提

GitHubにリポジトリが作られていること。

手順

  1. GitHubのリポジトリにアクセスする
  2. Settings -> Secrets -> New repository secretを順に押下する
  3. 以下を入力してAdd secretを押下する
    • Name: NPM_TOKEN (名称は任意。後述のGitHub Actionsで使用する)
    • Value: 先ほど取得したトークン

release-itの設定例

.release-it.js
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"
    }
  }
}

設定ファイルは jsonyaml でも書けますが、ここでは 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の設定例

.github/workflows/release.yml
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について解説しますが、majarminorも基本的に同じです。

利用したいパッケージは通常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)
  • コミットメッセージに bump up version minor が含まれていた時
    • -> Minor version up (e.g. 1.0.0 -> 1.1.0)
  • 上記に該当しない場合
    • -> Patch version up (e.g. 1.0.0 -> 1.0.1)

GitHub Actionsの実行

ここまでの設定が完了した状態でmasterブランチに変更が入るとGitHub Actionsが実行されます。
実行されたAction

完了すると公開されたことが確認できるようになります。
実際にリリースされたパッケージ

1回のバージョンアップに複数のPull Requestをまとめたい場合

ここからは設定でなく運用テクニックの紹介です。

運用していると、例えばメジャーバージョンアップする時に「AとBとCを同時にリリースしたい」といったケースが発生すると思います。
そのような場合はバージョンアップ用の集約ブランチを作り、そこに各Pull Requestをマージし、最後に集約ブランチをmasterブランチにマージするのがよいと思います。

実際にシミュレーションしてみる

サンプルとして作成したリポジトリで実施してみました。

状況

マイナーバージョンアップを予定している。
その際に#2#3#5を同時にリリースしたい。

手順

  1. 集約ブランチ #4 を作る。
    • 差分がないブランチからPull Requestを作ることはできないため、空コミットを作ってからPull Requestを作成する。
    • e.g. git commit --allow-empty -m "bump up version minor"
  2. 各修正のマージ先をmasterブランチでなく集約ブランチに変更してからマージする。
  3. 集約ブランチをmasterブランチにマージする。

この操作により複数のPull Requestを一つのリリースにまとめることができました。
release-itによって生成されたコミット

参考にした記事

GitHub Actionsとrelease-it npmでリリース作業を自動化する
こちらの記事がとても参考になりました。
上述のコミットメッセージによるMajor、Minor、Patchの切替もこちらを元にしています。
また、本記事と目指している方向が少し違うので、そういった意味でも参考になると思います。

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?