create Jenkinsfile.combined and extract build teps

Signed-off-by: Jakub Sokołowski <jakub@status.im>
This commit is contained in:
Jakub Sokołowski 2018-08-14 14:09:52 -04:00
parent 449e5257d5
commit d38f74fdfd
No known key found for this signature in database
GPG Key ID: 4EF064D0E6D63020
13 changed files with 743 additions and 30 deletions

3
.gitignore vendored
View File

@ -113,3 +113,6 @@ fastlane/README.md
/package-lock.json /package-lock.json
/package.json /package.json
/.re-natal /.re-natal
# Jenkins
pkg

72
ci/Jenkinsfile.android Normal file
View File

@ -0,0 +1,72 @@
pipeline {
agent { label 'macos' }
options {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '4',
))
}
environment {
LANG = 'en_US.UTF-8'
LANGUAGE = 'en_US.UTF-8'
LC_ALL = 'en_US.UTF-8'
FASTLANE_DISABLE_COLORS = 1
REALM_DISABLE_ANALYTICS = 1
ANDROID_HOME = '/usr/local/share/android-sdk'
ANDROID_SDK_ROOT = '/usr/local/share/android-sdk'
ANDROID_NDK = '/Users/jenkins/android-ndk-r10e'
ANDROID_NDK_HOME = '/Users/jenkins/android-ndk-r10e'
}
stages {
stage('Prep') {
steps {
script {
/* Necessary to load methods */
mobile = load 'ci/mobile.groovy'
mobile.prepDeps()
}
}
}
stage('Tests') {
steps {
script { mobile.runTests() }
}
}
stage('Build') {
steps {
script { mobile.leinBuild() }
}
}
stage('Compile') {
steps {
script { apk = mobile.compileAndroid(e2e: params.RUN_E2E) }
}
}
stage('Bundle') {
when { expression { !params.RUN_E2E } }
steps {
script { mobile.bundleAndroid() }
}
}
stage('Archive') {
when { expression { !params.RUN_E2E } }
steps {
script { archiveArtifacts apk }
}
}
stage('Run e2e') {
when { expression { params.RUN_E2E } }
steps { script {
apk = mobile.uploadSauceLabs()
build(
job: 'end-to-end-tests/status-app-nightly', wait: false,
parameters: [string(name: 'apk', value: "--apk=${apk}")]
)
} }
}
}
}

115
ci/Jenkinsfile.combined Normal file
View File

@ -0,0 +1,115 @@
pipeline {
agent { label 'master' }
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '10',
))
}
stages {
stage('Tag') {
steps { script {
common = load('ci/common.groovy')
/* to avoid race conditions in parallel builds */
print "Build Number: ${common.tagBuild()}"
} }
}
stage('Build') {
parallel {
stage('MacOS') {
steps { script {
osx = build('status-react/combined/desktop-macos')
} }
}
stage('Linux') {
steps { script {
nix = build('status-react/combined/desktop-linux')
} }
}
stage('iOS') {
steps { script {
ios = build('status-react/combined/mobile-ios')
} }
}
stage('Android') {
steps { script {
dro = build('status-react/combined/mobile-android')
} }
}
stage('Android e2e') {
steps {
build('status-react/combined/mobile-android-e2e')
}
}
}
}
stage('Archive') {
steps {
sh('rm -f pkg/*')
copyArtifacts(
projectName: 'status-react/combined/mobile-ios', target: 'pkg',
flatten: true, selector: specific("${ios.number}")
)
copyArtifacts(
projectName: 'status-react/combined/mobile-android', target: 'pkg',
flatten: true, selector: specific("${dro.number}")
)
copyArtifacts(
projectName: 'status-react/combined/desktop-macos', target: 'pkg',
flatten: true, selector: specific("${osx.number}")
)
copyArtifacts(
projectName: 'status-react/combined/desktop-linux', target: 'pkg',
flatten: true, selector: specific("${nix.number}")
)
archiveArtifacts('pkg/*')
}
}
stage('Upload') {
when { expression { params.PUBLISH } }
steps { script {
def pkg = "pkg/StatusIm-${GIT_COMMIT.take(6)}"
apkUrl = common.uploadArtifact("${pkg}.apk")
ipaUrl = common.uploadArtifact("${pkg}.ipa")
dmgUrl = common.uploadArtifact("${pkg}.dmg")
appUrl = common.uploadArtifact("${pkg}.AppImage")
} }
}
stage('Notify') {
steps {
slackSend(
message: (
"Build success! "+
"<${currentBuild.absoluteUrl}|${currentBuild.displayName}> "+
"(${currentBuild.durationString})\n"+
(params.PUBLISH ?
"APK: ${apkUrl}\n"+
"IPA: ${ipaUrl}\n"+
"DMG: ${dmgUrl}\n"+
"APP: ${appUrl}\n"
: '')
),
color: 'good'
)
}
}
stage('Publish') {
when { expression { params.PUBLISH } }
steps {
build(
job: 'misc/status-im.github.io-update_env',
parameters: [
[name: 'APK_URL', value: apkUrl, $class: 'StringParameterValue'],
[name: 'IOS_URL', value: ipaUrl, $class: 'StringParameterValue'],
[name: 'DMG_URL', value: dmgUrl, $class: 'StringParameterValue'],
[name: 'NIX_URL', value: appUrl, $class: 'StringParameterValue']
]
)
}
}
}
}

65
ci/Jenkinsfile.ios Normal file
View File

@ -0,0 +1,65 @@
pipeline {
agent { label 'fastlane' }
parameters {
booleanParam(
name: 'RUN_E2E',
defaultValue: false,
description: 'If true triggers end-to-end tests.'
)
}
options {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
environment {
LANG = 'en_US.UTF-8'
LANGUAGE = 'en_US.UTF-8'
LC_ALL = 'en_US.UTF-8'
FASTLANE_DISABLE_COLORS=1
REALM_DISABLE_ANALYTICS=1
}
stages {
stage('Prep') {
steps {
script {
/* Necessary to load methods */
mobile = load 'ci/mobile.groovy'
mobile.prepDeps()
}
}
}
stage('Tests') {
steps {
script { mobile.runTests() }
}
}
stage('Build') {
steps {
script { mobile.leinBuild() }
}
}
stage('Compile') {
steps {
script { api = mobile.compileiOS() }
}
}
stage('Archive') {
steps {
script { archiveArtifacts api }
}
}
stage('Upload') {
when { expression { params.RUN_E2E } }
steps {
script { env.DIAWI_URL = uploadiOS() }
}
}
}
}

47
ci/Jenkinsfile.linux Normal file
View File

@ -0,0 +1,47 @@
pipeline {
agent { label 'linux-new' }
options {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
environment {
LANG = 'en_US.UTF-8'
LANGUAGE = 'en_US.UTF-8'
LC_ALL = 'en_US.UTF-8'
}
stages {
stage('Prep') {
steps {
script {
/* Necessary to load methods */
desktop = load 'ci/desktop.groovy'
desktop.prepDeps()
}
}
}
stage('Build') {
steps {
script { desktop.buildClojureScript() }
}
}
stage('Compile') {
steps {
script { desktop.compileLinux() }
}
}
stage('Bundle') {
steps {
script { app = desktop.bundleLinux() }
}
}
stage('Archive') {
steps { archiveArtifacts app }
}
}
}

47
ci/Jenkinsfile.macos Normal file
View File

@ -0,0 +1,47 @@
pipeline {
agent { label 'macos' }
options {
buildDiscarder(logRotator(
numToKeepStr: '10',
daysToKeepStr: '30',
artifactNumToKeepStr: '1',
))
}
environment {
LANG = 'en_US.UTF-8'
LANGUAGE = 'en_US.UTF-8'
LC_ALL = 'en_US.UTF-8'
}
stages {
stage('Prep') {
steps {
script {
/* Necessary to load methods */
desktop = load 'ci/desktop.groovy'
desktop.prepDeps()
}
}
}
stage('Build') {
steps {
script { desktop.buildClojureScript() }
}
}
stage('Compile') {
steps {
script { desktop.compileMacOS() }
}
}
stage('Bundle') {
steps {
script { dmg = desktop.bundleMacOS() }
}
}
stage('Archive') {
steps { archiveArtifacts dmg }
}
}
}

View File

@ -150,7 +150,10 @@ timeout(90) {
} }
stage('Build (Android) for e2e tests') { stage('Build (Android) for e2e tests') {
sh 'cd android && mv app/build/outputs/apk/release/app-release.apk app/build/outputs/apk/release/app-release.original.apk && ENVFILE=.env.e2e ./gradlew assembleRelease' sh 'cd android && \
mv app/build/outputs/apk/release/app-release.apk \
app/build/outputs/apk/release/app-release.original.apk \
&& ENVFILE=.env.e2e ./gradlew assembleRelease'
} }
stage('Upload apk for e2e tests') { stage('Upload apk for e2e tests') {

View File

@ -134,7 +134,8 @@ timeout(90) {
} }
stage('Upload apk for e2e tests') { stage('Upload apk for e2e tests') {
env.SAUCE_LABS_APK = 'im.status.ethereum-e2e-' + shortCommit + '.apk' if (env.CHANGE_ID != null) {
env.SAUCE_LABS_APK = 'im.status.ethereum-e2e-' + env.CHANGE_ID + '.apk'
withCredentials([ withCredentials([
string(credentialsId: 'SAUCE_ACCESS_KEY', variable: 'SAUCE_ACCESS_KEY'), string(credentialsId: 'SAUCE_ACCESS_KEY', variable: 'SAUCE_ACCESS_KEY'),
string(credentialsId: 'SAUCE_USERNAME', variable: 'SAUCE_USERNAME'), string(credentialsId: 'SAUCE_USERNAME', variable: 'SAUCE_USERNAME'),
@ -146,6 +147,7 @@ timeout(90) {
sh 'fastlane android upload_diawi' sh 'fastlane android upload_diawi'
} }
} }
}
stage('Run extended e2e tests') { stage('Run extended e2e tests') {
build job: 'end-to-end-tests/status-app-nightly', parameters: [string(name: 'apk', value: '--apk=' + env.SAUCE_LABS_APK)], wait: false build job: 'end-to-end-tests/status-app-nightly', parameters: [string(name: 'apk', value: '--apk=' + env.SAUCE_LABS_APK)], wait: false

60
ci/common.groovy Normal file
View File

@ -0,0 +1,60 @@
def installJSDeps(platform) {
def attempt = 1
def maxAttempts = 10
def installed = false
/* prepare environment for specific platform build */
sh "scripts/prepare-for-platform.sh ${platform}"
while (!installed && attempt <= maxAttempts) {
println "#${attempt} attempt to install npm deps"
sh 'npm install'
installed = fileExists('node_modules/web3/index.js')
attemp = attempt + 1
}
}
def doGitRebase() {
try {
sh 'git rebase origin/develop'
} catch (e) {
sh 'git rebase --abort'
throw e
}
}
def tagBuild() {
withCredentials([[
$class: 'UsernamePasswordMultiBinding',
credentialsId: 'status-im-auto',
usernameVariable: 'GIT_USER',
passwordVariable: 'GIT_PASS'
]]) {
return sh(
returnStdout: true,
script: './scripts/build_no.sh --increment'
).trim()
}
}
def uploadArtifact(filename) {
def domain = 'ams3.digitaloceanspaces.com'
def bucket = 'status-im-desktop'
withCredentials([usernamePassword(
credentialsId: 'digital-ocean-access-keys',
usernameVariable: 'DO_ACCESS_KEY',
passwordVariable: 'DO_SECRET_KEY'
)]) {
sh """
s3cmd \\
--acl-public \\
--host='${domain}' \\
--host-bucket='%(bucket)s.${domain}' \\
--access_key=${DO_ACCESS_KEY} \\
--secret_key=${DO_SECRET_KEY} \\
put ${filename} s3://${bucket}/
"""
}
def url = "https://${bucket}.${domain}/${filename}"
return url
}
return this

183
ci/desktop.groovy Normal file
View File

@ -0,0 +1,183 @@
common = load 'ci/common.groovy'
qtBin = '/opt/qt59/bin'
packageFolder = './StatusImPackage'
external_modules_dir = [
'node_modules/react-native-i18n/desktop',
'node_modules/react-native-config/desktop',
'node_modules/react-native-fs/desktop',
'node_modules/react-native-http-bridge/desktop',
'node_modules/react-native-webview-bridge/desktop',
'node_modules/react-native-keychain/desktop',
'node_modules/react-native-securerandom/desktop',
'modules/react-native-status/desktop',
]
def cleanupBuild() {
sh """
rm -rf \\
node_modules ${packageFolder} \\
desktop/modules desktop/node_modules
"""
}
def cleanupAndDeps() {
cleanupBuild()
sh 'cp .env.jenkins .env'
sh 'lein deps'
common.installJSDeps('desktop')
}
def slackNotify(message, color = 'good') {
slackSend(
color: color,
channel: '#jenkins-desktop',
message: "develop (${env.CHANGE_BRANCH}) ${message} ${env.BUILD_URL}"
)
}
def buildClojureScript() {
sh 'rm -f index.desktop.js'
sh 'lein prod-build-desktop'
sh "mkdir ${packageFolder}"
sh """
react-native bundle \\
--entry-file index.desktop.js \\
--dev false --platform desktop \\
--bundle-output ${packageFolder}/StatusIm.jsbundle \\
--assets-dest ${packageFolder}/assets
"""
}
def uploadArtifact(filename) {
def domain = 'ams3.digitaloceanspaces.com'
def bucket = 'status-im-desktop'
withCredentials([usernamePassword(
credentialsId: 'digital-ocean-access-keys',
usernameVariable: 'DO_ACCESS_KEY',
passwordVariable: 'DO_SECRET_KEY'
)]) {
sh """
s3cmd \\
--acl-public \\
--host='${domain}' \\
--host-bucket='%(bucket)s.${domain}' \\
--access_key=${DO_ACCESS_KEY} \\
--secret_key=${DO_SECRET_KEY} \\
put ${filename} s3://${bucket}/
"""
}
def url = "https://${bucket}.${domain}/${filename}"
return url
}
/* MAIN --------------------------------------------------*/
def prepDeps() {
common.doGitRebase()
cleanupAndDeps()
}
def compileLinux() {
/* add path for QT installation binaries */
env.PATH = "${qtBin}:${env.PATH}"
dir('desktop') {
sh 'rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile'
sh """
cmake -Wno-dev \\
-DCMAKE_BUILD_TYPE=Release \\
-DEXTERNAL_MODULES_DIR='${external_modules_dir.join(";")}' \\
-DJS_BUNDLE_PATH='${workspace}/${packageFolder}/StatusIm.jsbundle' \\
-DCMAKE_CXX_FLAGS:='-DBUILD_FOR_BUNDLE=1'
"""
sh 'make'
}
}
def bundleLinux() {
def appFile
dir(packageFolder) {
sh 'rm -rf StatusImAppImage'
/* TODO this needs to be fixed: status-react/issues/5378 */
sh 'cp /opt/StatusImAppImage.zip ./'
sh 'unzip ./StatusImAppImage.zip'
sh 'rm -rf AppDir'
sh 'mkdir AppDir'
}
sh "cp -r ./deployment/linux/usr ${packageFolder}/AppDir"
sh "cp ./deployment/linux/.env ${packageFolder}/AppDir"
sh "cp ./desktop/bin/StatusIm ${packageFolder}/AppDir/usr/bin"
sh 'wget https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage'
sh 'chmod a+x ./linuxdeployqt-continuous-x86_64.AppImage'
sh 'rm -f Application-x86_64.AppImage'
sh 'rm -f StatusIm-x86_64.AppImage'
sh "ldd ${packageFolder}/AppDir/usr/bin/StatusIm"
sh """
./linuxdeployqt-continuous-x86_64.AppImage \\
${packageFolder}/AppDir/usr/share/applications/StatusIm.desktop \\
-verbose=3 -always-overwrite -no-strip \\
-no-translations -bundle-non-qt-libs \\
-qmake=${qtBin}/qmake \\
-extra-plugins=imageformats/libqsvg.so \\
-qmldir='${workspace}/node_modules/react-native'
"""
dir(packageFolder) {
sh 'ldd AppDir/usr/bin/StatusIm'
sh 'cp -r assets/share/assets AppDir/usr/bin'
sh 'cp -rf StatusImAppImage/* AppDir/usr/bin'
sh 'rm -f AppDir/usr/bin/StatusIm.AppImage'
}
sh """
./linuxdeployqt-continuous-x86_64.AppImage \\
${packageFolder}/AppDir/usr/share/applications/StatusIm.desktop \\
-verbose=3 -appimage -qmake=${qtBin}/qmake
"""
dir(packageFolder) {
sh 'ldd AppDir/usr/bin/StatusIm'
sh 'rm -rf StatusIm.AppImage'
appFile = "StatusIm-${GIT_COMMIT.take(6)}.AppImage"
sh "mv ../StatusIm-x86_64.AppImage ${appFile}"
}
return "${packageFolder}/${appFile}".drop(2)
}
def compileMacOS() {
/* add path for QT installation binaries */
env.PATH = "/Users/administrator/qt/5.9.1/clang_64/bin:${env.PATH}"
dir('desktop') {
sh 'rm -rf CMakeFiles CMakeCache.txt cmake_install.cmake Makefile'
sh """
cmake -Wno-dev \\
-DCMAKE_BUILD_TYPE=Release \\
-DEXTERNAL_MODULES_DIR='${external_modules_dir.join(";")}' \\
-DJS_BUNDLE_PATH='${workspace}/${packageFolder}/StatusIm.jsbundle' \\
-DCMAKE_CXX_FLAGS:='-DBUILD_FOR_BUNDLE=1'
"""
sh 'make'
}
}
def bundleMacOS() {
def dmgFile
dir(packageFolder) {
sh 'git clone https://github.com/vkjr/StatusAppFiles.git'
sh 'unzip StatusAppFiles/StatusIm.app.zip'
sh 'cp -r assets/share/assets StatusIm.app/Contents/MacOs'
sh 'chmod +x StatusIm.app/Contents/MacOs/ubuntu-server'
sh 'cp ../desktop/bin/StatusIm StatusIm.app/Contents/MacOs'
sh """
macdeployqt StatusIm.app -verbose=1 -dmg \\
-qmldir='${workspace}/node_modules/react-native/ReactQt/runtime/src/qml/'
"""
sh 'rm -fr StatusAppFiles'
dmgFile = "StatusIm-${GIT_COMMIT.take(6)}.dmg"
sh "mv StatusIm.dmg ${dmgFile}"
}
return "${packageFolder}/${dmgFile}".drop(2)
}
return this

102
ci/mobile.groovy Normal file
View File

@ -0,0 +1,102 @@
common = load 'ci/common.groovy'
def uploadArtifact() {
def artifact_dir = pwd() + '/android/app/build/outputs/apk/release/'
println (artifact_dir + 'app-release.apk')
def artifact = (artifact_dir + 'app-release.apk')
def server = Artifactory.server('artifacts')
def filename = "im.status.ethereum-${GIT_COMMIT.take(6)}-n-fl.apk"
def newArtifact = (artifact_dir + filename)
sh "cp ${artifact} ${newArtifact}"
def uploadSpec = '{ "files": [ { "pattern": "*apk/release/' + filename + '", "target": "nightlies-local" }]}'
def buildInfo = server.upload(uploadSpec)
return 'http://artifacts.status.im:8081/artifactory/nightlies-local/' + filename
}
def prepDeps() {
sh 'rm -rf node_modules'
sh 'cp .env.nightly .env'
common.installJSDeps('mobile')
sh 'mvn -f modules/react-native-status/ios/RCTStatus dependency:unpack'
/* generate ios/StatusIm.xcworkspace */
dir('ios') {
sh 'pod install'
}
}
def runTests() {
sh 'lein test-cljs'
}
def leinBuild() {
sh 'lein prod-build'
}
def compileAndroid(e2e = false) {
build_no = common.tagBuild()
if (e2e) {
env.ENVFILE=".env.e2e"
}
dir('android') {
sh './gradlew react-native-android:installArchives'
sh './gradlew assembleRelease'
}
def pkg = "StatusIm-${GIT_COMMIT.take(6)}.apk"
sh "cp android/app/build/outputs/apk/release/app-release.apk ${pkg}"
return pkg
}
def bundleAndroid() {
withCredentials([
string(credentialsId: "SUPPLY_JSON_KEY_DATA", variable: 'GOOGLE_PLAY_JSON_KEY'),
string(credentialsId: "SLACK_URL", variable: 'SLACK_URL')
]) {
sh 'bundle exec fastlane android nightly'
}
}
def uploadSauceLabs() {
env.SAUCE_LABS_APK = "im.status.ethereum-e2e-${GIT_COMMIT.take(6)}.apk"
withCredentials([
string(credentialsId: 'SAUCE_ACCESS_KEY', variable: 'SAUCE_ACCESS_KEY'),
string(credentialsId: 'SAUCE_USERNAME', variable: 'SAUCE_USERNAME'),
string(credentialsId: 'GIT_HUB_TOKEN', variable: 'GITHUB_TOKEN'),
string(credentialsId: 'SLACK_JENKINS_WEBHOOK', variable: 'SLACK_URL')
]) {
sh 'fastlane android saucelabs'
}
return env.SAUCE_LABS_APK
}
def compileiOS() {
version = readFile("${env.WORKSPACE}/VERSION").trim()
build_no = common.tagBuild()
withCredentials([
string(credentialsId: 'SLACK_URL', variable: 'SLACK_URL'),
string(credentialsId: "slave-pass-${env.NODE_NAME}", variable: 'KEYCHAIN_PASSWORD'),
string(credentialsId: 'FASTLANE_PASSWORD', variable: 'FASTLANE_PASSWORD'),
string(credentialsId: 'APPLE_ID', variable: 'APPLE_ID'),
string(credentialsId: 'fastlane-match-password', variable:'MATCH_PASSWORD')
]) {
sh "plutil -replace CFBundleShortVersionString -string ${version} ios/StatusIm/Info.plist"
sh "plutil -replace CFBundleVersion -string ${build_no} ios/StatusIm/Info.plist"
sh 'fastlane ios nightly'
}
def pkg = "StatusIm-${GIT_COMMIT.take(6)}.ipa"
sh "cp status-adhoc/StatusIm.ipa ${pkg}"
return pkg
}
def uploadiOS() {
withCredentials([
string(credentialsId: 'diawi-token', variable: 'DIAWI_TOKEN'),
string(credentialsId: 'GIT_HUB_TOKEN', variable: 'GITHUB_TOKEN'),
string(credentialsId: 'SLACK_JENKINS_WEBHOOK', variable: 'SLACK_URL')
]) {
sh 'fastlane android upload_diawi'
}
diawiUrl = readFile "${env.WORKSPACE}/fastlane/diawi.out"
return diawiUrl
}
return this

View File

@ -156,9 +156,6 @@ platform :ios do
export_method: "app-store", export_method: "app-store",
output_directory: "status_appstore" output_directory: "status_appstore"
) )
upload_to_testflight(
ipa: "status_appstore/StatusIm.ipa"
)
slack( slack(
message: "New nightly build uploaded to TestFlight", message: "New nightly build uploaded to TestFlight",
@ -227,7 +224,6 @@ platform :ios do
) )
end end
desc "This fastlane step is a workaround!" desc "This fastlane step is a workaround!"
desc "every now and then Realm fails on iOS on the 'Download Core` step" desc "every now and then Realm fails on iOS on the 'Download Core` step"
desc "the issue is because multiple downloads use the same temp dir" desc "the issue is because multiple downloads use the same temp dir"
@ -241,6 +237,10 @@ platform :ios do
) )
end end
desc "This fastlane step cleans up XCode DerivedData folder"
lane :cleanup do
clear_derived_data
end
end end

View File

@ -1,7 +1,4 @@
#!/usr/bin/env sh #!/usr/bin/env sh
set -e
# #
# This script manages app build numbers. # This script manages app build numbers.
# It returns the next build number to be used. # It returns the next build number to be used.
@ -21,7 +18,7 @@ set -e
# #
getNumber () { getNumber () {
echo "$BUILD" | sed 's/[^0-9]*//g' echo "$1" | sed 's/[^0-9]*//g'
} }
REGEX='^build-[0-9]\+$' REGEX='^build-[0-9]\+$'
@ -29,16 +26,34 @@ REGEX='^build-[0-9]\+$'
# make sure we have all the tags # make sure we have all the tags
git fetch --tags --quiet >/dev/null || >&2 echo "Could not fetch tags from remote" git fetch --tags --quiet >/dev/null || >&2 echo "Could not fetch tags from remote"
# even if the current commit has a tag already, it is normal that the same commit # check if current commit has a build tag
# is built multiple times (with different build configurations, for instance), # since we are building in separate jobs we have to check for a tag
# so we increment the build number every time. BUILD_TAG=$(git tag --points-at HEAD | grep -e "$REGEX")
# chech for multiple lines
if [ 1 -lt $(echo "$BUILD_TAG" | grep -c -) ]; then
echo "Commit marked with more than one build tag!" >&2
echo "$BUILD_TAG" >&2
exit 1
fi
# use already existing build number if applicable
if [ -n "$BUILD_TAG" ]; then
echo "Current commit already tagged: $BUILD_TAG" >&2
getNumber $BUILD_TAG
exit 0
fi
# if no tag was found and --increment was not given stop
if [ "$1" != "--increment" ]; then
exit 0
fi
# find the last used build number # find the last used build number
BUILD=$(git tag -l --sort=-v:refname | grep -e "$REGEX" | head -n 1) BUILD=$(git tag -l --sort=-v:refname | grep -e "$REGEX" | head -n 1)
# extract the number # extract the number
BUILD_NO=$(getNumber "$BUILD") BUILD_NO=$(getNumber "$BUILD")
if [ "$1" = "--increment" ]; then
# These need to be provided by Jenkins # These need to be provided by Jenkins
if [ -z "${GIT_USER}" ] || [ -z "${GIT_PASS}" ]; then if [ -z "${GIT_USER}" ] || [ -z "${GIT_PASS}" ]; then
echo "Git credentials not specified! (GIT_USER, GIT_PASS)" >&2 echo "Git credentials not specified! (GIT_USER, GIT_PASS)" >&2
@ -50,7 +65,6 @@ if [ "$1" = "--increment" ]; then
echo "Tagging HEAD: build-$BUILD_NO" >&2 echo "Tagging HEAD: build-$BUILD_NO" >&2
git tag "build-$BUILD_NO" HEAD git tag "build-$BUILD_NO" HEAD
git push --tags https://${GIT_USER}:${GIT_PASS}@github.com/status-im/status-react git push --tags https://${GIT_USER}:${GIT_PASS}@github.com/status-im/status-react
fi
# finally print build number # finally print build number
echo "$BUILD_NO" echo "$BUILD_NO"