// Loading code requires a NODE context // But we want the code accessible outside the node Context // So declare common (object created by the LOAD operation) outside the Node block. def common // This step is necessary to get the files directly from the git repo, as for the // first build it is not yet cloned into the workspace. Normally we use an agent // of a certain label (like core-os_buildagent) to have define credentials to get // the files. In the current case we use any agent. node() { def repoPreCloneDir = "repo-preclone" def nodeHostname = sh(returnStdout: true, script: "set +x && hostname | cut -d '_' -f1").trim() def cloneCredentials = ("${nodeHostname}" == "nwl") ? 'nmgit_credentials' : 'gitCredentials' dir(repoPreCloneDir) { // clone the repository to get the file with the target list sshagent (credentials: [cloneCredentials]) { sh "set +x && git clone --depth 1 --branch main ssh://git@bitbucket.gad.local:7999/nm-nsp/nwl-ci.git ." } // load common file common = load "./jobs/Jenkinsfile_Common" } sh("rm -rf ${repoPreCloneDir}") } // declarative pipeline pipeline { agent any parameters { string(name: 'BUILD_BRANCH', defaultValue: 'main', description: 'Enter the branch of the NWL to build (default = main), will skip deployment if not main') booleanParam(name: 'CLEAN_BUILD', defaultValue: true, description: 'do a clean build, i.e. remove the yocto directory and start from scratch') booleanParam(name: 'DEPLOY_TO_NEXUS', defaultValue: true, description: 'deploy the built artifact to Nexus') booleanParam(name: 'SKIP_SSTATE_UPLOAD', defaultValue: false, description: 'skip uploading/synchronizing the sstate-cache to the mirror') booleanParam(name: 'DEBUGGING', defaultValue: false, description: 'debugging mode, removes quiet mode for bitbake') } options { timeout(time: 5, unit: 'HOURS') disableConcurrentBuilds() buildDiscarder( logRotator(numToKeepStr: '20', daysToKeepStr: '7') ) } // ToDo: Remove this statement unless necessary, The cron trigger is set on // the job configuration and should be sufficient - untested. triggers { cron('H H(5-6) * * 1-5') } stages { stage('Check Parameters') { steps { script { printJobParameters() checkJobParameters(common) setDisplayName(common) } } } stage('Prepare') { steps { script { if(params.CLEAN_BUILD) { println "CLEAN BUILD REQUESTED, cleaning..." common.cleaningClonedRepoDir() } setupEnvironment(common, "${params.BUILD_BRANCH}") } } } stage('Update Source Revisions') { steps { script { updateTheSourceRevisions(common, "${env.BRANCH_TO_BUILD}") } } } stage('Build All Targets') { steps { script { buildAllTargets(common, "${env.BRANCH_TO_BUILD}") } } } } // stages } //----------------------------------------------------------------------------- def printJobParameters() { println "----------------------------------\n\ Job Parameters:\n\ ----------------------------------\n\ BUILD_BRANCH = ${params.BUILD_BRANCH}\n\ CLEAN_BUILD = ${params.CLEAN_BUILD}\n\ DEPLOY_TO_NEXUS = ${params.DEPLOY_TO_NEXUS}\n\ SKIP_SSTATE_UPLOAD = ${params.SKIP_SSTATE_UPLOAD}\n\ DEBUGGING = ${params.DEBUGGING}\n\ ----------------------------------\n" } //--------------------------------------------------------------------------------------------------------------------- def checkJobParameters(commonHelpers) { // Check the selected target and overwrite it with a default one when triggered by a timer if(commonHelpers.isJobTriggeredByTimer()) { println "INFO: Triggered by Timer" } } //--------------------------------------------------------------------------------------------------------------------- def setDisplayName(commonHelpers) { def buildName = "#${env.BUILD_NUMBER}" def postfix = commonHelpers.isJobTriggeredByTimer() ? "-nightly" : "" currentBuild.displayName = "${buildName}${postfix}" } //--------------------------------------------------------------------------------------------------------------------- def setupEnvironment(commonHelpers, selectedBranch) { env.BUILD_JOB = "${env.TARGET_BUILD_JOB}" env.SRCREV_JOB = "${env.SRCREV_UPDATE_JOB}" env.BRANCH_TO_BUILD = "${selectedBranch}" } //----------------------------------------------------------------------------- def runUpdateSrcRevJob(commonHelpers, buildBranch, isCleanRequested, isDryRun) { def updateJob = null try { updateJob = build(job: "${env.SRCREV_JOB}", quietPeriod: 0, propagate: false, wait: true, parameters: [string(name: 'BUILD_BRANCH', value: buildBranch), booleanParam(name: 'CLEAN_BUILD', value: isCleanRequested), booleanParam(name: 'DRY_RUN', value: isDryRun)] ) } catch(Exception e) { error("Exception: " + e.toString()) } // assert to be sure if(updateJob == null) { error("Something went really wrong with ${env.SRCREV_JOB}") } if(updateJob.getResult() != 'SUCCESS') { error("Failed to update the source revisions, check the job") } } //----------------------------------------------------------------------------- def updateTheSourceRevisions(commonHelpers, buildBranch) { def branchToBuild = buildBranch catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { runUpdateSrcRevJob(commonHelpers, buildBranch, true, false) copyArtifacts(projectName: "${env.SRCREV_JOB}", target: ".", flatten: true) branchToBuild = sh(returnStdout: true, script: "cat ./${env.NIGHTLY_BRANCH_FILE}").trim() } // end catchError // update the branch to build if the source revisions are updated env.BRANCH_TO_BUILD = "${branchToBuild}" } //----------------------------------------------------------------------------- def getTargetsFromList() { def theTargets = sh(returnStdout: true, script: "set +x && cat ./jobs/nwlTargets | grep -v select").trim().split("\n") return theTargets } //----------------------------------------------------------------------------- def isMachineSane(machine) { // ToDo: place here any exclusions if necessary return true } //----------------------------------------------------------------------------- def runBuildJob(commonHelpers, buildTarget, buildBranch) { def buildJob = null def theBuildResult = 'SUCCESS' Boolean hasException = false try { buildJob = build(job: "${env.BUILD_JOB}", quietPeriod: 0, propagate: false, wait: true, parameters: [string(name: 'TARGET', value: buildTarget), string(name: 'BUILD_BRANCH', value: buildBranch), booleanParam(name: 'CLEAN_BUILD', value: params.CLEAN_BUILD), booleanParam(name: 'DEPLOY_TO_NEXUS', value: params.DEPLOY_TO_NEXUS), booleanParam(name: 'SKIP_SSTATE_UPLOAD', value: params.SKIP_SSTATE_UPLOAD), booleanParam(name: 'FORCE_SRC_REV_UPDATE', value: false), booleanParam(name: 'DEBUGGING', value: params.DEBUGGING)] ) } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) { println "job ${env.BUILD_JOB} for TARGET=${buildTarget} was cancelled or aborted" theBuildResult = 'ABORTED' } catch(Exception e) { hasException = true theBuildResult = 'FAILURE' println "Exception caught: " + e.toString() } finally { if(!hasException && (buildJob != null)) { theBuildResult = buildJob.getResult() } return theBuildResult } // assert to be sure if(buildJob == null) { error("Something went really wrong with ${env.BUILD_JOB} (TARGET=${buildTarget})") } return buildJob.getResult() } //----------------------------------------------------------------------------- def buildMachine(commonHelpers, machine, buildBranch) { Boolean isMachineSuccessfullyBuilt = true println "BUILDING ${machine}" commonHelpers.setupTimeMeasurement() // NOTE: this catchError statement is needed in case of an // abort of the build job or similar failures catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') { def buildJobStatus = runBuildJob(commonHelpers, machine, buildBranch) if(buildJobStatus != 'SUCCESS') { isMachineSuccessfullyBuilt = false if(buildJobStatus == 'ABORTED') { currentBuild.result = 'ABORTED' } } } if(!isMachineSuccessfullyBuilt) { println "Failed building properly machine ${machine}" } commonHelpers.printMeasuredTimeToNow("building ${machine}") return isMachineSuccessfullyBuilt } //----------------------------------------------------------------------------- def buildAllTargets(commonHelpers, buildBranch) { Boolean areBuildsSuccessful = true def firstMachineFailing = "" def listOfTargets = getTargetsFromList() println "list of all targets = " + listOfTargets catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') { for (machine in listOfTargets) { if(!commonHelpers.isCurrentJobAborted() && isMachineSane(machine)) { Boolean isMachineSuccess = buildMachine(commonHelpers, machine, buildBranch) if(!isMachineSuccess && areBuildsSuccessful) { areBuildsSuccessful = false firstMachineFailing = machine } } // end isMachineSane } // end for // if there are builds failing, throw error to mark stage and build as FAILURE: if(!areBuildsSuccessful) { error("Failing build - first machine failing = ${firstMachineFailing}") } } // end catchError }