4
1

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 1 year has passed since last update.

GitHub Actionsでリリースノートをいい感じに自動生成する

Last updated at Posted at 2023-06-14

結果から

スクリーンショット 2023-06-13 15.29.43.png
こんな感じのリリースノートが生成されます!

前提

Automatically generated release notes とは

公式ドキュメント

要約すると、.github/release.ymlファイルをリポジトリに置いて、プルリクエストにラベルを貼ればいい感じのリリースノートが作れるぞってことです!

release.ymlでリリース内容をカテゴリ分けして、対応するラベルを定義します。
実際見た方がわかりやすいので、今回作ったyamlファイルを以下に載せます。

changelog:
  categories:
    - title: Breaking Changes 🛠
      labels:
        - Semver-Major
    - title: Exciting New Features 🎉
      labels:
        - Semver-Minor
    - title: Fixes and improvements 🐛
      labels:
        - Semver-Patch
    - title: Dependencies
      labels:
        - dependencies
    - title: Other Changes
      labels:
        - "*"

説明すると、一番上の設定はプルリクエストにSemver-Majorラベルが貼ってあったら、リリースノートにBreaking Changes 🛠セクションを設けて、そのセクション内に対象のプルリクエストを記載するという意味です。

他の設定も同様で、もちろんtitleやlabelsは好きに変更できます。
今回はセマンティックバージョニングに対応させる為にそれっぽい名前にしてます。

ちなみにdependenciesはdependabotが生成するプルリクエストに自動で付与されるラベルです。

プルリクエストにラベルを貼る

release.ymlが用意できたら、次はラベル貼りです。
手動で貼っても良いのですが、どうせなら自動化したいですよね。

GitHub Actionsからgithub-scriptを使うことで実現可能です。
github-scriptは、JavaScriptでGitHub APIを叩けるやつです。

実際作ったyamlファイルはこんな感じ。

name: Set Label to Pull Request

inputs:
  semver:
    required: true

runs:
  using: "composite"
  steps:
    - uses: actions/github-script@v6
      with:
        script: |
          const { SEMVER } = process.env
          github.rest.issues.setLabels({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: context.payload.pull_request.number,
            labels: [SEMVER]
          });
      env:
        SEMVER: ${{ inputs.semver }}

いくつか今回の要件に合わせた記法が含まれてますが(※後ほど解説します)
ラベルの付与はgithub.rest.issues.setLabelsAPIを呼び出せばOK。

APIの呼び出しに使っているgithubは、github-scriptが提供している引数で、デフォルトで使えます。

setLabelsAPIのリファレンスはこちら
なお、addLabelsという似たAPIがありますが、こちらはその名の通りラベルを追加します。setLabelsは今付与されているラベルがあったら削除してから貼る挙動。

リリースノートの生成

今回導入したリポジトリではリリースの作成にaction-gh-releaseというライブラリを使っていたので、これのgenerate_release_notesという設定をtrueにするだけでした。

他の手段としては、GUI上でリリースを作成する際にGenerate release notesボタンを押下するか、gh release create --generate-notesコマンドを実行する方法もあるようです。

package.jsonのバージョンに連動してプルリクエストにラベルを付与したい

さて、ここからが独自要件です。まずは前提から。

  • 対象とするリポジトリは、社内で使っている共通ライブラリ
  • 一つのリポジトリ内で複数のパッケージを管理している
  • セマンティックバージョニングを採用しており、パッケージに何らかの変更を加えたら、package.jsonのversionを手動で変更してプルリクエストに含める運用をしている

ここで改めてsetLabelsを実行するyamlファイルを見てみましょう。

name: Set Label to Pull Request

inputs:
  semver:
    required: true

runs:
  using: "composite"
  steps:
    - uses: actions/github-script@v6
      with:
        script: |
          const { SEMVER } = process.env
          github.rest.issues.setLabels({
            owner: context.repo.owner,
            repo: context.repo.repo,
            issue_number: context.payload.pull_request.number,
            labels: [SEMVER]
          });
      env:
        SEMVER: ${{ inputs.semver }}

using: "composite"という記述がありますね。
これは複数のワークフローで同じアクションを実行したい場合に一連のステップを切り出しておいて、ワークフローから利用することで処理を共通化する仕組みです。
複数のパッケージで使いたかったので、採用しています。

compositeの詳細はこちら。構文の詳細はこちらも参照。

inputs構文は、他のstep(利用する側のワークフロー)から値を受け取る為に記載しています。
ここでは、ラベルに記載する文字列を受け取っていますね。
この文字列が「Semver-Major」とか「Semver-Minor」になります。
package.jsonのversionが1.0.0だったとして、これを1.0.1に変えたら、「Semver-Patch」が渡ってくるようにしたいわけです。

では、どうするか。
やるべきことは、以下のフローになります。

  1. package.jsonから現在のversionと変更後のversionを取得する
  2. それらを比較し、メジャー・マイナー・パッチのどのバージョンが上がっているかを検出する
  3. 検出結果から、付与するラベルを決定する

この一連の流れをアクションyamlにすると、以下のようになります。

name: utility/version-check

on:
  pull_request:
    branches:
      - main
    paths:
      - "utility/**"

jobs:
  version-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Get new version
        id: new-package-version
        uses: martinbeentjes/npm-get-version-action@v1.3.1
        with:
          path: utility

      - uses: actions/checkout@v3
        with:
          ref: "main"

      - name: Get current version
        id: current-package-version
        uses: martinbeentjes/npm-get-version-action@v1.3.1
        with:
          path: utility

      - uses: actions/checkout@v3

      - name: Check version update
        id: check-version-update
        uses: ./.github/workflows/composite/check-version-update
        with:
          new-version: ${{ steps.new-package-version.outputs.current-version }}
          current-version: ${{ steps.current-package-version.outputs.current-version }}

      - name: Set Label to Pull Request
        uses: ./.github/workflows/composite/set-label
        with:
          semver: ${{ steps.check-version-update.outputs.semver }}

実は元々version-checkという「package.jsonのversionをちゃんとインクリメントしているか」チェックするワークフローが作られており、ラベル付与においてもこの仕組みを利用しました。

npm-get-version-actionというライブラリで、現在のブランチのpackage.jsonからversionを取得します。

最初は作業ブランチ側のversionを取得して、その後actions/checkout@v3の対象をmainにすることでマージ対象のブランチからversionを取得しているわけですね。

そして、それらをcheck-version-updateに渡す。ここでもcompositeを使っています。

その内容がこちら

name: check-version-update

inputs:
  new-version:
    required: true
  current-version:
    required: true
outputs:
  semver:
    description: "Semantic Versioning"
    value: ${{ steps.check-version-update.outputs.semver }}
runs:
  using: "composite"
  steps:
    - name: Check version update
      id: check-version-update
      shell: bash
      run: |
        new_version=${{ inputs.new-version }}
        new_ver_array=(${new_version//./ })
        current_version=${{ inputs.current-version }}
        current_ver_array=(${current_version//./ })
        if [ ${new_ver_array[0]} -gt ${current_ver_array[0]} ]; then echo "semver=Semver-Major" >> "$GITHUB_OUTPUT"; exit 0; fi
        if [ ${new_ver_array[0]} -eq ${current_ver_array[0]} ] && [ ${new_ver_array[1]} -gt ${current_ver_array[1]} ]; then echo "semver=Semver-Minor" >> "$GITHUB_OUTPUT"; exit 0; fi
        if [ ${new_ver_array[0]} -eq ${current_ver_array[0]} ] && [ ${new_ver_array[1]} -eq ${current_ver_array[1]} ] && [ ${new_ver_array[2]} -gt ${current_ver_array[2]} ]; then echo "semver=Semver-Patch" >> "$GITHUB_OUTPUT"; exit 0; fi
        echo "Please update version in package.json"
        exit 1

bashで1.0.0などの文字列をドット区切りで配列にする書き方が珍しいですね。
あとは条件分岐でラベルに使いたい文字列を出力してます。echo "semver=Semver-Major" >> "$GITHUB_OUTPUT";とかがそれです。

stepの出力仕様についてはこちら

ここまで出来たら、あとは度々掲示しているsetLabelsを実行しているアクションと繋いで完了です!

感想

リリースノートの自動生成を行う技術記事は他にも色々あったものの、GitHub Actionsの更新が多いからか記述方法が古かったり、そもそもやり方が違うものも多い状況でした。
ということで本記事を書いてみましたが、これもすぐに古くなるんだろうなあ。。

参考

actions/github-script と composite アクションでカスタムアクションをかんたんに作れる
GitHubのリリースノートを自動化する仕組み

4
1
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
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?