Autify実行結果をリリース前に確認するフローをGitHub Actionsなどで省力化しました

  • URLをコピーしました!

こんにちは!エンジニアリングマネージャー代行の小張です。

Autify実行結果の確認をGitHub Actionsなどを使って省力化したので、その背景やGitHub Actionsの設定をご紹介します。

目次

背景

PR TIMESではリリース前のQAとしてAutify NoCode(以下Autify)を使ったE2Eテストを行っています。

Autifyの活用事例については以下をご覧ください。

あわせて読みたい
テスト自動化でリファクタリングを効率化 開発本部QAチームの山田です。 テストの自動化によりリファクタリングの際のQAも大きく効率化できましたので、ご紹介します。 【テスト自動化】 以前こちらの記事でもご...

リリース前QAとして8つのテストプラン(合計で4066個のステップ)を実行しており、1つのプランに約2時間ほどかかっています。

これらをPull requestごとに実行するのは現実的ではないため、次の日のリリース内容をまとめたブランチをステージング環境にデプロイしておき、深夜にAutifyを実行するようにしています。

ブランチ運用について

翌日のリリース内容をまとめるためブランチ運用は以下のようにしています。

  1. 実装者がfeatureブランチで実装を完了する
  2. release-checkブランチにPull requestを出してマージする
  3. デプロイの時刻になるまで1-2を繰り返す
  4. release-checkブランチをデプロイし、Autifyを実行する
  5. 翌日、Autifyの結果に問題がないことを確認する
  6. featureブランチをそれぞれ本番リリースする
featureブランチをrelease-checkとmasterそれぞれにマージする

特徴的な部分として、release-checkブランチに集めた修正内容を直接masterにリリースするのではなく、featureブランチを個別にリリースしていることが挙げられると思います。

こうすることで、万が一の場合にもRevertを行いやすくする狙いがあります。

これまでの運用フローと課題

このようにAutifyによる自動テストを行うため、以下のような運用を行っていました。

  1. release-checkブランチへのマージ受付開始をアナウンス
  2. 実装者がrelease-checkブランチにマージ
  3. マージ受付終了のアナウンス
  4. ステージング環境にデプロイ
  5. Autify実行
  6. 自動QA完了のアナウンス
  7. release-checkブランチの削除と再作成

このうち、1、3、4、6、7のステップ(上図でピンク色のところ)は自動化されていなかったため、有志5名のエンジニアで交代しながら運用しており、大きな負担となっていました。

また5名のエンジニアが不在だったり、会議で手が空かない場合に運用がストップしてしまうことも発生していました。

さらに2のステップ(上図で青色のところ)においても、実装者がrelease-checkブランチとmasterブランチ両方に対するPull requestを用意するという、あまり直感的でない運用に対する混乱がありました。

まとめると、複雑なフローを手動で運用していることにより、開発チーム全体に負荷がかかっている課題がありました。

解決に向けて取り組んだこと

1. Slack Workflowを使った自動アナウンスを導入

Slack Workflowを使い、毎日同じ時刻に決まったメッセージを投稿するようにしました。

Workflow Builderを使うと簡単に設定できます。

SlackのWorkflow Builderで平日の9時に投稿されるように設定
実際の投稿

2. GitHub Actionsを使って定時でデプロイされるように

これまでもステージングへのデプロイ自体はGitHub Actionsで行っていたものの、毎日決まった時刻にデプロイするために、人の手でActionを起動する必要があり少し手間でした。

そこで以下のように、デプロイするActionを定時で呼び出すworkflowを作成しました。

name: deploy-release-check

on:
  workflow_dispatch:
  schedule:
    # 平日の日本時間17:15に実行
    # 17時ちょうどに始めると遅延やスキップされる可能性が高くなると記載があるので、17:15に設定
    # @see https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#schedule
    - cron: "15 8 * * 1-5"

jobs:
  deploy-release-check:
	# usesを使ってデプロイするActionを起動する
    uses: ./.github/workflows/deploy_pr-check.yml
    with:
      deployed_branch: release-check

  # 成功した場合Slack通知する
  success-notification:
    runs-on: ubuntu-22.04
    needs: deploy-release-check

    steps:
      - name: Send Slack notification on success
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "repository": "${{ github.repository }}",
              "workflow_url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
              "title": "✅ release-checkのデプロイが成功しました"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_DEPLOY_RELEASE_CHECK }}

  # 失敗した場合Slack通知する
  failure-notification:
    runs-on: ubuntu-22.04
    needs: success-notification
    if: failure()

    steps:
      - name: Send Slack notification on failure
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "repository": "${{ github.repository }}",
              "workflow_url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
              "title": "❌ release-checkのデプロイが失敗しました"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL_DEPLOY_RELEASE_CHECK }}

slackapi/slack-github-actionというActionを使うことで、デプロイ結果をSlack通知しています。

自動デプロイに成功した場合
自動デプロイに失敗した場合

Slack通知をGitHub Actionsから行っている理由について

実はGitHub公式が提供しているSlack連携アプリでも、GitHub Actionsの実行結果をSlack通知することが可能ですが、通知にメンションをつけることができないのでslackapi/slack-github-actionを使っています。

3. GitHub Actionsを使ってrelease-checkブランチ再作成を行う

1日ごとにrelease-checkブランチの内容をリセットする必要があるため、毎日ブランチの削除と再作成を行う必要がありました。

そこで以下のように、自動でブランチを再作成するActionを作成しました。

name: recreate-release-check

on:
  workflow_dispatch:
  schedule:
    # 平日の日本時間8:45に実行
    - cron: "45 23 * * 1-5"

jobs:
  recreate-release-check:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Delete release-check branch
        run: |
          git push origin --delete release-check

      - name: Create ${{ env.RELEASE_CHECK_BRANCH }} branch from ${{ env.DEFAULT_BRANCH }}
        run: |
          git checkout master
          git pull origin master
          git checkout -b release-check
          git push origin release-check

4. release-check用のPull requestを自動で作成できるように

実装者はfeatureブランチで実装した後、master向けとrelease-check向けの2つのPull requestを用意する必要があります。(参照:ブランチ運用について

実装者の負担を軽くするため、master向けPull request上で/release-check とコメントすると、自動でrelease-check向けのPull requestを作成できるようにしました。

コメントすると自動でrelease-check向けPRを作成

実装はGitHub Actionsで行っています。

name: Create release-check PR

on:
  issue_comment:
    types:
      - created

jobs:
  create-release-check-pr:
    if: github.event.issue.pull_request && github.event.comment.body == '/release-check'
    runs-on: ubuntu-22.04

    steps:
      # NOTE: ghコマンドを使うためにactions/checkoutを先に使う必要がある。この時点ではdefault branchにcheckoutされる。
      - uses: actions/checkout@v4
      # GitHub Actionsのissue_commentイベントでは、PRのhead refが取得できないので、gh apiで取得する
      - name: Get pull request head ref and sha
        id: head_ref_sha
        # REST APIで全fieldを取るのではなく、GraphQLで必要なfieldのみ取得
        run: |
          data=$(gh api graphql -F owner='{owner}' -F repo='{repo}' -F number=${{ github.event.issue.number }} -f query='
              query pullRequestDetails($repo:String!, $owner:String!, $number:Int!) {
                repository(name: $repo, owner: $owner) {
                  pullRequest(number: $number) {
                    headRefOid,
                    headRefName
                  }
                }
              }
            ')
          echo "HEAD_SHA=$(echo $data | jq -r '.data.repository.pullRequest.headRefOid')" >> "$GITHUB_OUTPUT"
          echo "HEAD_REF=$(echo $data | jq -r '.data.repository.pullRequest.headRefName')" >> "$GITHUB_OUTPUT"
      # PRのhead refにcheckoutする
      - uses: actions/checkout@v4
        with:
          ref: ${{ steps.head_ref_sha.outputs.HEAD_REF }}

      # PRのstatusをpendingにする
      - name: Notify pending status
        run: |
          gh api \
            /repos/{owner}/{repo}/statuses/${{ steps.head_ref_sha.outputs.HEAD_SHA }} \
            -f state='pending' \
            -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \
            -f context='${{ github.workflow }}'

      # release-check向けのPRを作成
      - name: Create release-check PR
        id: create-release-check-pr
        run: |
          pr_url=$(gh pr create \
            -a ${{ github.event.comment.user.login }} \
            -B release-check \
            -b '#${{github.event.issue.number}} のrelease-check用PRです。' \
            -t 'release-check #${{github.event.issue.number}}')
          echo "PR_URL=$pr_url" >> "$GITHUB_OUTPUT"

      # 成功失敗をPRにコメントする
      - if: success()
        name: Comment success
        run: |
          gh pr comment ${{ github.event.issue.number }} -b '<h2>✅ release-check用PRを作成しました。</h2><a href="${{ steps.create-release-check-pr.outputs.PR_URL }}">${{ steps.create-release-check-pr.outputs.PR_URL }}</a>'
      - if: failure()
        name: Comment failure
        run: |
          gh pr comment ${{ github.event.issue.number }} -b '## ❌ release-check用PRを作成できませんでした。'

      # PRのstatusをsuccessにする
      - if: success()
        name: Notify success status
        run: |
          gh api \
            /repos/{owner}/{repo}/statuses/${{ steps.head_ref_sha.outputs.HEAD_SHA }} \
            -f state='success' \
            -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \
            -f context='${{ github.workflow }}'
      # PRのstatusをfailureにする
      - if: failure()
        name: Notify failure status
        run: |
          gh api \
            /repos/{owner}/{repo}/statuses/${{ steps.head_ref_sha.outputs.HEAD_SHA }} \
            -f state='failure' \
            -f target_url='https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}' \
            -f context='${{ github.workflow }}'

コメントされたPull requestのHEADコミットにチェックアウトする必要があるのですが、HEADコミットのSHAを取得する方法に苦労しました。

issue_commentイベントからは取得できなかったため(2024-08-13現在)、GitHub APIからGraphQLで取得するようにしています。

その他

運用工数の削減とは別軸で、Autifyの実行精度を上げるため以下の仕組みも導入しました。

GitHub Actionsによる自動rebase

実装した当日にリリースする場合など、masterブランチにマージされた変更が、release-checkブランチにはマージされていないケースが起こり得ます。

Autifyの結果をできる限り正しくするために、release-checkブランチが最新のmasterに追従することが重要です。

そこでmasterに変更が入るごとに、release-checkブランチをrebaseするGitHub Actionsを作成しています。

name: Rebase release-check on master

on:
  push:
    branches:
      - master

jobs:
  rebase-release-check:
    runs-on: ubuntu-22.04

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Set up Git
        run: |
          git config user.name 'github-actions[bot]'
          git config user.email 'github-actions[bot]@users.noreply.github.com'

      # release-checkブランチをrebaseする
      - name: Rebase release-check onto master
        id: rebase-release-check
        run: |
          git checkout release-check
          git rebase origin/master
        continue-on-error: true

      # コンフリクトがあった場合にSlack通知する
      - name: Check for conflicts
        if: steps.rebase-release-check.outcome == 'failure'
        run: git rebase --abort

      - name: Send Slack notification on failure
        if: steps.rebase-release-check.outcome == 'failure'
        uses: slackapi/slack-github-action@v1.26.0
        with:
          payload: |
            {
              "branch_name": "${{ github.ref_name }}",
              "repository": "${{ github.repository }}",
              "workflow_url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

      # コンフリクトがなければpushする
      - name: Push changes
        if: steps.rebase-release-check.outcome == 'success'
        run: |
          git push --force-with-lease --force-if-includes -u origin release-check

ごく稀にコンフリクトが発生しrebaseに失敗するケースがあるので、コンフリクト時にSlack通知する設定をしています。

まとめ

ここまでの取り組みで、有志5名のエンジニアによる対応工数は0にすることができました。

またrelease-check向けのPull requestが簡単に作れるようになり、開発チーム全体の負荷も下げることができました。

人の手で運用しなくなったことで、始業時間ぴったりにマージ受付を開始したり、デプロイ時刻を終業時刻に近づけることができるなど、より利便性が上がる結果にもなりました。

これからも様々な技術を使いながら、品質と開発生産性の両立を目指していきたいと思います。

We are hiring!

エンジニアリングマネージャーはもちろん、各種ポジションで採用を行っています!

株式会社PR TIMES
開発部の土台を支え、組織作りからユーザーに貢献するエンジニアリングマネージャーを募集! - 株式会社PR ... 株式会社PR TIMESでは現在03-01. 開発部 エンジニアリングマネージャー候補を募集しています。
株式会社PR TIMES
02.開発部 の求人一覧 - 株式会社PR TIMES 株式会社PR TIMESが公開している、02.開発部 の求人一覧です
  • URLをコピーしました!

この記事を書いた人

2021卒でフロントエンド開発を担当しています。

目次