【Github】Github Actions ~ pull_request / pull_request_target ~

■ はじめに

https://dk521123.hatenablog.com/entry/2024/01/28/004128

の続き。

仕事で、Github の プルリクエストが発行された際に
Linter を起動してほしいってオーダーを受けたので
on: pull_request 周辺について調べてみた

目次

【1】プルリク契機のイベント
 1)補足:pull_request_target に関する詳細
【2】構文
 1)types
【3】判定
 1)プルリクかどうかを判定するには
 2)Draft プルリクかどうかを判定するには
【4】サンプル
 例1:プルリク時にSQL linter を実行
 例2:差分だけをLintする(案1)
 例3:差分だけをLintする(案2)

【1】プルリク契機のイベント

# Events Explanations Comments
1 pull_request プルリクのアクティビティが発生した時
2 pull_request_comment プルリクのコメントが作成/編集/削除された時
3 pull_request_review プルリクのレビューが送信/編集/無視された時
4 pull_request_review_comment プルリクのレビューコメントが変更された時
5 pull_request_target プルリクのアクティビティが発生した時 「1)pull_request_target に関する詳細」参照

1)補足:pull_request_target に関する詳細

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#pull_request_target

* pull request のベースのコンテキストで実行
 => 以下を避けられる
 + リポジトリを変更
 + ワークフローで使うシークレットを盗む
 + pull request の head から安全ではないコードが実行される

* ワークフローでは、pull request に対するラベルやコメントなどを
 フォークから行うことができる

pull_request vs pull_request_target

pull_request pull_request_target Comments
フォークしたリポジトリにも書き込み権限・Secretsを渡さない フォークしたリポジトリにも書き込み権限・Secretsを渡す フォーク 元で設定している secrets にアクセスできないとGITHUB_TOKEN / SLACK_TOKENを参照できない

使用上の注意

* pull request からコードをビルドまたは実行する必要がある場合は、
 このイベントを使わない

【2】構文

on:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize
    branches:
      # プルリクエストのマージ対象がmainの場合実施
      - 'main'
    # ブランチ除外
    #branches-ignore:
    #  - 'mona/octocat'
    paths:
      # pull request に SQLファイル (.sql) への変更が含まれているときに実行
      - '**.sql'
    # paths-ignore:
    #   - 'tests/**.sql'

https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#running-your-pull_request-workflow-based-on-the-head-or-base-branch-of-a-pull-request
https://docs.github.com/ja/actions/using-workflows/triggering-a-workflow#using-filters-to-target-specific-branches-for-pull-request-events

1)types

* デフォルトは、『types: [ opened, synchronize, reopened ]』

主なTypes

types Explanations
opened プルリク(Draft pull-requestを含む)が発行時
reopened プルリク(Draft pull-requestを含む)が再Open時
synchronize プルリクにコミットが追加された時
ready_for_review プルリクが Draft から Open になった時

【3】判定

* Reusable Github workflow を使う際に、
 プルリクかどうかを判定する必要があったのでメモ。 

1)プルリクかどうかを判定するには

github.event_name == 'pull_request'

2)Draft プルリクかどうかを判定するには

github.event.pull_request.draft == true

【4】サンプル

例1:プルリク時にSQL linter を実行

Github Actions ~ SQL Linter ~
https://dk521123.hatenablog.com/entry/2024/03/04/180308

name: DemoForPullRequest

on:
  pull_request_target:
    types:
      - opened
      - reopened
      - synchronize
    paths:
      - '**.sql'
jobs:
  sample-job:
    runs-on: ubuntu-latest
    steps:
      - name: Run checkout
        uses: actions/checkout@v4
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
            python-version: '3.10'
      - name: install SQLFluff
        run: 'pip install sqlfluff'
      - name: format
        run: |
          for file in 'sqls/*.sql' 
          do
            sqlfluff lint $file --dialect snowflake --format github-annotation
          done

例2:差分だけをLintする(案1)

* 以下のサイトの方法を参考に実装。

https://qiita.com/kenz_firespeed/items/b37a6a1a7f0aff931c7c

name: DemoForPullRequest

on:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize
    paths:
      - '**.sql'
env:
  base_branch: develop
jobs:
  lint-job:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
            python-version: '3.10'
      - name: install SQLFluff
        run: 'pip install sqlfluff'
      - name: Switch to pull request branch
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}
      - name: Fetch base branch
        run: git fetch origin ${base_branch}:${base_branch}
      - name: Run actions using diff_files
        run: |
          diff_files=$(git diff --name-only HEAD ${base_branch} -- "sqls/**.sql" \
            | tr "\n" " ")
          echo "- diff_files: ${diff_files}"

          for file in ${diff_files}
          do
            echo "- target_file: ${file}"
            sqlfluff lint $file --dialect snowflake --format github-annotation-native
          done

補足1:github.event.pull_request.head.sha
https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#pull_request

より抜粋
~~~~~~~~~~~~~
pull request の head ブランチへの最後のコミットのコミット ID を取得する場合は、
代わりに github.event.pull_request.head.sha を使います
~~~~~~~~~~~~~

補足2:git diff コマンド

* 以下の関連記事を参照のこと

Git ~ 基本編 / 基本コマンド ~
https://dk521123.hatenablog.com/entry/2020/10/02/000000

例3:差分だけをLintする(案2)

* 以下のサイトの方法を参考に実装。
 => 案1との主な変更点は、★部分参照。

https://zenn.dev/snowcait/articles/6d207409cb1be0

name: DemoForPullRequestV2

on:
  pull_request:
    types:
      - opened
      - reopened
      - synchronize
    paths:
      - '**.sql'
env:
  base_branch: develop
jobs:
  lint-job:
    runs-on: ubuntu-latest
    steps:
      - name: Setup Python
        uses: actions/setup-python@v4
        with:
            python-version: '3.10'
      - name: install SQLFluff
        run: 'pip install sqlfluff'
      - name: Switch to pull request branch
        uses: actions/checkout@v4
        with:
          # ★1:分岐を特定するために fetch-depth: 0 で履歴をすべて取得する必要があ
          fetch-depth: 0
      - name: Run actions using diff_files
        run: |
          # ★2:...: 分岐からの差分(ベースブランチの変更が含まれない = PR の Files changed)
          diff_files=$(git diff --name-only origin/${base_branch}...origin/${GITHUB_HEAD_REF} -- "sqls/**.sql" \
            | tr "\n" " ")
          echo "- diff_files: ${diff_files}"

          for file in ${diff_files}
          do
            echo "- target_file: ${file}"
            sqlfluff lint $file --dialect snowflake --format github-annotation-native
          done

補足3: fetch-depth
https://dk521123.hatenablog.com/entry/2022/06/16/151443

より抜粋
~~~~~~~~~~~~~~~~~~~~~
* 0 は、全てのブランチ・タグの全ての履歴を取得することを意味する
* Default: 1 (最新のコミットのみを取得する)
~~~~~~~~~~~~~~~~~~~~~

ex. Fetch all history for all tags and branches
https://github.com/actions/checkout?tab=readme-ov-file#fetch-all-history-for-all-tags-and-branches

- uses: actions/checkout@v4
  with:
    fetch-depth: 0

参考文献

https://qiita.com/Soh1121/items/b2bc51afc933c910806c
https://til.toshimaru.net/2021-12-12
https://madogiwa0124.hatenablog.com/entry/2022/05/29/110148
https://pankona.github.io/blog/2021/03/29/github-actions-pull-request-target/

関連記事

Github Actions ~ 基礎知識編 ~
https://dk521123.hatenablog.com/entry/2021/11/04/142835
Github Actions ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2022/06/16/151443
Github Actions ~ 基本編 ~
https://dk521123.hatenablog.com/entry/2023/12/22/195715
Github Actions ~ あれこれ編 ~
https://dk521123.hatenablog.com/entry/2023/12/21/155224
Github Actions ~ GITHUB_ENV ~
https://dk521123.hatenablog.com/entry/2023/12/29/000840
Github Actions ~ GITHUB_OUTPUT ~
https://dk521123.hatenablog.com/entry/2024/01/30/002943
Github Actions ~ ワークフロー制御 ~
https://dk521123.hatenablog.com/entry/2024/01/28/004128
Github Actions ~ SQL Linter ~
https://dk521123.hatenablog.com/entry/2024/03/04/180308
SQL Linter ~ SQLFluff ~
https://dk521123.hatenablog.com/entry/2024/02/28/225002
reviewdog ~ 入門編 ~
https://dk521123.hatenablog.com/entry/2024/04/13/232832
Git ~ 基本編 / 基本コマンド ~
https://dk521123.hatenablog.com/entry/2020/10/02/000000