From 45f966b21ba003845be38a8c5674a84613eae18a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Soko=C5=82owski?= Date: Tue, 10 Nov 2020 00:48:31 +0100 Subject: [PATCH] ci: fix iOS signing, use same keychain name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using different temporary keychains does not work if we do not set `default_keychain=true`, because `codesign` then can't find the cert: ``` error: No signing certificate "iOS Distribution" found: No "iOS Distribution" signing certificate matching team ID ``` But if we set `default_keychain=true` then we cause a race condition when the keychain is deleted by a parallel job while another is using it as its default. For this reason we have to use a static keychain name and keep it between builds. I tried disabling `default_keychain=true` in #11378 but it worked only because the default user keychain already had the cert. Signed-off-by: Jakub SokoĊ‚owski Signed-off-by: Andrea Maria Piana --- ci/Jenkinsfile.android | 2 +- ci/Jenkinsfile.combined | 2 +- ci/Jenkinsfile.ios | 2 +- ci/Jenkinsfile.nix-cache | 2 +- ci/tools/Jenkinsfile.fastlane-clean | 2 +- ci/tools/Jenkinsfile.playstore-meta | 2 +- fastlane/Fastfile | 190 ++++++++++++++-------------- 7 files changed, 98 insertions(+), 104 deletions(-) diff --git a/ci/Jenkinsfile.android b/ci/Jenkinsfile.android index a41c8b2814..77ee67f42b 100644 --- a/ci/Jenkinsfile.android +++ b/ci/Jenkinsfile.android @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.combined b/ci/Jenkinsfile.combined index 42bf61044b..59be5cf573 100644 --- a/ci/Jenkinsfile.combined +++ b/ci/Jenkinsfile.combined @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label 'linux' } diff --git a/ci/Jenkinsfile.ios b/ci/Jenkinsfile.ios index 6f41064a97..2d354ac1f7 100644 --- a/ci/Jenkinsfile.ios +++ b/ci/Jenkinsfile.ios @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label 'macos-xcode-11.5' } diff --git a/ci/Jenkinsfile.nix-cache b/ci/Jenkinsfile.nix-cache index accd37511b..62b442bc8e 100644 --- a/ci/Jenkinsfile.nix-cache +++ b/ci/Jenkinsfile.nix-cache @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label params.AGENT_LABEL } diff --git a/ci/tools/Jenkinsfile.fastlane-clean b/ci/tools/Jenkinsfile.fastlane-clean index fbcb4876e7..7dad559c7e 100644 --- a/ci/tools/Jenkinsfile.fastlane-clean +++ b/ci/tools/Jenkinsfile.fastlane-clean @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label 'macos' } diff --git a/ci/tools/Jenkinsfile.playstore-meta b/ci/tools/Jenkinsfile.playstore-meta index 9512a2075c..a3ca213ceb 100644 --- a/ci/tools/Jenkinsfile.playstore-meta +++ b/ci/tools/Jenkinsfile.playstore-meta @@ -1,4 +1,4 @@ -library 'status-react-jenkins@v1.2.6' +library 'status-react-jenkins@v1.2.5' pipeline { agent { label 'linux' } diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a4249ac815..b52f2f3651 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -69,36 +69,30 @@ def upload_to_saucelabs(file) end end -# Helper which acts like a Python context manager -def with(ctx) - yield ctx.setup -ensure - ctx.teardown -end - -# Creates temporary keychain for build duration +# Creates and unlocks a keychain into which Fastlane match imports signing keys and certs. class Keychain - attr_accessor :name, :path, :pass + attr_accessor :name, :pass def initialize(name) - # We use epoch time to void clashes with CI builds - @name = "#{name}_#{Time.now.to_f}.keychain-db" - @path = "~/Library/Keychains/#{@name}" - @pass = rand().to_s + # Local devs will not have KEYCHAIN_PASSWORD set, and will be prompted for password. + return "login.keychain-db" unless ENV['KEYCHAIN_PASSWORD'] + # We user the same keychain every time because we need to set a default. + @name = "#{name}.keychain-db" + @pass = ENV['KEYCHAIN_PASSWORD'] Fastlane::Actions::CreateKeychainAction.run( name: @name, password: @pass, unlock: true, + # Fastlane can't find the signing cert without setting a default. + default_keychain: true, + # Deleting the keychain would cause race condition for parallel jobs. + require_create: false, # Lock it up after 25 minutes just in case we don't delete it. - timeout: 1500, - # Setting a default can cause a race condition with parallel jobs. - default_keychain: false, + lock_when_sleeps: true, + lock_after_timeout: true, + timeout: 1500 ) end - - # for use in with() - def setup; self end - def teardown; Fastlane::Actions::DeleteKeychainAction.run(name: @name) end end # builds an ios app with ad-hoc configuration and put it @@ -115,33 +109,33 @@ def build_ios_adhoc(readonly: false, pr_build: false) scheme = pr_build ? 'StatusImPR' : 'StatusIm' app_id = pr_build ? 'im.status.ethereum.pr' : 'im.status.ethereum' - with Keychain.new('adhoc') do |kc| - match( - type: 'adhoc', - readonly: readonly, - app_identifier: app_id, - force_for_new_devices: true, - keychain_name: kc.name, - keychain_password: kc.pass - ) + kc = Keychain.new('fastlane') - build_ios_app( - scheme: scheme, - workspace: 'ios/StatusIm.xcworkspace', - configuration: 'Release', - clean: true, - export_method: 'ad-hoc', - output_name: 'StatusIm', - output_directory: 'status-ios', - export_options: { - signingStyle: 'manual', - provisioningProfiles: { - "im.status.ethereum": "match AdHoc im.status.ethereum", - "im.status.ethereum.pr": "match AdHoc im.status.ethereum.pr" - } + match( + type: 'adhoc', + readonly: readonly, + app_identifier: app_id, + force_for_new_devices: true, + keychain_name: kc.name, + keychain_password: kc.pass + ) + + build_ios_app( + scheme: scheme, + workspace: 'ios/StatusIm.xcworkspace', + configuration: 'Release', + clean: true, + export_method: 'ad-hoc', + output_name: 'StatusIm', + output_directory: 'status-ios', + export_options: { + signingStyle: 'manual', + provisioningProfiles: { + "im.status.ethereum": "match AdHoc im.status.ethereum", + "im.status.ethereum.pr": "match AdHoc im.status.ethereum.pr" } - ) - end + } + ) end # builds an ios app with e2e configuration and put it @@ -151,37 +145,37 @@ def build_ios_e2e showsdks_output = sh('xcodebuild', '-showsdks') simulator_sdk = showsdks_output.scan(/iphonesimulator\d\d?\.\d\d?/).first - with Keychain.new('adhoc') do |kc| - match( - type: 'adhoc', - readonly: true, - force_for_new_devices: true, - keychain_name: kc.name, - keychain_password: kc.pass - ) + kc = Keychain.new('fastlane') - build_ios_app( - # Creating a build for the iOS Simulator - # 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9 - sdk: simulator_sdk, - destination: 'generic/platform=iOS Simulator', - # 2. fixing compilations issues as stated in https://stackoverflow.com/a/20505258 - # it looks like i386 isn't supported by React Native - xcargs: 'ARCHS="x86_64" ONLY_ACTIVE_ARCH=NO', - # 3. directory where to up StatusIm.app - derived_data_path: 'status-ios', - output_name: 'StatusIm.app', - # ------------------------------------- - # Normal stuff - scheme: 'StatusIm', - workspace: 'ios/StatusIm.xcworkspace', - configuration: 'Release', - # Simulator apps can't be archived... - skip_archive: true, - # ...and we don't need an .ipa file for them, because we use .app directly - skip_package_ipa: true - ) - end + match( + type: 'adhoc', + readonly: true, + force_for_new_devices: true, + keychain_name: kc.name, + keychain_password: kc.pass + ) + + build_ios_app( + # Creating a build for the iOS Simulator + # 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9 + sdk: simulator_sdk, + destination: 'generic/platform=iOS Simulator', + # 2. fixing compilations issues as stated in https://stackoverflow.com/a/20505258 + # it looks like i386 isn't supported by React Native + xcargs: 'ARCHS="x86_64" ONLY_ACTIVE_ARCH=NO', + # 3. directory where to up StatusIm.app + derived_data_path: 'status-ios', + output_name: 'StatusIm.app', + # ------------------------------------- + # Normal stuff + scheme: 'StatusIm', + workspace: 'ios/StatusIm.xcworkspace', + configuration: 'Release', + # Simulator apps can't be archived... + skip_archive: true, + # ...and we don't need an .ipa file for them, because we use .app directly + skip_package_ipa: true + ) zip( path: 'status-ios/Build/Products/Release-iphonesimulator/StatusIm.app', @@ -231,30 +225,30 @@ platform :ios do desc '`fastlane ios release` builds a release & uploads it to TestFlight' lane :release do - with Keychain.new('adhoc') do |kc| - match( - type: 'appstore', - readonly: true, - app_identifier: 'im.status.ethereum', - keychain_name: kc.name, - keychain_password: kc.pass - ) + kc = Keychain.new('fastlane') - build_ios_app( - scheme: 'StatusIm', - workspace: 'ios/StatusIm.xcworkspace', - configuration: 'Release', - clean: true, - export_method: 'app-store', - output_directory: 'status-ios', - include_symbols: false, - export_options: { - "combileBitcode": true, - "uploadBitcode": false, - "ITSAppUsesNonExemptEncryption": false - } - ) - end + match( + type: 'appstore', + readonly: true, + app_identifier: 'im.status.ethereum', + keychain_name: kc.name, + keychain_password: kc.pass + ) + + build_ios_app( + scheme: 'StatusIm', + workspace: 'ios/StatusIm.xcworkspace', + configuration: 'Release', + clean: true, + export_method: 'app-store', + output_directory: 'status-ios', + include_symbols: false, + export_options: { + "combileBitcode": true, + "uploadBitcode": false, + "ITSAppUsesNonExemptEncryption": false + } + ) upload_to_testflight( ipa: 'status-ios/StatusIm.ipa',