10
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?

ZOZOAdvent Calendar 2024

Day 5

GitHub Actions Tips

Last updated at Posted at 2024-12-04

この記事はZOZO AdventCalender 2024シリーズ5の5日目の記事です。

GitHub Actions Tips

本記事では筆者がGitHub Actionsでworkflowを実装した際に得た知見を共有します。
主にactions/checkoutに関連した高速化についてのTipsを紹介したいと思います。

大規模リポジトリで使うactions/checkout

GitHub Actionsでworkflowを実装する際には、まずリポジトリをチェックアウトするためにactions/checkoutを使うことが多いと思います。
actions/checkoutはGitHub Actionsの公式アクションで、リポジトリをチェックアウトするためのアクションです。
しかし、大規模なリポジトリでデフォルト設定のまま使うと、チェックアウトに時間がかかりすぎてしまうことがあります。
なお、デフォルト設定でもfetch-depthは1に設定されているため、最新コミットのみを取得するShallowClone自体は有効になっています。

そのworkflow、本当にリポジトリのファイル全部必要ですか?

workflowの処理がリポジトリのファイル全てを必要としない場合、sparse-checkoutが有効です。
sparse-checkoutは、リポジトリ内の特定のディレクトリやファイルのみを指定してチェックアウトすることができる機能です。
例えば.githubディレクトリとsrcディレクトリ以下のファイルしか使わない場合、以下のように設定します。
※ この設定自体はREADMEにも記載されています。

- name: Checkout
  uses: actions/checkout@v4
  with:
    sparse-checkout: |
      .github
      src

この設定を有効にすることで、workflowで必要なファイルに絞ってチェックアウトすることができるため、チェックアウトにかかる時間を短縮することができます。
大量のファイルがコミットされているリポジトリで特に有効です。
筆者の試したリポジトリでは、数分かかっていた処理が数秒で終わるようになりました。

そのworkflow、そもそもチェックアウト自体必要ですか?

workflowの処理が

  • リポジトリ内のファイルは使わない
  • 履歴が必要(diffやPRの差分を見るなど)でfetch:depth: 0でフルクローンしてる

というケースだと、チェックアウトしているけど時間をかけてダウンロードしたファイルを使っていないという無駄が発生しています。
こういったケースでは、actions/checkout自体使うのをやめましょう。

ではどうするか?

actions/checkoutを使わずにdiffやPRの差分を取得したりするには、GitHub APIを使う方法があります。
GitHub Actionsのデフォルトのランナーには、GitHub CLIがあらかじめインストールされているため、GitHub CLIを使ってGitHub APIを叩くことができます。
例えばPullRequestの差分を取得する場合、Pull Request Eventをトリガーとしたworkflowで以下のように差分を取得することができます。

on:
  pull_request:
    types: [opened, synchronize, closed]

jobs:
  diff:
    runs-on: ubuntu-latest
    steps:
      - name: Get diff
        env:
          GH_TOKEN: ${{ github.token }}
        run: |
          gh api /repos/${{ github.repository }}/pulls/${{ github.event.number }}/files --jq '.[] | .filename'

このようにGitHub APIを使うことで、リポジトリをチェックアウトすることなく、リポジトリの情報を取得することができます。
workflowの処理がリポジトリのファイル自体を必要としない場合、actions/checkoutを使わずにGitHub APIを使うことで、チェックアウト自体を省略できるので大幅に処理時間を短縮することができます。
なお、gh pr diffコマンドでPullRequestの差分を取得することもできますが、gh prを使う場合、.gitディレクトリが必要なため、actions/checkoutを使って.gitディレクトリだけ先にチェックアウトする必要があります。

応用

ここまでで一部のディレクトリ・ファイルだけ必要なケース、ファイルは必要ないけどリポジトリの情報は必要なケースを紹介しましたが、一部のディレクトリ・ファイルだけ必要だけど必要なものはPullRequestの差分を取得しないとわからず、事前にsparse-checkoutの設定をするのが難しいというケースもあるかと思います。
そういった場合は、はじめにGitHub APIで差分を取得して、sparse-checkoutの設定を動的に行うという方法を紹介したいと思います。
サンプルコードは以下の通りです。

on:
  pull_request:
    branches:
      - main
    types: [opened, synchronize, closed]

jobs:
  get-diff:
    runs-on: ubuntu-latest
    env:
      GH_TOKEN: ${{github.token}}
    steps:
      - name: Get diff
        id: get-diff
        run: |
          diff=$(gh api /repos/${{github.repository}}/pulls/${{github.event.number}}/files --jq '.[] | .filename')
          {
            echo 'diff<<EOF'
            echo "${diff}"
            echo EOF
          } >> "${GITHUB_OUTPUT}"
          echo "${diff}" >> "${GITHUB_STEP_SUMMARY}"
      - name: checkout
        uses: actions/checkout@v4
        with:
          sparse-checkout: |
            ${{ steps.get-diff.outputs.diff }}
      - name: tree
        run: tree >> "${GITHUB_STEP_SUMMARY}"

stepごとに解説していきたいと思います。

  1. Get diff
    GitHub APIを使ってPullRequestの差分を取得します。--jq '.[] | .filename'でファイル名のみを取得しています。
    また、GITHUB_OUTPUTはそのままでは改行を含んだ文字を出力できませんが、区切り文字で囲って出力することで改行を含んだ文字を出力することができます。
    参考: https://docs.github.com/ja/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings
  2. checkout
    Get diffで取得した差分をsparse-checkoutの設定としています。
    本記事の例では、差分のファイルパスをそのままsparse-checkoutの設定としていますが、Get diffのステップでファイルが含まれるディレクトリを取得して出力することで、ディレクトリを指定してsparse-checkoutの設定をすることも可能です。
  3. tree
    実際にどういうファイルがチェックアウトされたかを確認するために、treeコマンドを実行しています。
    出力結果は以下の通りです。
    A/1/test.txtA/2/test.txtの2ファイルに修正を加えたPullRequestを作成し、このworkflowを実行した結果です。
    A/1/test.txt
    A/2/test.txt
    
    .
    ├── A
    │   ├── 1
    │   │   └── test.txt
    │   └── 2
    │       └── test.txt
    ├── README.md
    └── test.txt
    
    3 directories, 4 files
    
    比較用に、このworkflowを実行したリポジトリのディレクトリ構成を記載します。
    .
    ├── A
    │   ├── 1
    │   │   └── test.txt
    │   ├── 2
    │   │   └── test.txt
    │   └── 3
    │       └── test.txt
    ├── README.md
    └── test.txt
    
    5 directories, 5 files
    
    PullRequestに含まれていないA/3ディレクトリがチェックアウトされていないことが確認できます。

まとめ

本記事では、主にactions/checkoutに関連した高速化についてのTipsを紹介しました。
actions/checkoutはよく使われるactonですが、大規模リポジトリで使う場合はworkflowのボトルネックになりがちです。
workflowを見直してみると、案外使う必要がなかったりするかもしれません。

10
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
10
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?