diff options
author | Matt Rendina <mrendina@stsci.edu> | 2018-05-07 12:20:06 -0400 |
---|---|---|
committer | Matt Rendina <mrendina@stsci.edu> | 2018-05-07 12:20:06 -0400 |
commit | d089296d81797a0f1495531b89da6d7df1da3570 (patch) | |
tree | 6444633f55708e7e0fb289bbef52b0d55d5ef981 | |
download | jscu_refactor-d089296d81797a0f1495531b89da6d7df1da3570.tar.gz |
Initial commit
-rw-r--r-- | src/BuildConfig.groovy | 26 | ||||
-rw-r--r-- | vars/utils.groovy | 145 |
2 files changed, 171 insertions, 0 deletions
diff --git a/src/BuildConfig.groovy b/src/BuildConfig.groovy new file mode 100644 index 0000000..5fd1687 --- /dev/null +++ b/src/BuildConfig.groovy @@ -0,0 +1,26 @@ +// src/BuildConfig.groovy +package BuildConfig; + +class BuildConfig implements Serializable { + def nodetype = "" + def build_mode = "" + def env_vars = [] + def env_vars_raw = [] + def build_cmds = [] + def test_cmds = [] + + def failedFailureNewThresh = '' + def failedFailureThresh = '' + def failedUnstableNewThresh = '' + def failedUnstableThresh= '' + + def skippedFailureNewThresh = '' + def skippedFailureThresh = '' + def skippedUnstableNewThresh = '' + def skippedUnstableThresh= '' + + // Constructors + BuildConfig() { + this.nodetype = "" + } +} diff --git a/vars/utils.groovy b/vars/utils.groovy new file mode 100644 index 0000000..50c7c2e --- /dev/null +++ b/vars/utils.groovy @@ -0,0 +1,145 @@ +// Jenkinsfile support utilities +import BuildConfig.BuildConfig +import org.apache.commons.lang3.SerializationUtils + + +// Clone the source repository and examine the most recent commit message. +// If a '[ci skip]' or '[skip ci]' directive is present, immediately +// terminate the job with a success code. +// If no skip directive is found, stash all the source files for efficient retrieval +// by subsequent nodes. +def scm_checkout() { + skip_job = 0 + node("on-master") { + stage("Setup") { + checkout(scm) + // Obtain the last commit message and examine it for skip directives. + logoutput = sh(script:"git log -1 --pretty=%B", returnStdout: true).trim() + if (logoutput.contains("[ci skip]") || logoutput.contains("[skip ci]")) { + skip_job = 1 + currentBuild.result = 'SUCCESS' + println("\nBuild skipped due to commit message directive.\n") + return skip_job + } + stash includes: '**/*', name: 'source_tree', useDefaultExcludes: false + } + } + return skip_job +} + + +// Execute build/test task(s) based on passed-in configuration(s). +// Each task is defined by a BuildConfig object. +// A list of such objects is iterated over to process all configurations. +// Arguments: +// configs - list of BuildConfig objects +// (optional) concurrent - boolean, whether or not to run all build +// configurations in parallel. The default is +// true when no value is provided. +def run(configs, concurrent = true) { + def tasks = [:] + for (config in configs) { + def myconfig = new BuildConfig() // MUST be inside for loop. + myconfig = SerializationUtils.clone(config) + + // Code defined within 'tasks' is eventually executed on a separate node. + // 'tasks' is a java.util.LinkedHashMap, which preserves insertion order. + tasks["${config.nodetype}/${config.build_mode}"] = { + node(config.nodetype) { + def runtime = [] + // Expand environment variable specifications by using the shell + // to dereference any var references and then render the entire + // value as a canonical path. + for (var in myconfig.env_vars) { + def varName = var.tokenize("=")[0].trim() + def varValue = var.tokenize("=")[1].trim() + // examine var value, if it contains var refs, expand them. + def expansion = varValue + if (varValue.contains("\$")) { + expansion = sh(script: "echo \"${varValue}\"", returnStdout: true) + } + + // Change values of '.' and './' to the node's WORKSPACE. + // Replace a leading './' with the node's WORKSPACE. + if (expansion == '.' || expansion == './') { + expansion = env.WORKSPACE + } else if(expansion.size() > 2 && expansion[0..1] == './') { + expansion = "${env.WORKSPACE}/${expansion[2..-1]}" + } + + // Replace all ':.' combinations with the node's WORKSPACE. + expansion = expansion.replaceAll(':\\.', ":${env.WORKSPACE}") + + // Convert var value to canonical based on a WORKSPACE base directory. + if (expansion.contains('..')) { + expansion = new File(expansion).getCanonicalPath() + } + expansion = expansion.trim() + runtime.add("${varName}=${expansion}") + } + for (var in myconfig.env_vars_raw) { + runtime.add(var) + } + println(runtime) + withEnv(runtime) { + stage("Build (${myconfig.build_mode})") { + unstash "source_tree" + for (cmd in myconfig.build_cmds) { + sh(script: cmd) + } + } + if (myconfig.test_cmds.size() > 0) { + try { + stage("Test (${myconfig.build_mode})") { + for (cmd in myconfig.test_cmds) { + sh(script: cmd) + } + } + } + finally { + // If a non-JUnit format .xml file exists in the + // root of the workspace, the XUnitBuilder report + // ingestion will fail. + report_exists = sh(script: "test -e *.xml", returnStatus: true) + if (report_exists == 0) { + step([$class: 'XUnitBuilder', + thresholds: [ + [$class: 'SkippedThreshold', unstableThreshold: "${myconfig.skippedUnstableThresh}"], + [$class: 'SkippedThreshold', failureThreshold: "${myconfig.skippedFailureThresh}"], + [$class: 'FailedThreshold', unstableThreshold: "${myconfig.failedUnstableThresh}"], + [$class: 'FailedThreshold', failureThreshold: "${myconfig.failedFailureThresh}"]], + tools: [[$class: 'JUnitType', pattern: '*.xml']]]) + } else { + println("No .xml files found in workspace. Test report ingestion skipped.") + } + } + } + } // end withEnv + } // end node + } //end tasks + + } //end for + + if (concurrent == true) { + stage("Matrix") { + parallel(tasks) + } + } else { + // Run tasks sequentially. Any failure halts the sequence. + def iter = 0 + tasks.each{ key, value -> + def localtask = [:] + localtask[key] = tasks[key] + stage("Serial-${iter}") { + parallel(localtask) + } + iter++ + } + } +} + + +// Convenience function that performs a deep copy on the supplied object. +def copy(obj) { + return SerializationUtils.clone(obj) +} |