| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import org.jenkinsci.plugins.workflow.libs.Library |
| |
| @Library('jenkins-pipeline-shared-libraries') _ |
| |
| import org.kie.jenkins.MavenCommand |
| import org.kie.jenkins.MavenStagingHelper |
| |
| deployProperties = [:] |
| |
| optaplannerRepository = 'incubator-kie-optaplanner' |
| optaplannerFolder = 'optaplanner' |
| quickstartsRepository = 'incubator-kie-optaplanner-quickstarts' |
| quickstartsFolder = 'quickstarts' |
| |
| imageUtils = null |
| |
| pipeline { |
| agent { |
| docker { |
| image env.AGENT_DOCKER_BUILDER_IMAGE |
| args env.AGENT_DOCKER_BUILDER_ARGS |
| label util.avoidFaultyNodes() |
| } |
| } |
| |
| options { |
| timestamps() |
| timeout(time: 120, unit: 'MINUTES') |
| disableConcurrentBuilds(abortPrevious: true) |
| } |
| |
| environment { |
| OPTAPLANNER_CI_EMAIL_TO = credentials("${JENKINS_EMAIL_CREDS_ID}") |
| |
| PR_BRANCH_HASH = "${util.generateHash(10)}" |
| |
| } |
| |
| stages { |
| stage('Initialize') { |
| steps { |
| script { |
| cleanWs(disableDeferredWipeout: true) |
| |
| if (params.DISPLAY_NAME) { |
| currentBuild.displayName = params.DISPLAY_NAME |
| } |
| |
| if (isRelease() || isCreatePr()) { |
| // Verify version is set |
| assert getProjectVersion() |
| |
| if (isRelease()) { |
| // Verify if on right release branch |
| assert getBuildBranch() == util.getReleaseBranchFromVersion(getProjectVersion()) |
| } |
| } |
| |
| checkout scm // To make sure the repository containing the script is available on the Jenkins node. |
| imageUtils = load '.ci/jenkins/scripts/imageUtils.groovy' |
| } |
| } |
| post { |
| success { |
| script { |
| setDeployPropertyIfNeeded('git.branch', getBuildBranch()) |
| setDeployPropertyIfNeeded('git.branchQuickstarts', getQuickStartsBranch()) |
| setDeployPropertyIfNeeded('git.author', getGitAuthor()) |
| setDeployPropertyIfNeeded('project.version', getProjectVersion()) |
| setDeployPropertyIfNeeded('release', isRelease()) |
| } |
| } |
| } |
| } |
| |
| stage('Clone repositories') { |
| steps { |
| script { |
| checkoutRepo(optaplannerRepository, optaplannerFolder) |
| checkoutQuickstarts(quickstartsFolder) |
| } |
| } |
| } |
| |
| stage('Prepare for PR') { |
| when { |
| expression { return isRelease() || isCreatePr() } |
| } |
| steps { |
| script { |
| prepareForPR(optaplannerFolder) |
| prepareForPR(quickstartsFolder) |
| } |
| } |
| } |
| |
| stage('Update project version') { |
| when { |
| expression { return getProjectVersion() != '' } |
| } |
| steps { |
| script { |
| if (getDroolsVersion()) { |
| maven.mvnSetVersionProperty(getOptaplannerMavenCommand(), 'version.org.drools', getDroolsVersion()) |
| } |
| maven.mvnVersionsSet(getOptaplannerMavenCommand(), getProjectVersion(), !isRelease()) |
| mavenCleanInstallOptaPlannerParents() |
| updateQuickstartsVersions() |
| } |
| } |
| } |
| |
| stage('Build OptaPlanner') { |
| steps { |
| script { |
| withCredentials([usernamePassword(credentialsId: env.MAVEN_REPO_CREDS_ID, usernameVariable: 'REPOSITORY_USER', passwordVariable: 'REPOSITORY_TOKEN')]) { |
| def installOrDeploy |
| if (shouldDeployToRepository()) { |
| installOrDeploy = "deploy -DdeployAtEnd -Dapache.repository.username=${REPOSITORY_USER} -Dapache.repository.password=${REPOSITORY_TOKEN} -DretryFailedDeploymentCount=5" |
| } else { |
| installOrDeploy = 'install' |
| } |
| |
| def mavenCommand = getOptaplannerMavenCommand() |
| .withProperty('maven.test.failure.ignore', true) |
| .withProperty('operator.image.build') |
| .skipTests(params.SKIP_TESTS) |
| def Closure mavenRunClosure = { |
| configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]) { |
| mavenCommand.withSettingsXmlFile(MAVEN_SETTINGS_FILE).run("clean $installOrDeploy") |
| } |
| } |
| if (isRelease()) { |
| release.gpgImportKeyFromFileWithPassword(getReleaseGpgSignKeyCredsId(), getReleaseGpgSignPassphraseCredsId()) |
| withCredentials([string(credentialsId: getReleaseGpgSignPassphraseCredsId(), variable: 'SIGNING_KEY_PASSWORD')]) { |
| mavenCommand.withProperty('gpg.passphrase', SIGNING_KEY_PASSWORD) |
| mavenCommand.withProfiles(['apache-release']) |
| |
| mavenRunClosure() |
| } |
| } |
| } else { |
| mavenRunClosure() |
| } |
| |
| } |
| if (isRelease()) { |
| updateAntoraYaml(optaplannerFolder) |
| } |
| } |
| } |
| post { |
| always { |
| script { |
| archiveJUnitTestResults() |
| util.archiveConsoleLog() |
| } |
| } |
| } |
| } |
| |
| stage('Build Quickstarts') { |
| steps { |
| script { |
| configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]){ |
| getOptaplannerQuickstartsMavenCommand() |
| .withProperty('maven.test.failure.ignore', true) |
| .skipTests(params.SKIP_TESTS) |
| .withSettingsXmlFile(MAVEN_SETTINGS_FILE) |
| .run('clean install') |
| } |
| } |
| } |
| post { |
| always { |
| script { |
| archiveJUnitTestResults() |
| util.archiveConsoleLog() |
| } |
| } |
| } |
| } |
| |
| stage('Create PRs') { |
| when { |
| expression { return isRelease() || isCreatePr() } |
| } |
| steps { |
| script { |
| commitAndCreatePR(optaplannerFolder, optaplannerRepository, getBuildBranch()) |
| commitAndCreatePR(quickstartsFolder, quickstartsRepository, getQuickStartsBranch()) |
| } |
| } |
| post { |
| success { |
| script { |
| setDeployPropertyIfNeeded("${optaplannerRepository}.pr.source.uri", "https://github.com/${getGitAuthor()}/${optaplannerRepository}") |
| setDeployPropertyIfNeeded("${optaplannerRepository}.pr.source.ref", getPRBranch()) |
| setDeployPropertyIfNeeded("${optaplannerRepository}.pr.target.uri", "https://github.com/${getGitAuthor()}/${optaplannerRepository}") |
| setDeployPropertyIfNeeded("${optaplannerRepository}.pr.target.ref", getBuildBranch()) |
| } |
| } |
| } |
| } |
| |
| stage('Push a temporary operator image to a registry') { |
| when { |
| expression { return isRelease() } |
| } |
| steps { |
| script { |
| pushOperatorTemporaryImage() |
| |
| // Store image deployment information |
| setDeployPropertyIfNeeded('operator.image.name', getOperatorImageName()) |
| setDeployPropertyIfNeeded('operator.image.tag', getOperatorImageTag()) |
| setDeployPropertyIfNeeded('operator.image.temporary_tag', getOperatorImageTemporaryTag()) |
| } |
| } |
| } |
| } |
| post { |
| always { |
| script { |
| def propertiesStr = deployProperties.collect { entry -> "${entry.key}=${entry.value}" }.join('\n') |
| writeFile(text: propertiesStr, file: env.PROPERTIES_FILE_NAME) |
| archiveArtifacts(artifacts: env.PROPERTIES_FILE_NAME) |
| } |
| } |
| unsuccessful { |
| sendErrorNotification() |
| } |
| cleanup { |
| script { |
| util.cleanNode() |
| } |
| } |
| } |
| } |
| |
| void sendErrorNotification() { |
| if (params.SEND_NOTIFICATION) { |
| String additionalInfo = "**[${getBuildBranch()}] Optaplanner - Deploy**" |
| mailer.sendMarkdownTestSummaryNotification("CI failures", [env.OPTAPLANNER_CI_EMAIL_TO], additionalInfo) |
| } else { |
| echo 'No notification sent per configuration' |
| } |
| } |
| |
| List getIntegrationTestProfiles() { |
| return params.SKIP_INTEGRATION_TESTS ? [] : ['integration-tests'] |
| } |
| |
| void updateQuickstartsVersions() { |
| maven.mvnSetVersionProperty(getOptaplannerQuickstartsMavenCommand(), 'version.org.optaplanner', getProjectVersion()) |
| maven.mvnVersionsUpdateParentAndChildModules(getOptaplannerQuickstartsMavenCommand(), getProjectVersion(), !isRelease()) |
| gradleVersionsUpdate(quickstartsFolder, getProjectVersion()) |
| |
| if (isRelease()) { |
| dir(quickstartsFolder) { |
| // TODO: Remove the exclusion after the kubernetes demo is migrated to 9. |
| assert !sh(script: |
| 'grep -Rn "SNAPSHOT" --include={pom.xml,build.gradle} --exclude-dir=kubernetes | ' + |
| 'grep -v -e "1.0-SNAPSHOT" | ' + |
| 'cat', returnStdout: true) |
| } |
| } |
| if (isCreatePr()) { |
| dir(quickstartsFolder) { |
| // TODO: Remove the exclusion after the kubernetes demo is migrated to 9. |
| assert !sh(script: |
| 'grep -Rn "SNAPSHOT" --include={pom.xml,build.gradle} --exclude-dir=kubernetes | ' + |
| 'grep -v -e "${getProjectVersion()}" | ' + |
| 'cat', returnStdout: true) |
| } |
| } |
| } |
| |
| void gradleVersionsUpdate(String folder, String newVersion) { |
| dir(folder) { |
| sh "find . -name build.gradle -exec sed -i -E 's/def optaplannerVersion = \"[^\"\\s]+\"/def optaplannerVersion = \"${newVersion}\"/' {} \\;" |
| } |
| } |
| |
| void archiveJUnitTestResults() { |
| if (!skipUnitTests()) { |
| junit testResults: '**/target/surefire-reports/**/*.xml, **/target/failsafe-reports/**/*.xml', allowEmptyResults: true |
| } |
| } |
| |
| void checkoutRepo(String repo, String dirName = repo) { |
| dir(dirName) { |
| deleteDir() |
| if (params.PR_TARGET_BRANCH) { |
| githubscm.checkoutIfExists(repo, getGitAuthor(), getBuildBranch(), 'apache', getFallbackBranch(repo), true) |
| } else { |
| checkout(githubscm.resolveRepository(repo, getGitAuthor(), getBuildBranch(), false, getGitAuthorCredsId())) |
| } |
| } |
| } |
| |
| void checkoutQuickstarts(String dirName = quickstartsRepository) { |
| dir(dirName) { |
| deleteDir() |
| if (params.PR_TARGET_BRANCH) { |
| githubscm.checkoutIfExists(quickstartsRepository, getGitAuthor(), getBuildBranch(), 'apache', getQuickStartsBranch(), true) |
| } else { |
| checkout(githubscm.resolveRepository(quickstartsRepository, getGitAuthor(), getQuickStartsBranch(), false, getGitAuthorCredsId())) |
| } |
| } |
| } |
| |
| String getFallbackBranch(String repo) { |
| def repositoryScm = githubscm.getRepositoryScm(repo, 'apache', params.PR_TARGET_BRANCH) |
| return repositoryScm ? params.PR_TARGET_BRANCH : 'main' |
| } |
| |
| void prepareForPR(String folder) { |
| dir(folder) { |
| githubscm.createBranch(getPRBranch()) |
| } |
| } |
| |
| void commitAndCreatePR(String folder, String repo, String buildBranch) { |
| dir(folder) { |
| def commitMsg = "[${buildBranch}] Update project version to ${getProjectVersion()}" |
| def prBody = "Generated by build ${BUILD_TAG}: ${BUILD_URL}." |
| if (isRelease()) { |
| prBody += '\nPlease do not merge, it should be merged automatically after testing.' |
| } else { |
| prBody += '\nPlease review and merge.' |
| } |
| githubscm.setUserConfigFromCreds(getGitAuthorPushCredsId()) |
| githubscm.commitChanges(commitMsg, { |
| githubscm.findAndStageNotIgnoredFiles('pom.xml') |
| githubscm.findAndStageNotIgnoredFiles('build.gradle') |
| githubscm.findAndStageNotIgnoredFiles('antora.yml') |
| }) |
| githubscm.pushObject('origin', getPRBranch(), getGitAuthorPushCredsId()) |
| deployProperties["${repo}.pr.link"] = isRelease() ? |
| githubscm.createPRWithLabels(commitMsg, prBody, buildBranch, ['DO_NOT_MERGE'] as String[], getGitAuthorCredsId()) : |
| githubscm.createPR(commitMsg, prBody, buildBranch, getGitAuthorCredsId()) |
| } |
| } |
| |
| void commitAndCreatePRIgnoringNpmRegistry(String folder, String repo, String buildBranch) { |
| dir(folder) { |
| sh 'sed \'s;repository.engineering.redhat.com/nexus/repository/;;\' -i */package-lock.json' |
| sh 'git add */package-lock.json' |
| } |
| commitAndCreatePR(folder, repo, buildBranch) |
| } |
| |
| MavenCommand getMavenDefaultCommand() { |
| MavenCommand mvnCmd = new MavenCommand(this, ['-fae', '-ntp']) |
| if (env.MAVEN_DEPENDENCIES_REPOSITORY) { |
| mvnCmd.withDependencyRepositoryInSettings('deps-repo', env.MAVEN_DEPENDENCIES_REPOSITORY) |
| } |
| return mvnCmd |
| } |
| |
| MavenCommand getOptaplannerMavenCommand() { |
| return getMavenDefaultCommand().inDirectory(optaplannerFolder).withProperty('full') |
| } |
| |
| MavenCommand getOptaplannerQuickstartsMavenCommand() { |
| return getMavenDefaultCommand().inDirectory(quickstartsFolder).withProperty('full') |
| } |
| |
| /** |
| * Builds the parent modules and the BOM so that project depending on these artifacts can resolve. |
| */ |
| void mavenCleanInstallOptaPlannerParents() { |
| configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]){ |
| getOptaplannerMavenCommand() |
| .skipTests(true) |
| .withOptions(['-U', '-pl org.optaplanner:optaplanner-build-parent,org.optaplanner:optaplanner-bom', '-am']) |
| .withSettingsXmlFile(MAVEN_SETTINGS_FILE) |
| .run('clean install') |
| } |
| } |
| |
| void runMavenDeploy(MavenCommand mvnCmd, String localDeploymentId = '') { |
| mvnCmd = mvnCmd.clone() |
| |
| if (localDeploymentId) { |
| mvnCmd.withLocalDeployFolder(getLocalDeploymentFolder(localDeploymentId)) |
| } else if (env.MAVEN_DEPLOY_REPOSITORY) { |
| mvnCmd.withDeployRepository(env.MAVEN_DEPLOY_REPOSITORY) |
| } |
| |
| configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]){ |
| mvnCmd |
| .withSettingsXmlFile(MAVEN_SETTINGS_FILE) |
| .skipTests(true) |
| .run('clean deploy') |
| } |
| } |
| |
| String getMavenRepoZipUrl() { |
| return "${params.MAVEN_DEPLOY_REPOSITORY.replaceAll('/content/', '/service/local/').replaceFirst('/*$', '')}/content-compressed" |
| } |
| |
| // Getters and Setters of params/properties |
| |
| boolean shouldDeployToRepository() { |
| return (env.MAVEN_DEPLOY_REPOSITORY || isNotTestingBuild()) && !isDeployDisabled() |
| } |
| |
| boolean isNotTestingBuild() { |
| return getGitAuthor() == 'apache' |
| } |
| |
| boolean isRelease() { |
| return env.RELEASE ? env.RELEASE.toBoolean() : false |
| } |
| |
| boolean isCreatePr() { |
| return params.CREATE_PR |
| } |
| |
| boolean skipUnitTests() { |
| return params.SKIP_TESTS |
| } |
| |
| boolean skipIntegrationTests() { |
| return params.SKIP_INTEGRATION_TESTS |
| } |
| |
| String getGitAuthor() { |
| // GIT_AUTHOR can be env or param |
| return "${GIT_AUTHOR}" |
| } |
| |
| String getGitAuthorCredsId() { |
| return env.GIT_AUTHOR_CREDS_ID |
| } |
| |
| String getGitAuthorPushCredsId() { |
| return env.GIT_AUTHOR_PUSH_CREDS_ID |
| } |
| |
| String getBuildBranch() { |
| return params.BUILD_BRANCH_NAME |
| } |
| |
| String getProjectVersion() { |
| return params.PROJECT_VERSION |
| } |
| |
| String getDroolsVersion() { |
| return params.DROOLS_VERSION |
| } |
| |
| String getPRBranch() { |
| return "${getProjectVersion()}-${env.PR_BRANCH_HASH}" |
| } |
| |
| void setDeployPropertyIfNeeded(String key, def value) { |
| if (value != null && value != '') { |
| deployProperties[key] = value |
| } |
| } |
| |
| String getQuickStartsBranch() { |
| return params.QUICKSTARTS_BUILD_BRANCH_NAME |
| } |
| |
| void updateAntoraYaml(String directory) { |
| if (isNotTestingBuild()) { |
| echo "updateAntoraYaml for ${directory}" |
| dir(directory) { |
| sh './build/release/update_antora_yml.sh' |
| } |
| } else { |
| echo 'No updateAntoraYaml due to testing build' |
| } |
| } |
| |
| /* OptaPlanner Operator */ |
| |
| String getOperatorImageRegistry() { |
| return params.OPERATOR_IMAGE_REGISTRY |
| } |
| |
| String getOperatorImageNamespace() { |
| return params.OPERATOR_IMAGE_NAMESPACE |
| } |
| |
| String getOperatorImageName() { |
| return env.OPERATOR_IMAGE_NAME |
| } |
| |
| String getOperatorImageTag() { |
| return params.OPERATOR_IMAGE_TAG ?: getProjectVersion() |
| } |
| |
| String getOperatorImageTemporaryTag() { |
| return "${getOperatorImageTag()}-temporary" |
| } |
| |
| void pushOperatorTemporaryImage() { |
| String localImage = "${getOperatorImageName()}:latest" |
| String temporaryImageTag = getOperatorImageTemporaryTag() |
| String temporaryImageFullName = imageUtils.getImageFullNameWithRegistry(getOperatorImageRegistry(), |
| getOperatorImageNamespace(), getOperatorImageName(), temporaryImageTag) |
| imageUtils.tagImage(localImage, temporaryImageFullName) |
| imageUtils.pushImage(temporaryImageFullName) |
| } |
| |
| boolean isDeployDisabled() { |
| return env.DISABLE_DEPLOY.toBoolean() |
| } |
| |
| String getReleaseGpgSignKeyCredsId() { |
| return env.RELEASE_GPG_SIGN_KEY_CREDS_ID |
| } |
| |
| String getReleaseGpgSignPassphraseCredsId() { |
| return env.RELEASE_GPG_SIGN_PASSPHRASE_CREDS_ID |
| } |