diff --git a/.ci/jenkins/Jenkinsfile.deploy b/.ci/jenkins/Jenkinsfile.deploy index 4e30c0c3d5..854766ca68 100644 --- a/.ci/jenkins/Jenkinsfile.deploy +++ b/.ci/jenkins/Jenkinsfile.deploy @@ -35,7 +35,7 @@ imageUtils = null pipeline { agent { - docker { + docker { image env.AGENT_DOCKER_BUILDER_IMAGE args env.AGENT_DOCKER_BUILDER_ARGS label util.avoidFaultyNodes() @@ -52,7 +52,6 @@ pipeline { OPTAPLANNER_CI_EMAIL_TO = credentials("${JENKINS_EMAIL_CREDS_ID}") PR_BRANCH_HASH = "${util.generateHash(10)}" - } stages { @@ -103,7 +102,7 @@ pipeline { stage('Prepare for PR') { when { - expression { return isRelease() || isCreatePr() } + expression { return isCreatePr() } } steps { script { @@ -144,19 +143,15 @@ pipeline { .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.gpgImportKeyFromStringWithoutPassword(getReleaseGpgSignKeyCredsId()) + releaseUtils.gpgImportKeyFromStringWithoutPassword(getReleaseGpgSignKeyCredsId()) mavenCommand.withProfiles(['apache-release']) - mavenRunClosure() - } else { - mavenRunClosure() } + configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]) { + mavenCommand.withSettingsXmlFile(MAVEN_SETTINGS_FILE).run("clean $installOrDeploy") + } } if (isRelease()) { updateAntoraYaml(optaplannerFolder) @@ -176,12 +171,16 @@ pipeline { stage('Build Quickstarts') { steps { script { - configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]){ - getOptaplannerQuickstartsMavenCommand() + withCredentials([usernamePassword(credentialsId: env.MAVEN_REPO_CREDS_ID, usernameVariable: 'REPOSITORY_USER', passwordVariable: 'REPOSITORY_TOKEN')]) { + 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) + .withProperty('apache.repository.username', REPOSITORY_USER) + .withProperty('apache.repository.password', REPOSITORY_TOKEN) .run('clean install') + } } } } @@ -197,7 +196,7 @@ pipeline { stage('Create PRs') { when { - expression { return isRelease() || isCreatePr() } + expression { return isCreatePr() } } steps { script { @@ -217,6 +216,18 @@ pipeline { } } + stage('Commit and Create Tag') { + when { + expression { return isRelease() } + } + steps { + script { + commitAndCreateTag(optaplannerFolder, getBuildBranch()) + commitAndCreateTag(quickstartsFolder, getQuickStartsBranch()) + } + } + } + stage('Push a temporary operator image to a registry') { when { expression { return isRelease() } @@ -255,19 +266,28 @@ pipeline { void sendErrorNotification() { if (params.SEND_NOTIFICATION) { String additionalInfo = "**[${getBuildBranch()}] Optaplanner - Deploy**" - mailer.sendMarkdownTestSummaryNotification("CI failures", [env.OPTAPLANNER_CI_EMAIL_TO], additionalInfo) + 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()) + maven.mvnVersionsUpdateParent(getOptaplannerQuickstartsMavenCommand(), getProjectVersion(), !isRelease()) + + withCredentials([usernamePassword(credentialsId: env.MAVEN_REPO_CREDS_ID, usernameVariable: 'REPOSITORY_USER', passwordVariable: 'REPOSITORY_TOKEN')]) { + configFileProvider([configFile(fileId: env.MAVEN_SETTINGS_CONFIG_FILE_ID, variable: 'MAVEN_SETTINGS_FILE')]) { + maven.mvnVersionsUpdateChildModules( + getOptaplannerQuickstartsMavenCommand() + .withSettingsXmlFile(MAVEN_SETTINGS_FILE) + .withProperty('apache.repository.username', REPOSITORY_USER) + .withProperty('apache.repository.password', REPOSITORY_TOKEN), + !isRelease() + ) + } + } + gradleVersionsUpdate(quickstartsFolder, getProjectVersion()) if (isRelease()) { @@ -279,6 +299,7 @@ void updateQuickstartsVersions() { 'cat', returnStdout: true) } } + if (isCreatePr()) { dir(quickstartsFolder) { // TODO: Remove the exclusion after the kubernetes demo is migrated to 9. @@ -335,6 +356,20 @@ void prepareForPR(String folder) { } } +void commitAndCreateTag(String folder, String buildBranch) { + dir(folder) { + def commitMsg = "[${buildBranch}] Update project version to ${getProjectVersion()}" + githubscm.setUserConfigFromCreds(getGitAuthorPushCredsId()) + githubscm.commitChanges(commitMsg, { + githubscm.findAndStageNotIgnoredFiles('pom.xml') + githubscm.findAndStageNotIgnoredFiles('build.gradle') + githubscm.findAndStageNotIgnoredFiles('antora.yml') + }) + githubscm.tagRepository(getGitTagName()) + githubscm.pushRemoteTag('origin', getGitTagName(), getGitAuthorPushCredsId()) + } +} + void commitAndCreatePR(String folder, String repo, String buildBranch) { dir(folder) { def commitMsg = "[${buildBranch}] Update project version to ${getProjectVersion()}" @@ -385,36 +420,19 @@ MavenCommand getOptaplannerQuickstartsMavenCommand() { * 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() + withCredentials([usernamePassword(credentialsId: env.MAVEN_REPO_CREDS_ID, usernameVariable: 'REPOSITORY_USER', passwordVariable: 'REPOSITORY_TOKEN')]) { + 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) + .withProperty('apache.repository.username', REPOSITORY_USER) + .withProperty('apache.repository.password', REPOSITORY_TOKEN) .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() { @@ -532,4 +550,8 @@ String getReleaseGpgSignKeyCredsId() { String getReleaseGpgSignPassphraseCredsId() { return env.RELEASE_GPG_SIGN_PASSPHRASE_CREDS_ID -} \ No newline at end of file +} + +String getGitTagName() { + return params.GIT_TAG_NAME +} diff --git a/.ci/jenkins/config/branch.yaml b/.ci/jenkins/config/branch.yaml index 316bb68802..0403272be8 100644 --- a/.ci/jenkins/config/branch.yaml +++ b/.ci/jenkins/config/branch.yaml @@ -87,8 +87,8 @@ cloud: release: gpg: sign: - key-credentials-id: 'GPG_KEY' - passphrase-credentials-id: '' + key_credentials_id: GPG_KEY_FILE + passphrase_credentials_id: '' jenkins: email_creds_id: OPTAPLANNER_CI_NOTIFICATION_EMAILS agent: diff --git a/.ci/jenkins/dsl/jobs.groovy b/.ci/jenkins/dsl/jobs.groovy index 64a62c5919..d189091f68 100644 --- a/.ci/jenkins/dsl/jobs.groovy +++ b/.ci/jenkins/dsl/jobs.groovy @@ -149,19 +149,14 @@ void setupProjectReleaseJob() { GIT_BRANCH_NAME: "${GIT_BRANCH}", GIT_AUTHOR: "${GIT_AUTHOR_NAME}", - - DEFAULT_STAGING_REPOSITORY: "${MAVEN_NEXUS_STAGING_PROFILE_URL}", - ARTIFACTS_REPOSITORY: "${MAVEN_ARTIFACTS_REPOSITORY}", - OPTAPLANNER_LATEST_STREAM: "${GIT_MAIN_BRANCH}" ]) KogitoJobTemplate.createPipelineJob(this, jobParams)?.with { parameters { stringParam('RESTORE_FROM_PREVIOUS_JOB', '', 'URL to a previous stopped release job which needs to be continued') - stringParam('OPTAPLANNER_VERSION', '', 'Project version of OptaPlanner and its examples to release as Major.minor.micro') - stringParam('OPTAPLANNER_RELEASE_BRANCH', '', '(optional) Use to override the release branch name deduced from the OPTAPLANNER_VERSION') + stringParam('RELEASE_VERSION', '', 'Project version of OptaPlanner and its examples to release as Major.minor.micro') - stringParam('DROOLS_VERSION', '', '(optional) Drools version to be set to the project before releasing the artifacts.') + stringParam('GIT_TAG_NAME', '', 'Git tag to create. i.e.: 10.0.0-rc1') booleanParam('SKIP_TESTS', false, 'Skip all tests') } @@ -370,6 +365,8 @@ void setupDeployJob(JobType jobType, String envName = '') { stringParam('OPERATOR_IMAGE_REGISTRY_TOKEN_CREDENTIALS_ID', "${CLOUD_IMAGE_REGISTRY_TOKEN_CREDENTIALS_ID}", 'Image registry token credentials id.') stringParam('OPERATOR_IMAGE_NAMESPACE', "${CLOUD_IMAGE_NAMESPACE}", 'Operator image namespace to use to deploy image.') stringParam('OPERATOR_IMAGE_TAG', '', 'Image tag to use to deploy the operator image. OptaPlanner project version if not set.') + + stringParam('GIT_TAG_NAME', '', 'Optional if not RELEASE. Tag to be created in the repository') } } } diff --git a/.ci/jenkins/project/Jenkinsfile.release b/.ci/jenkins/project/Jenkinsfile.release index b52329f201..2119bc50cf 100644 --- a/.ci/jenkins/project/Jenkinsfile.release +++ b/.ci/jenkins/project/Jenkinsfile.release @@ -22,10 +22,8 @@ import org.jenkinsci.plugins.workflow.libs.Library @Library('jenkins-pipeline-shared-libraries')_ OPTAPLANNER_DEPLOY = 'optaplanner-deploy' -OPTAPLANNER_PROMOTE = 'optaplanner-promote' ARTIFACTS_STAGING_STAGE = 'stage.artifacts.staging' -ARTIFACTS_RELEASE_STAGE = 'stage.artifacts.release' JOB_PROPERTY_PREFIX = 'build' JOB_RESULT_PROPERTY_KEY = 'result' @@ -54,24 +52,17 @@ pipeline { echo "Release properties imported from previous job: ${releaseProperties}" } - assert getOptaPlannerVersion() + assert getReleaseVersion() currentBuild.displayName = getDisplayName() - sendNotification("Release Pipeline has started...\nOptaplanner version = ${getOptaPlannerVersion()}\n=> ${env.BUILD_URL}") - - // Safety measure to not publish to main JBoss - if (getGitAuthor() != 'apache' && !getArtifactsRepositoryParam()) { - sendNotification("Git Author is different from `apache` and no `ARTIFACTS_REPOSITORY` parameter has been provided. Are you sure you want to continue ? => ${env.BUILD_URL}input") - input message: 'Should the pipeline continue with no `ARTIFACTS_REPOSITORY` defined ?', ok: 'Yes' - } + sendNotification("Release Pipeline has started...\nOptaplanner version = ${getReleaseVersion()}\n=> ${env.BUILD_URL}") } } post { always { - setReleasePropertyIfneeded('optaplanner.version', getOptaPlannerVersion()) - setReleasePropertyIfneeded('optaplanner.branch', getOptaPlannerReleaseBranch()) - setReleasePropertyIfneeded('drools.version', getDroolsVersion()) + setReleasePropertyIfneeded('release.version', getReleaseVersion()) + setReleasePropertyIfneeded('git.tag.name', getGitTagName()) } } } @@ -82,7 +73,6 @@ pipeline { def buildParams = getDefaultBuildParams() addSkipTestsParam(buildParams) addSkipIntegrationTestsParam(buildParams) - addStringParam(buildParams, 'QUICKSTARTS_BUILD_BRANCH_NAME', getOptaPlannerReleaseBranch()) buildJob(OPTAPLANNER_DEPLOY, buildParams) } } @@ -92,54 +82,12 @@ pipeline { steps { script { if (!areArtifactsStaged()) { - sendNotification("All artifacts have been staged. You can find them here: ${getStagingRepository()}") + sendNotification('All artifacts have been staged.') } setArtifactsStaged() } } } - - stage('Are staged artifacts released?') { - when { - // Execute only if artifacts repository was not given, which means the staging repository has been created - expression { return !getArtifactsRepositoryParam() && !areArtifactsReleased() } - } - steps { - script { - String body = "${getOptaPlannerVersion()} artifacts are ready for release.\n" + - "Please release the staging repositories and then confirm here: ${env.BUILD_URL}input" - sendNotification(body) - input message: 'Has the staging repository been released ?', ok: 'Yes' - - sendNotification('Artifacts have been released. Finalizing now the release ...') - setArtifactsReleased() - } - } - } - - stage('Promote OptaPlanner') { - when { - expression { return isJobConsideredOk(OPTAPLANNER_DEPLOY) } - } - steps { - script { - def buildParams = getDefaultBuildParams() - addDeployBuildUrlParam(buildParams, OPTAPLANNER_DEPLOY) - - buildJob(OPTAPLANNER_PROMOTE, buildParams) - } - } - } - - stage('Setup next snapshot version') { - steps { - script { - def buildParams = [] - addStringParam(buildParams, 'OPTAPLANNER_VERSION', util.getNextVersion(getOptaPlannerVersion(), 'micro')) - build(job: '../setup-branch/0-setup-branch', wait: false, parameters: buildParams, propagate: false) - } - } - } } post { always { @@ -301,9 +249,10 @@ def readPropertiesFromUrl(String url, String propsFilename) { List getDefaultBuildParams() { List buildParams = [] - addDisplayNameParam(buildParams, getDisplayName(getOptaPlannerVersion())) - addStringParam(buildParams, 'PROJECT_VERSION', getOptaPlannerVersion()) - addStringParam(buildParams, 'DROOLS_VERSION', getDroolsVersion()) + addDisplayNameParam(buildParams, getDisplayName(getReleaseVersion())) + addStringParam(buildParams, 'PROJECT_VERSION', getReleaseVersion()) + addStringParam(buildParams, 'DROOLS_VERSION', getReleaseVersion()) + addStringParam(buildParams, 'GIT_TAG_NAME', getGitTagName()) return buildParams } @@ -346,34 +295,18 @@ String constructKey(String prefix, String paramId) { } String getDisplayName(version = '') { - version = version ?: getOptaPlannerVersion() + version = version ?: getReleaseVersion() return "Release ${version}" } -String getOptaPlannerVersion() { - return params.OPTAPLANNER_VERSION ?: getReleaseProperty('optaplanner.version') -} - -String getDroolsVersion() { - return params.DROOLS_VERSION ?: getReleaseProperty('drools.version') +String getReleaseVersion() { + return params.RELEASE_VERSION ?: getReleaseProperty('release.version') } String getGitAuthor() { return env.GIT_AUTHOR } -String getArtifactsRepositoryParam() { - return env['ARTIFACTS_REPOSITORY'] ?: '' -} - -String getOptaPlannerReleaseBranch() { - return params.OPTAPLANNER_RELEASE_BRANCH ?: (getReleaseProperty('optaplanner.branch') ?: util.getReleaseBranchFromVersion(getOptaPlannerVersion())) -} - -String getStagingRepository() { - return getArtifactsRepositoryParam() ?: env.DEFAULT_STAGING_REPOSITORY -} - void setReleasePropertyIfneeded(String key, def value) { if (value) { releaseProperties[key] = value @@ -402,10 +335,6 @@ void setArtifactsStaged() { setReleasePropertyIfneeded(ARTIFACTS_STAGING_STAGE, true) } -boolean areArtifactsReleased() { - return hasReleaseProperty(ARTIFACTS_RELEASE_STAGE) -} - -void setArtifactsReleased() { - setReleasePropertyIfneeded(ARTIFACTS_RELEASE_STAGE, true) +String getGitTagName() { + return params.GIT_TAG_NAME ?: getReleaseProperty('git.tag.name') }