-
Notifications
You must be signed in to change notification settings - Fork 71
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[CI] sign artifacts for the release (partially implemented) (#172)
- Loading branch information
Showing
1 changed file
with
84 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,12 +3,12 @@ | |
@Library('apm@current') _ | ||
|
||
pipeline { | ||
agent { label 'linux && immutable' } | ||
agent { label 'linux && docker && ubuntu-18.04 && immutable' } | ||
environment { | ||
REPO = 'apm-agent-php' | ||
BASE_DIR = "src/go.elastic.co/apm/${env.REPO}" | ||
NOTIFY_TO = credentials('notify-to') | ||
JOB_GCS_BUCKET = credentials('gcs-bucket') | ||
SLACK_CHANNEL = '#apm-agent-php' | ||
NOTIFY_TO = '[email protected]' | ||
ONLY_DOCS = "false" | ||
} | ||
options { | ||
|
@@ -51,7 +51,7 @@ pipeline { | |
} | ||
failFast false | ||
matrix { | ||
agent { label 'linux && immutable' } | ||
agent { label 'linux && docker && ubuntu-18.04 && immutable' } | ||
options { skipDefaultCheckout() } | ||
axes { | ||
axis { | ||
|
@@ -140,7 +140,8 @@ pipeline { | |
unstash 'generate-for-package-7.4-Dockerfile.alpine' | ||
sh script: "make -C packaging package", label: 'package' | ||
sh script: "make -C packaging info", label: 'package info' | ||
stash includes: 'build/packages/*', name: 'package' | ||
// checksum files are regenerated by the signing component in the internal-ci instance. | ||
stash(includes: 'build/packages/*', name: 'package', excludes: 'build/packages/**/*.sha512') | ||
} | ||
} | ||
} | ||
|
@@ -159,7 +160,7 @@ pipeline { | |
} | ||
failFast false | ||
matrix { | ||
agent { label 'linux && immutable' } | ||
agent { label 'linux && docker && ubuntu-18.04 && immutable' } | ||
options { skipDefaultCheckout() } | ||
axes { | ||
axis { | ||
|
@@ -197,7 +198,7 @@ pipeline { | |
} | ||
matrix { | ||
// TODO: This should be uncommented out when the implementation is in place | ||
// agent { label 'linux && immutable' } | ||
// agent { label 'linux && docker && ubuntu-18.04 && immutable' } | ||
options { skipDefaultCheckout() } | ||
axes { | ||
axis { | ||
|
@@ -245,27 +246,64 @@ pipeline { | |
} | ||
} | ||
} | ||
// This meta-stage happens in the internal-ci instance to be able to sign the artifacts correctly. | ||
stage('Release') { | ||
options { | ||
skipDefaultCheckout() | ||
timeout(time: 12, unit: 'HOURS') | ||
} | ||
when { | ||
beforeAgent true | ||
tag pattern: 'v\\d+.*', comparator: 'REGEXP' | ||
allOf { | ||
tag pattern: 'v\\d+.*', comparator: 'REGEXP' | ||
expression { isInternalCI() } | ||
} | ||
} | ||
agent { label 'linux && docker && ubuntu-18.04 && immutable' } | ||
environment { | ||
BUCKET_NAME = 'internal-ci-artifacts' | ||
BUCKET_SUBFOLDER = "${env.REPO}/${env.TAG_NAME}" | ||
BUCKET_PATH = "gs://${env.BUCKET_NAME}/${env.BUCKET_SUBFOLDER}" | ||
BUCKET_CREDENTIALS = 'internal-ci-gcs-plugin' | ||
SIGNED_ARTIFACTS = 'signed-artifacts' | ||
BUCKET_SUBFOLDER_SIGNED_ARTIFACTS = "${env.BUCKET_SUBFOLDER}/${env.SIGNED_ARTIFACTS}" | ||
BUCKET_SIGNED_ARTIFACTS_PATH = "gs://${env.BUCKET_NAME}/${env.BUCKET_SUBFOLDER_SIGNED_ARTIFACTS}" | ||
} | ||
stages { | ||
stage('Notify') { | ||
options { skipDefaultCheckout() } | ||
steps { | ||
emailext subject: "[${env.REPO}] Release ready to be pushed", to: "${NOTIFY_TO}", | ||
body: "Please go to ${env.BUILD_URL}input to approve or reject within 12 hours.\n Changes: ${env.TAG_NAME}" | ||
script { | ||
def should_continue = input(message: "You are about to release version ${env.TAG_NAME}", | ||
parameters: [ [$class: 'ChoiceParameterDefinition', | ||
name: 'Do you wish to release it?', | ||
choices: ['Yes', 'No']] ]) | ||
env.RELEASE = should_continue.equals('Yes') | ||
notifyStatus(slackStatus: 'warning', subject: "[${env.REPO}] Release ready to be pushed", | ||
body: "Please (<${env.BUILD_URL}input|approve>) it or reject within 12 hours.\n Changes: ${env.TAG_NAME}") | ||
setEnvVar('RELEASE', askAndWait("You are about to release version ${env.TAG_NAME}. Do you wish to release it?")) | ||
} | ||
} | ||
stage('Signing CI') { | ||
when { | ||
beforeAgent true | ||
expression { return env.RELEASE == 'true' } | ||
} | ||
options { skipDefaultCheckout() } | ||
steps { | ||
deleteDir() | ||
unstash 'source' | ||
dir("${BASE_DIR}") { | ||
unstash 'package' | ||
googleStorageUpload(bucket: env.BUCKET_PATH, | ||
credentialsId: env.BUCKET_CREDENTIALS, | ||
pathPrefix: 'build/packages/', | ||
pattern: 'build/packages/**/*', | ||
sharedPublicly: false, | ||
showInline: true) | ||
build(wait: true, propagate: true, job: 'elastic+unified-release+master+sign-artifacts-with-gpg', parameters: [string(name: 'gcs_input_path', value: "${env.BUCKET_PATH}")]) | ||
dir("${SIGNED_ARTIFACTS}") { | ||
googleStorageDownload(bucketUri: "${env.BUCKET_SIGNED_ARTIFACTS_PATH}/*", | ||
credentialsId: env.BUCKET_CREDENTIALS, | ||
localDirectory: 'build/packages/', | ||
pathPrefix: "${env.BUCKET_SUBFOLDER_SIGNED_ARTIFACTS}") | ||
stash allowEmpty: false, name: env.SIGNED_ARTIFACTS, useDefaultExcludes: false | ||
} | ||
archiveArtifacts(allowEmptyArchive: true, artifacts: "${SIGNED_ARTIFACTS}/**/*") | ||
} | ||
} | ||
} | ||
|
@@ -279,15 +317,15 @@ pipeline { | |
deleteDir() | ||
unstash 'source' | ||
dir("${BASE_DIR}") { | ||
unstash 'package' | ||
unstash "${env.SIGNED_ARTIFACTS}" | ||
withCredentials([string(credentialsId: '2a9602aa-ab9f-4e52-baf3-b71ca88469c7', variable: 'GITHUB_TOKEN')]) { | ||
sh script: 'make -f .ci/Makefile release', label: 'release' | ||
} | ||
} | ||
} | ||
post { | ||
success { | ||
emailext subject: "[${env.REPO}] Release published", to: "${env.NOTIFY_TO}", body: "Great news, the release has been done successfully." | ||
notifyStatus(slackStatus: 'good', subject: "[${env.REPO}] Release *${env.TAG_NAME}* published", body: "(<${env.RUN_DISPLAY_URL}|Open>)") | ||
} | ||
always { | ||
script { | ||
|
@@ -297,11 +335,38 @@ pipeline { | |
} | ||
} | ||
} | ||
post { | ||
failure { | ||
notifyStatus(slackStatus: 'danger', subject: "[${env.REPO}] Release *${env.TAG_NAME}* failed", body: "(<${env.RUN_DISPLAY_URL}|Open>)") | ||
} | ||
} | ||
} | ||
} | ||
post { | ||
cleanup { | ||
notifyBuildResult() | ||
// Reporting disables in the `internal-ci` since credentials are not in place | ||
// OTOH it avoids duplicated notifications | ||
whenFalse(isInternalCI()){ | ||
notifyBuildResult() | ||
} | ||
} | ||
} | ||
} | ||
|
||
// TODO: create an input step to avoid this try/catch and return true/false | ||
def askAndWait(message) { | ||
try { | ||
input(message: message, ok: 'Yes') | ||
return true | ||
} catch(err) { | ||
return false | ||
} | ||
} | ||
|
||
def notifyStatus(def args = [:]) { | ||
slackSend(channel: env.SLACK_CHANNEL, color: args.slackStatus, message: "${args.subject}. ${args.body}", | ||
tokenCredentialId: 'jenkins-slack-integration-token') | ||
// transform slack URL format '(<URL|description>)' to 'URL'. | ||
def bodyEmail = args.body.replaceAll('\\(<', '').replaceAll('\\|.*>\\)', '') | ||
emailext(subject: args.subject, to: "${env.NOTIFY_TO}", body: bodyEmail) | ||
} |