🧹

Renovate の Package 更新に合わせて Package.resolved も GitHub Actions で更新する

2023/06/28に公開

パッケージの更新を自動で行ってくれる Renovate ですが、記事執筆時点では残念ながら SwiftPM に完全に対応されているわけではなく、Package.swift と一緒に更新されて欲しい Package.resolved の更新は行ってくれません (issue は作られていて作業も少し進んでいるようではあります)。

https://github.com/renovatebot/renovate/issues/6924

ただ、現状の Renovate でも Package.swift の更新だけは行ってくれるので、それに合わせて Package.resolved を更新してくれる GitHub Actions の workflow を作成しようと思い、実際に作成しました。

あくまで例とはなりますが、以下のような workflow でそのような機能が実現できました。

name: Update Package.resolved for Renovate

on:
  pull_request:
    types: [opened, synchronize]
    paths:
      - "**/Package.swift"

jobs:
  get-changed-files:
    runs-on: ubuntu-latest
    # branch 名に `renovate` が含まれていなければ処理を skip する
    if: contains(github.head_ref, 'renovate')
    outputs:
      all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }}
    steps:
      - uses: actions/checkout@v3
        with:
          token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
      - name: Get changed files
        id: changed-files
        uses: tj-actions/changed-files@v36
  update-package-resolved:
    runs-on: macos-latest
    needs: get-changed-files
    # `Package.resolved` が含まれている場合には処理を実行しないようにして、workflow の無限ループを防いでいる
    if: ${{ !contains(join(needs.get-changed-files.outputs.all_changed_files, ' '), 'Package.resolved') }}
    steps:
      - uses: actions/checkout@v3
        with:
          token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
      - name: Setup Xcode
        uses: maxim-lobanov/setup-xcode@v1
        with:
          xcode-version: latest-stable
      - name: Setup ssh
        run: |
          SSH_PATH="$HOME/.ssh"

          mkdir -p "$SSH_PATH"
          touch "$SSH_PATH/known_hosts"

          echo "$SSH_PRIVATE_KEY" > "$SSH_PATH/id_rsa"

          chmod 700 "$SSH_PATH"
          ssh-keyscan github.com >> ~/.ssh/known_hosts
          chmod 600 "$SSH_PATH/known_hosts"
          chmod 600 "$SSH_PATH/id_rsa"

          eval $(ssh-agent)
          ssh-add "$SSH_PATH/id_rsa"
        env:
          SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
      # xcodebuild -resolvePackageDependencies で任意の workspace などを指定して `Package.resolved` をアップデートする
      - name: Update Package.resolved
        run: |
	  ...
          xcodebuild -resolvePackageDependencies -workspace "$workspace" -scheme "$scheme"
      # 既存の Action を利用しているが、単純な操作なので普通に git command でも良さそう
      - uses: stefanzweifel/git-auto-commit-action@v4
        with:
          commit_message: Update Package.resolved
          commit_user_name: ...
          commit_user_email: ...
          commit_author: ...
        env:
          GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}

特に複雑な workflow ではないですが、以下の 2 点だけ簡単に補足しておこうと思います。

  • get-changed-files
  • private な Swift Package を取得するための ssh の設定

get-changed-files

自分が今回関わっていたプロジェクトではいくつかの Package.swift が存在していました。
そのため、「変更された Package.swift の file path に基づいて、特定の Package.resolved を更新する」という挙動を実現するために、ファイルの差分を取得しています。
また、PR の差分に Package.resolved が含まれているかどうかの判定のためにも利用しています。

ssh の設定

private な Swift Package を CI 上で取得したい場合、例えば ssh を利用して Package を取得するようにしておく必要があります (詳しい話については以下を参考にさせていただきました)。

https://yutailang0119.hatenablog.com/entry/resolve-private-swiftpm-on-ci

その場合、以下の記事に記載されているような手順で ssh の設定も行っておく必要があります (Node の話ですが、ssh のための設定手順は同じです)。

https://kayex.hateblo.jp/entry/git-actions-ssh

後は、ssh のセットアップを workflow 上で行った後で xcodebuild を実行すれば、xcodebuild は自動でマシンの ssh 設定を使ってくれるため、問題なく private な Swift Package も取得できるようになります。
xcodebuild の挙動などについては以下の記事を参考にしました。

https://techlife.cookpad.com/entry/2022/06/01/090000

おわりに

ちなみに、この workflow を作ってしまった後で、「実は既にそういうもの作られているのでは...?」と思って軽く検索してみただけでもいくつかヒットしてしまい、最初に検索しておかなかったことを少し後悔しました。

https://speakerdeck.com/ikesyo/renovateniyoruiosraiburarifalsezi-dong-geng-xin?slide=12

https://blog.kyash.co/entry/2023/05/17/172951

自分が今回紹介した workflow は、プロジェクトによってはもっとシンプルにできたり、そもそも冗長な処理があるものになってしまっているかもしれない (今パッと見ただけでもいくつかありそうだった) ですが、Renovate の利用中に困ったときなど、何かの参考になったら嬉しいです。

Discussion