【CI/CD】BitriseでDeployGateなiOSをFastlane matchでやってみる
IT技術
(株)ライトコードの笹川(ささがわ)です!
CIシリーズ第2弾です!
引き続き、Bitriseの使い方を紹介します。
前回の記事の宣言通り、今回は「iOS」です。
iOSは、1ビルドあたり10分以内であれば、無料で利用できるのは魅力的ですね!
前回の記事:【CI/CD】BitriseでDeployGateをAndroidでやってみる
早速設定を始めてみましょう
iOSビルドの環境はこちら
- CLIは、fastlane
- 証明書の設定は、Manual
- ビルド時にfastlane matchを利用
- Configrationは、「Debug」「Stage」「Release」の3種類
- 証明書もそれぞれ「Development」「Adhoc」「Appstore」となります。
- Xcodeは、10.2.1
設定してみる
今回は、Fastlane matchを利用したSigningを利用しますので、公式ドキュメント通りには進めません。
とりあえず、fastlaneをworkflowsに設定し、実行したいlaneを設定します。
お察しの通りエラーが発生いたします…
1[14:25:08]: Cloning remote git repo...
2[14:25:08]: If cloning the repo takes too long, you can use the `clone_branch_directly` option in match.
3Cloning into '/var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/d20190528-1491-1suoeby'...
4fatal: could not read Username for 'https://github.com': terminal prompts disabled
5[14:25:08]: Exit status: 128
6[14:25:08]: Error cloning certificates repo, please make sure you have read access to the repository you want to use
7[14:25:08]: Run the following command manually to make sure you're properly authenticated:
8[14:25:08]: $ git clone https://github.com/[match用のリポジトリ].git /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/d20190528-1491-1suoeby
9+------------------+--------------------+
10| Lane Context |
11+------------------+--------------------+
12| DEFAULT_PLATFORM | ios |
13| PLATFORM_NAME | ios |
14| LANE_NAME | ios deploy_develop |
15+------------------+--------------------+
16[14:25:08]: Error cloning certificates git repo, please make sure you have access to the repository - see instructions above
Fastlane match を利用したドキュメントについては、記載が…ない!
公式ドキュメントには下記のように書いてあります。
サードパーティツールをcode signingの管理に利用する場合、そのツールのドキュメントやissueトラッカーを利用してください。
Bitriseでは、こちらで用意したStep(Certificate and profile installer)やtools (codesigndoc)についてのカスタマーサポートは可能ですが、サードパーティツールについてのカスタマーサポートは行なっておりません。
Fastlane matchのエラーを解消する
ここからは、他のCIサービスなども含めて使い方を調査し試行錯誤することにしました。
Fastlane matchを利用する際のパスワードの設定が漏れていました。
こちらは Workflow Editer の Env Vars で MATCH_PASSWORD に対して matchを利用する際のパスワードを設定しておきます。
fastfile や Matchfileなどへの記載は不要です。
設定して、Rebuildします。
match(sync_code_signing)の設定は、これで問題なしです。
gymでのエラーを解消する
matchが成功したあとは、また別のエラーが発生しました。
1[15:00:36]: $ set -o pipefail && xcodebuild -workspace ./JENA_INTERVIEW.xcworkspace -scheme {ProjectFile} -destination 'generic/platform=iOS' -archivePath /Users/vagrant/Library/Developer/Xcode/Archives/2019-05-28/{ProjectFile}\ 2019-05-28\ 15.00.36.xcarchive archive | tee /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/fastlane_logs916760609/gym/{ProjectFile}-{ProjectFile}.log | xcpretty
2[15:00:38]: ▸ --- xcodebuild: WARNING: Using the first of multiple matching destinations:
3[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
4[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
5[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
6[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
7[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
8[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
9[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
10[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
11[15:00:38]: ▸ { platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
12[15:00:42]: ▸ ❌ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}')
13[15:00:42]: ▸ ** ARCHIVE FAILED **
14--- xcodebuild: WARNING: Using the first of multiple matching destinations:
15{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
16{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
17{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
18{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
19{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
20{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
21{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
22{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
23{ platform:iOS, id:dvtdevice-DVTiPhonePlaceholder-iphoneos:placeholder, name:Generic iOS Device }
24❌ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}')
25** ARCHIVE FAILED **
26[15:00:42]: Exit status: 65
27
28~省略~
29
30[15:00:42]: ▸ note: Using new build system
31[15:00:42]: ▸ note: Planning build
32[15:00:42]: ▸ note: Constructing build description
33[15:00:42]: ▸ Build system information
34[15:00:42]: ▸ error: No profile for team '{TeamID}' matching '{Adhoc ProvisioningProfile}' found: Xcode couldn't find any provisioning profiles matching '{TeamID}/{Adhoc ProvisioningProfile}'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor. (in target '{ProjectFile}')
こちらのビルドですが、Developmentの証明書を利用したビルドをする予定で Configration も Debug となっております。
エラー文を見るとDevelopmentの証明書じゃなくて、Adhocの証明書を利用してビルドをしようと失敗しているようです。
指定した証明書を利用するようにlaneの内容を書き換えます。
(変数は、適宜置き換えてください。)
laneの内容を書き換え
1lane :develop_deploy do
2 get_provisioning_profiles(type: "development")
3
4 settings_to_override = {
5 :BUNDLE_IDENTIFIER => ENV["APP_ID"],
6 :PROVISIONING_PROFILE_SPECIFIER => ENV["PROVISIONING_PROFILE_DEVELOPMENT"],
7 :DEVELOPMENT_TEAM => ENV["FASTLANE_TEAM_ID"]
8 }
9
10 gym(
11 scheme: "{schema}",
12 configuration: "Debug",
13 export_method: "development",
14 export_options: {
15 provisioningProfiles: {
16 ENV["APP_ID"] => ENV["PROVISIONING_PROFILE_DEVELOPMENT"]
17 },
18 }
19 )
20end
設定してRebuildします。
これで、gymの設定は問題ないです。
Certificateのエラーを解消する
上記のgymの設定が完了したあとに別のエラーが発生しました。
1[13:57:34]: $ set -o pipefail && xcodebuild -workspace ./{ProjectFile}.xcworkspace -scheme {ProjectFile} -destination 'generic/platform=iOS' -archivePath /Users/vagrant/Library/Developer/Xcode/Archives/2019-06-01/{ProjectFile}\ 2019-06-01\ 13.57.34.xcarchive BUNDLE_IDENTIFIER={Application Id} PROVISIONING_PROFILE_SPECIFIER={Development ProvisioningProfile} DEVELOPMENT_TEAM={Team Id} archive | tee /var/folders/6q/wgy6jtp12w5gzgm9lzcglpqw0000gn/T/fastlane_logs410590617/gym/{ProjectFile}-JENA_INTERVIEW.log | xcpretty
2[13:57:40]: ▸ ❌ error: No signing certificate "iOS Development" found: No "iOS Development" signing certificate matching team ID "{Team id}" with a private key was found. (in target '{ProjectFile}')
3[13:57:40]: ▸ ** ARCHIVE FAILED **
どうやら、Certificateの署名そのものでエラーが発生しているようです。
certificate-and-profile-installer を Workflows に追加します。
「Code Signing タブ」をタップし、「Developer用のCertificate」から「exportしたp12ファイル」をアップロードします。
パスワードは、exportしたときに設定したものを入力してください。
設定してRebuildします。
cocoapodsのエラーを解消する
自動でcocoapodsのバージョンがアップグレードされていました。
そのため、Gemfileでcocoapodsのバージョンを指定するようにしたら、fastlaneでcocoapodsコマンドが失敗するようになってしまいました。
1[16:13:27]: Exit status of command 'bundle exec pod install' was 1 instead of 0.
2bundler: failed to load command: pod (/Users/vagrant/.rbenv/versions/2.5.3/bin/pod)
3Bundler::GemNotFound: Could not find gem 'cocoapods (~> 1.7.0)' in any of the gem sources listed in your Gemfile.
Scriptを追加
こちらに関しては、下記のScriptを追加し対応しました。
1 - script@1.1.5:
2 title: Do anything with Script step
3 inputs:
4 - content: |-
5 #!/usr/bin/env bash
6
7 bundle install --path vendor/bundle --jobs=2
これで、cocoapodsのバージョン指定をしてもエラーが発生しなくなりました。
DeployGateにアップロードする
これでアプリケーションファイル出力のビルドは、問題なく実行できるようになりました。
次に、出力したappファイルをDeployGateで配信できるようにします。
こちらは、Bitriseのworkflowを利用せずにfastlaneで対応します。
laneでの書き方はこちら
1desc "Upload to Deploy Gate"
2lane :upload_deploy_gate do
3 deploygate(
4 api_token: ENV['DEPLOYGATE_API_KEY'],
5 user: ENV['DEPLOYGATE_USER'],
6 message: "{DeploGateの対象ファイルに対するメッセージ}",
7 )
8end
gymコマンドのあとに、こちらを呼び出せばアップロードが行われます。
Deploy to Bitrise.ioで保存されるようにする
DeployGate には、アップロードできるようになりましたが、appファイルとdYSMファイルを別途保管していることが多いのでこちらも設定します。
fastlane で出力先を指定せずにgymを実行すると、プロジェクトルートにファイルが出力されます。
ですから、Artifacts として保存しておきたい場合は、以下のどちらかになります。
- fastlaneで出力したファイルを移動する
- Artifactsとして参照するパスを変更する
Bitriseの仕様としての正解はわかりませんが、Workflow側で細かい設定をすると後に影響しそうでしたので前者で対応することにしました。
Scriptを追加
具体的な方法としては、Workflowのfastlaneの次にScriptを追加します。
1- script@1.1.5:
2 inputs:
3 - content: |-
4 #!/usr/bin/env bash
5 cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa
6 cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip
デフォルトのDeployディレクトリに対してcpコマンドでファイルをコピーしています。
これで無事、Aritfactsにもファイルが保存されるようになりました。
さいごに
Androidの設定をした記事でも述べたように、BitriseではGUIでCI設定ができるのは利点の一つです。
今回のようにfastlane matchを利用した場合に、「どんなエラーが出て」「どんな対応をするか」は探しても見つかりませんでした。
iOSの証明書管理によく利用される fastlane match ですが、実際に採用している人も多いのではないでしょうか。
この記事が誰かの役に立ってくれたら幸いです!
オススメ本
こちらの記事もオススメ!
2020.08.14スマホ技術 特集Android開発Android開発をJavaからKotlinへ変えていくためのお勉強DelegatedPropert...
2020.07.17ライトコード的「やってみた!」シリーズ「やってみた!」を集めました!(株)ライトコードが今まで作ってきた「やってみた!」記事を集めてみました!※作成日が新し...
関連記事
最終的に出来上がったymlファイル
1---
2format_version: '7'
3default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
4project_type: ios
5trigger_map:
6- push_branch: develop
7 workflow: deploy_develop
8- push_branch: stage*
9 workflow: deploy_stage
10- push_branch: release*
11 workflow: deploy_appstore
12workflows:
13 code_sign:
14 steps:
15 - activate-ssh-key@4.0.3:
16 run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
17 - git-clone@4.0.14: {}
18 - cache-pull@2.0.1: {}
19 - certificate-and-profile-installer@1.10.1: {}
20 - script@1.1.5:
21 title: Do anything with Script step
22 inputs:
23 - content: |-
24 #!/usr/bin/env bash
25
26 bundle install --path vendor/bundle --jobs=2
27 after_run: []
28 deploy_develop:
29 steps:
30 - fastlane@2.4.0:
31 inputs:
32 - lane: develop_deploy
33 - script@1.1.5:
34 inputs:
35 - content: |-
36 #!/usr/bin/env bash
37 cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa
38 before_run:
39 - code_sign
40 after_run:
41 - deploy_to_bitrise
42 description: 'Upload to Deploygate of Development build '
43 deploy_appstore:
44 steps:
45 - fastlane@2.4.0:
46 inputs:
47 - lane: appstore_deploy
48 - script@1.1.5:
49 inputs:
50 - content: |-
51 #!/usr/bin/env bash
52 cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa
53 cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip
54 before_run:
55 - code_sign
56 after_run:
57 - deploy_to_bitrise
58 deploy_stage:
59 steps:
60 - fastlane@2.4.0:
61 inputs:
62 - lane: stage_deploy
63 - script@1.1.5:
64 inputs:
65 - content: |-
66 #!/usr/bin/env bash
67 ls $BITRISE_SOURCE_DIR
68 cp $BITRISE_SOURCE_DIR/{App Name}.ipa $BITRISE_DEPLOY_DIR/{App Name}.ipa
69 cp $BITRISE_SOURCE_DIR/{App Name}.app.dSYM.zip $BITRISE_DEPLOY_DIR/{App Name}.app.dSYM.zip
70 before_run:
71 - code_sign
72 after_run:
73 - deploy_to_bitrise
74 deploy_to_bitrise:
75 steps:
76 - deploy-to-bitrise-io@1.4.2: {}
77 - cache-push@2.2.0: {}
78 before_run: []
79app:
80 envs:
81 - opts:
82 is_expand: false
83 BITRISE_PROJECT_PATH: {App Name}.xcworkspace
84 - opts:
85 is_expand: false
86 BITRISE_SCHEME: Debug
87 - opts:
88 is_expand: false
89 BITRISE_EXPORT_METHOD: development
90 - opts:
91 is_expand: false
92 MATCH_PASSWORD: "{MATCH_PASSWORD}"
ライトコードでは、エンジニアを積極採用中!
ライトコードでは、エンジニアを積極採用しています!社長と一杯しながらお話しする機会もご用意しております。そのほかカジュアル面談等もございますので、くわしくは採用情報をご確認ください。
採用情報へ
新潟生まれ新潟育ち本業はモバイルアプリエンジニア。 日々、猫(犬)エンジニアとして活躍中!