手作業のリリースノート作成を卒業する。GitHub ActionsとRelease Pleaseで組む変更履歴・タグ自動化レシピ

手作業のリリースノート作成を卒業する。GitHub ActionsとRelease Pleaseで組む変更履歴・タグ自動化レシピ

公開: 2026/10/31
目次
開閉

本番リリースの直前、マージされたプルリクエストの一覧を遡りながら「今回の変更点はどれだっけ」「次のバージョンは v1.4.0 と v1.3.5 のどちらにすべきだろう」と手作業でリリースノートをまとめる作業。

開発規模が小さいうちは数分で終わりますが、関わるメンバーが増えたり、DependabotとGitHub Actionsによる自動マージを導入して日々のマージ頻度が上がったりすると、変更履歴(CHANGELOG.md)の集計とGitタグの管理はすぐに重荷になります。

手作業での集計は記載漏れやバージョンの打ち間違いを招きやすく、何より「リリース作業そのものが億劫になり、デプロイの頻度が落ちる」という悪循環につながります。

今回は、日々のコミットメッセージ規約(Conventional Commits)を起点に、Googleがメンテナンスしている release-please-action(およびコアエンジンの release-please)を使って「リリース準備PRの自動生成からCHANGELOG更新、GitHub Releaseの発行まで」を一気通貫で自動化する実践レシピをまとめます。

検証環境と前提バージョン

  • GitHub Actions: googleapis/release-please-action@v4(およびNode 24ランタイム対応の @v5 / release-please v17系)
  • ローカル検証環境: macOS 15 Sequoia (zsh) / Windows 11 Pro 24H2 (PowerShell 7.4)
  • Git / GitHub CLI: Git v2.45.0 / GitHub CLI (gh) v2.60+ / Node.js v24.13.0

1. いきなり本番タグを切らない「リリース準備PR」方式の安心感

リリース自動化ツールには、メインブランチへマージされた瞬間に即座にGitタグを切る方式(semantic-release など)もありますが、現場で運用する際に使いやすいのが Release Please の「Release PR(リリース準備用のプルリクエスト)を常時メンテナンスし続ける方式」です。

graph TD
    A["開発者が feat: / fix: コミットを main にマージ"] --> B["GitHub Actions (Release Please) が起動"]
    B --> C["次のSemVerを自動判定し CHANGELOG.md と package.json を更新"]
    C --> D["『chore(main): release 1.2.0』というリリース準備PRを自動作成・更新"]
    D --> E["人間がタイミングを見て リリース準備PR をマージ"]
    E --> F["自動で Gitタグ (v1.2.0) と GitHub Release を発行"]

この方式には、実務上2つの大きな利点があります。

  1. リリースのタイミングを人間がコントロールできる 機能追加のPRを3本マージしている間、Release Pleaseは裏側で1つの「リリース準備PR」の本文と CHANGELOG.md を自動更新し続けます。そして「よし、今日リリースしよう」と決めたタイミングでそのPRをマージした瞬間にだけ、GitタグとGitHub Releaseが発行されます。
  2. 公開前にリリースノートの文面を確認・手直しできる 自動生成された CHANGELOG.md とバージョン番号(package.json や Cargo.toml 等)の差分が通常のプルリクエストとして可視化されます。もしコミットメッセージのタイポや補足したい移行手順があれば、マージ前にそのPRブランチへ直接コミットして文面を整えることができます。

コミットプレフィックスとSemVer(セマンティックバージョニング)の対応

Release Pleaseは、デフォルトで以下のルールに従って次のバージョン番号を自動算出します。

コミットプレフィックス意味・用途バージョンの上がり方(例: 1.1.2 の場合)
fix:バグ修正・軽微な不具合対応パッチ(Patch) が上がる → 1.1.3
feat:新機能の追加マイナー(Minor) が上がる → 1.2.0
feat!: / fix!:(または本文に BREAKING CHANGE:)互換性のない破壊的変更メジャー(Major) が上がる → 2.0.0
chore: / ci: / docs: / refactor:内部整理・CI設定・ドキュメント更新原則として単独では新規リリースを発火しない

2. 実践設定:マニフェスト駆動の最小3ファイル構成

現在の release-please-action(v4 / v5)では、アクションの引数(with:)に直接細かいオプションを並べる旧方式ではなく、リポジトリルートに設定ファイルを置く マニフェスト駆動(Manifest-driven)方式 が標準となっています。

以下の3ファイルをリポジトリに配置するだけで導入できます。

① .release-please-manifest.json(現在のバージョン管理ファイル)

リポジトリルート(.)の現在のバージョン番号を記録するファイルです。初回導入時は、現在の最新タグのバージョン(これから 1.0.0 を目指すなら "0.1.0" や "1.0.0")を記述します。

{
  ".": "1.1.0"
}

② release-please-config.json(生成ルールと対象セクションの定義)

どの言語のバージョンファイルを書き換えるか(release-type)と、CHANGELOG.md にどのコミット種別を出力するかを定義します。

{
  "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
  "packages": {
    ".": {
      "release-type": "node",
      "changelog-path": "CHANGELOG.md"
    }
  },
  "changelog-sections": [
    { "type": "feat", "section": "Features" },
    { "type": "fix", "section": "Bug Fixes" },
    { "type": "perf", "section": "Performance Improvements" },
    { "type": "revert", "section": "Reverts" },
    { "type": "docs", "section": "Documentation", "hidden": true },
    { "type": "chore", "section": "Miscellaneous Chores", "hidden": true },
    { "type": "ci", "section": "Continuous Integration", "hidden": true },
    { "type": "refactor", "section": "Code Refactoring", "hidden": true },
    { "type": "test", "section": "Tests", "hidden": true }
  ]
}
  • release-type の選び方: Node.jsプロジェクト(package.json の version を自動更新したい場合)は "node"、Pythonは "python"、Rustは "rust"、Goや特定言語のパッケージファイルを持たない汎用リポジトリは "simple" を指定します。
Lowom 編集長 編集長
TIPS ノイズになる内部コミットを hidden: true で隠す
初期状態で運用を始めると、タイポ修正やCIの微調整まで変更履歴に混ざって読みづらくなりがちです。上記のように docs や ci、refactor に hidden: true を指定しておくと、利用者やチームメンバーが本当に知りたい『機能追加(Features)』と『バグ修正(Bug Fixes)』だけの見通しの良いCHANGELOGを維持できます。

③ .github/workflows/release-please.yml(GitHub Actions ワークフロー)

main ブランチへのプッシュ(PRのマージ)をトリガーに起動するワークフロー定義です。

name: Release Please

on:
  push:
    branches:
      - main

permissions:
  contents: write
  pull-requests: write

jobs:
  release-please:
    runs-on: ubuntu-latest
    outputs:
      releases_created: ${{ steps.release.outputs.releases_created }}
      release_created: ${{ steps.release.outputs.release_created }}
      tag_name: ${{ steps.release.outputs.tag_name }}
    steps:
      - name: Run Release Please
        uses: googleapis/release-please-action@v4
        id: release

3. 一次検証ログ:PR自動生成からリリース発行までの実挙動

実際に上記の3ファイルを配置した検証リポジトリにおいて、新機能(feat:)とバグ修正(fix:)のPRをマージした際の挙動を、GitHub CLI(gh)のエイリアスと拡張によるルーティン自動化でも紹介した gh コマンドで手元から確認してみます。

ステップ1: feat: と fix: のマージによるリリース準備PRの自動生成

main ブランチに feat(auth): OAuth2トークンの自動リフレッシュ機能を追加 (#14) と fix(api): タイムアウト時のリトライ間隔の計算式を修正 (#15) をマージすると、数十秒後にGitHub Actionsが走り、以下のPRが自動で作成されます。

$ gh pr list
Showing 1 of 1 open pull request in example-org/web-service

#16  chore(main): release 1.2.0  release-please--branches--main  about 1 minute ago

今回は 1.1.0 の状態から feat:(マイナー更新)が含まれているため、自動的に次期バージョンが 1.2.0 と判定されています。

このPR(#16)に含まれる CHANGELOG.md の差分を gh pr diff 16 で確認すると、PR番号とコミットハッシュへのリンク付きで綺麗に整形されていることが分かります。

+## [1.2.0](https://github.com/example-org/web-service/compare/v1.1.0...v1.2.0) (2026-10-31)
+
+
+### Features
+
+* **auth:** OAuth2トークンの自動リフレッシュ機能を追加 ([#14](https://github.com/example-org/web-service/issues/14)) ([a1b2c3d](https://github.com/example-org/web-service/commit/a1b2c3d))
+
+
+### Bug Fixes
+
+* **api:** タイムアウト時のリトライ間隔の計算式を修正 ([#15](https://github.com/example-org/web-service/issues/15)) ([e4f5g6h](https://github.com/example-org/web-service/commit/e4f5g6h))

ステップ2: リリース準備PRのマージとGitHub Releaseの自動発行

リリース準備が整った段階で、この #16 のPRをマージ(gh pr merge 16 --squash)します。すると再度 release-please ジョブが起動し、マージされたコミットを検知して即座に v1.2.0 タグとGitHub Releaseを作成します。

$ gh release view v1.2.0
v1.2.0
draft:  false
prerelease:     false
created:        2026-10-31T13:20:15Z
published:      2026-10-31T13:20:16Z
tag:    v1.2.0
url:    https://github.com/example-org/web-service/releases/tag/v1.2.0
--
## [1.2.0](https://github.com/example-org/web-service/compare/v1.1.0...v1.2.0) (2026-10-31)

### Features
* **auth:** OAuth2トークンの自動リフレッシュ機能を追加 (#14) (a1b2c3d)

### Bug Fixes
* **api:** タイムアウト時のリトライ間隔の計算式を修正 (#15) (e4f5g6h)

ブラウザでリリース作成画面を開き、前のタグとの差分を比較しながらテキストを貼り付ける作業は、これで一切不要になります。


4. 現場で必ず直面する3つの落とし穴と回避策

公式のREADME通りにYAMLを書いただけでは、最初のリポジトリ設定や既存のCIパイプラインとの兼ね合いでうまく動かない箇所がいくつかあります。実務で導入する際に押さえておきたい3つのポイントを共有します。

落とし穴1: リポジトリ権限エラー(HttpError: GitHub Actions is not permitted to create or approve pull requests)

ワークフローYAMLに pull-requests: write を記述していても、初回実行時にActionsのログで以下のエラーが出て失敗することがあります。

RequestError [HttpError]: GitHub Actions is not permitted to create or approve pull requests.
    at /home/runner/work/_actions/googleapis/release-please-action/v4/dist/index.js:...
  status: 403,

これは、GitHubのリポジトリ(またはOrganization)の初期設定で、ActionsによるPR作成がセキュリティ上ブロックされているためです。

  • 解決策: リポジトリの Settings → Actions → General を開き、一番下の Workflow permissions にある 「Allow GitHub Actions to create and approve pull requests」 にチェックを入れて保存します。

落とし穴2: 生成されたタグで後続のデプロイ・パッケージ公開ワークフローが発火しない

「v* タグがプッシュされたら、Dockerイメージのビルドやnpmパッケージの公開ワークフロー(on: push: tags: ['v*'])を動かす」という設計にしている現場は非常に多いと思います。

しかし、デフォルトの GITHUB_TOKEN を使って Release Please が作成したGitタグは、GitHub Actionsの無限ループ防止仕様によって 別ファイルのワークフローを一切トリガーしません。

これを回避するには、以下の2つの方法があります。

  1. 推奨:同一ワークフロー内で outputs.release_created を判定して後続ジョブを繋ぐ Personal Access Token(PAT)やGitHub Appの管理コストを増やしたくない場合は、release-please.yml の中にそのままビルド・デプロイジョブを繋ぐのが最もシンプルで安全です。
  deploy:
    needs: release-please
    # リリースPRがマージされ、実際にGitHub Releaseが発行された時だけ実行される
    if: ${{ needs.release-please.outputs.release_created == 'true' }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ needs.release-please.outputs.tag_name }}
      - name: Build and Deploy
        run: |
          echo "Deploying version ${{ needs.release-please.outputs.tag_name }}..."
  1. 別ワークフローを動かしたい場合:Fine-grained PAT または GitHub App トークンを渡す どうしても既存の on: push: tags: ワークフローを分離したまま発火させたい場合は、Contents: Read and write と Pull requests: Read and write 権限を持たせたトークンを発行し、with: token: に指定します。
Lowom 編集長 編集長
CAUTION Dependabot自動マージと併用する際の注意点
もし個人アクセストークン(PAT)やGitHub Appトークンを使ってRelease Pleaseを動かしている場合、Dependabot等の自動マージルールで『chore(main): release ...』のPRまで誤って自動マージしないよう注意してください。自動マージ側は『actor == dependabot[bot]』のように作成者を厳密に絞っておくのが鉄則です。

落とし穴3: 開発途中の「WIP」「タイポ修正」コミットでCHANGELOGが汚れる

開発ブランチの中で wip や fix typo といった細かいコミットを積み重ね、それを通常のマージコミット(Create a merge commit)で main に取り込むと、Release Pleaseはブランチ内のすべてのコミットを走査するため、意図しないコミット履歴がCHANGELOGに紛れ込むことがあります。

これを防ぐには、チームや個人の運用として以下のどちらかを取り入れると綺麗に回ります。

  • ローカルでコミット履歴を整えてからマージする: 開発中の細かい手直しは、Gitの「fixup」と「autosquash」で履歴を整える実践技を使って論理的な1つのコミットにまとめてからプッシュします。
  • GitHubの「Squash and merge」を標準にする: リポジトリの Settings → General → Pull Requests にて、Allow squash merging のみを有効にし、Default commit message を Pull request title(または Pull request title and description)に設定します。 こうすれば、ブランチ内のコミットがどれだけ荒れていても、PRのタイトルさえ feat: ... や fix: ... の形式で書いておけば、1PR=1行の美しいリリースノートが生成されます。

補足:ローカルのCLI(macOS / Windows)で事前確認したい場合

設定ファイル(release-please-config.json)を変更した際、GitHubにプッシュする前に手元のMac(zsh)やWindows(PowerShell 7)からどんなリリースPRが作られるか試したい場合は、npx 経由でCLIを直接叩いてドライラン確認することも可能です。

# ローカル環境でのバージョン確認(Node.js v20+ / v24+)
$ npx release-please --version
17.1.3

# リモートリポジトリに対して設定ファイルの構文やPR生成対象をドライラン確認
$ npx release-please manifest-pr \
    --repo-url="example-org/web-service" \
    --token="$(gh auth token)" \
    --dry-run

※WindowsのPowerShellで実行する場合は、$(gh auth token) がそのままサブシェル展開として同様に機能します。


まとめ:リリース作業を「イベント」から「日常の通過点」へ

手作業でのリリースノート作成やバージョン採番を自動化すると、単に1回あたり15分の事務作業が減るだけでなく、「いつでもボタン1つ(PRマージ1回)で正確にリリースできる」という心理的な余裕が生まれます。

導入のステップはシンプルです。

  1. 普段のPRタイトル(またはコミット)の先頭に feat: や fix: を付ける習慣を始める
  2. リポジトリルートに .release-please-manifest.json と release-please-config.json を置く
  3. .github/workflows/release-please.yml を追加し、SettingsでPR作成権限をオンにする

ぜひ手元の個人開発リポジトリや社内ツールから取り入れて、変更履歴の管理コストをゼロにする快適さを体験してみてください。

GitHub Actionsを活用した日々の運用自動化や、コマンドラインからのPR操作効率化については、以下の記事もあわせて参考にしてみてください。

Lowom 編集長
この記事を書いた人:Lowom 編集長 現役Webエンジニア

都内IT企業に勤める業界20年のWebエンジニア。業務効率化・自動化スクリプトや快適な開発環境の構築、厳選したツール・ガジェットの活用法など、手元で実際に検証したリアルな一次情報をお届けします。