TENTIALのテックブログ

株式会社TENTIALのエンジニアチームが開発や組織のよもやまを謳っていきます

GitHub Actions + GitHub CLIだけでリリースノートを自動生成する

DevOpsエンジニアの田島です。

当社ではECサイトの開発にあたって社内向けリリースノートを作成しており、リリースごとに以下のようなメッセージがslackに投稿されるようになっています。

実際のリリースノート

さてリリースノートの自動化と言えばGitHubの自動生成リリースノート(あるいはそのAPI)やRelease Drafterを思い浮かべる方が多いかと思います。ですが今回はあえて、それらを使用せずに実装を行った話をします。

概要

タイトルにもある通り使用するのはGitHub CLIです。とは言えCLIでコマンド一発!というわけではなく、

  1. pr viewコマンドでmainブランチにマージされたPRに含まれるPRを抽出
  2. 同じくpr viewコマンドで各PRや必要に応じてissueを解析
  3. 用意したテンプレートに解析内容を転記

という手順を地道に行っていきます。これを行うメリットとしては

  • 序文で触れた2ツールに比べてカスタマイズが自由
    • PR本文からリンクを取得して転記
    • タグ以外の要素を用いてPRを分類 ... 等
  • 任意のPRからリリースノートを作成できる
    • 過去のリリースノートを後から作成することも可能

などが挙げられますが、逆に言えばこれらのメリットに魅力を感じない場合は上記ツールを検討するのがよいでしょう。

PRに含まれるPRの抽出

プロテクトされた(直pushが禁止された)develop、releaseおよびmainブランチ、そして

  1. feature/hoge → develop
  2. feature/fuga → develop
  3. develop → release
  4. bug/piyo → release
  5. release → main

の5本のPRがあった状態を考えてみます。このときgh pr view {5のPR番号} --json commitsコマンドを使用すると以下のようなデータが取得できます。

{
  "commits": [
    {
      "authoredDate": "2023-12-07T10:17:47Z",
      "authors": [
        {
          "email": "...",
          "id": "...",
          "login": "...",
          "name": "..."
        }
      ],
      "committedDate": "2023-12-07T10:17:47Z",
      "messageBody": "",
      "messageHeadline": "feat: changed hoge to fuga #1135",
      "oid": "1bf295b4c9250a649d421f4c281a1faafc857a7b"
    },
    {
      "authoredDate": "2023-12-07T04:58:41Z",
      "authors": [
        {
          "email": "...",
          "id": "...",
          "login": "...",
          "name": "..."
        }
      ],
      "committedDate": "2023-12-07T04:58:41Z",
      "messageBody": "\n\nブログ執筆に伴いホゲをフガに変更",
      "messageHeadline": "Merge pull request #1140 from org/feature/hoge#1135…",
      "oid": "ab70db8c708523d02b227e04368dbc604c882fc7"
    },

    ...

  ]
}

ここで注目するのはmessageHeadlineですね。ここにはコミットメッセージの1行目が格納されますので、PRをマージした際のコミットメッセージであるMerge pull request #でgrepします。

      "messageHeadline": "Merge pull request #1140 from org/feature/hoge#1135…",
      "messageHeadline": "Merge pull request #1141 from org/feature/fuga#1136…",
      "messageHeadline": "Merge pull request #1142 from org/develop…",
      "messageHeadline": "Merge pull request #1143 from org/bug/piyo#1138…",

これでrelease → mainのPRには4本のPRが入っていることが確認でき、またそれぞれのPR番号も知ることができました。

PRの解析

先ほど使ったgh pr viewコマンド(リファレンス)では--json/--jqオプションを使用することによってPRの様々な情報を取得することができます。

Specify one or more comma-separated fields for --json:
additions
assignees
author
baseRefName
body
changedFiles
closed
closedAt
comments
commits
createdAt
deletions
files
headRefName
headRefOid
headRepository
headRepositoryOwner
id
isCrossRepository
isDraft
labels
latestReviews
maintainerCanModify
mergeCommit
mergeStateStatus
mergeable
mergedAt
mergedBy
milestone
number
potentialMergeCommit
projectCards
reactionGroups
reviewDecision
reviewRequests
reviews
state
statusCheckRollup
title
updatedAt
url

試しにfeature/hoge → developのPRを解析してみましょう。

gh pr view 1140 --json author --json title --json body --json commits
{
  "author": {
    "id": "MDQ6VXNlcjQxMDMwMzE4",
    "is_bot": false,
    "login": "ikumi-rai",
    "name": ""
  },
  "body": "issue #1135\r\n\r\n## 概要\r\n...",
  "commits": [
    {
      "authoredDate": "2023-12-07T10:17:47Z",
      "authors": [
        {
          "email": "...",
          "id": "...",
          "login": "ikumi-rai",
          "name": "ikumi-rai"
        }
      ],
      "committedDate": "2023-12-07T10:17:47Z",
      "messageBody": "",
      "messageHeadline": "feat: changed hoge to fuga #1135",
      "oid": "1bf295b4c9250a649d421f4c281a1faafc857a7b"
    }
  ],
  "title": "ブログ執筆に伴いホゲをフガに変更"
}

ここまで来ればあとは自由にリリースノートを記述するだけです。

テンプレートに解析内容を転記

テンプレートはどのような形でもよいと思いますが、参考までに当社のテンプレートをご紹介します。

# What's new

## ⚔️ Quest

$quest

## 👾 Slime Buster

$slime

## 🔧 Maintenance

$maintenance

## 🧙‍♂️ Other

$other

<br>

---

date: $date  
commit: $commit

これをいい感じに置換して使わなかった行を削除すればリリースノートの完成です! なお完成したノートはgh release createコマンドで公開し、公開されたreleaseが公式インテグレーションを通してslackに投稿されます。

GitHub Actions

最後にGitHub Actionsワークフローの設定例を見ていきましょう。 リリースノートの生成を行うスタートポイントがmainブランチにマージされたPRの番号でしたので、このmainブランチにマージされたPRの番号をスクリプトに教えてあげる必要があります。

name: Release Note Creator
on:
  pull_request:
    types:
      - closed
    branches:
      - main
jobs:
  release:
    if: github.event.pull_request.merged == true
    name: Release Note
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          sparse-checkout: .github
      - run: bash .github/release_note_creator.sh ${{ github.event.pull_request.number }}

参考: pull request がマージされたときに pull_request ワークフローを実行する

(余談ですが本当はrelease_note_creator.pyです。このようなスクリプトは大体Pythonで書いています。)

その他の活用

任意のPRからリリースノートを作成できる特性を活かしてこのPRがリリースノートにどのように反映されるのかを事前に確認できるプレビュー機能も稼働しています。この機能は通常任意のタイミングで実行できるもの(未完成でも相談ベースでPRを出してよいという運用のため)なのですが、メンバーからの提案でmainを対象にして出したPRだけはオープンのタイミングで自動的に実行されるよう設定を行いました。

リリースノートプレビュー

本番反映前の最終チェックで確認すべきPRが一覧で見れる!という需要だったようです。ツール開発って面白いですね。

以上TENTIALアドベントカレンダー、「GitHub Actions + GitHub CLIだけでリリースノートを自動生成する」でした。