0.はじめに

たびけんというサービスを開発しております。たびけんは少人数で開発しているので、マンパワーが足りてません。頻繁に開発が行われると、どの機能やバグを修正したのか、リリース前の確認では対象を洗い出すのが大変(面倒)だったり、それをもとにチェンジログを作成するのも大変(面倒)でした。

なので、リリースの確認作業とチェンジログの作成を中心に省力化について検討したあところ、すごく良い感じにまとまったので、テックブログに紹介させていただきます。

1.開発フローについて

たびけんのリポジトリ構成は以下のとおりです。

チケット管理はYoutrackで行っています。トピックブランチはYoutrackの課題番号と同じにして、Youtrackと紐付けができるようにしています。

また、トピックブランチはdevelopブランチから切るようにして、作業が終了したらdevelopブランチにマージする作業完了プルリクエストを作成します。

いくつかのトピックブランチをマージして開発が終了し、リリースのタイミングになったら、masterブランチにマージするリリース確認用プルリクエストを作成します。

リリース確認後にmasterブランチにマージすると、リリース準備完了でタグの付与とリリースノート(チェンジログ)の作成を行っていました。

2.リリース作業を変える!!

今回、開発フローは変えずにGithub Actionによる自動化を要所で取り込むことで、省力化を図ります。Github Actionを使う箇所は以下に設定しました。

  • 作業完了プルリクエストマージ時
    • リリース確認用プルリクエストの作成
  • リリース確認用プルリクエストのマージ時
    • チェンジログ作成
    • リリースOKのリビジョンにタグ付け
    • リリースノートの作成

取り入れたポイントを開発フローの図中に書き加えたのが以下の図です。

逆に手作業として残している部分は以下の通りです。これらは自動化せずに、人間が判断したほうが良いと考えたものになります。

  • 作業完了プルリクエストの作成
  • 作業完了プルリクエストのラベル付与
  • リリースモジュールのバージョン指定

3.事前準備

事前準備として、package.jsonにGithubのラベルに対応するようにchangelogの設定と、Actionsのスクリプトを.github/workflowsに配置してプッシュします。

package.jsonの設定
“changelog”: {
    “labels”: {
   ”enhancement”: “New Feature”,
      “bug”: “Bug Fix”,
      “refactoring”: “Refactoring”
    }
}

左側の文字列(enhancement、bug、refactoring)がGithubのラベルと対応します。上記の場合enhancementとついているプルリクエストをまとめて、New Featureというタイトルをつけて列挙します。こんな感じ

.github/workflows/create-release-pr.yml

作業完了プルリクエストをマージした時、リリース確認用のプルリクエストを作成するようにします。すでにリリース確認用のプルリクエストが存在する場合は更新になるので、このスクリプト1本で完結します。

# リリース用プルリクエストを作成する
name: create-release-pr

# トリガー(プルリクエストでクローズしたとき)
on:
  pull_request:
    branches:
      – develop
    types: [closed]

# ジョブ設定
jobs:

  # プルリクエストの作成ジョブ
  create-release-pr:
    # プルリクエストがマージされたときに実行
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest

    # ステップ
    steps:
      # マージ先の develop ブランチ時で実行される
      – uses: actions/checkout@v2
        with:
          fetch-depth: 0

      # package.jsonからバージョンを取得する
      # ${{ steps.package-version.outputs.current-version}}で取得可能
      – name: Get Version From package.json
        id: package-version
        uses: martinbeentjes/npm-get-version-action@master

      # package-versionで取得したバージョンを表示
      – name: Echo Version
        run: echo v${{ steps.package-version.outputs.current-version}}

      # プルリクエストを生成する
      # v${{ steps.package-version.outputs.current-version}}
      – name: Create Release PullRequest
        uses: bakunyo/git-pr-release-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GIT_PR_RELEASE_BRANCH_PRODUCTION: master
          GIT_PR_RELEASE_BRANCH_STAGING: develop
          GIT_PR_RELEASE_LABELS: release
          GIT_PR_RELEASE_TITLE: v${{ steps.package-version.outputs.current-version}}
          GIT_PR_RELEASE_TEMPLATE: .git-pr-release-template

上記ファイルを.github/workflows/create-release-pr.ymlに配置します。

.github/workflows/release.yml

lerna-changelogを実行してチェンジログを生成し、softprops/action-gh-release@v1リリース確認用プルリクエストのタイトル(バージョン番号)でタグとリリースノートを作成します。作成したリリースノートの本文は、直前のステップで生成したチェンジログをファイルとして指定します。GithubのReleseのページに以下のように出力されます。

# リリースアクションのテスト
name: release

# トリガー(プルリクエストで、ステージングブランチをクローズしたとき)
on:
  pull_request:
    branches:
      – master
    types: [closed]

# ジョブ設定
jobs:

  # リリース
  release:
    # プルリクエストがマージされたときに実行
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest

    # ステップ
    steps:
      # マージ先の master ブランチ時で実行される
      – uses: actions/checkout@v2
        with:
          fetch-depth: 0 # git describeするために履歴が必要
     
      # チェンジログをlerna-changelogで生成する
      – name: チェンジログ作成
        env:
          GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Get PrevTag From git
          PREV_TAG=$(git describe –abbrev=0)
          LATEST_TAG=${{ github.event.pull_request.title }}

          npx lerna-changelog –from=$PREV_TAG > ./RELEASE_NOTE$LATEST_TAG.md
          cat ./RELEASE_NOTE$LATEST_TAG.md

      # softprops/action-gh-release@v1でリリース
      – name: リリース作成
        uses: softprops/action-gh-release@v1
        with:
          name: Release ${{ github.event.pull_request.title }}
          tag_name: ${{ github.event.pull_request.title }}
          body_path: ./RELEASE_NOTE${{ github.event.pull_request.title }}.md
          draft: false
          prerelease: false

上記ファイルを.github/workflows/release.ymlに配置します。

4.Actions適用後の操作

作業完了プルリクエスト作成+ラベル付与

トピックブランチをマージする作業完了のプルリクエストは手動で作成することにしました。

作業完了のプルリクエストをマージするまでにやることは「ラベルを付与する」ことです。チェンジログの生成はリリース時に行うため、その前であればOK.

作業完了プルリクエストマージ

作業完了プルリクエストをマージします。.github/workflows/create-release-pr.ymlが実行され、リリース確認用プルリクエストが生成(更新)されます

リリース確認

リリース確認用プルリクエストのチェックリストを元に動作確認します。

マージ

リリース確認用プルリクエストをマージします。.github/workflows/release.ymlが実行され、マージ後のリビジョンにタグが付与され、リリースノート(チェンジログ)が生成されます。

検証用に同じ課題番号でプルリクをたくさん作ってしまったので、よくわからなくってますね・・・ここに出てくるメッセージはプルリクエストのタイトルならので、同じ課題番号で作業してしまった場合は枝番をつけたりして対応すると見やすくなりそうです。

5.スクリプト解説

以下にスクリプトの解説をまとめて記載します。

Actions実行のトリガー設定について
# トリガー(プルリクエストでクローズしたとき)
on:
  pull_request:
    branches:
      – develop
    types: [closed]

on.pull_requestでプルリクエストの操作に対してトリガーを指定できます。

branchesを指定すると特定ブランチにに対するプルリクエストの条件(複数可)を指定でき。typesを指定すると、プルリクエストの特定の操作の条件(複数可)を指定できます。

上記は developに対してのプルリクエストがクローズされた場合に実行するようにしています。

Actionsの実行判定について
  # プルリクエストの作成ジョブ
  create-release-pr:
    # プルリクエストがマージされたときに実行
    if: github.event.pull_request.merged == true
    runs-on: ubuntu-latest

on.pull_requestのtypesの指定によっては、意図しないタイミングでトリガーが発火しActionsが実行されてしまう場合があります。例えば、closed指定時は、マージによるクローズでも、単純にクローズした場合でも同様にclosedでトリガーが発火してしまいます。

上記のような意図しないタイミングで発火するのを抑止するために、if による記述で実行を中断することができます。(発火はするが、ジョブの実行を中止する動作になります)

リリース確認用プルリクエストの作成

bakunyo/git-pr-release-action@masterで、リリース確認用プルリクエストを生成しています。プルリクエストが存在しない場合は作成し、存在する場合は更新されるので便利です。

    # プルリクエストを生成する
      # v${{ steps.package-version.outputs.current-version}}
      – name: Create Release PullRequest
        uses: bakunyo/git-pr-release-action@master
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GIT_PR_RELEASE_BRANCH_PRODUCTION: master
          GIT_PR_RELEASE_BRANCH_STAGING: develop
          GIT_PR_RELEASE_LABELS: release
          GIT_PR_RELEASE_TITLE: v${{ steps.package-version.outputs.current-version}}
          GIT_PR_RELEASE_TEMPLATE: .git-pr-release-template

GIT_PR_RELEASE_TEMPLATE に .git-pr-release-template を指定しプルリクエストの概要欄にチェックリストを生成するように設定します。後述する、テンプレートファイルのパスを指定するものなので、配置場所が変わるなら、この設定も変更する必要があります。

.git-pr-release-template
<%= ENV[‘GIT_PR_RELEASE_TITLE’] %>
<% pull_requests.each do |pr| -%>
<%= pr.to_checklist_item %>
<% end -%>

上記ファイルをGIT_PR_RELEASE_TEMPLATEに指定のパスに配置してください。

1行目はプルリクエストのタイトルとして出力されます。上記だと、環境変数GIT_PR_RELEASE_TITLEに指定した、package.jsonのバージョンが指定されます。

次の行からは概要で、前バージョンからdevelopブランチにマージされてきたプルリクエストをの一覧をチェックリストで出力するようにします。リリース確認時はこのチェックリストを元に修正点を確認していき、確認漏れを防ぎます。

以下がリリース確認用プルリクエストの表示例です。中央の概要欄にマージしたプルリクエストの一覧がチェックボックス付きで表示されます。

修正点を確認するたびに、チェックしていけば、確認漏れがなくリリースできると思います。

チェンジログ生成
    # チェンジログをlerna-changelogで生成する
      – name: チェンジログ作成
        env:
          GITHUB_AUTH: ${{ secrets.GITHUB_TOKEN }}
        run: |
          # Get PrevTag From git
          PREV_TAG=$(git describe –abbrev=0)
          LATEST_TAG=${{ github.event.pull_request.title }}

          npx lerna-changelog –from=$PREV_TAG > ./RELEASE_NOTE$LATEST_TAG.md
          cat ./RELEASE_NOTE$LATEST_TAG.md

lerna-changelogを実行します。–fromオプションにより、指定したバージョン以降の変更をチェンジログとして出力します。指定するバージョンは、git describe –abbrev=0 で取得した、前回リリースしたバージョンです。

タグ付けとリリースの作成
    # softprops/action-gh-release@v1でリリース
      – name: リリース作成
        uses: softprops/action-gh-release@v1
        with:
          name: Release ${{ github.event.pull_request.title }}
          tag_name: ${{ github.event.pull_request.title }}
          body_path: ./RELEASE_NOTE${{ github.event.pull_request.title }}.md
          draft: false
          prerelease: false

softprops/action-gh-release@v1を使ってタグ付けとリリースの作成を行います。

body_pathに前ステップで生成したチェンジログのパスを指定します。

draft(下書き)とプレリリースはfalseで無効にします。

6.まとめ

いかがでしたか。Github Actionsのコードでで記事が長くなってしまいましたが、プルリクエストを使ってリリースする内容の確認とチェンジログを作成+Github Actionsで省力化をしてみました。プロジェクトは様々ですので、自分たちのプロジェクトにそのまま適用できないかもしれませんが、使ってみて、Github Actionsがかなり柔軟なことを実感しました。

まずは、小さなことでOKなので自動化に挑戦してみてはいかがでしょうか。