GitHub Actions を使って push だけでnpmに公開 & CHANGELOG更新する仕組みを作ろう!

April 26, 2021

こんにちは! N Inc.でフロントエンドの開発に参加している五十嵐(@thegodofneet)です。みなさんはデプロイフロー、整えていますか?

main ブランチに push したら CI/CD が走って本番環境にデプロイ…というユースケースはよく耳にするかもしれませんが、インフラや DX のレイヤーの話で、私みたいなアプリケーションエンジニアには縁のない話。そう思うかもしれません。

しかし、先日 npm モジュールを GitHub Packages に公開する必要を迫られやむなく「semantic-release」という CLI ツールを試してみたところ、任意のブランチに push したらレジストリに公開されるというフローを簡単にセットアップできたのみならず、勝手にメジャーバージョンかマイナーバージョンかを判定してくれたり、モジュールの更新履歴を記した CHANGELOG.md を自動で生成して tag を切ってくれたりと大変体験がよかったためシェアしようと思います。

この記事では

  1. semantic-release の機能説明とセットアップの方法
  2. GitHub Actions から npmjs.com レジストリに公開する方法
  3. 設定のカスタマイズと CHANGELOG の生成方法

を解説します。

semantic-release でできること

semantic-release は Node.js 向けの完全自動の バージョン管理 & パッケージ公開ツール です。Conventional Commits というコミットメッセージのルールに基づいて記述された変更点を元に、 Semantic Versioning というバージョン番号の仕様に基づいてバージョン管理を行います。

conventional commits

例えば現在のバージョンが 1.0.0 だとしましょう。新機能を追加した際にはコミットメッセージを:

git commit -m "feat: 新機能Aの追加"

のように feat: で始めれば、次のリリース時に 1.1.0 のように 2 桁目が更新されます。他にも バグ修正 を行った際は fix:1.0.1 のように 3 桁目を、破壊的変更 を行った際は BREAKING CHANGE:2.0.0 のように 1 桁目の数字を自動的にインクリメントしてくれます。

このコミットの記述方法とバージョン管理方法は ElectronAngular でも採用されており、ライブラリ開発者はもちろん、利用者側も変更点がわかりやすく package.json とも相性が良いです。

semantic-release のインストール

semantic-release は npm の公式レジストリで公開されており、下記のコマンドでインストールできます。

yarn install semantic-release

--help でヘルプを表示してインストールされていることが確認できます

yarn run semantic-release --help

設定ファイルの作成

インストールが完了したら、 semantic-release を利用するために、リリースを行えるブランチを設定します。このツールは Babel や ESlint のように .releaserc または release.config.js というファイルを package.json と同じディレクトリに作成するか、 package.json 自体に release というフィールドを作成することで設定の記述が行なえます。

// release.config.js
{
  branches: ["main"];
}

上記内容でファイルを作成すると main ブランチで semantic-release の利用が可能になります。試しに yarn run semantic-release と実行してみましょう。

出力

無事プラグインが読み込まれ、コミットメッセージを解析しているのがわかると思います。 デフォルトではローカル環境ではパッケージは公開されず、 GitHub Actions や Circle CI といった CI 環境でのみパッケージが公開されるようになっており、それ以外の場合はドライラン扱いになるので安心して試すことができます。

GitHub Actions で自動リリースの設定

semantic-release 自体は単なる CLI ツールのため、どこかにホストしなければパッケージ公開を自動化することはできません。この記事では GitHub Actions を用いた設定の方法を紹介します。

はじめに、パッケージをレジストリに公開するための設定をします。 package.json と同じディレクトリに .npmrc という名前で下記の内容のファイルを作成してください。

//registry.npmjs.org/:_authToken=${NPM_TOKEN}

このファイルは npm CLI での環境設定や認証情報を設定するファイルで、ここでは npm 公式レジストリ registry.npmjs.org でのアクセストークンとして NPM_TOKEN という環境変数を利用する旨を設定しました。

続いて、この環境変数を CI 上で代入するための設定を行います。まず npmjs.org の設定画面 にアクセスし、新しいトークンを生成します。

出力

自分の npmjs.com アカウントのトークンが取得できたら、次はトークンを GitHub 上に渡します。 Settings > Secrets > New Repository Secret からトークンをシークレットとして登録すると、GitHub Actions 上で実行されるジョブから secrets.<シークレット名> として設定した値を利用できるようになります。ここでは先程 .npmrc に設定した NPM_TOKEN と同じ名前にします。

出力

.npmrc ではわざわざ環境変数を利用しなくても文字列を直書きすることが可能ですが、オープンソースとして公開されている場合や、ソースコードが流出した際のリスクを考えると、このようにサービス上からのみ利用できるように設定しておくのが安全です。

これでパッケージを公開するための認証ができるようになったので、次は GitHub Actions のワークフローを登録します。 package.json と同じディレクトリに .github/workflows というディレクトリを作成し、そのディレクトリ内に任意の名前で Yaml ファイルを作成します。

name: Publish

on:
  push:
    branches:
      - master # -- (1)

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      NPM_TOKEN: ${{secrets.NPM_TOKEN}} # -- (2)
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v1
        with:
          node-version: 12
      - run: yarn install --frozen-lockfile
      - run: yarn build
      - run: yarn run semantic-release # -- (3)

注意点は下記の 3 つです。

  1. on.push.branches に自動リリースを行いたいブランチを記述します。前節で書いた設定ファイル .releaserc と同じブランチである必要があります。
  2. semantic-release CLI を実行するジョブ内で .npmrc で展開するためにシークレット secrets.NPM_TOKEN を環境変数 NPM_TOKEN として渡します。
  3. 最後に semantic-release CLI を実行します。バンドルのビルドやテストを実行した後に行われているかを確認してください。

作成したファイルを push すると、 GitHub リポジトリ上の Actions タブ内に Publish という名前でワークフローが作成され、 master に新しいコミットが push されたときにそれまでのコミットメッセージに対して semantic-release が実行されるようになりました。

ワークフロー

加えて、 on をカスタマイズすることでトリガーのタイミングを変更することが可能です。例えば 毎日 0 時に最新のコミットをビルドして配信したい という場合は、下記のように schedule というイベントを使うことで毎晩定期的に実行することができます:

#...
on:
  schedule:
    - cron: "0 0 * * *"

semantic-release は常に最後のリリースから最新のコミットまでの差分を検出し必要なときにだけリリースを行うため、昨晩から変更がない場合は無駄にリリースされることはありません。

設定のカスタマイズ

.releaserc では先ほど紹介した  利用可能なブランチの他にも、ブランチごとのタグの設定や、利用するプラグインの設定が行えるようになっていて、デフォルトでは下記の設定が有効になっています。

キー  説明 デフォルト値
branches リリースを行う対象になるブランチ ["master", "next"]
plugins 利用するプラグイン一覧 ['@semantic-release/commit-analyzer', '@semantic-release/release-notes-generator', '@semantic-release/npm', '@semantic-release/github']

branches の設定

安定版とプレビュー版を並行してリリースしている開発環境ではブランチごとにリリースやバージョンアップの方針を変更する必要があると思います。実は semantic-release ではデフォルトで登録されているブランチ名に限ってちょうどよい設定が割り当てられています。

ブランチ名 説明
master 普通のリリースが行われる
next next タグ(NPM の機能)にリリースされ、npm install foo@next のようにしてインストールできる。チーム内でテストする際などに使える
next-major next タグと同じ。メジャーリリースとパッチで開発ブランチを分けている人用。
beta beta タグにリリースされ、npm install foo@beta のようにしてインストールできるようになる。
alpha alpha タグにリリースされ、npm install foo@alpha のようにしてインストールできるようになる。

さらに、実は branch キーは文字列だけでなくオブジェクトを渡すことができ、ブランチ名に対して対象となるリリースタグや対応する本番ブランチが設定できるようになっています。

// release.config.js
{
  branches: [
    "master",
    // 'develop' ブランチを モジュール名@next として公開
    { name: "develop", channel: "next" },
  ];
}

この設定を利用すれば git-flow のようなブランチ名の管理設定にしていても、対応するブランチに push すれば自動てタグ付きでレジストリに公開することができ、実際にそのような設定をしてくれるプラグインもあります。

CHANGELOG の生成

デフォルトでは commit-analyzerrelease-notes-generatornpmgithub の 4 つのプラグインが有効になっており、これだけでもコミットから差分を検知して npm や GitHub に公開することが可能です。

もしリポジトリ上のファイルからパッケージの更新履歴を調べたい場合は、別途プラグインを導入することで Conventional Commit に基づいた CHANGELOG.md を自動生成することが可能です。下記コマンドで changeloggit プラグインをインストールできます。

yarn add --dev @semantic-release/changelog @semantic-release/git

追加したプラグインはそれぞれ以下の役割があります。

  • @semantic-release/changelog: コミットログから自動的に CHANGELOG.md を生成するためのプラグインです。
  • @semantic-release/git: リリースフローが実行された後に変更があったファイルをコミットして origin に push するプラグインです。 CHANGELOG.md のほかに、 package.json の version フィールドをコミットするためにも使われます。

つぎに、設定ファイルでプラグインを読み込みます。ファイルの plugins にプラグイン名を追加します。

// release.config.js
{
  branches: [/* ... */],
  plugins: [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    "@semantic-release/changelog",
    "@semantic-release/npm",
    "@semantic-release/github",
    "@semantic-release/git"
  ]
}

設定ファイルをコミットして対象のブランチでリリースをトリガーすると、次のリリースから CHANGELOG が生成されるようになり、リリースノートに書かれるのと同等な内容が CHANGELOG.md に出力され、リポジトリにコミットされるようになりました。

ワークフロー

まとめ

この記事では semantic-release の機能説明と GitHub Actions との連携方法、設定のカスタマイズ方法とプラグインの解説をしました。

最近は Dependabot のような Semantic Versioning を活用した依存パッケージの自動更新ツールも登場しており、バージョンの数字を規則的に更新することの重要性が以前より更に増してきています。バージョンを正しく管理することで利用者にとって使いやすいライブラリになることは言うまでもありません。ぜひ semantic-release を活用して、堅牢なデプロイフローを構築してみてください!

一緒に働きませんか?

N Inc.では、「現実世界をモデル化する」エンジニアを募集しています。

詳しい情報については、特設サイトをご覧ください!

エンジニア採用特設サイト