🛠️

GitHubのDependabotでSwift Packageのアップデートを監視する

2023/09/21に公開

2023/8/1にようやくDependabotがSwiftをサポートしました🎉

https://github.blog/changelog/2023-08-01-swift-support-for-dependabot-updates/

ということで、Dependabotを使ってSwift Packageのアップデートを監視する方法をまとめます。

前提

  • DependabotにはDependabot alertsDependabot security updatesDependabot version updatesの3種類があるが、今回は3つ目の話
  • あくまでSwift Packageの依存ライブラリのアップデート検出が対象
    • アップデートを監視できるのはPackage.swiftで依存の定義をしている外部Package
    • Xcode Project(.xcodeproj)で依存の定義をした外部Packageは対象外

方法

Dependabot version updatesを有効にするには、リポジトリのルートディレクトリに.githubというディレクトリを配置し、その中にdependabot.ymlファイルを置くだけでよいです。

例えば、以下のような構成の自作のSwift PackageでDependabot version updatesを有効にする場合

.
├── LICENSE
├── README.md
├── Package.swift
├── Package.resolved
├── Sources
└── Tests

以下のようにYAMLを書けば、毎日深夜2時にライブラリのアップデートを確認してPRを立ててくれます。(細かい構文に関してはこちら

version: 2
updates:
  - package-ecosystem: "swift"
    directory: "/"
    schedule:
      interval: "daily"
      timezone: "Asia/Tokyo"
      time: "02:00"

なお、重要なポイントとして、Dependabotが動作するにはPackage.resolvedが必須です。
これがないと

updater | 2023/09/15 04:35:45 ERROR <job_722281318> Error processing github.com/firebase/firebase-ios-sdk (NoMethodError)
updater | 2023/09/15 04:35:45 ERROR <job_722281318> undefined method `content' for nil:NilClass
updater | 
updater |           return if updated_lockfile_content == lockfile.content
updater |                                                         ^^^^^^^^

のようなログを吐くエラーとなって、Dependabotの処理が失敗します。


次に、Xcode Project(要はアプリ)でローカルのSwift Packageによるマルチモジュール構成などを構築している場合

.
├── SampleApp
├── SampleApp.xcodeproj
└── LocalPackage
    ├── Package.swift
    ├── Package.resolved (普通はない状態だと思われる)
    ├── Sources
    └── Tests

まず、LocalPackageだけをXcodeで開いてResolve Package Dependenciesを走らせれば、Package.resolvedファイルが生成されます。これが必須です。

この状態で以下のようにYAMLを書けばDependabot version updatesが有効になります。

version: 2
updates:
  - package-ecosystem: "swift"
    directory: "/LocalPackage"
    schedule:
      interval: "daily"
      timezone: "Asia/Tokyo"
      time: "02:00"

ちなみに、ここでLocalPackage/Package.resolvedではなく、SampleApp.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolvedのシンボリックリンクをおけばうまく動かないかなと思って実験してみましたがダメでした。


動作確認

リポジトリのInsights > Dependency graph > dependabot > Check for updates を押せば、手動でdependabot.ymlを動かすことができますが、この場合にはPRが作られません。あくまでscheduleで指定した時間に自動で動いたときにだけPRが作られることに注意してください。また、pushしただけでもCheck for updatesが走るのですが、その間はscheduleで指定した方の処理も行われないので、動作確認をしたいときは10分後くらいに発火するようにするといいです。

依存パッケージがプライベートリポジトリの場合

社内ライブラリや個人の公開していないライブラリを使って運用している場合、プライベートリポジトリのSwift Packageに依存することになると思います。その場合は、それ用に別途設定が必要です。

DependabotのSwift対応状況は、プライベートリポジトリに関してgit onlyと書かれているので、type: gitのregistry設定が必要です。

version: 2
registries:
  private-libraries: #ここの名前は任意
    type: git
    url: https://github.com
    username: user-name #プライベートリポジトリへのRead権限を持つアカウント名
    password: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
updates:
  - package-ecosystem: "swift"
    registries: "*"
・・・
  • YAMLファイルにregistriesの記述をする
  • 各プライベートリポジトリへのRead権限を持つアカウントを用意する
  • 上記のアカウントのPersonal Access Tokenを発行する
  • Personal Access TokenをDependabotを動かしたいリポジトリのSettings > Secrets and Variables > Dependabotに登録する

Swift PackageライブラリのURL指定に気をつける

現状のDependabotはPackage.swiftで指定されているSwift PackageのurlPackage.resolvedで指定されているSwift Packageのlocationが完全一致していないと、更新の監視対象から除外してしまうようです。

Package.swift
dependencies: [
+   .package(url: "https://github.com/org/repo-name.git", exact: "1.0.0"),
]
Package.resolved
{
  "pins": [
    {
      "identity" : "library-name",
      "kind" : "remoteSourceControl",
+     "location" : "https://github.com/org/repo-name",
      "state" : {
        "revision" : "b35827a61c1420e40ff8e7c584b5042144d20195",
        "version" : "1.0.0"
      }
    },
  ],
  "version" : 3
}

上記のようにPackage.swiftの方には末尾に.gitが含まれ、Package.resolvedの方には末尾に.gitが含まれていないような場合、Pull Requestを立ててくれなくなってしまいます。
これはDependabotの考慮不足なところであると推測します。

Discussion