// 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 }