Azure Devops PipelineでiOSアプリのCIを設定してみた
Azure Devopsが大変優秀だということで、リポジトリ管理からスプリント管理まで全部をこちらにまとめてしまおうという動きがアルバイト先でありました。
それに伴って、今までCircle CI動かしてたパイプラインをAzureのPipelineに移行しました。
その設定の際の知見をまとめたいと思います。
Azure Devopsについて
Azure Devopsでは、アジャイル計画ツールやGitリポジトリのホスティングサービス等、チーム開発に必要なツールがひとつにまとまっていて、それをプロジェクトごとに管理することができます。
チームメンバー5人までなら無料で始めることができるので、最初からお金をかけたくない・少しずつ移行していきたいというチームにもおすすめ。
無料でもプライベートリポジトリは何個でも作ることができますが、Pipelineに関しては並列実行ができない・ビルド時間月1800分までという制限が付きます。
Pipelineの設定
azure-pipelines.yml
をプロジェクトのルートに作成し、その中にパイプラインの処理を書いていきます。
タスクは、画像のようなAzure Devops上のタスク一覧からGUIで追加すると、yamlファイルにコードで起こしてくれます。
ローカルでyamlを編集するのでも良いのですが、Devops上で編集するとインデントのミス等をその場で指摘してもらえるのでとても便利です。
基本的な設定はドキュメントを見てもらうと良いので、私自身が苦戦した所・ややこしいところだけピックアップしてお話します。
躓いたポイント
xcWorkspacePathはオプションだが自分で指定しないといけない
Xcode BuildタスクのxcWorkspacePath
という項目は自身で設定しなくても動くオプション項目です。
そのため最初は、こういうのは設定しなくてもよしなにxcworkspaceを見つけてきてくれるだろうと思ってそのまま動かしたら、何やら違うプロジェクトのxcworkspaceを開こうとして、指定されたSchemaがないと怒られる。
おかしいなと思ってxcWorkspacePath
のデフォルト値を確認すると、**/*.xcodeproj/project.xcworkspace
になっている。
どうやらCarthageのCheckoutフォルダ配下のいずれかのライブラリのxcworkspaceを開こうとしてしまってたみたいですね。
ここをApp名.xcodeproj/project.xcworkspace
にしてあげることで解決しました。
ちなみに、Cocoapodsを使ってるプロジェクトの場合はApp名.xcworkspace
を指定してあげると良いです。
インストール先のPathを指定するとキャッシュがうまくいかない
bundle installする際はいつも --path vendor/bundle
にpath指定でやってたのですが、ここでpathを指定するとキャッシュがうまくいきません。
bundle installすると(Pipeline.Workspace)/.bundle
配下に入るので、そこを参照しに行くようになってるみたいです。
ちなみに、現在このキャッシュタスクはベータ版でキャッシュをクリアする機能がありません。
そのため、設定途中でクリアしたいとなったらバージョン名(v0, v1等)をつけたりしてキャッシュのキーを変えることで対応ができます。
ブランチの指定の仕方がややこしい
指定ブランチへのマージ・PRのオープン等を引き金としてテストを発火させることができるのですが指定するブランチがややこしい(主観)ので注意が要るなと感じました。
trigger:
で指定したブランチは、そのブランチへのpushとマージで発火します。(ここは普通)
pr:
で指定したブランチは、指定したブランチに向けたPRがオープンされたら発火します。(ここがややこしい)
完成形
ざっとiOSアプリのCIに必要な処理を書いた設定ファイルがこちらです。
bundle installはfastlaneを使った処理をあとから追加したくて書いてます。
trigger: - develop pr: - develop - master pool: vmImage: 'macos-latest' variables: MINT_PATH: $(Pipeline.Workspace)/.mint BUNDLE_PATH: $(Pipeline.Workspace)/.bundle stages: - stage: Build jobs: - job: Build steps: - task: CacheBeta@0 inputs: key: v0 | gems | $(Agent.OS) | Gemfile.lock path: $(BUNDLE_PATH) displayName: 'Cache gems' - script: bundle install displayName: Bundle Install - task: CmdLine@2 inputs: script: brew install mint displayName: Mint Install - task: CacheBeta@1 inputs: key: v0 | mint | $(Agent.OS) | Mintfile path: $(MINT_PATH) displayName: Cache Mint - script: mint bootstrap displayName: Tools Install by Mint - task: CmdLine@2 inputs: script: 'sudo xcode-select --switch /Applications/Xcode_11.1.app/Contents/Developer' displayName: Xcode select - task: CmdLine@2 inputs: script: | # 秘密テキストの環境変数が指定できるので、そこに事前に取得したGithubのアクセストークンを設定しておく export GITHUB_ACCESS_TOKEN=$(GITHUB_ACCESS_TOKEN) mint run Carthage carthage bootstrap --no-use-binaries --platform iOS --cache-builds && echo '*** Resolved dependencies:' && cat 'Cartfile.resolved' displayName: Carthage Build - task: CmdLine@2 inputs: # ライブラリを使ってテスト用のモッククラスを作成するためのスクリプト script: mint run SwiftyMocky swiftymocky generate displayName: MockFile Generate - task: Xcode@5 inputs: actions: 'build' configuration: 'Debug' sdk: 'iphonesimulator13.1' xcWorkspacePath: 'App名.xcodeproj/project.xcworkspace' scheme: 'App名' xcodeVersion: 'specifyPath' xcodeDeveloperDir: '/Applications/Xcode_11.1.app' packageApp: false destinationPlatformOption: 'iOS' destinationSimulators: 'iPhone 8' displayName: Xcode Build - task: Xcode@5 inputs: actions: 'test' configuration: 'Debug' sdk: 'iphonesimulator13.1' xcWorkspacePath: 'App名.xcodeproj/project.xcworkspace' scheme: 'App名' xcodeVersion: 'specifyPath' xcodeDeveloperDir: '/Applications/Xcode_11.1.app' packageApp: false destinationPlatformOption: 'iOS' destinationSimulators: 'iPhone 8' displayName: Xcode Test
なお今回は一旦無料の枠の中でやっているので、並列実行処理はありません。
ビルド→テストの処理はこの前リリースされたマルチステージ機能を活かし、ビルド成功時のみテストを実行するという処理に書き換えても良いかなと思います。
まだまだCI初心者なので、間違ってたりアドバイスなどあればコメントおねがいします!