Use modern build system for iOS

This commit is contained in:
Pedro Pombeiro 2019-09-21 11:44:03 +02:00
parent f7076016d8
commit 51dd7af5f8
No known key found for this signature in database
GPG Key ID: C4A24185B2AA48A1
4 changed files with 190 additions and 209 deletions

View File

@ -1,13 +1,13 @@
# iOS # iOS
app_identifier("im.status.ethereum") # The bundle identifier of your app app_identifier('im.status.ethereum') # The bundle identifier of your app
apple_id(ENV["FASTLANE_APPLE_ID"]) # Your Apple email address apple_id(ENV['FASTLANE_APPLE_ID']) # Your Apple email address
itc_team_id("118430139") # iTunes Connect Team ID itc_team_id('118430139') # iTunes Connect Team ID
# Android # Android
# json_key_file("") # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one # json_key_file('') # Path to the json secret file - Follow https://docs.fastlane.tools/actions/supply/#setup to get one
package_name("im.status.ethereum") # e.g. com.krausefx.app package_name('im.status.ethereum') # e.g. com.krausefx.app
# For more information about the Appfile, see: # For more information about the Appfile, see:
# https://docs.fastlane.tools/advanced/#appfile # https://docs.fastlane.tools/advanced/#appfile

View File

@ -11,321 +11,302 @@
# There are a few env variables defined in the .env file in # There are a few env variables defined in the .env file in
# this directory (fastlane/.env) # this directory (fastlane/.env)
# unlocks keychain if KEYCHAIN_PASSWORD variable is present # unlocks keychain if KEYCHAIN_PASSWORD variable is present
# (to be used on CI machines) # (to be used on CI machines)
def unlock_keychain_if_needed def unlock_keychain_if_needed
if ENV["KEYCHAIN_PASSWORD"] return unless ENV['KEYCHAIN_PASSWORD']
unlock_keychain(
path:"login.keychain", unlock_keychain(
password:ENV["KEYCHAIN_PASSWORD"], path: 'login.keychain',
set_default: true) password: ENV['KEYCHAIN_PASSWORD'],
end set_default: true
)
end end
def curl_upload(url, file, auth, conn_timeout=5, timeout=60, retries=3) def curl_upload(url, file, auth, conn_timeout = 5, timeout = 60, retries = 3)
rval = sh( rval = sh(
"curl", 'curl',
"--silent", '--silent',
"--user", auth, '--user', auth,
"--write-out", "\nHTTP_CODE:%{http_code}", '--write-out', "\nHTTP_CODE:%{http_code}",
"--request", "POST", '--request', 'POST',
"--header", "Content-Type: application/octet-stream", '--header', 'Content-Type: application/octet-stream',
"--data-binary", "@../#{file}", # `fastlane` is the cwd so we go one folder up # we retry few times if upload doesn't succeed in sensible time
# we retry few times if upload doesn't succeed in sensible time '--retry-connrefused', # consider ECONNREFUSED as error too retry
"--retry-connrefused", # consider ECONNREFUSED as error too retry '--data-binary', "@../#{file}", # `fastlane` is the cwd so we go one folder up
"--connect-timeout", conn_timeout.to_s, # max time in sec. for establishing connection '--connect-timeout', conn_timeout.to_s, # max time in sec. for establishing connection
"--max-time", timeout.to_s, # max time in sec. for whole transfer to take '--max-time', timeout.to_s, # max time in sec. for whole transfer to take
"--retry", retries.to_s, # number of retries to attempt '--retry', retries.to_s, # number of retries to attempt
"--retry-max-time", timeout.to_s, # same as --max-time but for retries '--retry-max-time', timeout.to_s, # same as --max-time but for retries
"--retry-delay", "0", # an exponential backoff algorithm in sec. '--retry-delay', '0', # an exponential backoff algorithm in sec.
url url
) )
# We're not using --fail because it suppresses server response # We're not using --fail because it suppresses server response
if not rval.include? "HTTP_CODE:200" raise "Error:\n#{rval}" unless rval.include? 'HTTP_CODE:200'
raise "Error:\n#{rval}"
end rval
return rval
end end
def retry_curl_upload(url, file, auth, conn_timeout=5, timeout=60, retries=3) def retry_curl_upload(url, file, auth, conn_timeout = 5, timeout = 60, retries = 3)
# since curl doesn't retry on connection and operation timeouts we roll our own # since curl doesn't retry on connection and operation timeouts we roll our own
try = 0 (1..retries).each do |try|
begin begin
return curl_upload(url, file, auth, conn_timeout, timeout, retries) return curl_upload(url, file, auth, conn_timeout, timeout, retries)
rescue => error rescue StandardError => e
try += 1 if try == retries
if try <= retries UI.error "Error:\n#{e}"
UI.important "Warning: Retrying cURL upload! (attempt #{try}/#{retries})" raise
retry end
else UI.important "Warning: Retrying cURL upload! (attempt #{try}/#{retries})"
UI.error "Error:\n#{error}"
raise
end
end end
end
end end
# uploads `file` to sauce labs (overwrites if there is anoter file from the # uploads `file` to sauce labs (overwrites if there is anoter file from the
# same commit) # same commit)
def upload_to_saucelabs(file) def upload_to_saucelabs(file)
key = ENV["SAUCE_ACCESS_KEY"] key = ENV['SAUCE_ACCESS_KEY']
username = ENV["SAUCE_USERNAME"] username = ENV['SAUCE_USERNAME']
unique_name = ENV["SAUCE_LABS_NAME"] unique_name = ENV['SAUCE_LABS_NAME']
url = "https://saucelabs.com/rest/v1/storage/#{username}/#{unique_name}?overwrite=true" url = "https://saucelabs.com/rest/v1/storage/#{username}/#{unique_name}?overwrite=true"
upload_result = retry_curl_upload(url, file, "#{username}:#{key}") upload_result = retry_curl_upload(url, file, "#{username}:#{key}")
# fail the lane if upload fails # fail the lane if upload fails
unless upload_result.include? 'filename'
UI.user_error!( UI.user_error!(
"failed to upload file to saucelabs despite retries: #{upload_result}" "failed to upload file to saucelabs despite retries: #{upload_result}"
) unless upload_result.include? "filename" )
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
# to "status-adhoc" output folder # to "status-adhoc" output folder
# `readonly`: # `readonly`:
# if true - only fetch existing certificates and profiles, don't upgrade from AppStoreConnect # if true - only fetch existing certificates and profiles, don't upgrade from AppStoreConnect
# if false - read list of devices from AppStoreConnect, and upgrade the provisioning profiles from it # if false - read list of devices from AppStoreConnect, and upgrade the provisioning profiles from it
def build_ios_adhoc(readonly) def build_ios_adhoc(readonly)
match( match(
type: "adhoc", type: 'adhoc',
force_for_new_devices: true, force_for_new_devices: true,
readonly: readonly, readonly: readonly,
keychain_name: "login.keychain" keychain_name: 'login.keychain'
) )
build_ios_app( build_ios_app(
scheme: "StatusIm", scheme: 'StatusIm',
workspace: "ios/StatusIm.xcworkspace", workspace: 'ios/StatusIm.xcworkspace',
configuration: "Release", configuration: 'Release',
clean: true, clean: true,
export_method: "ad-hoc", export_method: 'ad-hoc',
# Temporary fix for Xcode 10.1 output_directory: 'status-adhoc'
xcargs: "-UseModernBuildSystem=N", )
output_directory: "status-adhoc",
export_options: {
"UseModernBuildSystem": "N"
}
)
end end
# builds an ios app with e2e configuration and put it # builds an ios app with e2e configuration and put it
# to "status-e2e" output folder # to "status-e2e" output folder
def build_ios_e2e def build_ios_e2e
# determine a simulator SDK installed
showsdks_output = sh('xcodebuild', '-showsdks')
simulator_sdk = showsdks_output.scan(/iphonesimulator\d\d?\.\d\d?/).first
# determine a simulator SDK installed match(
showsdks_output = sh('xcodebuild', '-showsdks') type: 'adhoc',
simulator_sdk = showsdks_output.scan(/iphonesimulator\d\d?\.\d\d?/).first force_for_new_devices: true,
readonly: true,
keychain_name: 'login.keychain'
)
match( build_ios_app(
type: "adhoc", # Creating a build for the iOS Simulator
force_for_new_devices: true, # 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9
readonly: true, sdk: simulator_sdk,
keychain_name: "login.keychain" 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-e2e',
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(
build_ios_app( path: 'status-e2e/Build/Products/Release-iphonesimulator/StatusIm.app',
# Creating a build for the iOS Simulator output_path: 'status-e2e/StatusIm.app.zip',
# 1. https://medium.com/rocket-fuel/fastlane-to-the-simulator-87549b2601b9 verbose: false
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
# UseModernBuildSystem: Temporary fix for Xcode 10.1
xcargs: "ARCHS=\"x86_64\" ONLY_ACTIVE_ARCH=NO -UseModernBuildSystem=N",
# 3. directory where to up StatusIm.app
derived_data_path: "status-e2e",
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,
export_options: {
"UseModernBuildSystem": "N"
}
)
zip(
path: "status-e2e/Build/Products/Release-iphonesimulator/StatusIm.app",
output_path: "status-e2e/StatusIm.app.zip",
verbose: false,
)
end end
def upload_to_diawi(source) def upload_to_diawi(source)
diawi( diawi(
file: source, file: source,
last_hope_attempts_count: 3, last_hope_attempts_count: 3,
token: ENV["DIAWI_TOKEN"] token: ENV['DIAWI_TOKEN']
) )
# save the URL to a file for use in CI # save the URL to a file for use in CI
File.write("diawi.out", lane_context[SharedValues::UPLOADED_FILE_LINK_TO_DIAWI]) File.write('diawi.out', lane_context[SharedValues::UPLOADED_FILE_LINK_TO_DIAWI])
end end
platform :ios do platform :ios do
desc "`fastlane ios adhoc` - ad-hoc lane for iOS." desc '`fastlane ios adhoc` - ad-hoc lane for iOS.'
desc "This lane is used for PRs, Releases, etc." desc 'This lane is used for PRs, Releases, etc.'
desc "It creates an .ipa that can be used by a list of devices, registeded in the App Store Connect." desc 'It creates an .ipa that can be used by a list of devices, registeded in the App Store Connect.'
desc "This .ipa is ready to be distibuted through diawi.com" desc 'This .ipa is ready to be distibuted through diawi.com'
lane :adhoc do lane :adhoc do
unlock_keychain_if_needed unlock_keychain_if_needed
build_ios_adhoc(true) build_ios_adhoc(true)
end end
desc "`fastlane ios e2e` - e2e lane for iOS." desc '`fastlane ios e2e` - e2e lane for iOS.'
desc "This lane is used for SauceLabs end-to-end testing." desc 'This lane is used for SauceLabs end-to-end testing.'
desc "It creates an .app that can be used inside of a iPhone simulator." desc 'It creates an .app that can be used inside of a iPhone simulator.'
lane :e2e do lane :e2e do
unlock_keychain_if_needed unlock_keychain_if_needed
build_ios_e2e build_ios_e2e
end end
desc "`fastlane ios pr` - makes a new pr build" desc '`fastlane ios pr` - makes a new pr build'
desc "This lane builds a new adhoc build and leaves an .ipa that is ad-hoc signed (can be uploaded to diawi)" desc 'This lane builds a new adhoc build and leaves an .ipa that is ad-hoc signed (can be uploaded to diawi)'
lane :pr do lane :pr do
unlock_keychain_if_needed unlock_keychain_if_needed
build_ios_adhoc(false) build_ios_adhoc(false)
end end
desc "`fastlane ios nightly` - makes a new nightly" desc '`fastlane ios nightly` - makes a new nightly'
desc "This lane builds a new nightly and leaves an .ipa that is ad-hoc signed (can be uploaded to diawi)" desc 'This lane builds a new nightly and leaves an .ipa that is ad-hoc signed (can be uploaded to diawi)'
lane :nightly do lane :nightly do
unlock_keychain_if_needed unlock_keychain_if_needed
build_ios_adhoc(false) build_ios_adhoc(false)
end end
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
match( match(
type: "appstore", type: 'appstore',
readonly: true, readonly: true,
keychain_name: "login.keychain" keychain_name: 'login.keychain'
) )
build_ios_app( build_ios_app(
scheme: "StatusIm", scheme: 'StatusIm',
workspace: "ios/StatusIm.xcworkspace", workspace: 'ios/StatusIm.xcworkspace',
configuration: "Release", configuration: 'Release',
clean: true, clean: true,
export_method: "app-store", export_method: 'app-store',
output_directory: "status_appstore", output_directory: 'status_appstore',
include_symbols: false, include_symbols: false,
# Temporary fix for Xcode 10.1 export_options: {
xcargs: "-UseModernBuildSystem=N", "combileBitcode": true,
export_options: { "uploadBitcode": false,
"UseModernBuildSystem": "N", "ITSAppUsesNonExemptEncryption": false
"combileBitcode": true, }
"uploadBitcode": false,
"ITSAppUsesNonExemptEncryption": false
}
) )
upload_to_testflight( upload_to_testflight(
ipa: "status_appstore/StatusIm.ipa" ipa: 'status_appstore/StatusIm.ipa'
) )
end end
desc "`fastlane ios clean` - remove inactive TestFlight users" desc '`fastlane ios clean` - remove inactive TestFlight users'
lane :clean do lane :clean do
clean_testflight_testers( clean_testflight_testers(
username: ENV["FASTLANE_APPLE_ID"], username: ENV['FASTLANE_APPLE_ID'],
days_of_inactivity: 30, days_of_inactivity: 30,
oldest_build_allowed: 2019032709 oldest_build_allowed: 2_019_032_709
) )
end end
desc "`fastlane ios upload-diawi` - upload .ipa to diawi" desc '`fastlane ios upload-diawi` - upload .ipa to diawi'
desc "expects to have an .ipa prepared: `status-adhoc/StatusIm.ipa`" desc 'expects to have an .ipa prepared: `status-adhoc/StatusIm.ipa`'
desc "expects to have a diawi token as DIAWI_TOKEN env variable" desc 'expects to have a diawi token as DIAWI_TOKEN env variable'
desc "expects to have a github token as GITHUB_TOKEN env variable" desc 'expects to have a github token as GITHUB_TOKEN env variable'
desc "will fails if file isn't there" desc "will fails if file isn't there"
desc "---" desc '---'
desc "Output: writes `fastlane/diawi.out` file url of the uploded file" desc 'Output: writes `fastlane/diawi.out` file url of the uploded file'
lane :upload_diawi do lane :upload_diawi do
ipa = ENV["DIAWI_IPA"] || "status-adhoc/StatusIm.ipa" ipa = ENV['DIAWI_IPA'] || 'status-adhoc/StatusIm.ipa'
upload_to_diawi(ipa) upload_to_diawi(ipa)
end end
desc "`fastlane ios saucelabs` - upload .app to sauce labs" desc '`fastlane ios saucelabs` - upload .app to sauce labs'
desc "also notifies in a GitHub comments" desc 'also notifies in a GitHub comments'
desc "expects to have an .apk prepared: `result/app.apk`" desc 'expects to have an .apk prepared: `result/app.apk`'
desc "expects to have a saucelabs access key as SAUCE_ACCESS_KEY env variable" desc 'expects to have a saucelabs access key as SAUCE_ACCESS_KEY env variable'
desc "expects to have a saucelabs username token as SAUCE_USERNAME env variable" desc 'expects to have a saucelabs username token as SAUCE_USERNAME env variable'
desc "expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable" desc 'expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable'
desc "will fails if file isn't there" desc "will fails if file isn't there"
lane :saucelabs do lane :saucelabs do
upload_to_saucelabs( upload_to_saucelabs(
"status-e2e/StatusIm.app.zip" 'status-e2e/StatusIm.app.zip'
) )
end end
desc "This fastlane step cleans up XCode DerivedData folder" desc 'This fastlane step cleans up XCode DerivedData folder'
lane :cleanup do lane :cleanup do
clear_derived_data clear_derived_data
end end
end end
platform :android do platform :android do
# Optional env variables # Optional env variables
APK_PATH = ENV["APK_PATH"] || "result/app.apk" APK_PATH = ENV['APK_PATH'] || 'result/app.apk'
desc "Deploy a new internal build to Google Play" desc 'Deploy a new internal build to Google Play'
desc "expects GOOGLE_PLAY_JSON_KEY environment variable" desc 'expects GOOGLE_PLAY_JSON_KEY environment variable'
lane :nightly do lane :nightly do
upload_to_play_store( upload_to_play_store(
track: "internal", track: 'internal',
apk: APK_PATH, apk: APK_PATH,
json_key_data: ENV["GOOGLE_PLAY_JSON_KEY"] json_key_data: ENV['GOOGLE_PLAY_JSON_KEY']
) )
end end
desc "Deploy a new alpha (public) build to Google Play" desc 'Deploy a new alpha (public) build to Google Play'
desc "expects GOOGLE_PLAY_JSON_KEY environment variable" desc 'expects GOOGLE_PLAY_JSON_KEY environment variable'
lane :release do lane :release do
upload_to_play_store( upload_to_play_store(
track: "alpha", track: 'alpha',
apk: APK_PATH, apk: APK_PATH,
json_key_data: ENV["GOOGLE_PLAY_JSON_KEY"] json_key_data: ENV['GOOGLE_PLAY_JSON_KEY']
) )
end end
desc "Upload metadata to Google Play." desc 'Upload metadata to Google Play.'
desc "Metadata is always updated when builds are uploaded," desc 'Metadata is always updated when builds are uploaded,'
desc "but this action can update metadata without uploading a build." desc 'but this action can update metadata without uploading a build.'
desc "expects GOOGLE_PLAY_JSON_KEY environment variable" desc 'expects GOOGLE_PLAY_JSON_KEY environment variable'
lane :upload_metadata do lane :upload_metadata do
upload_to_play_store( upload_to_play_store(
skip_upload_apk: true, skip_upload_apk: true,
json_key_data: ENV["GOOGLE_PLAY_JSON_KEY"] json_key_data: ENV['GOOGLE_PLAY_JSON_KEY']
) )
end end
desc "`fastlane android upload_diawi` - upload .apk to diawi" desc '`fastlane android upload_diawi` - upload .apk to diawi'
desc "expects to have an .apk prepared: `result/app.apk`" desc 'expects to have an .apk prepared: `result/app.apk`'
desc "expects to have a diawi token as DIAWI_TOKEN env variable" desc 'expects to have a diawi token as DIAWI_TOKEN env variable'
desc "expects to have a github token as GITHUB_TOKEN env variable" desc 'expects to have a github token as GITHUB_TOKEN env variable'
desc "will fails if file isn't there" desc "will fails if file isn't there"
desc "---" desc '---'
desc "Output: writes `fastlane/diawi.out` file url of the uploded file" desc 'Output: writes `fastlane/diawi.out` file url of the uploded file'
lane :upload_diawi do lane :upload_diawi do
upload_to_diawi(APK_PATH) upload_to_diawi(APK_PATH)
end end
desc "`fastlane android saucelabs` - upload .apk to sauce labs" desc '`fastlane android saucelabs` - upload .apk to sauce labs'
desc "expects to have an .apk prepared: `result/app.apk`" desc 'expects to have an .apk prepared: `result/app.apk`'
desc "expects to have a saucelabs access key as SAUCE_ACCESS_KEY env variable" desc 'expects to have a saucelabs access key as SAUCE_ACCESS_KEY env variable'
desc "expects to have a saucelabs username token as SAUCE_USERNAME env variable" desc 'expects to have a saucelabs username token as SAUCE_USERNAME env variable'
desc "expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable" desc 'expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable'
desc "will fails if file isn't there" desc "will fails if file isn't there"
lane :saucelabs do lane :saucelabs do
upload_to_saucelabs(APK_PATH) upload_to_saucelabs(APK_PATH)

View File

@ -1,9 +1,9 @@
source "https://rubygems.org" source 'https://rubygems.org'
gem "fastlane", ">= 2.127.2" gem 'fastlane', '>= 2.127.2'
plugins_path = File.join(File.dirname(__FILE__), 'Pluginfile') plugins_path = File.join(__dir__, 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path) eval_gemfile(plugins_path) if File.exist?(plugins_path)
plugins_path = ENV["FASTLANE_PLUGINFILE_PATH"] plugins_path = ENV['FASTLANE_PLUGINFILE_PATH']
eval_gemfile(plugins_path) if plugins_path eval_gemfile(plugins_path) if plugins_path

View File

@ -1,9 +1,9 @@
git_url("git@github.com:status-im/ios-certificates.git") git_url('git@github.com:status-im/ios-certificates.git')
type("development") # The default type, can be: appstore, adhoc, enterprise or development type('development') # The default type, can be: appstore, adhoc, enterprise or development
# app_identifier(["tools.fastlane.app", "tools.fastlane.app2"]) # app_identifier(['tools.fastlane.app', 'tools.fastlane.app2'])
username(ENV["FASTLANE_APPLE_ID"]) # Your Apple Developer Portal username username(ENV['FASTLANE_APPLE_ID']) # Your Apple Developer Portal username
# For all available options run `fastlane match --help` # For all available options run `fastlane match --help`
# Remove the # in the beginning of the line to enable the other options # Remove the # in the beginning of the line to enable the other options