add an e2e build target for ios
Squashe commits: - add an e2e build target for ios - add correct sdk and destination for simulator - fixup! add correct sdk and destination for simulator - drop xcarchive_path since we are not using it - temporarily bind ios build to macos-03 - Detect installed simulator SDK and use it. - Signed-off-by: Jakub Sokołowski <jakub@status.im> Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
parent
9e75b89d58
commit
a91a799eb5
|
@ -91,6 +91,7 @@ status-go-*.zip
|
|||
ios/Pods
|
||||
ios/StatusIm.xcworkspace
|
||||
.ruby-version
|
||||
status-e2e/
|
||||
|
||||
#python
|
||||
*.pyc
|
||||
|
|
|
@ -26,45 +26,44 @@ pipeline {
|
|||
}
|
||||
stage('Build') {
|
||||
parallel {
|
||||
stage('MacOS') {
|
||||
when { expression { btype != 'release' } }
|
||||
stage('MacOS') { when { expression { btype != 'release' } }
|
||||
steps { script {
|
||||
osx = cmn.buildBranch('status-react/combined/desktop-macos')
|
||||
} } }
|
||||
stage('Linux') {
|
||||
when { expression { btype != 'release' } }
|
||||
stage('Linux') { when { expression { btype != 'release' } }
|
||||
steps { script {
|
||||
nix = cmn.buildBranch('status-react/combined/desktop-linux')
|
||||
} } }
|
||||
stage('Windows') {
|
||||
when { expression { btype != 'release' } }
|
||||
stage('Windows') { when { expression { btype != 'release' } }
|
||||
steps { script {
|
||||
win = cmn.buildBranch('status-react/combined/desktop-windows')
|
||||
} } }
|
||||
stage('iOS') { steps { script {
|
||||
ios = cmn.buildBranch('status-react/combined/mobile-ios')
|
||||
} } }
|
||||
stage('iOS e2e') { steps { script {
|
||||
iose2e = cmn.buildBranch('status-react/combined/mobile-ios', 'e2e')
|
||||
} } }
|
||||
stage('Android') { steps { script {
|
||||
dro = cmn.buildBranch('status-react/combined/mobile-android')
|
||||
apk = cmn.buildBranch('status-react/combined/mobile-android')
|
||||
} } }
|
||||
stage('Android e2e') { steps { script {
|
||||
e2e = cmn.buildBranch('status-react/combined/mobile-android', 'e2e')
|
||||
apke2e = cmn.buildBranch('status-react/combined/mobile-android', 'e2e')
|
||||
} } }
|
||||
}
|
||||
}
|
||||
stage('Archive') {
|
||||
steps { script {
|
||||
sh('rm -f pkg/*')
|
||||
|
||||
if (btype != 'release') {
|
||||
cmn.copyArts('status-react/combined/desktop-macos', osx.number)
|
||||
cmn.copyArts('status-react/combined/desktop-linux', nix.number)
|
||||
cmn.copyArts('status-react/combined/desktop-windows', win.number)
|
||||
}
|
||||
cmn.copyArts('status-react/combined/mobile-ios', ios.number)
|
||||
cmn.copyArts('status-react/combined/mobile-android', dro.number)
|
||||
cmn.copyArts('status-react/combined/mobile-android', e2e.number)
|
||||
cmn.copyArts('status-react/combined/mobile-ios', ios.number)
|
||||
cmn.copyArts('status-react/combined/mobile-ios', iose2e.number)
|
||||
cmn.copyArts('status-react/combined/mobile-android', apk.number)
|
||||
cmn.copyArts('status-react/combined/mobile-android', apke2e.number)
|
||||
dir('pkg') {
|
||||
/* generate sha256 checksums for upload */
|
||||
sh "sha256sum * | tee ${cmn.pkgFilename(btype, 'sha256')}"
|
||||
|
@ -74,7 +73,7 @@ pipeline {
|
|||
}
|
||||
stage('Upload') {
|
||||
steps { script {
|
||||
e2eUrl = cmn.uploadArtifact(cmn.pkgFind('e2e.apk'))
|
||||
apke2eUrl = cmn.uploadArtifact(cmn.pkgFind('e2e.apk'))
|
||||
apkUrl = cmn.uploadArtifact(cmn.pkgFind("${btype}.apk"))
|
||||
if (btype != 'release') {
|
||||
dmgUrl = cmn.uploadArtifact(cmn.pkgFind('dmg'))
|
||||
|
@ -85,18 +84,23 @@ pipeline {
|
|||
appUrl = null
|
||||
exeUrl = null
|
||||
}
|
||||
iose2eUrl = cmn.uploadArtifact(cmn.pkgFind("e2e.app.zip"))
|
||||
/* special case for iOS Diawi links */
|
||||
ipaUrl = ios.getBuildVariables().get('DIAWI_URL')
|
||||
/* upload the sha256 checksums file too */
|
||||
shaUrl = cmn.uploadArtifact(cmn.pkgFind('sha256'))
|
||||
/* add URLs to the build description */
|
||||
cmn.setBuildDesc(
|
||||
Apk: apkUrl, e2e: e2eUrl, iOS: ipaUrl, App: appUrl, Mac: dmgUrl, Win: exeUrl,
|
||||
Apk: apkUrl, Apke2e: apke2eUrl,
|
||||
iOS: ipaUrl, iOSe2e: iose2eUrl,
|
||||
App: appUrl, Mac: dmgUrl, Win: exeUrl,
|
||||
)
|
||||
/* Create latest.json with newest nightly URLs */
|
||||
if (btype == 'nightly') {
|
||||
cmn.updateLatestNightlies(
|
||||
APK: apkUrl, IOS: ipaUrl, APP: appUrl, MAC: dmgUrl, WIN: exeUrl, SHA: shaUrl
|
||||
APK: apkUrl, IOS: ipaUrl,
|
||||
APP: appUrl, MAC: dmgUrl,
|
||||
WIN: exeUrl, SHA: shaUrl
|
||||
)
|
||||
}
|
||||
} }
|
||||
|
@ -105,7 +109,9 @@ pipeline {
|
|||
steps { script {
|
||||
if (env.CHANGE_ID != null) {
|
||||
cmn.githubNotify(
|
||||
apk: apkUrl, e2e: e2eUrl, ipa: ipaUrl, app: appUrl, dmg: dmgUrl, win: exeUrl,
|
||||
apk: apkUrl, apke2e: apke2eUrl,
|
||||
ipa: ipaUrl, iose2e: iose2eUrl,
|
||||
app: appUrl, dmg: dmgUrl, win: exeUrl,
|
||||
)
|
||||
}
|
||||
} }
|
||||
|
@ -130,7 +136,7 @@ pipeline {
|
|||
stage('Run e2e') {
|
||||
when { expression { btype == 'nightly' } }
|
||||
steps { script {
|
||||
e2eApk = e2e.getBuildVariables().get('SAUCE_URL')
|
||||
e2eApk = apke2e.getBuildVariables().get('SAUCE_URL')
|
||||
build(
|
||||
job: 'end-to-end-tests/status-app-nightly', wait: false,
|
||||
parameters: [string(name: 'apk', value: "--apk=${e2eApk}")]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
pipeline {
|
||||
agent { label 'fastlane' }
|
||||
agent { label 'macos' }
|
||||
|
||||
options {
|
||||
timestamps()
|
||||
|
@ -7,8 +7,8 @@ pipeline {
|
|||
timeout(time: 35, unit: 'MINUTES')
|
||||
/* Limit builds retained */
|
||||
buildDiscarder(logRotator(
|
||||
numToKeepStr: '60',
|
||||
daysToKeepStr: '30',
|
||||
numToKeepStr: '90',
|
||||
daysToKeepStr: '60',
|
||||
artifactNumToKeepStr: '60',
|
||||
))
|
||||
}
|
||||
|
@ -66,7 +66,14 @@ pipeline {
|
|||
}
|
||||
stage('Upload') {
|
||||
steps {
|
||||
script { env.DIAWI_URL = mobile.ios.uploadToDiawi() }
|
||||
script {
|
||||
switch (cmn.getBuildType()) {
|
||||
case 'nightly':
|
||||
env.DIAWI_URL = mobile.ios.uploadToDiawi(); break;
|
||||
case 'e2e':
|
||||
env.SAUCE_URL = mobile.ios.uploadToSauceLabs(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,9 +26,9 @@ def uploadToPlayStore(type = 'nightly') {
|
|||
def uploadToSauceLabs() {
|
||||
def changeId = common.getParentRunEnv('CHANGE_ID')
|
||||
if (changeId != null) {
|
||||
env.SAUCE_LABS_APK = "${changeId}.apk"
|
||||
env.SAUCE_LABS_NAME = "${changeId}.apk"
|
||||
} else {
|
||||
env.SAUCE_LABS_APK = "im.status.ethereum-e2e-${GIT_COMMIT.take(6)}.apk"
|
||||
env.SAUCE_LABS_NAME = "im.status.ethereum-e2e-${GIT_COMMIT.take(6)}.apk"
|
||||
}
|
||||
withCredentials([
|
||||
string(credentialsId: 'SAUCE_ACCESS_KEY', variable: 'SAUCE_ACCESS_KEY'),
|
||||
|
@ -36,11 +36,11 @@ def uploadToSauceLabs() {
|
|||
]) {
|
||||
sh 'bundle exec fastlane android saucelabs'
|
||||
}
|
||||
return env.SAUCE_LABS_APK
|
||||
return env.SAUCE_LABS_NAME
|
||||
}
|
||||
|
||||
def uploadToDiawi() {
|
||||
env.SAUCE_LABS_APK = "im.status.ethereum-e2e-${GIT_COMMIT.take(6)}.apk"
|
||||
env.SAUCE_LABS_NAME = "im.status.ethereum-e2e-${GIT_COMMIT.take(6)}.apk"
|
||||
withCredentials([
|
||||
string(credentialsId: 'diawi-token', variable: 'DIAWI_TOKEN'),
|
||||
]) {
|
||||
|
|
|
@ -144,7 +144,7 @@ def githubNotify(Map urls) {
|
|||
message += "CI BUILD SUCCESSFUL in ${currentBuild.durationString} (${GIT_COMMIT})\n"
|
||||
message += '| | | | | |\n'
|
||||
message += '|-|-|-|-|-|\n'
|
||||
message += "| [Android](${urls.apk})([e2e](${urls.e2e})) | [iOS](${urls.ipa}) |"
|
||||
message += "| [Android](${urls.apk}) ([e2e](${urls.apke2e})) | [iOS](${urls.ipa}) ([e2e](${urls.iose2e})) |"
|
||||
if (dmgUrl != null) {
|
||||
message += " [MacOS](${urls.dmg}) | [AppImage](${urls.app}) | [Windows](${urls.win}) |"
|
||||
} else {
|
||||
|
@ -163,7 +163,13 @@ def githubNotify(Map urls) {
|
|||
}
|
||||
|
||||
def pkgFind(glob) {
|
||||
return findFiles(glob: "pkg/*${glob}")[0].path
|
||||
def fullGlob = "pkg/*${glob}"
|
||||
def found = findFiles(glob: fullGlob)
|
||||
if (found.size() == 0) {
|
||||
sh 'ls -l pkg/'
|
||||
error("File not found via glob: ${fullGlob} ${found.size()}")
|
||||
}
|
||||
return found[0].path
|
||||
}
|
||||
|
||||
def setBuildDesc(Map links) {
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
common = load('ci/common.groovy')
|
||||
cmn = load('ci/common.groovy')
|
||||
|
||||
def plutil(name, value) {
|
||||
sh "plutil -replace ${name} -string ${value} ios/StatusIm/Info.plist"
|
||||
}
|
||||
|
||||
def compile(type = 'nightly') {
|
||||
def target = 'nightly'
|
||||
|
||||
if (type == 'release') {
|
||||
target = 'adhoc'
|
||||
def target
|
||||
switch (type) {
|
||||
case 'release': target = 'adhoc'; break;
|
||||
case 'testflight': target = 'release'; break;
|
||||
case 'e2e': target = 'e2e'; break;
|
||||
default: target = 'nightly';
|
||||
}
|
||||
|
||||
if (type == 'testflight') {
|
||||
target = 'release'
|
||||
}
|
||||
|
||||
/* configure build metadata */
|
||||
plutil('CFBundleShortVersionString', common.version())
|
||||
plutil('CFBundleVersion', common.buildNumber())
|
||||
plutil('CFBundleBuildUrl', currentBuild.absoluteUrl)
|
||||
/* the dir might not exist */
|
||||
sh 'mkdir -p status-e2e'
|
||||
/* build the actual app */
|
||||
withCredentials([
|
||||
string(credentialsId: 'SLACK_URL', variable: 'SLACK_URL'),
|
||||
|
@ -29,12 +28,16 @@ def compile(type = 'nightly') {
|
|||
]) {
|
||||
sh "bundle exec fastlane ios ${target}"
|
||||
}
|
||||
if (type != 'testflight') {
|
||||
def pkg = common.pkgFilename(type, 'ipa')
|
||||
/* rename built file for uploads and archivization */
|
||||
def pkg = ''
|
||||
if (type == 'e2e') {
|
||||
pkg = cmn.pkgFilename('e2e', 'app.zip')
|
||||
sh "cp status-e2e/StatusIm.app.zip ${pkg}"
|
||||
} else if (type != 'testflight') {
|
||||
pkg = cmn.pkgFilename(type, 'ipa')
|
||||
sh "cp status-adhoc/StatusIm.ipa ${pkg}"
|
||||
return pkg
|
||||
}
|
||||
return ''
|
||||
return pkg
|
||||
}
|
||||
|
||||
def uploadToDiawi() {
|
||||
|
@ -47,4 +50,20 @@ def uploadToDiawi() {
|
|||
return diawiUrl
|
||||
}
|
||||
|
||||
def uploadToSauceLabs() {
|
||||
def changeId = cmn.getParentRunEnv('CHANGE_ID')
|
||||
if (changeId != null) {
|
||||
env.SAUCE_LABS_NAME = "${changeId}.app.zip"
|
||||
} else {
|
||||
env.SAUCE_LABS_NAME = "im.status.ethereum-e2e-${cmn.gitCommit()}.app.zip"
|
||||
}
|
||||
withCredentials([
|
||||
string(credentialsId: 'SAUCE_ACCESS_KEY', variable: 'SAUCE_ACCESS_KEY'),
|
||||
string(credentialsId: 'SAUCE_USERNAME', variable: 'SAUCE_USERNAME'),
|
||||
]) {
|
||||
sh 'bundle exec fastlane ios saucelabs'
|
||||
}
|
||||
return env.SAUCE_LABS_NAME
|
||||
}
|
||||
|
||||
return this
|
||||
|
|
|
@ -27,7 +27,7 @@ def podUpdate() {
|
|||
try {
|
||||
wait(lockFile)
|
||||
sh "touch ${lockFile}"
|
||||
sh 'pod update --silent'
|
||||
sh 'pod update --silent --no-ansi'
|
||||
} finally {
|
||||
sh "rm ${lockFile}"
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ end
|
|||
# uploads `file` to sauce labs (overwrites if there is anoter file from the
|
||||
# same commit)
|
||||
def upload_to_saucelabs(file)
|
||||
username = ENV["SAUCE_USERNAME"]
|
||||
key = ENV["SAUCE_ACCESS_KEY"]
|
||||
unique_name = ENV["SAUCE_LABS_APK"]
|
||||
username = ENV["SAUCE_USERNAME"]
|
||||
unique_name = ENV["SAUCE_LABS_NAME"]
|
||||
|
||||
url = "https://saucelabs.com/rest/v1/storage/" + username + '/' + unique_name + "?overwrite=true"
|
||||
|
||||
|
@ -71,6 +71,50 @@ def build_ios_adhoc
|
|||
)
|
||||
end
|
||||
|
||||
# builds an ios app with e2e configuration and put it
|
||||
# to "status-e2e" output folder
|
||||
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
|
||||
|
||||
match(
|
||||
type: "adhoc",
|
||||
force_for_new_devices: true,
|
||||
readonly: true,
|
||||
keychain_name: "login.keychain"
|
||||
)
|
||||
|
||||
|
||||
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-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(
|
||||
path: "status-e2e/Build/Products/Release-iphonesimulator/StatusIm.app",
|
||||
output_path: "status-e2e/StatusIm.app.zip",
|
||||
verbose: false,
|
||||
)
|
||||
end
|
||||
|
||||
def upload_to_diawi(source)
|
||||
diawi(
|
||||
|
@ -84,7 +128,7 @@ end
|
|||
|
||||
platform :ios do
|
||||
desc "`fastlane ios adhoc` - ad-hoc lane for iOS."
|
||||
desc "This lane is used 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 "This .ipa is ready to be distibuted through diawi.com"
|
||||
lane :adhoc do
|
||||
|
@ -92,6 +136,14 @@ platform :ios do
|
|||
build_ios_adhoc
|
||||
end
|
||||
|
||||
desc "`fastlane ios e2e` - e2e lane for iOS."
|
||||
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."
|
||||
lane :e2e do
|
||||
unlock_keychain_if_needed
|
||||
build_ios_e2e
|
||||
end
|
||||
|
||||
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)"
|
||||
lane :pr do
|
||||
|
@ -149,6 +201,19 @@ platform :ios do
|
|||
upload_to_diawi("status-adhoc/StatusIm.ipa")
|
||||
end
|
||||
|
||||
desc "`fastlane ios saucelabs` - upload .app to sauce labs"
|
||||
desc "also notifies in a GitHub comments"
|
||||
desc "expects to have an .apk prepared: `android/app/build/outputs/apk/release/app-release.apk`"
|
||||
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 destination name as SAUCE_LABS_NAME env variable"
|
||||
desc "will fails if file isn't there"
|
||||
lane :saucelabs do
|
||||
upload_to_saucelabs(
|
||||
"status-e2e/StatusIm.app.zip"
|
||||
)
|
||||
end
|
||||
|
||||
desc "This fastlane step cleans up XCode DerivedData folder"
|
||||
lane :cleanup do
|
||||
clear_derived_data
|
||||
|
@ -204,7 +269,7 @@ platform :android do
|
|||
desc "expects to have an .apk prepared: `android/app/build/outputs/apk/release/app-release.apk`"
|
||||
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 destination name as SAUCE_LABS_APK env variable"
|
||||
desc "expects to have a saucelabs destination name as SAUCE_LABS_NAME env variable"
|
||||
desc "will fails if file isn't there"
|
||||
lane :saucelabs do
|
||||
upload_to_saucelabs(
|
||||
|
|
Loading…
Reference in New Issue