// vim: syn=groovy // // Copyright (c) 2024 Wind River Systems, Inc. // // SPDX-License-Identifier: Apache-2.0 // library "common@${params.JENKINS_SCRIPTS_BRANCH}" PROPS = null IMG_PARAMS = null IMAGES_FAILED = false def parseProps(text) { def x = {} for (line in text.split (/\n+/)) { if (line.matches (/\s*(?:#.*)?#/)) { continue } parts = line.split ("=", 2) key = parts[0] value = parts[1] x."${key}" = value } return x } def loadEnv() { def data = {} data.NEED_BUILD = false data.SUPPRESS_DOCKER_IMAGE_BUILD_ERRORS = true ws(params.BUILD_HOME) { if (fileExists ("NEED_BUILD")) { data.NEED_BUILD = true } } final String configText = sh (script: "${Constants.SCRIPTS_DIR}/print-config.sh", returnStdout: true) final props = parseProps (configText) data.BUILD_OUTPUT_HOME_URL = props.BUILD_OUTPUT_HOME_URL data.PUBLISH_URL = props.PUBLISH_URL PROPS = data return data.NEED_BUILD } def partJobName(name) { final String folder = env.JOB_NAME.replaceAll (/(.*\/).+$/, '$1'); if (folder == env.JOB_NAME) { error "This job must be in a Jenkins folder!" } return "/" + folder + "parts/" + name } def runPart(name, params = []) { // Tell Jenkins to checkout the same commit of the sub-job's Jenkinsfile, // as the current builds' Jenkinsfile's commit. final gitRef = string (name: 'JENKINS_SCRIPTS_BRANCH', value: env.GIT_COMMIT) build job: partJobName (name), parameters: copyCurrentParams() + [ gitRef ] + params } def printBuildFooter() { if (PROPS) { String msg = "" msg += "\n" msg += "========================================\n" msg += "\n" if (PROPS.NEED_BUILD) { msg += "Build output: ${PROPS.BUILD_OUTPUT_HOME_URL}\n" if (PROPS.PUBLISH_URL) { msg += "Publish output: ${PROPS.PUBLISH_URL}\n" } if (IMAGES_FAILED) { msg += "\n" msg += "WARNING:\n" msg += "WARNING: docker images build attempted, but failed!\n" msg += "WARNING: see log output above\n" msg += "WARNING:\n" } } else { echo "*** NO CHANGES - BUILD NOT REQUIRED" } msg += "\n" msg += "========================================\n" msg += "\n" echo (msg) } } pipeline { agent any options { timestamps() } parameters { string( name: 'MASTER_JOB_NAME', description: 'Name of the job that has trigger this pipeline.' ) string( name: 'MASTER_BUILD_NUMBER', description: 'Number of the job that has trigger this pipeline.' ) string( name: 'BUILD_HOME', description: 'Full path to where the build system is located' ) string( name: 'TIMESTAMP', description: 'Time when the build is started' ) string( name: 'PUBLISH_TIMESTAMP', description: 'Time when the build is published' ) booleanParam( name: 'REBUILD_BUILDER_IMAGES' ) booleanParam( name: 'BUILDER_USE_DOCKER_CACHE' ) booleanParam( name: 'BUILD_PACKAGES', description: "Enable stage 'Build packages'" ) booleanParam( name: 'REFRESH_SOURCE' ) booleanParam( name: 'PKG_REUSE' ) booleanParam( name: 'BUILD_ISO' ) booleanParam( name: 'DRY_RUN' ) booleanParam( name: 'SHELL_XTRACE' ) booleanParam( name: 'CLEAN_PACKAGES' ) booleanParam( name: 'CLEAN_ISO' ) booleanParam( name: 'CLEAN_REPOMGR' ) booleanParam( name: 'CLEAN_DOWNLOADS' ) booleanParam( name: 'CLEAN_DOCKER' ) booleanParam( name: 'FORCE_BUILD' ) booleanParam( name: 'USE_DOCKER_CACHE', ) string( name: 'JENKINS_SCRIPTS_BRANCH' ) string( name: 'REMOTE_SERVER', description: 'Address of the remote server who holds the base build system that the patch will be built on top of.' + 'Used together with REMOTE_BUILD_HOME' + 'e.g.: http://example-build-server.com:8080' ) string( name: 'REMOTE_BUILD_HOME', description: 'Full path from the remote server who holds the base build system that the patch will be built on top of.' + 'Used together with REMOTE_SERVER' + 'e.g.: /localdisk/loadbuild/starlingx-master/latest_build' ) booleanParam( name: 'SIGN_PATCH', defaultValue: true, description: 'Send patch to be signed by signing server.' ) booleanParam( name: 'PATCH_BUILD', defaultValue: true, description: 'Flag that enable --reuse_maximum when build-packages. Meant to be used together with PKG_REUSE.' ) string( name: 'SW_VERSION', description: 'Version of the build being used. e.g., XX.YY' ) string( name: 'PATCH_NUM', description: 'Number of the patch, e.g., 1. To be used together with SW_VERSION like this: XX.YY.PP.' ) string( name: 'CUSTOM_PATCH_RECIPE', description: "Allow you to specify the path to a custom patch recipe to be used when creating the patch.", defaultValue: "" ) string( name: 'PATCH_NAME', description: "Allow you to specify a custom patch name for the .patch file.", defaultValue: "" ) string( name: 'PATCH_PREVIOUS', description: "Git ref for the previous created patch. It can be a git tag name.", defaultValue: "" ) string( name: 'PATCH_TAG', description: "Git ref to be used as HEAD", defaultValue: "HEAD" ) string( name: 'STX_SHARED_SOURCE', description: "Full HTTPS address of the deb-local-source repository from where we pull the packages to be re-used", defaultValue: "" ) string( name: 'STX_SHARED_REPO', description: "Full HTTPS address of the deb-local-build repository from where we pull the packages to be re-used", defaultValue: "" ) text( name: 'PATCH_LIST', defaultValue: '-', description: '''\
List of Gerrit URLs to apply before running the build, one per line "[PATH] URL REF", eg:
https://review.opendev.org/starlingx/config refs/changes/71/859571/4
https://review.opendev.org/starlingx/stx-puppet refs/changes/75/859575/1
https://review.opendev.org/starlingx/tools refs/changes/76/859576/2
or with paths relative to repo root:
cgcs-root/stx/config https://review.opendev.org/starlingx/config refs/changes/71/859571/4
cgcs-root/stx/stx-puppet https://review.opendev.org/starlingx/stx-puppet refs/changes/75/859575/1
stx-tools https://review.opendev.org/starlingx/tools refs/changes/76/859576/2
'''
)
}
stages {
stage('Start Environment') {
steps {
script {
// Initialize BUILD_HOME, create build.conf & stx.conf
runPart("init-env")
// Update source tree
runPart("clone-source")
// create BUILD & stx.conf
runPart("configure-build")
// Stop containers before updating source treee
runPart("stop-containers")
// Create changelog, LAST_COMMITS, NEED_BUILD etc
runPart("create-changelog")
// Is build required?
if (!loadEnv()) {
println "*** NO CHANGES, BUILD NOT REQUIRED ***"
}
}
}
}
stage('Build') {
when { expression { PROPS.NEED_BUILD } }
stages {
stage('Prepare:CLEAN') {
steps {
// Delete or keep packages, aptly state, etc depending on build params
runPart("clean-build")
// start containers
runPart("start-containers")
// login to docker early to catch login errors
runPart ("docker-login")
}
}
stage('Prepare:DOWNLOAD') {
steps {
// populate mirrors
runPart("download-prerequisites")
}
}
stage('PACKAGES') {
when {
expression {
params.BUILD_PACKAGES
}
}
steps {
// build and publish packages
runPart("build-packages")
runPart("publish-packages")
// build iso
runPart ("build-iso")
}
}
stage('PATCH:prepare') {
steps {
// pull ostree that we will use as base
runPart("ostree-pull")
}
}
stage('PATCH:make') {
steps {
// create the patch
runPart("patch-make")
// create the pre-patched iso
runPart("patch-iso")
// publish patches and pre-patched iso
runPart("publish-patch")
}
}
stage('PATCH:export') {
steps {
runPart("build-export-dir")
}
}
}
post {
always {
echo "build result: ${currentBuild.result}"
runPart("stop-containers")
// archive anything we may have missed
runPart("archive-misc")
// save this job's build number on disk (for publish-logs)
saveCurrentJenkinsBuildInfo()
}
success {
// copy LAST_COMMITS to archive root & update the "latest_build" symlink in
// both archive and publish roots
sh("BUILD_STATUS=success ${Constants.SCRIPTS_DIR}/create-latest-symlinks.sh")
// Print archive & publish URLs
printBuildFooter()
// publish this job's Jenkins log
runPart("publish-logs")
}
unsuccessful {
sh("BUILD_STATUS=fail ${Constants.SCRIPTS_DIR}/create-latest-symlinks.sh")
// publish this job's Jenkins log
runPart("publish-logs")
}
}
}
} // stages
}