同じクラウドMacでも、開発者がターミナルから実行した fastlane は成功するのに、CIジョブではgem不足と表示されることがあります。runnerを修正すると、今度はログインシェルが別のRubyを参照する場合もあります。こうした障害の多くはfastlane自体ではなく、システムRuby、バージョンマネージャー、Bundler設定、ジョブ環境の組み合わせによるパスのずれが原因です。解決策はgemを何度もインストールし直すことではなく、Rubyツールチェーン全体をプロジェクトの一部として管理することです。
実際に実行されているRubyを確認する
最初からインストールコマンドを実行してはいけません。ログインシェルとCIジョブのそれぞれで、次の結果を記録します。
command -v ruby
ruby -v
command -v bundle
bundle -v
gem env home
bundle config list
printf '%s
' "$PATH"
特に、ruby と bundle が同じプレフィックス配下にあるかを比較してください。Rubyがバージョンマネージャーのディレクトリにあり、Bundlerがシステムディレクトリにある場合、その後のインストール先が誤ったgemパスになる可能性があります。CIに GEM_HOME、GEM_PATH、BUNDLE_PATH が設定されていないかも確認します。残存している環境変数は、プロジェクト設定を上書きします。
対話型ターミナルで実行できても、自動ジョブが同じ環境を持つとは限りません。CIは、シェルの起動スクリプトが偶然PATHを書き換えることに依存せず、明示的なバージョンファイルとプロジェクト設定から起動する必要があります。
診断用の成果物は1つ作成すれば十分です。ログにはトークン、証明書の内容、環境変数全体を出力しないでください。ほとんどの解決先の問題は、パスとバージョンだけで判断できます。
Ruby、Bundler、fastlaneのバージョンを固定する
リポジトリのルートには .ruby-version、Gemfile、Gemfile.lock をコミットします。Rubyのバージョンには、曖昧な 3.3 ではなく、インストール可能な完全なバージョンを指定する必要があります。まずチームで使用するバージョンを決めてから、次を実行します。
printf '%s
' '3.3.6' > .ruby-version
bundle init
bundle add fastlane --version '~> 2.0'
bundle lock
Gemfile は許容するバージョン範囲を表し、Gemfile.lock は今回解決された正確なバージョンを記録します。CIでビルドのたびに bundle update を実行してはいけません。それではロックファイルによる制約が機能しなくなります。インストール後は、すべてのコマンドをBundler経由で実行します。
bundle exec fastlane --version
bundle exec fastlane ios ci
グローバルな fastlane をショートカットとして使用しないでください。別のRubyから提供されている可能性があるほか、システム更新や手動デバッグの後に内容が変わることもあります。プロジェクトで特定のBundlerバージョンが必要な場合は、Gemfile.lock の BUNDLED WITH セクションからバージョンを読み取り、そのバージョンをインストールしてから bundle install を実行します。
依存関係のインストール先をプロジェクトディレクトリに限定する
プロジェクト単位の設定は、リポジトリに隣接する .bundle/config に書き込みます。ホスト全体に適用されるBundlerのグローバル設定は変更しないでください。
bundle config set --local path vendor/bundle
bundle config set --local clean true
bundle install --jobs 4 --retry 2
通常、vendor/bundle はGitにコミットせず、CIキャッシュで管理します。これによりシステムgemを汚染せず、複数のプロジェクトで異なるバージョンを使用できます。インストール後は、次のチェックで解決経路が完全であることを確認できます。
test -f Gemfile.lock
test "$(ruby -e 'print RUBY_VERSION')" = "$(cat .ruby-version)"
bundle check
bundle exec ruby -e 'require "fastlane"; puts Fastlane::VERSION'
最後のコマンドが失敗しても、すぐにすべてのキャッシュを削除してはいけません。まず bundle config list と bundle env を確認し、ジョブが現在のリポジトリのGemfileを読み込んでいることを確かめます。親ディレクトリのGemfileや、BUNDLE_GEMFILE で指定された別のファイルを参照していないか確認してください。
クリーンな非対話環境を再現する
runnerへ正式に組み込む前に、最小限の環境で一度検証できます。
RUBY_BIN="$(dirname "$(command -v ruby)")"
env -i \
HOME="$HOME" \
PATH="$RUBY_BIN:/usr/bin:/bin:/usr/sbin:/sbin" \
BUNDLE_GEMFILE="$PWD/Gemfile" \
bundle exec fastlane --version
この手順により、個人用のシェル設定だけに記述されたパス、エイリアス、環境変数を事前に検出できます。コマンドが失敗する場合は、CIに個人設定全体を読み込ませるのではなく、runnerの明示的な初期化処理を修正してください。
混在を防ぐキャッシュキーを設計する
ネイティブ拡張を含むgemのキャッシュキーを、Gemfile.lock だけで構成してはいけません。Rubyのバージョン、CPUアーキテクチャ、macOSのメジャーおよびマイナーバージョンが異なると、コンパイル済みファイルを読み込めない場合があります。キャッシュキーには、少なくとも次のフィールドを含めます。
| フィールド | 取得方法 | 目的 |
|---|---|---|
| Rubyバージョン | ruby -e 'print RUBY_VERSION' |
ABIの違いを分離 |
| CPUアーキテクチャ | uname -m |
異なるネイティブコードを区別 |
| macOSバージョン | sw_vers -productVersion |
システムライブラリの違いを回避 |
| ロックファイルのハッシュ | shasum -a 256 Gemfile.lock |
依存関係の変更時に無効化 |
次のように、安定したフィンガープリントを生成できます。
RUBY_VERSION_KEY="$(ruby -e 'print RUBY_VERSION')"
ARCH_KEY="$(uname -m)"
OS_KEY="$(sw_vers -productVersion | cut -d. -f1,2)"
LOCK_KEY="$(shasum -a 256 Gemfile.lock | cut -d' ' -f1)"
printf '%s-%s-%s-%s
' "$RUBY_VERSION_KEY" "$ARCH_KEY" "$OS_KEY" "$LOCK_KEY"
キャッシュを復元した後も、必ず bundle check を実行します。チェックに失敗した場合にのみ bundle install を実行して不足分を補います。「キャッシュの展開に成功した」ことを、依存関係が利用可能である証明として扱ってはいけません。
障害を特定可能にする検証ゲートを設ける
最終的なジョブは、「環境の検証」「依存関係の検証」「業務lane」の3段階で実行します。第1段階でバージョンとパスを確認し、第2段階で bundle check を実行してから、第3段階でfastlaneを呼び出します。いずれかの段階が失敗した場合は直ちに停止し、後続処理で理解しにくいプラグイン不足や定数読み込みエラーとして現れることを防ぎます。
次の項目をマージチェックに追加することを推奨します。
.ruby-versionとrunnerが実際に使用するRubyが完全に一致している。Gemfile.lockがコミットされており、ジョブの実行前後で変更されていない。- fastlaneは
bundle exec経由でのみ呼び出されている。 .bundle/configがプロジェクト単位の依存関係ディレクトリを使用している。- キャッシュキーにRuby、アーキテクチャ、システムバージョン、ロックファイルのハッシュが含まれている。
- ログにはバージョン、パス、検証結果だけを残し、機密性の高い環境変数の値を出力していない。
- runnerとログインシェルが、同じ明示的な初期化ロジックを使用している。
これらの制約を適用すれば、Rubyツールチェーンは「ホストにインストール済みのコマンド群」ではなく、監査可能なビルド入力になります。以後Rubyやfastlaneをアップグレードするときは、バージョンファイルとロックファイルを独立したコミットで更新し、同じ検証手順で変更範囲を確認できます。障害が発生してから、ジョブがどの環境を呼び出したのか推測する必要はありません。
よくある質問
Gemfile.lockを保存してもfastlaneのバージョンが変わるのはなぜですか?
グローバルのfastlaneを直接実行するか、実行前にロックファイルを更新している可能性があります。bundle exec fastlaneを使い、ロックファイルを固定入力として扱います。
vendor/bundleを複数のクラウドMacで共有できますか?
無条件には共有できません。Rubyのバージョン、CPUアーキテクチャ、macOSのメジャー・マイナーバージョン、Gemfile.lockのハッシュをキャッシュキーに含めます。
CIだけ成功して対話シェルで失敗する場合は何を確認しますか?
command -v ruby、ruby -v、bundle config list、環境変数を比較します。PATHやRuby管理ツールの初期化方法が異なるケースが一般的です。
クラウドでMac miniワークフローを継続運用
RunAMac M4、レンタル期間、デプロイ先ノードを選び、開発、ビルド、実験のタスクを専有物理ノードで実行できます。