ci: fix iOS signing, use same keychain name

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 <jakub@status.im>
Signed-off-by: Andrea Maria Piana <andrea.maria.piana@gmail.com>
This commit is contained in:
Jakub Sokołowski 2020-11-10 00:48:31 +01:00 committed by Andrea Maria Piana
parent dbabcc223e
commit 0b8c673094
No known key found for this signature in database
GPG Key ID: AA6CCA6DE0E06424
7 changed files with 98 additions and 104 deletions

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label 'macos-xcode-11.5' } agent { label 'macos-xcode-11.5' }

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label params.AGENT_LABEL } agent { label params.AGENT_LABEL }

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label 'macos' } agent { label 'macos' }

View File

@ -1,4 +1,4 @@
library 'status-react-jenkins@v1.2.6' library 'status-react-jenkins@v1.2.5'
pipeline { pipeline {
agent { label 'linux' } agent { label 'linux' }

View File

@ -69,36 +69,30 @@ def upload_to_saucelabs(file)
end end
end end
# Helper which acts like a Python context manager # Creates and unlocks a keychain into which Fastlane match imports signing keys and certs.
def with(ctx)
yield ctx.setup
ensure
ctx.teardown
end
# Creates temporary keychain for build duration
class Keychain class Keychain
attr_accessor :name, :path, :pass attr_accessor :name, :pass
def initialize(name) def initialize(name)
# We use epoch time to void clashes with CI builds # Local devs will not have KEYCHAIN_PASSWORD set, and will be prompted for password.
@name = "#{name}_#{Time.now.to_f}.keychain-db" return "login.keychain-db" unless ENV['KEYCHAIN_PASSWORD']
@path = "~/Library/Keychains/#{@name}" # We user the same keychain every time because we need to set a default.
@pass = rand().to_s @name = "#{name}.keychain-db"
@pass = ENV['KEYCHAIN_PASSWORD']
Fastlane::Actions::CreateKeychainAction.run( Fastlane::Actions::CreateKeychainAction.run(
name: @name, name: @name,
password: @pass, password: @pass,
unlock: true, 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. # Lock it up after 25 minutes just in case we don't delete it.
timeout: 1500, lock_when_sleeps: true,
# Setting a default can cause a race condition with parallel jobs. lock_after_timeout: true,
default_keychain: false, timeout: 1500
) )
end end
# for use in with()
def setup; self end
def teardown; Fastlane::Actions::DeleteKeychainAction.run(name: @name) end
end end
# builds an ios app with ad-hoc configuration and put it # 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' scheme = pr_build ? 'StatusImPR' : 'StatusIm'
app_id = pr_build ? 'im.status.ethereum.pr' : 'im.status.ethereum' app_id = pr_build ? 'im.status.ethereum.pr' : 'im.status.ethereum'
with Keychain.new('adhoc') do |kc| kc = Keychain.new('fastlane')
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( match(
scheme: scheme, type: 'adhoc',
workspace: 'ios/StatusIm.xcworkspace', readonly: readonly,
configuration: 'Release', app_identifier: app_id,
clean: true, force_for_new_devices: true,
export_method: 'ad-hoc', keychain_name: kc.name,
output_name: 'StatusIm', keychain_password: kc.pass
output_directory: 'status-ios', )
export_options: {
signingStyle: 'manual', build_ios_app(
provisioningProfiles: { scheme: scheme,
"im.status.ethereum": "match AdHoc im.status.ethereum", workspace: 'ios/StatusIm.xcworkspace',
"im.status.ethereum.pr": "match AdHoc im.status.ethereum.pr" 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 end
# builds an ios app with e2e configuration and put it # builds an ios app with e2e configuration and put it
@ -151,37 +145,37 @@ def build_ios_e2e
showsdks_output = sh('xcodebuild', '-showsdks') showsdks_output = sh('xcodebuild', '-showsdks')
simulator_sdk = showsdks_output.scan(/iphonesimulator\d\d?\.\d\d?/).first simulator_sdk = showsdks_output.scan(/iphonesimulator\d\d?\.\d\d?/).first
with Keychain.new('adhoc') do |kc| kc = Keychain.new('fastlane')
match(
type: 'adhoc',
readonly: true,
force_for_new_devices: true,
keychain_name: kc.name,
keychain_password: kc.pass
)
build_ios_app( match(
# Creating a build for the iOS Simulator type: 'adhoc',
# 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9 readonly: true,
sdk: simulator_sdk, force_for_new_devices: true,
destination: 'generic/platform=iOS Simulator', keychain_name: kc.name,
# 2. fixing compilations issues as stated in https://stackoverflow.com/a/20505258 keychain_password: kc.pass
# 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 build_ios_app(
derived_data_path: 'status-ios', # Creating a build for the iOS Simulator
output_name: 'StatusIm.app', # 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9
# ------------------------------------- sdk: simulator_sdk,
# Normal stuff destination: 'generic/platform=iOS Simulator',
scheme: 'StatusIm', # 2. fixing compilations issues as stated in https://stackoverflow.com/a/20505258
workspace: 'ios/StatusIm.xcworkspace', # it looks like i386 isn't supported by React Native
configuration: 'Release', xcargs: 'ARCHS="x86_64" ONLY_ACTIVE_ARCH=NO',
# Simulator apps can't be archived... # 3. directory where to up StatusIm.app
skip_archive: true, derived_data_path: 'status-ios',
# ...and we don't need an .ipa file for them, because we use .app directly output_name: 'StatusIm.app',
skip_package_ipa: true # -------------------------------------
) # Normal stuff
end 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( zip(
path: 'status-ios/Build/Products/Release-iphonesimulator/StatusIm.app', 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' desc '`fastlane ios release` builds a release & uploads it to TestFlight'
lane :release do lane :release do
with Keychain.new('adhoc') do |kc| kc = Keychain.new('fastlane')
match(
type: 'appstore',
readonly: true,
app_identifier: 'im.status.ethereum',
keychain_name: kc.name,
keychain_password: kc.pass
)
build_ios_app( match(
scheme: 'StatusIm', type: 'appstore',
workspace: 'ios/StatusIm.xcworkspace', readonly: true,
configuration: 'Release', app_identifier: 'im.status.ethereum',
clean: true, keychain_name: kc.name,
export_method: 'app-store', keychain_password: kc.pass
output_directory: 'status-ios', )
include_symbols: false,
export_options: { build_ios_app(
"combileBitcode": true, scheme: 'StatusIm',
"uploadBitcode": false, workspace: 'ios/StatusIm.xcworkspace',
"ITSAppUsesNonExemptEncryption": false configuration: 'Release',
} clean: true,
) export_method: 'app-store',
end output_directory: 'status-ios',
include_symbols: false,
export_options: {
"combileBitcode": true,
"uploadBitcode": false,
"ITSAppUsesNonExemptEncryption": false
}
)
upload_to_testflight( upload_to_testflight(
ipa: 'status-ios/StatusIm.ipa', ipa: 'status-ios/StatusIm.ipa',