Github ActionsのComposite Actionを利用して他リポジトリへPRを送る雛形を作成する
ZOZO Advent Calendar 2023 4日目の記事になります。
こんにちは!今年もAdvent Calenderの時期がやってきました!小ネタを絞り出して記事を書こうかと思います。
はじめに
皆さんはGtihub Actionsの複合アクション(Composite Action)を利用したことがありますか?Github ActionsでCIを作成しているとWorkflowの処理に似通った処理をするStepが出てくると思います。2-3stepで処理が済めば良いのですが、5-10stepくらいにまたがる処理の場合はWorkflowの見通しが悪くなり、修正も大変になります。この問題を解決するのがComposite Actionになります。 今回はComposite Actionの使用例としてCIから他リポジトリへPRを作成するような処理を紹介します。Composite Actionの基本的な利用方法は下記ドキュメントにまとまっているので併せてご確認ください。
仕組みの説明
具体的なComposite Actionの中身を見る前にどのような仕組みを作りたいか簡単に説明します。 利用背景例として設定ファイルを管理するリポジトリがあり、設定ファイルを任意のタイミングで他リポジトリへ反映したい場合を考えます。イメージとして下記図のような形でPRを送る形にすれば、他リポジトリの設定を任意に更新できます。
Composite Actionの実装
下記実装がComposite Actionの実装になります。
処理の流れとしては、最初に設定を同期したいリポジトリをCheckoutします。次に設定ファイルが配置されている場所(今回はdownload-artifactを利用しています)と同期するリポジトリ内のファイルをrsync
コマンドで同期します。最後に同期したディレクトリのdiffを確認して、必要であればPRを作成するような処理になります。汎用性を持たせるためにinputs
部分で諸々パラメータを渡せるようにしています。
name: 'Create github pull request' description: 'Create github pull request and sync data' inputs: sync-source-and-destination-dir: description: 'Receive json data to sync another respository directories. ex: [{"source_dir": "source_dir", "dst_dir": "dst_dir"}]' required: true download-artifact-name: description: 'download artifact name' required: true download-artifact-path: description: 'download artifact path' required: true branch-name: description: 'branch name' required: true pull-request-title: description: 'pull request title' required: true runs: using: "composite" steps: - name: delete branch if exists run: | git push origin :${{ inputs.branch-name }} || true shell: bash - name: create branch run: | git switch -c ${{ inputs.branch-name }} shell: bash - name: show cuurent branch run: | git branch shell: bash - name: Extract to an appropriate directory uses: actions/download-artifact@v3 with: name: ${{ inputs.download-artifact-name }} path: ${{ inputs.download-artifact-path }} - name: set git config run: | git config user.name github-actions git config user.email github-actions@github.com shell: bash # 同期するディレクトリを指定する - name: sync data and add git run: | for row in $(echo '${{ inputs.sync-source-and-destination-dir }}' | jq -c '.[]'); do source_dir=$(echo $row | jq -r '.source_dir') dst_dir=$(echo $row | jq -r '.dst_dir') rsync -v --delete -d $source_dir $dst_dir git add $dst_dir done shell: bash # diffを確認して後続の処理を行うかを判断する - name: check diff id: changes run: | diff_file=`git diff --cached --name-status | wc -l` if [ $diff_file -gt 0 ]; then echo "skip_ci=true" >> $GITHUB_OUTPUT else echo "skip_ci=false" >> $GITHUB_OUTPUT fi shell: bash - name: git commit if: ${{ steps.changes.outputs.skip_ci != 'false' }} run: | git commit -m "update views" ${DOWNLOAD_PATH} shell: bash - name: git push if: ${{ steps.changes.outputs.skip_ci != 'false' }} run: | git push origin HEAD shell: bash # gh commandを利用するための認証 - name: gh command authorization if: ${{ steps.changes.outputs.skip_ci != 'false' }} run: | echo ${PERSONAL_ACCESS_TOKEN} > token.txt gh auth login --with-token < token.txt shell: bash # PRの作成 - name: create Pull Request if: ${{ steps.changes.outputs.skip_ci != 'false' }} run: | gh pr create --title "${{ inputs.pull-request-title }}" --body "- [ ] ${{github.event.pull_request.html_url}}" shell: bash
Composite Action呼び出し側の実装
Composite Actionの呼び出し側は下記イメージで呼び出します。呼び出し部分はSync backend repository directories and Create PR
というjobで行われます。with
部分でComposite Actionに渡すパラメータを指定しています。sync-source-and-destination-dir
はjsonでパラメータを渡すようにできており、PRを作成したいリポジトリの複数ディレクトリを同期できるようにしています。
name: "sample" on: pull_request: branches: - 'main' types: [opened, synchronize, closed] jobs: backend-pr: runs-on: ubuntu-latest env: PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} DOWNLOAD_NAME: config_files steps: # PRを作成したいリポジトリをチェックアウト - uses: actions/checkout@v3 with: token: ${{ env.PERSONAL_ACCESS_TOKEN }} repository: hoge/backend - uses: actions/checkout@v3 with: path: fuga - name: Sync backend repository directories and Create PR # Composite Actionが格納されているディレクトリを指定 uses: ./hoge/.github/actions with: branch-name: update-config-$(date "+%Y%m%d") download-artifact-name: ${{ env.DOWNLOAD_NAME }} download-artifact-path: ${{ runner.temp }} sync-source-and-destination-dir: ' [{ "source_dir": "${{ runner.temp }}/hoge_setting/", "dst_dir": "backend/hoge_setting/" }, { "source_dir": "${{ runner.temp }}/fuga_setting/", "dst_dir": "backend/fuga_setting/" }]' pull-request-title: 'update settings $(TZ=JST-9 date +"%Y-%m-%d %T %Z")'
まとめ
Composite Actionを利用することで複数のstepにまたがる処理をまとめる事ができました。CIは気がついたらyamlの記述量が膨大になって見通しが悪くなることが多いのでComposite Actionで共通処理をうまくまとめてみると良さそうです