生成されたXcodeプロジェクト
Help me get started with Tuist. Follow the setup at:
https://tuist.dev/en/docs/guides/get-started/generated-xcode-project
TuistにSwiftマニフェストからXcodeプロジェクトを記述・生成させたい場合は、この手順に従ってください。生成されたプロジェクトは、モジュール化されたXcodeプロジェクトの複雑さを、グラフの簡潔で宣言的な記述に圧縮します。また、モジュールキャッシュと選択的テストには必須の要件です。
以下の各セクションでは、現在不足している点から始まり、そのギャップを埋める機能について説明します。
前提条件#
- XcodeがインストールされたmacOS。
- Tuistコマンドラインインターフェース。
プロジェクトの作成#
動作を確認する最も簡単な方法は、新しいプロジェクトを作成することです。空のディレクトリで tuist init を実行し、生成されたプロジェクトを作成 を選択して、プラットフォームを選び、名前を確認したら、認証を行ってプロジェクトを所有するアカウントを選択してください。
mkdir MyApp && cd MyApp
tuist init
コーディングエージェントやスクリプトから実行する場合は、まず tuist auth login を実行してください(ブラウザでのフローではEnterキーを押すまで待機します)。その後、非インタラクティブな形式を使用します:
tuist init --build-system generated-xcode --name MyApp --platform ios --account <account>
initが完了したら、tuist generate を実行します。Tuistはマニフェストの隣に .xcworkspace を書き込み、Xcodeで開きます。ターゲットをビルドして実行してください。シミュレータでサンプルアプリが起動するはずです。
これで「接続済み+生成中」の状態になります。以下はすべて任意かつ独立した項目です。
既存のアプリを移行する場合は、まず Xcodeプロジェクト移行ガイド を使って接続し、その後戻ってきて、あなたの課題に合うセクションを続けてください。
プロジェクト生成#
.xcodeproj は、アプリの構造をXMLにバンドルします。ファイル参照、ビルドフェーズ、ターゲット依存関係、スキーム、ビルド設定がすべて同じツリー内に存在し、グラフをグラフとして推論するためのプリミティブがありません。プロジェクトが大きくなるにつれて、その構造を頭の中で把握するのが難しくなり、Xcodeにはツールがハッシュを取って変更がない場合に作業をスキップするための安定したハンドルもありません。
生成されたプロジェクトは、グラフを宣言的なSwiftに圧縮します。Project.swift はターゲット、依存関係、リソースを直接記述し、Tuistはその背後でグラフの安定したモデルを維持します。このモデルこそが、以下のセクションを可能にするものです。モジュールキャッシングはこれをハッシュしてバイナリを再利用し、選択的テストはこれをハッシュして入力に変更のないテストをスキップします。
import ProjectDescription
let project = Project(
name: "MyApp",
targets: [
.target(
name: "MyApp",
destinations: .iOS,
product: .app,
bundleId: "dev.tuist.MyApp",
sources: ["MyApp/Sources/**"],
dependencies: []
)
]
)
各 tuist generate は、マニフェストから決定論的なワークスペースを生成します。.xcodeproj と .xcworkspace を .gitignore に追加してください。
モジュールキャッシュ#
モジュール化されたXcodeプロジェクトをゼロからコンパイルするのは、マシンごとのコストです。チームメンバー全員とCIランナーそれぞれが、同じオブジェクトファイルのコピーを各自で作成します。Xcodeのコンパilationキャッシュは内側のループを短縮しますが、すべてのターゲットのマシンごとのビルドを排除することはできず、フレームワーク全体を事前ビルドされたバイナリで置き換えることもできません。
モジュールキャッシュはそれを実現します。グラフ内のキャッシュ可能なすべての依存関係(フレームワーク、ライブラリ、バンドル)を一度ビルドし、結果のバイナリをターゲットの入力のハッシュに対応付けて保存し、後続の生成ではターゲットをそのバイナリに置き換えます。変更のないモジュールはコンパイルされなくなります:
tuist cache
初回実行ではすべてをコンパイルし、バイナリをあなたのアカウントにアップロードします。次の tuist generate では、変更のない依存関係はキャッシュされたバイナリに置き換えられ、Xcodeはソースからコンパイルする代わりに .xcframework に対してリンクします。
選択的テスト#
xcodebuild test は変更がどのテストに影響するかを認識しないため、CIはプッシュごとにスイート全体を実行します。スイートが大きくなるにつれて、実際に実行が必要なものと実行されるもののギャップが、数分から数十分に広がります。
選択的テストは、最後の成功したテスト実行以降に変更があった影響を受けるテストのみを実行します。プロジェクトグラフと、モジュールキャッシュが依存するのと同じハッシュアルゴリズムを使用します:
tuist test
最初の tuist test はすべてを実行し、ターゲットごとのハッシュを永続化します。後続の実行では、入力に変更のないターゲットをスキップします。tuist test をCIで xcodebuild test の代わりに使用するように移せば、フィードバックが数分ではなく数秒で届くようになります。
パッケージレジストリ#
Swift Package Managerは、パッケージがレジストリではなくURLで指定されるため、各パッケージのgit履歴をディープクローンすることで依存関係を解決します。推移的なパッケージが数十あるプロジェクトでは、クリーンなチェックアウトでの解決に数分かかり、それがすべてのCIジョブで繰り返されます。
Tuist Package Registryは、Swift Package Indexが追跡している同じパッケージを提供しますが、本物のレジストリとして機能するため、SwiftPMは実際に必要なコミットのみを取得します。Tuist.swift で registryEnabled: true を設定することで、一度有効にできます:
let tuist = Tuist(
project: .tuist(
generationOptions: .options(
registryEnabled: true
)
)
)
再生成してください。パッケージ解決が数分から数秒に短縮されます。
ビルドインサイト#
Xcodeはログとビルドレポートにターゲットごとのビルド時間を記録します。いずれも実行間やマシン間で集計されないため、ビルド時間の劣化は通常、CI全体の低速化としてのみ表面化します。
ビルドインサイトは、生成されたスキームに対して、すべてのビルドの時間とフェーズのタイミングを自動的に記録します。追加の設定は不要です。次の tuist generate +ビルドサイクル後に、ダッシュボードの ビルド タブを開いてください。
テストインサイト#
Xcodeはテストごとの結果を1回の実行ごとに報告します。実際に必要なクロスランのシグナル、つまり不安定率、週ごとの期間、どのシミュレータバリアントが失敗するかを集計しません。
テストインサイトは、生成されたスキームに対して、すべてのテストの結果と時間を自動的に記録し、実行間の結果を相関付けます。不安定なテスト、遅いテスト、失敗はダッシュボードの テスト タブに表示されます。不安定なテストが蓄積された場合は、ダッシュボードから隔離して、マージをブロックしないようにしてください。
チームを巻き込む#
モジュールキャッシュと選択的テストは、全員が同じ共有面にアクセスしているときに最も効果を発揮します。ダッシュボードのアカウント設定からチームメイトを組織に招待し、シングルサインオン(Google、Okta、Microsoft)を設定して、オンボーディングを一人ひとりの tuist auth login ではなくクリックだけで完了できるようにしてください。