BitriseでSwift Package Manager(SPM)のパッケージをキャッシュする
はじめに
自分のXcodeプロジェクトではライブラリ管理を徐々にCocoaPodsからSwift Package Manager(以下 SPM)へ移行してるんですが、CocoaPodsの時にやっていたのと同じようなBitriseのキャッシュ設定をSPM用にも入れたいなと思いちょっと調べてみました。
SPMで取ってきたパッケージをBitriseでキャッシュさせるのどうやるんかなぁ🤔
— asmz (@_asmz) 2020年10月19日
で、先に言ってしまうと、調べた結果こちらの記事がとても参考になった(と言うかCIサービスがCircleCIなところ以外はほとんどこれと一緒)ので、気になる方はこちらと併せてご確認ください。
今回やりたいこと
CocoaPodsでは、落としてきたライブラリたちが全て./Pods
に入るので、BitriseのCache:Pushでは以下のようにCache Pathsに設定することで./Podfile.lock
に変更が入った際に./Pods
をキャッシュする、という形にしていました。
./Pods -> ./Podfile.lock
今回やりたいこととしては基本的にはこれと同じ方針で、SPM依存パッケージの変更があったら、SPM依存パッケージファイル群をキャッシュする設定をBitriseに入れようと思います。
SPMパッケージ変更の検知
SPMではパッケージをXcodeのGUI上で操作して追加するので、CocoaPodsで言うところのPodfile.lock
のように依存パッケージが記載されているファイルはどこにあるんだろ、と思い調べたところここに入っていました。
$ ls -l XXXX.xcworkspace/xcshareddata/swiftpm/ total 8 -rw-r--r-- 1 asmz staff 1396 10 19 17:14 Package.resolved $
このPackage.resolved
を今回SPMパッケージ変更の検知に用います。
なお、このファイルはBitrise側で使用するため、リポジトリ管理されている必要があります。
SPMパッケージ保存場所の変更
上記のパッケージ変更検知を受け、実際にキャッシュしたいディレクトリを指定する必要があるのですが、デフォルト設定だとSPMパッケージはDerivedDataに保存されるようです。
これだと動的にディレクトリ名が変わってしまいBitriseのキャッシュStepに組み込めないため、以下のように明示的にパッケージ保存場所を指定します。
[xcodebuildの場合]
xcodebuild build ... -clonedSourcePackagesDirPath {packages_path}
[fastlane scanの場合]
run_tests( ... cloned_source_packages_path: "{packages_path}" )
[fastlane gymの場合]
build_app( ... cloned_source_packages_path: "{packages_path}" )
これで {packages_path}
で指定した場所にSPMのパッケージ群が落ちてくる形になるので、ここをCI側でキャッシュ指定させれば良いですね。
なお余談として、自分はこれ以外にfastlane actionのxcovを使ってコードカバレッジを取得しているのですが、xcovも内部でxcodebuildコマンドを叩いているようでその際にSPM依存関係がチェックされ、存在しなければパッケージ導入処理が走ります。
今回、↑でパッケージのパスを変えた関係で、このxcovでパッケージ導入処理が走ってしまったので調べたら、xcovにも同様のcloned_source_packages_path
オプションが追加されていました。
ご利用のfastlaneコマンドで、同じようにSPMパッケージ導入が始まってしまうActionありましたら、このオプション追加されていないか確認してみると良いかもです。
Bitriseキャッシュ設定
あとはBitriseのCache:Push Stepで以下のようにCache Pathsを指定します。
{packages_path} -> ./{project_name}.xcworkspace/xcshareddata/swiftpm/Package.resolved
{packages_path}
とPackage.resolvedのパスはそれぞれ先に確認した内容を入れてください。
Bitrise実行結果
以上の設定でBitriseを回してうまくCacheがPushできれば、以降Cache:PullでSPMパッケージがキャッシュから取得できるかと思います。
[キャッシュ設定前]
[00:11:01]: Resolving Swift Package Manager dependencies... [00:11:01]: $ xcodebuild -resolvePackageDependencies -workspace ./XXXX.xcworkspace -scheme XXXX [00:11:04]: ▸ Command line invocation: [00:11:04]: ▸ /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -resolvePackageDependencies -workspace ./XXXX.xcworkspace -scheme XXXX [00:11:08]: ▸ Resolve Package Graph [00:11:08]: ▸ Fetching https://github.com/kishikawakatsumi/KeychainAccess [00:11:10]: ▸ Fetching https://github.com/onevcat/Kingfisher [00:11:13]: ▸ Fetching https://github.com/ishkawa/APIKit [00:11:14]: ▸ Fetching https://github.com/facebook/facebook-ios-sdk [00:11:19]: ▸ Fetching https://github.com/bannzai/Gedatsu [00:11:25]: ▸ Cloning https://github.com/bannzai/Gedatsu [00:11:25]: ▸ Checking out https://github.com/bannzai/Gedatsu at 1.2.0 [00:11:26]: ▸ Cloning https://github.com/ishkawa/APIKit [00:11:26]: ▸ Checking out https://github.com/ishkawa/APIKit at 5.1.0 [00:11:26]: ▸ Cloning https://github.com/kishikawakatsumi/KeychainAccess [00:11:27]: ▸ Checking out https://github.com/kishikawakatsumi/KeychainAccess at 4.2.1 [00:11:27]: ▸ Cloning https://github.com/onevcat/Kingfisher [00:11:28]: ▸ Checking out https://github.com/onevcat/Kingfisher at 5.15.6 [00:11:28]: ▸ Cloning https://github.com/facebook/facebook-ios-sdk [00:11:29]: ▸ Checking out https://github.com/facebook/facebook-ios-sdk at 7.1.1 [00:11:36]: ▸ Resolved source packages: [00:11:36]: ▸ APIKit: https://github.com/ishkawa/APIKit @ 5.1.0 [00:11:36]: ▸ KeychainAccess: https://github.com/kishikawakatsumi/KeychainAccess @ 4.2.1 [00:11:36]: ▸ Kingfisher: https://github.com/onevcat/Kingfisher @ 5.15.6 [00:11:36]: ▸ Gedatsu: https://github.com/bannzai/Gedatsu @ 1.2.0 [00:11:36]: ▸ Facebook: https://github.com/facebook/facebook-ios-sdk @ 7.1.1 [00:11:36]: ▸ resolved source packages: APIKit, KeychainAccess, Kingfisher, Gedatsu, Facebook
[キャッシュ設定後]
[12:16:13]: Resolving Swift Package Manager dependencies... [12:16:13]: $ xcodebuild -resolvePackageDependencies -workspace ./XXXX.xcworkspace -scheme XXXX -clonedSourcePackagesDirPath ./swift_packages [12:16:17]: ▸ Command line invocation: [12:16:17]: ▸ /Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -resolvePackageDependencies -workspace ./XXXX.xcworkspace -scheme XXXX -clonedSourcePackagesDirPath ./swift_packages [12:16:17]: ▸ User defaults from command line: [12:16:17]: ▸ IDEClonedSourcePackagesDirPathOverride = /Users/vagrant/git/swift_packages [12:16:21]: ▸ Resolve Package Graph [12:16:25]: ▸ Resolved source packages: [12:16:25]: ▸ Facebook: https://github.com/facebook/facebook-ios-sdk @ 7.1.1 [12:16:25]: ▸ KeychainAccess: https://github.com/kishikawakatsumi/KeychainAccess @ 4.2.1 [12:16:25]: ▸ APIKit: https://github.com/ishkawa/APIKit @ 5.1.0 [12:16:25]: ▸ Kingfisher: https://github.com/onevcat/Kingfisher @ 5.15.6 [12:16:25]: ▸ Gedatsu: https://github.com/bannzai/Gedatsu @ 1.2.0 [12:16:25]: ▸ resolved source packages: Facebook, KeychainAccess, APIKit, Kingfisher, Gedatsu
各パッケージ取得のためのGit Cloneがなくなっていることが分かります。
(しかし↑だと、もともと約35sしか処理に時間がかかっていないこともあり、約半分の約12sまで削減されても体感としてはそんなに効果を感じられませんが。。。)
おわりに
以上がBitriseでのSPMパッケージキャッシュ手順でした。
なお、参考にした元の記事ではこれをCircleCIで行っているように、このキャッシュ対象の設定自体はBitriseに寄らずどのCIサービスでも有効です。
是非お試しいただければ。