use extendedStage for Builder wrapper

refs DE-338

[canvas-builds-refspec=e12b0f989dc38492981a9f286e079afc70e24cd5]

Change-Id: I1fd2647d5ef6e9cc4714daac0433c29b1939e156
Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/261323
Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com>
QA-Review: Aaron Ogata <aogata@instructure.com>
Product-Review: Aaron Ogata <aogata@instructure.com>
Reviewed-by: Kyle Rosenbaum <krosenbaum@instructure.com>
This commit is contained in:
Aaron Ogata 2021-03-22 14:36:59 -07:00
parent e82364a79c
commit adf58468d1
1 changed files with 340 additions and 341 deletions

681
Jenkinsfile vendored
View File

@ -313,6 +313,7 @@ library "canvas-builds-library@${getCanvasBuildsRefspec()}"
configuration.setUseCommitMessageFlags(env.GERRIT_EVENT_TYPE != 'change-merged')
extendedStage.setAlwaysAllowStages([
'Builder',
'Setup',
'Rebase',
'Build Docker Image',
@ -419,401 +420,399 @@ pipeline {
def rootStages = [:]
rootStages['Builder'] = {
stage('Builder') {
// Use a nospot instance for now to avoid really bad UX. Jenkins currently will
// wait for the current steps to complete (even wait to spin up a node), causing
// extremely long wait times for a restart. Investigation in DE-166 / DE-158.
protectedNode('canvas-docker-nospot', { status -> cleanupFn(status) }, { status -> postFn(status) }) {
buildSummaryReport.extendedStageAndReportIfFailure('Setup') {
extendedStage.withOptions('Builder', rootStages, extendedStage.DISABLE_MEASURE_TIMINGS) {
// Use a nospot instance for now to avoid really bad UX. Jenkins currently will
// wait for the current steps to complete (even wait to spin up a node), causing
// extremely long wait times for a restart. Investigation in DE-166 / DE-158.
protectedNode('canvas-docker-nospot', { status -> cleanupFn(status) }, { status -> postFn(status) }) {
buildSummaryReport.extendedStageAndReportIfFailure('Setup') {
timeout(time: 2) {
echo "Cleaning Workspace From Previous Runs"
sh 'ls -A1 | xargs rm -rf'
sh 'find .'
cleanAndSetup()
def refspecToCheckout = env.GERRIT_PROJECT == "canvas-lms" ? env.GERRIT_REFSPEC : env.CANVAS_LMS_REFSPEC
checkoutRepo("canvas-lms", refspecToCheckout, 100)
if(env.GERRIT_PROJECT != "canvas-lms") {
dir(env.LOCAL_WORKDIR) {
checkoutRepo(GERRIT_PROJECT, env.GERRIT_REFSPEC, 2)
}
// Plugin builds using the dir step above will create this @tmp file, we need to remove it
// https://issues.jenkins.io/browse/JENKINS-52750
sh 'rm -vr gems/plugins/*@tmp'
}
buildParameters += string(name: 'CANVAS_BUILDS_REFSPEC', value: "${env.CANVAS_BUILDS_REFSPEC}")
buildParameters += string(name: 'PATCHSET_TAG', value: "${env.PATCHSET_TAG}")
buildParameters += string(name: 'POSTGRES', value: "${env.POSTGRES}")
buildParameters += string(name: 'RUBY', value: "${env.RUBY}")
// if (currentBuild.projectName.contains("rails-6")) {
// when updating this for future rails versions, change the value back to ${env.CANVAS_RAILSX_Y}
buildParameters += string(name: 'CANVAS_RAILS6_0', value: "1")
// }
// If modifying any of our Jenkinsfiles set JENKINSFILE_REFSPEC for sub-builds to use Jenkinsfiles in
// the gerrit rather than master.
if(env.GERRIT_PROJECT == 'canvas-lms' && git.changedFiles(jenkinsFiles, 'HEAD^') ) {
buildParameters += string(name: 'JENKINSFILE_REFSPEC', value: "${env.GERRIT_REFSPEC}")
}
if (env.GERRIT_PROJECT != "canvas-lms") {
// the plugin builds require the canvas lms refspec to be different. so only
// set this refspec if the main build is requesting it to be set.
// NOTE: this is only being set in main-from-plugin build. so main-canvas wont run this.
buildParameters += string(name: 'CANVAS_LMS_REFSPEC', value: env.CANVAS_LMS_REFSPEC)
}
gems = configuration.plugins()
echo "Plugin list: ${gems}"
def pluginsToPull = []
gems.each {
if (env.GERRIT_PROJECT != it) {
pluginsToPull.add([name: it, version: getPluginVersion(it), target: "gems/plugins/$it"])
}
}
pluginsToPull.add([name: 'qti_migration_tool', version: getPluginVersion('qti_migration_tool'), target: "vendor/qti_migration_tool"])
pullRepos(pluginsToPull)
libraryScript.load('bash/docker-tag-remote.sh', './build/new-jenkins/docker-tag-remote.sh')
}
}
if(!configuration.isChangeMerged() && env.GERRIT_PROJECT == 'canvas-lms' && !configuration.skipRebase()) {
buildSummaryReport.extendedStageAndReportIfFailure('Rebase') {
timeout(time: 2) {
echo "Cleaning Workspace From Previous Runs"
sh 'ls -A1 | xargs rm -rf'
sh 'find .'
cleanAndSetup()
def refspecToCheckout = env.GERRIT_PROJECT == "canvas-lms" ? env.GERRIT_REFSPEC : env.CANVAS_LMS_REFSPEC
checkoutRepo("canvas-lms", refspecToCheckout, 100)
if(env.GERRIT_PROJECT != "canvas-lms") {
dir(env.LOCAL_WORKDIR) {
checkoutRepo(GERRIT_PROJECT, env.GERRIT_REFSPEC, 2)
}
// Plugin builds using the dir step above will create this @tmp file, we need to remove it
// https://issues.jenkins.io/browse/JENKINS-52750
sh 'rm -vr gems/plugins/*@tmp'
rebaseHelper(GERRIT_BRANCH)
if ( GERRIT_BRANCH ==~ /dev\/.*/ ) {
rebaseHelper("master")
}
buildParameters += string(name: 'CANVAS_BUILDS_REFSPEC', value: "${env.CANVAS_BUILDS_REFSPEC}")
buildParameters += string(name: 'PATCHSET_TAG', value: "${env.PATCHSET_TAG}")
buildParameters += string(name: 'POSTGRES', value: "${env.POSTGRES}")
buildParameters += string(name: 'RUBY', value: "${env.RUBY}")
// if (currentBuild.projectName.contains("rails-6")) {
// when updating this for future rails versions, change the value back to ${env.CANVAS_RAILSX_Y}
buildParameters += string(name: 'CANVAS_RAILS6_0', value: "1")
// }
// If modifying any of our Jenkinsfiles set JENKINSFILE_REFSPEC for sub-builds to use Jenkinsfiles in
// the gerrit rather than master.
if(env.GERRIT_PROJECT == 'canvas-lms' && git.changedFiles(jenkinsFiles, 'HEAD^') ) {
buildParameters += string(name: 'JENKINSFILE_REFSPEC', value: "${env.GERRIT_REFSPEC}")
}
if (env.GERRIT_PROJECT != "canvas-lms") {
// the plugin builds require the canvas lms refspec to be different. so only
// set this refspec if the main build is requesting it to be set.
// NOTE: this is only being set in main-from-plugin build. so main-canvas wont run this.
buildParameters += string(name: 'CANVAS_LMS_REFSPEC', value: env.CANVAS_LMS_REFSPEC)
}
gems = configuration.plugins()
echo "Plugin list: ${gems}"
def pluginsToPull = []
gems.each {
if (env.GERRIT_PROJECT != it) {
pluginsToPull.add([name: it, version: getPluginVersion(it), target: "gems/plugins/$it"])
}
}
pluginsToPull.add([name: 'qti_migration_tool', version: getPluginVersion('qti_migration_tool'), target: "vendor/qti_migration_tool"])
pullRepos(pluginsToPull)
libraryScript.load('bash/docker-tag-remote.sh', './build/new-jenkins/docker-tag-remote.sh')
}
}
if(!configuration.isChangeMerged() && env.GERRIT_PROJECT == 'canvas-lms' && !configuration.skipRebase()) {
buildSummaryReport.extendedStageAndReportIfFailure('Rebase') {
timeout(time: 2) {
rebaseHelper(GERRIT_BRANCH)
if ( GERRIT_BRANCH ==~ /dev\/.*/ ) {
rebaseHelper("master")
}
if(!env.JOB_NAME.endsWith('Jenkinsfile') && git.changedFiles(jenkinsFiles, 'origin/master')) {
error "Jenkinsfile has been updated. Please retrigger your patchset for the latest updates."
}
if(!env.JOB_NAME.endsWith('Jenkinsfile') && git.changedFiles(jenkinsFiles, 'origin/master')) {
error "Jenkinsfile has been updated. Please retrigger your patchset for the latest updates."
}
}
}
}
if (configuration.isChangeMerged()) {
buildSummaryReport.extendedStageAndReportIfFailure('Build Docker Image (Pre-Merge)') {
timeout(time: 20) {
credentials.withStarlordCredentials {
withEnv([
"CACHE_LOAD_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"CACHE_LOAD_FALLBACK_SCOPE=${env.IMAGE_CACHE_BUILD_SCOPE}",
"CACHE_SAVE_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"COMPILE_ADDITIONAL_ASSETS=0",
"JS_BUILD_NO_UGLIFY=1",
"RAILS_LOAD_ALL_LOCALES=0",
"RUBY_RUNNER_PREFIX=${env.RUBY_RUNNER_PREFIX}",
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_CACHE_PREFIX=${env.WEBPACK_CACHE_PREFIX}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
]) {
slackSendCacheBuild {
try {
sh "build/new-jenkins/docker-build.sh"
} catch(e) {
handleDockerBuildFailure("$PATCHSET_TAG-pre-merge-failed", e)
}
if (configuration.isChangeMerged()) {
buildSummaryReport.extendedStageAndReportIfFailure('Build Docker Image (Pre-Merge)') {
timeout(time: 20) {
credentials.withStarlordCredentials {
withEnv([
"CACHE_LOAD_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"CACHE_LOAD_FALLBACK_SCOPE=${env.IMAGE_CACHE_BUILD_SCOPE}",
"CACHE_SAVE_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"COMPILE_ADDITIONAL_ASSETS=0",
"JS_BUILD_NO_UGLIFY=1",
"RAILS_LOAD_ALL_LOCALES=0",
"RUBY_RUNNER_PREFIX=${env.RUBY_RUNNER_PREFIX}",
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_CACHE_PREFIX=${env.WEBPACK_CACHE_PREFIX}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
]) {
slackSendCacheBuild {
try {
sh "build/new-jenkins/docker-build.sh"
} catch(e) {
handleDockerBuildFailure("$PATCHSET_TAG-pre-merge-failed", e)
}
}
// We need to attempt to upload all prefixes here in case instructure/ruby-passenger
// has changed between the post-merge build and this pre-merge build.
sh(script: """
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_BUILDER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $YARN_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $RUBY_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_CACHE_PREFIX
""", label: 'upload cache images')
// We need to attempt to upload all prefixes here in case instructure/ruby-passenger
// has changed between the post-merge build and this pre-merge build.
sh(script: """
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_BUILDER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $YARN_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $RUBY_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_CACHE_PREFIX
""", label: 'upload cache images')
}
}
}
}
}
buildSummaryReport.extendedStageAndReportIfFailure('Build Docker Image') {
timeout(time: 20) {
credentials.withStarlordCredentials {
def cacheScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : env.IMAGE_CACHE_BUILD_SCOPE
slackSendCacheBuild {
withEnv([
"CACHE_LOAD_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"CACHE_LOAD_FALLBACK_SCOPE=${env.IMAGE_CACHE_BUILD_SCOPE}",
"CACHE_SAVE_SCOPE=${cacheScope}",
"CACHE_UNIQUE_SCOPE=${env.IMAGE_CACHE_UNIQUE_SCOPE}",
"COMPILE_ADDITIONAL_ASSETS=${configuration.isChangeMerged() ? 1 : 0}",
"JS_BUILD_NO_UGLIFY=${configuration.isChangeMerged() ? 0 : 1}",
"RAILS_LOAD_ALL_LOCALES=${getRailsLoadAllLocales()}",
"RUBY_RUNNER_PREFIX=${env.RUBY_RUNNER_PREFIX}",
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_CACHE_PREFIX=${env.WEBPACK_CACHE_PREFIX}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
]) {
try {
sh "build/new-jenkins/docker-build.sh $PATCHSET_TAG"
} catch(e) {
handleDockerBuildFailure(PATCHSET_TAG, e)
}
}
}
sh "./build/new-jenkins/docker-with-flakey-network-protection.sh push $PATCHSET_TAG"
if(configuration.isChangeMerged()) {
def GIT_REV = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
sh "docker tag \$PATCHSET_TAG \$BUILD_IMAGE:${GIT_REV}"
sh "./build/new-jenkins/docker-with-flakey-network-protection.sh push \$BUILD_IMAGE:${GIT_REV}"
}
sh(script: """
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_BUILDER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $YARN_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $RUBY_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_CACHE_PREFIX
""", label: 'upload cache images')
if (isPatchsetPublishable()) {
sh 'docker tag $PATCHSET_TAG $EXTERNAL_TAG'
sh './build/new-jenkins/docker-with-flakey-network-protection.sh push $EXTERNAL_TAG'
}
}
}
}
buildSummaryReport.extendedStageAndReportIfFailure('Run Migrations') {
timeout(time: 10) {
credentials.withStarlordCredentials {
def cacheLoadScope = configuration.isChangeMerged() || configuration.getBoolean('skip-cache') ? '' : env.IMAGE_CACHE_MERGE_SCOPE
def cacheSaveScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : ''
withEnv([
"CACHE_LOAD_SCOPE=${cacheLoadScope}",
"CACHE_SAVE_SCOPE=${cacheSaveScope}",
"CACHE_UNIQUE_SCOPE=${env.IMAGE_CACHE_UNIQUE_SCOPE}",
"CASSANDRA_IMAGE_TAG=${imageTag.cassandra()}",
"CASSANDRA_PREFIX=${env.CASSANDRA_PREFIX}",
"COMPOSE_FILE=docker-compose.new-jenkins.yml",
"DYNAMODB_IMAGE_TAG=${imageTag.dynamodb()}",
"DYNAMODB_PREFIX=${env.DYNAMODB_PREFIX}",
"POSTGRES_IMAGE_TAG=${imageTag.postgres()}",
"POSTGRES_PREFIX=${env.POSTGRES_PREFIX}",
"POSTGRES_PASSWORD=sekret"
]) {
sh """
# Due to https://issues.jenkins.io/browse/JENKINS-15146, we have to set it to empty string here
export CACHE_LOAD_SCOPE=\${CACHE_LOAD_SCOPE:-}
export CACHE_SAVE_SCOPE=\${CACHE_SAVE_SCOPE:-}
./build/new-jenkins/run-migrations.sh
./build/new-jenkins/docker-with-flakey-network-protection.sh push $CASSANDRA_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $DYNAMODB_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $POSTGRES_PREFIX || true
"""
}
archiveArtifacts(artifacts: "migrate-*.log", allowEmptyArchive: true)
sh 'docker-compose down --remove-orphans'
}
}
}
stage('Parallel Run Tests') {
withEnv([
"CASSANDRA_IMAGE_TAG=${env.CASSANDRA_IMAGE}",
"DYNAMODB_IMAGE_TAG=${env.DYNAMODB_IMAGE}",
"POSTGRES_IMAGE_TAG=${env.POSTGRES_IMAGE}",
]) {
def stages = [:]
if (!configuration.isChangeMerged()) {
echo 'adding Linters'
buildSummaryReport.extendedStageAndReportIfFailure('Linters', stages) {
credentials.withStarlordCredentials {
credentials.withGerritCredentials {
withEnv([
"FORCE_FAILURE=${configuration.getBoolean('force-failure-linters', 'false')}",
"PLUGINS_LIST=${configuration.plugins().join(' ')}",
"SKIP_ESLINT=${configuration.getString('skip-eslint', 'false')}",
"UPLOAD_DEBUG_IMAGE=${configuration.getBoolean('upload-linter-debug-image', 'false')}",
]) {
sh 'build/new-jenkins/linters/run-gergich.sh'
}
}
if (env.MASTER_BOUNCER_RUN == '1' && !configuration.isChangeMerged()) {
credentials.withMasterBouncerCredentials {
sh 'build/new-jenkins/linters/run-master-bouncer.sh'
}
}
}
}
}
}
buildSummaryReport.extendedStageAndReportIfFailure('Build Docker Image') {
timeout(time: 20) {
echo 'adding Consumer Smoke Test'
buildSummaryReport.extendedStageAndReportIfFailure('Consumer Smoke Test', stages) {
sh 'build/new-jenkins/consumer-smoke-test.sh'
}
echo 'adding Vendored Gems'
extendedStage('Vendored Gems', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/vendored-gems', buildParameters + [
string(name: 'CASSANDRA_IMAGE_TAG', value: "${env.CASSANDRA_IMAGE_TAG}"),
string(name: 'DYNAMODB_IMAGE_TAG', value: "${env.DYNAMODB_IMAGE_TAG}"),
string(name: 'POSTGRES_IMAGE_TAG', value: "${env.POSTGRES_IMAGE_TAG}"),
], true, "", "Vendored Gems")
}
buildSummaryReport.extendedStageAndReportIfFailure(JS_BUILD_IMAGE_STAGE, stages) {
credentials.withStarlordCredentials {
def cacheScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : env.IMAGE_CACHE_BUILD_SCOPE
try {
def cacheScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : env.IMAGE_CACHE_BUILD_SCOPE
slackSendCacheBuild {
withEnv([
"CACHE_LOAD_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"CACHE_LOAD_FALLBACK_SCOPE=${env.IMAGE_CACHE_BUILD_SCOPE}",
"CACHE_SAVE_SCOPE=${cacheScope}",
"CACHE_UNIQUE_SCOPE=${env.IMAGE_CACHE_UNIQUE_SCOPE}",
"COMPILE_ADDITIONAL_ASSETS=${configuration.isChangeMerged() ? 1 : 0}",
"JS_BUILD_NO_UGLIFY=${configuration.isChangeMerged() ? 0 : 1}",
"KARMA_BUILDER_PREFIX=${env.KARMA_BUILDER_PREFIX}",
"PATCHSET_TAG=${env.PATCHSET_TAG}",
"RAILS_LOAD_ALL_LOCALES=${getRailsLoadAllLocales()}",
"RUBY_RUNNER_PREFIX=${env.RUBY_RUNNER_PREFIX}",
"WEBPACK_BUILDER_PREFIX=${env.WEBPACK_BUILDER_PREFIX}",
"WEBPACK_CACHE_PREFIX=${env.WEBPACK_CACHE_PREFIX}",
"YARN_RUNNER_PREFIX=${env.YARN_RUNNER_PREFIX}",
"WEBPACK_BUILDER_IMAGE=${env.WEBPACK_BUILDER_IMAGE}",
]) {
try {
sh "build/new-jenkins/docker-build.sh $PATCHSET_TAG"
} catch(e) {
handleDockerBuildFailure(PATCHSET_TAG, e)
}
sh "./build/new-jenkins/js/docker-build.sh $KARMA_RUNNER_IMAGE"
}
}
sh "./build/new-jenkins/docker-with-flakey-network-protection.sh push $PATCHSET_TAG"
if(configuration.isChangeMerged()) {
def GIT_REV = sh(script: 'git rev-parse HEAD', returnStdout: true).trim()
sh "docker tag \$PATCHSET_TAG \$BUILD_IMAGE:${GIT_REV}"
sh "./build/new-jenkins/docker-with-flakey-network-protection.sh push \$BUILD_IMAGE:${GIT_REV}"
}
sh(script: """
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_BUILDER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $YARN_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $RUBY_RUNNER_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $WEBPACK_CACHE_PREFIX
""", label: 'upload cache images')
if (isPatchsetPublishable()) {
sh 'docker tag $PATCHSET_TAG $EXTERNAL_TAG'
sh './build/new-jenkins/docker-with-flakey-network-protection.sh push $EXTERNAL_TAG'
}
}
}
}
buildSummaryReport.extendedStageAndReportIfFailure('Run Migrations') {
timeout(time: 10) {
credentials.withStarlordCredentials {
def cacheLoadScope = configuration.isChangeMerged() || configuration.getBoolean('skip-cache') ? '' : env.IMAGE_CACHE_MERGE_SCOPE
def cacheSaveScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : ''
withEnv([
"CACHE_LOAD_SCOPE=${cacheLoadScope}",
"CACHE_SAVE_SCOPE=${cacheSaveScope}",
"CACHE_UNIQUE_SCOPE=${env.IMAGE_CACHE_UNIQUE_SCOPE}",
"CASSANDRA_IMAGE_TAG=${imageTag.cassandra()}",
"CASSANDRA_PREFIX=${env.CASSANDRA_PREFIX}",
"COMPOSE_FILE=docker-compose.new-jenkins.yml",
"DYNAMODB_IMAGE_TAG=${imageTag.dynamodb()}",
"DYNAMODB_PREFIX=${env.DYNAMODB_PREFIX}",
"POSTGRES_IMAGE_TAG=${imageTag.postgres()}",
"POSTGRES_PREFIX=${env.POSTGRES_PREFIX}",
"POSTGRES_PASSWORD=sekret"
]) {
sh """
# Due to https://issues.jenkins.io/browse/JENKINS-15146, we have to set it to empty string here
export CACHE_LOAD_SCOPE=\${CACHE_LOAD_SCOPE:-}
export CACHE_SAVE_SCOPE=\${CACHE_SAVE_SCOPE:-}
./build/new-jenkins/run-migrations.sh
./build/new-jenkins/docker-with-flakey-network-protection.sh push $CASSANDRA_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $DYNAMODB_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $POSTGRES_PREFIX || true
./build/new-jenkins/docker-with-flakey-network-protection.sh push $KARMA_RUNNER_IMAGE
./build/new-jenkins/docker-with-flakey-network-protection.sh push $KARMA_BUILDER_PREFIX
"""
} catch(e) {
handleDockerBuildFailure(KARMA_RUNNER_IMAGE, e)
}
archiveArtifacts(artifacts: "migrate-*.log", allowEmptyArchive: true)
sh 'docker-compose down --remove-orphans'
}
}
}
stage('Parallel Run Tests') {
withEnv([
"CASSANDRA_IMAGE_TAG=${env.CASSANDRA_IMAGE}",
"DYNAMODB_IMAGE_TAG=${env.DYNAMODB_IMAGE}",
"POSTGRES_IMAGE_TAG=${env.POSTGRES_IMAGE}",
]) {
def stages = [:]
echo 'adding Javascript (Jest)'
extendedStage('Javascript (Jest)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if (!configuration.isChangeMerged()) {
echo 'adding Linters'
buildSummaryReport.extendedStageAndReportIfFailure('Linters', stages) {
credentials.withStarlordCredentials {
credentials.withGerritCredentials {
withEnv([
"FORCE_FAILURE=${configuration.getBoolean('force-failure-linters', 'false')}",
"PLUGINS_LIST=${configuration.plugins().join(' ')}",
"SKIP_ESLINT=${configuration.getString('skip-eslint', 'false')}",
"UPLOAD_DEBUG_IMAGE=${configuration.getBoolean('upload-linter-debug-image', 'false')}",
]) {
sh 'build/new-jenkins/linters/run-gergich.sh'
}
}
if (env.MASTER_BOUNCER_RUN == '1' && !configuration.isChangeMerged()) {
credentials.withMasterBouncerCredentials {
sh 'build/new-jenkins/linters/run-master-bouncer.sh'
}
}
}
}
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
echo 'adding Consumer Smoke Test'
buildSummaryReport.extendedStageAndReportIfFailure('Consumer Smoke Test', stages) {
sh 'build/new-jenkins/consumer-smoke-test.sh'
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "jest"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Jest)")
}
echo 'adding Javascript (Coffeescript)'
extendedStage('Javascript (Coffeescript)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
echo 'adding Vendored Gems'
extendedStage('Vendored Gems', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/vendored-gems', buildParameters + [
string(name: 'CASSANDRA_IMAGE_TAG', value: "${env.CASSANDRA_IMAGE_TAG}"),
string(name: 'DYNAMODB_IMAGE_TAG', value: "${env.DYNAMODB_IMAGE_TAG}"),
string(name: 'POSTGRES_IMAGE_TAG', value: "${env.POSTGRES_IMAGE_TAG}"),
], true, "", "Vendored Gems")
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "coffee"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Coffeescript)")
}
echo 'adding Javascript (Karma)'
extendedStage('Javascript (Karma)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
buildSummaryReport.extendedStageAndReportIfFailure(JS_BUILD_IMAGE_STAGE, stages) {
credentials.withStarlordCredentials {
try {
def cacheScope = configuration.isChangeMerged() ? env.IMAGE_CACHE_MERGE_SCOPE : env.IMAGE_CACHE_BUILD_SCOPE
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "karma"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Karma)")
}
withEnv([
"CACHE_LOAD_SCOPE=${env.IMAGE_CACHE_MERGE_SCOPE}",
"CACHE_LOAD_FALLBACK_SCOPE=${env.IMAGE_CACHE_BUILD_SCOPE}",
"CACHE_SAVE_SCOPE=${cacheScope}",
"KARMA_BUILDER_PREFIX=${env.KARMA_BUILDER_PREFIX}",
"PATCHSET_TAG=${env.PATCHSET_TAG}",
"RAILS_LOAD_ALL_LOCALES=${getRailsLoadAllLocales()}",
"WEBPACK_BUILDER_IMAGE=${env.WEBPACK_BUILDER_IMAGE}",
]) {
sh "./build/new-jenkins/js/docker-build.sh $KARMA_RUNNER_IMAGE"
}
echo 'adding Contract Tests'
extendedStage('Contract Tests', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/contract-tests', buildParameters + [
string(name: 'CASSANDRA_IMAGE_TAG', value: "${env.CASSANDRA_IMAGE_TAG}"),
string(name: 'DYNAMODB_IMAGE_TAG', value: "${env.DYNAMODB_IMAGE_TAG}"),
string(name: 'POSTGRES_IMAGE_TAG', value: "${env.POSTGRES_IMAGE_TAG}"),
], true, "", "Contract Tests")
}
sh """
./build/new-jenkins/docker-with-flakey-network-protection.sh push $KARMA_RUNNER_IMAGE
./build/new-jenkins/docker-with-flakey-network-protection.sh push $KARMA_BUILDER_PREFIX
"""
} catch(e) {
handleDockerBuildFailure(KARMA_RUNNER_IMAGE, e)
}
}
if (sh(script: 'build/new-jenkins/check-for-migrations.sh', returnStatus: true) == 0) {
echo 'adding CDC Schema check'
extendedStage('CDC Schema Check', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/cdc-event-transformer-master', buildParameters + [
string(name: 'CANVAS_LMS_IMAGE_PATH', value: "${env.PATCHSET_TAG}"),
], true, "", "CDC Schema Check")
}
}
else {
echo 'no migrations added, skipping CDC Schema check'
}
echo 'adding Javascript (Jest)'
extendedStage('Javascript (Jest)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "jest"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Jest)")
}
echo 'adding Javascript (Coffeescript)'
extendedStage('Javascript (Coffeescript)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "coffee"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Coffeescript)")
}
echo 'adding Javascript (Karma)'
extendedStage('Javascript (Karma)', stages) {
waitUntil { extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'PENDING' }
if(extendedStage.getStageStatus(JS_BUILD_IMAGE_STAGE) != 'SUCCESS') {
error "image dependency failed to build"
}
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/JS', buildParameters + [
string(name: 'KARMA_RUNNER_IMAGE', value: env.KARMA_RUNNER_IMAGE),
string(name: 'TEST_SUITE', value: "karma"),
], true, BLUE_OCEAN_TESTS_TAB, "Javascript (Karma)")
}
echo 'adding Contract Tests'
extendedStage('Contract Tests', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/contract-tests', buildParameters + [
if (
!configuration.isChangeMerged() &&
(
dir(env.LOCAL_WORKDIR){ (sh(script: '${WORKSPACE}/build/new-jenkins/spec-changes.sh', returnStatus: true) == 0) } ||
configuration.forceFailureFSC() == '1'
)
) {
echo 'adding Flakey Spec Catcher'
extendedStage('Flakey Spec Catcher', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/flakey-spec-catcher', buildParameters + [
string(name: 'CASSANDRA_IMAGE_TAG', value: "${env.CASSANDRA_IMAGE_TAG}"),
string(name: 'DYNAMODB_IMAGE_TAG', value: "${env.DYNAMODB_IMAGE_TAG}"),
string(name: 'POSTGRES_IMAGE_TAG', value: "${env.POSTGRES_IMAGE_TAG}"),
], true, "", "Contract Tests")
], configuration.fscPropagate(), "", "Flakey Spec Catcher")
}
}
if (sh(script: 'build/new-jenkins/check-for-migrations.sh', returnStatus: true) == 0) {
echo 'adding CDC Schema check'
extendedStage('CDC Schema Check', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/cdc-event-transformer-master', buildParameters + [
string(name: 'CANVAS_LMS_IMAGE_PATH', value: "${env.PATCHSET_TAG}"),
], true, "", "CDC Schema Check")
}
}
else {
echo 'no migrations added, skipping CDC Schema check'
}
// Flakey spec catcher using the dir step above will create this @tmp file, we need to remove it
// https://issues.jenkins.io/browse/JENKINS-52750
if(!configuration.isChangeMerged() && env.GERRIT_PROJECT != "canvas-lms") {
sh "rm -vrf $LOCAL_WORKDIR@tmp"
}
if (
!configuration.isChangeMerged() &&
(
dir(env.LOCAL_WORKDIR){ (sh(script: '${WORKSPACE}/build/new-jenkins/spec-changes.sh', returnStatus: true) == 0) } ||
configuration.forceFailureFSC() == '1'
)
) {
echo 'adding Flakey Spec Catcher'
extendedStage('Flakey Spec Catcher', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/flakey-spec-catcher', buildParameters + [
string(name: 'CASSANDRA_IMAGE_TAG', value: "${env.CASSANDRA_IMAGE_TAG}"),
string(name: 'DYNAMODB_IMAGE_TAG', value: "${env.DYNAMODB_IMAGE_TAG}"),
string(name: 'POSTGRES_IMAGE_TAG', value: "${env.POSTGRES_IMAGE_TAG}"),
], configuration.fscPropagate(), "", "Flakey Spec Catcher")
}
if(env.GERRIT_PROJECT == 'canvas-lms' && git.changedFiles(dockerDevFiles, 'HEAD^')) {
echo 'adding Local Docker Dev Build'
extendedStage('Local Docker Dev Build', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/local-docker-dev-smoke', buildParameters, true, "", "Local Docker Dev Build")
}
}
// Flakey spec catcher using the dir step above will create this @tmp file, we need to remove it
// https://issues.jenkins.io/browse/JENKINS-52750
if(!configuration.isChangeMerged() && env.GERRIT_PROJECT != "canvas-lms") {
sh "rm -vrf $LOCAL_WORKDIR@tmp"
}
if(env.GERRIT_PROJECT == 'canvas-lms' && git.changedFiles(dockerDevFiles, 'HEAD^')) {
echo 'adding Local Docker Dev Build'
extendedStage('Local Docker Dev Build', stages) {
buildSummaryReport.buildAndReportIfFailure('/Canvas/test-suites/local-docker-dev-smoke', buildParameters, true, "", "Local Docker Dev Build")
}
}
if(configuration.isChangeMerged()) {
buildSummaryReport.extendedStageAndReportIfFailure('Dependency Check', stages) {
catchError (buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
try {
snyk("canvas-lms:ruby", "Gemfile.lock", "$PATCHSET_TAG")
}
catch (err) {
if (err.toString().contains('Gemfile.lock does not exist')) {
snyk("canvas-lms:ruby", "Gemfile.lock.next", "$PATCHSET_TAG")
} else {
throw err
}
if(configuration.isChangeMerged()) {
buildSummaryReport.extendedStageAndReportIfFailure('Dependency Check', stages) {
catchError (buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
try {
snyk("canvas-lms:ruby", "Gemfile.lock", "$PATCHSET_TAG")
}
catch (err) {
if (err.toString().contains('Gemfile.lock does not exist')) {
snyk("canvas-lms:ruby", "Gemfile.lock.next", "$PATCHSET_TAG")
} else {
throw err
}
}
}
}
def distribution = load 'build/new-jenkins/groovy/distribution.groovy'
distribution.stashBuildScripts()
distribution.addRSpecSuites(stages)
distribution.addSeleniumSuites(stages)
parallel(stages)
}
def distribution = load 'build/new-jenkins/groovy/distribution.groovy'
distribution.stashBuildScripts()
distribution.addRSpecSuites(stages)
distribution.addSeleniumSuites(stages)
parallel(stages)
}
}
}