aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Rendina <mrendina@stsci.edu>2018-05-07 12:20:06 -0400
committerMatt Rendina <mrendina@stsci.edu>2018-05-07 12:20:06 -0400
commitd089296d81797a0f1495531b89da6d7df1da3570 (patch)
tree6444633f55708e7e0fb289bbef52b0d55d5ef981
downloadjscu_refactor-d089296d81797a0f1495531b89da6d7df1da3570.tar.gz
Initial commit
-rw-r--r--src/BuildConfig.groovy26
-rw-r--r--vars/utils.groovy145
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)
+}