Have a single notification about builds.

Signed-off-by: Igor Mandrigin <i@mandrigin.ru>
This commit is contained in:
Igor Mandrigin 2018-08-29 09:43:21 +02:00
parent 906fb8a3e8
commit e508d98316
No known key found for this signature in database
GPG Key ID: 4A0EDDE26E66BC8B
7 changed files with 90 additions and 100 deletions

View File

@ -28,7 +28,8 @@ pipeline {
print "Running ${params.BUILD_TYPE} build!" print "Running ${params.BUILD_TYPE} build!"
/* Necessary to load methods */ /* Necessary to load methods */
mobile = load 'ci/mobile.groovy' mobile = load 'ci/mobile.groovy'
mobile.prep(params.BUILD_TYPE) cmn = load 'ci/common.groovy'
mobile.prep(cmn.getBuildType())
} }
} }
} }
@ -49,7 +50,7 @@ pipeline {
} }
stage('Compile') { stage('Compile') {
steps { steps {
script { apk = mobile.android.compile(params.BUILD_TYPE) } script { apk = mobile.android.compile(cmn.getBuildType()) }
} }
} }
stage('Archive') { stage('Archive') {
@ -60,7 +61,7 @@ pipeline {
stage('Upload') { stage('Upload') {
steps { steps {
script { script {
switch (params.BUILD_TYPE) { switch (cmn.getBuildType()) {
case 'release': case 'release':
mobile.android.uploadToPlayStore(); break; mobile.android.uploadToPlayStore(); break;
case 'nightly': case 'nightly':
@ -72,7 +73,7 @@ pipeline {
} }
} }
stage('Run e2e') { stage('Run e2e') {
when { expression { params.BUILD_TYPE == 'e2e' } } when { expression { cmn.getBuildType() == 'e2e' } }
steps { script { steps { script {
build( build(
job: 'end-to-end-tests/status-app-nightly', wait: false, job: 'end-to-end-tests/status-app-nightly', wait: false,

View File

@ -1,13 +1,6 @@
pipeline { pipeline {
agent { label 'master' } agent { label 'master' }
parameters {
string(
name: 'BUILD_TYPE',
description: 'Values: nightly / e2e / release'
)
}
options { options {
disableConcurrentBuilds() disableConcurrentBuilds()
buildDiscarder(logRotator( buildDiscarder(logRotator(
@ -16,11 +9,15 @@ pipeline {
artifactNumToKeepStr: '10', artifactNumToKeepStr: '10',
)) ))
} }
stages { stages {
stage('Tag') { stage('Prep') {
steps { script { steps { script {
println "Current JOB: ${env.JOB_NAME}"
/* load common lib */
cmn = load('ci/common.groovy') cmn = load('ci/common.groovy')
/* to avoid missing build tag parallel builds */ /* to avoid missing build tag parallel builds */
print "Build Number: ${cmn.tagBuild(true)}" print "Build Number: ${cmn.tagBuild(true)}"
} } } }
@ -28,16 +25,16 @@ pipeline {
stage('Build') { stage('Build') {
parallel { parallel {
stage('MacOS') { steps { script { stage('MacOS') { steps { script {
osx = cmn.buildBranch('status-react/combined/desktop-macos') osx = cmn.buildBranch('status-react/combined/desktop-macos', cmn.getBuildType())
} } } } } }
stage('Linux') { steps { script { stage('Linux') { steps { script {
nix = cmn.buildBranch('status-react/combined/desktop-linux') nix = cmn.buildBranch('status-react/combined/desktop-linux', cmn.getBuildType())
} } } } } }
stage('iOS') { steps { script { stage('iOS') { steps { script {
ios = cmn.buildBranch('status-react/combined/mobile-ios') ios = cmn.buildBranch('status-react/combined/mobile-ios', cmn.getBuildType())
} } } } } }
stage('Android') { steps { script { stage('Android') { steps { script {
dro = cmn.buildBranch('status-react/combined/mobile-android') dro = cmn.buildBranch('status-react/combined/mobile-android', cmn.getBuildType())
} } } } } }
stage('Android e2e') { steps { script { stage('Android e2e') { steps { script {
e2e = cmn.buildBranch('status-react/combined/mobile-android', 'e2e') e2e = cmn.buildBranch('status-react/combined/mobile-android', 'e2e')
@ -55,10 +52,9 @@ pipeline {
} } } }
} }
stage('Upload') { stage('Upload') {
when { expression { params.BUILD_TYPE == 'nightly' } }
steps { script { steps { script {
e2eUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.e2e.apk')[0].path) e2eUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.e2e.apk')[0].path)
apkUrl = cmn.uploadArtifact(findFiles(glob: "pkg/*.${params.BUILD_TYPE}.apk")[0].path) apkUrl = cmn.uploadArtifact(findFiles(glob: "pkg/*.${cmn.getBuildType()}.apk")[0].path)
dmgUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.dmg')[0].path) dmgUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.dmg')[0].path)
appUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.AppImage')[0].path) appUrl = cmn.uploadArtifact(findFiles(glob: 'pkg/*.AppImage')[0].path)
/* special case for iOS Diawi links */ /* special case for iOS Diawi links */
@ -67,15 +63,14 @@ pipeline {
} }
stage('Notify') { stage('Notify') {
steps { script { steps { script {
slackSend( def message = (
message: (
(env.CHANGE_ID != null ? (env.CHANGE_ID != null ?
"Build PR #${BRANCH_NAME}(${CHANGE_BRANCH}) success! " : "Build PR #${BRANCH_NAME}(${CHANGE_BRANCH}) success! " :
"Build ${params.BUILD_TYPE} success! " "Build ${cmn.getBuildType()} success! "
)+ )+
"<${currentBuild.absoluteUrl}|${currentBuild.displayName}> "+ "<${currentBuild.absoluteUrl}|${currentBuild.displayName}> "+
"(${currentBuild.durationString})\n"+ "(${currentBuild.durationString})\n"+
(params.BUILD_TYPE == 'nightly' ? (cmn.getBuildType() == 'nightly' || cmn.getBuildType() == 'pr' ?
"Packages: "+ "Packages: "+
"<${apkUrl}|Android>, "+ "<${apkUrl}|Android>, "+
"(<${e2eUrl}|e2e>), "+ "(<${e2eUrl}|e2e>), "+
@ -86,13 +81,25 @@ pipeline {
"<${dro.getBuildVariables().get('DIAWI_URL')}|Android>, "+ "<${dro.getBuildVariables().get('DIAWI_URL')}|Android>, "+
"<${ios.getBuildVariables().get('DIAWI_URL')}|iOS>" "<${ios.getBuildVariables().get('DIAWI_URL')}|iOS>"
) )
), )
slackSend(
message: message,
color: 'good' color: 'good'
) )
if (env.CHANGE_ID != null) {
cmn.githubNotify(
apkUrl,
e2eUrl,
ipaUrl,
dmgUrl,
appUrl,
env.CHANGE_ID
)
}
} } } }
} }
stage('Publish') { stage('Publish') {
when { expression { params.BUILD_TYPE == 'nightly' } } when { expression { cmn.getBuildType() == 'nightly' } }
steps { steps {
build( build(
job: 'misc/status-im.github.io-update_env', job: 'misc/status-im.github.io-update_env',

View File

@ -32,7 +32,8 @@ pipeline {
print "Running ${params.BUILD_TYPE} build!" print "Running ${params.BUILD_TYPE} build!"
/* Necessary to load methods */ /* Necessary to load methods */
mobile = load 'ci/mobile.groovy' mobile = load 'ci/mobile.groovy'
mobile.prep(params.BUILD_TYPE) cmn = load 'ci/common.groovy'
mobile.prep(cmn.getBuildType())
} }
} }
} }
@ -53,7 +54,7 @@ pipeline {
} }
stage('Compile') { stage('Compile') {
steps { steps {
script { api = mobile.ios.compile(params.BUILD_TYPE) } script { api = mobile.ios.compile(cmn.getBuildType()) }
} }
} }
stage('Archive') { stage('Archive') {

View File

@ -21,6 +21,7 @@ pipeline {
script { script {
/* Necessary to load methods */ /* Necessary to load methods */
desktop = load 'ci/desktop.groovy' desktop = load 'ci/desktop.groovy'
cmn = load 'ci/common.groovy'
desktop.prepDeps() desktop.prepDeps()
} }
} }
@ -37,7 +38,7 @@ pipeline {
} }
stage('Bundle') { stage('Bundle') {
steps { steps {
script { app = desktop.bundleLinux(params.BUILD_TYPE) } script { app = desktop.bundleLinux(cmn.getBuildType()) }
} }
} }
stage('Archive') { stage('Archive') {

View File

@ -21,6 +21,7 @@ pipeline {
script { script {
/* Necessary to load methods */ /* Necessary to load methods */
desktop = load 'ci/desktop.groovy' desktop = load 'ci/desktop.groovy'
cmn = load 'ci/common.groovy'
desktop.prepDeps() desktop.prepDeps()
} }
} }
@ -37,7 +38,7 @@ pipeline {
} }
stage('Bundle') { stage('Bundle') {
steps { steps {
script { dmg = desktop.bundleMacOS(params.BUILD_TYPE) } script { dmg = desktop.bundleMacOS(cmn.getBuildType()) }
} }
} }
stage('Archive') { stage('Archive') {

View File

@ -2,7 +2,25 @@ def version() {
return readFile("${env.WORKSPACE}/VERSION").trim() return readFile("${env.WORKSPACE}/VERSION").trim()
} }
def buildBranch(name = null, buildType = params.BUILD_TYPE) { def getBuildType() {
def jobName = env.JOB_NAME
if (jobName.startsWith('status-react/pull requests')) {
return 'pr'
}
if (jobName.startsWith('status-react/nightly')) {
return 'nightly'
}
if (jobName.startsWith('status-react/release')) {
return 'release'
}
return params.BUILD_TYPE
}
def buildBranch(name = null, buildType) {
/* need to drop origin/ to match definitions of child jobs */ /* need to drop origin/ to match definitions of child jobs */
def branchName = env.GIT_BRANCH.replace('origin/', '') def branchName = env.GIT_BRANCH.replace('origin/', '')
/* always pass the BRANCH and BUILD_TYPE params with current branch */ /* always pass the BRANCH and BUILD_TYPE params with current branch */
@ -104,4 +122,27 @@ def pkgFilename(type, ext) {
return "StatusIm.${timestamp()}.${gitCommit()}.${type}.${ext}" return "StatusIm.${timestamp()}.${gitCommit()}.${type}.${ext}"
} }
def githubNotify(apkUrl, e2eUrl, ipaUrl, dmgUrl, appUrl, changeId) {
withCredentials([string(credentialsId: 'GIT_HUB_TOKEN', variable: 'githubToken')]) {
def message =
"#### :white_check_mark: CI BUILD SUCCESSFUL\\n" +
"Jenkins job: [${currentBuild.displayName}](${currentBuild.absoluteUrl})\\n"+
"##### Mobile\\n" +
"* [Android](${apkUrl}), ([e2e](${e2eUrl}))\\n" +
"* [iOS](${ipaUrl})\\n" +
"##### Desktop\\n" +
"* [MacOS](${dmgUrl})\\n" +
"* [AppImage](${appUrl})"
def script = "curl "+
"-u status-im:${githubToken} " +
"-H 'Content-Type: application/json' " +
"--data '{\"body\": \"${message}\"}' " +
"https://api.github.com/repos/status-im/status-react/issues/${changeId}/comments"
println("running script:\n****\n" + script + "\n****");
def ghOutput = sh(returnStdout: true, script: script)
println("Result of github comment curl: " + ghOutput);
}
}
return this return this

View File

@ -70,40 +70,6 @@ def build_ios_adhoc
end end
def notify_about_new_build(source, url)
branch_name = ENV["BRANCH_NAME"]
branch_name = "develop" if branch_name.nil?
msg = "Branch: " + branch_name + ", "
if source.end_with? ".ipa"
msg = msg + "iOS build uploaded to diawi: " + url
else
msg = msg + "Android build uploaded to diawi: " + url
end
slack(
message: msg,
slack_url: ENV["SLACK_URL"],
default_payloads: []
)
change_id = ENV["CHANGE_ID"]
unless change_id.nil?
github_api(
server_url: "https://api.github.com",
api_token: ENV["GITHUB_TOKEN"],
http_method: "POST",
path: "/repos/status-im/status-react/issues/" + change_id + "/comments",
body: {
"body": msg
}
)
end
end
def upload_to_diawi(source) def upload_to_diawi(source)
diawi( diawi(
token: ENV["DIAWI_TOKEN"], token: ENV["DIAWI_TOKEN"],
@ -113,14 +79,6 @@ def upload_to_diawi(source)
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
def upload_to_diawi_and_notify(source)
upload_to_diawi(source)
notify_about_new_build(
source,
lane_context[SharedValues::UPLOADED_FILE_LINK_TO_DIAWI]
)
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."
@ -132,36 +90,16 @@ platform :ios do
build_ios_adhoc build_ios_adhoc
end end
desc "`fastlane ios nightly` - makes a new nightly in TestFlight" 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
adhoc
end
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 adhoc
match(
type: "appstore",
force_for_new_devices: true,
readonly: true,
keychain_name: "login.keychain"
)
build_ios_app(
scheme: "StatusIm",
workspace: "ios/StatusIm.xcworkspace",
configuration: "Release",
clean: true,
export_method: "app-store",
output_directory: "status_appstore"
)
slack(
message: "New nightly build uploaded to TestFlight",
slack_url: ENV["SLACK_URL"],
default_payloads: []
)
# additional .ipa is for diawi
# we have to re-build it because it uses different config
build_ios_adhoc
end end
desc "`fastlane ios release` builds a release & uploads it to TestFlight" desc "`fastlane ios release` builds a release & uploads it to TestFlight"