Files
SCM-Manager/Jenkinsfile

262 lines
9.6 KiB
Plaintext
Raw Normal View History

2018-05-31 12:34:34 +02:00
#!groovy
// Keep the version in sync with the one used in pom.xml in order to get correct syntax completion.
2020-03-03 11:13:11 +01:00
@Library('github.com/cloudogu/ces-build-lib@1.35.1')
2018-05-31 12:34:34 +02:00
import com.cloudogu.ces.cesbuildlib.*
2018-09-24 13:04:03 +02:00
node('docker') {
2018-05-31 12:34:34 +02:00
// Change this as when we go back to default - necessary for proper SonarQube analysis
mainBranch = 'develop'
properties([
// Keep only the last 10 build to preserve space
2018-09-21 09:07:12 +02:00
buildDiscarder(logRotator(numToKeepStr: '10')),
2020-03-11 11:05:54 +01:00
disableConcurrentBuilds()
])
2018-05-31 12:34:34 +02:00
2020-03-11 11:05:54 +01:00
timeout(activity: true, time: 60, unit: 'MINUTES') {
2018-05-31 12:34:34 +02:00
Git git = new Git(this)
catchError {
2018-05-31 12:34:34 +02:00
Maven mvn = setupMavenBuild()
2018-05-31 12:34:34 +02:00
stage('Checkout') {
checkout scm
}
2018-05-31 12:34:34 +02:00
2020-03-11 11:05:54 +01:00
if (isReleaseBranch()) {
stage('Set Version') {
String releaseVersion = getReleaseVersion();
// set maven versions
mvn "versions:set -DgenerateBackupPoms=false -DnewVersion=${releaseVersion}"
// set versions for ui packages
// we need to install in order to set version with ui-scripts
mvn "-pl :scm-ui buildfrontend:install@install"
mvn "-pl :scm-ui buildfrontend:run@set-version"
// stage pom changes
sh "git status --porcelain | sed s/^...// | grep pom.xml | xargs git add"
// stage package.json changes
sh "git status --porcelain | sed s/^...// | grep package.json | xargs git add"
// stage lerna.json changes
sh "git add lerna.json"
// commit changes
sh "git -c user.name='CES Marvin' -c user.email='cesmarvin@cloudogu.com' commit -m 'release version ${releaseVersion}'"
// merge release branch into master
sh "git checkout master"
sh "git merge --ff-only ${env.BRANCH_NAME}"
// set tag
sh "git -c user.name='CES Marvin' -c user.email='cesmarvin@cloudogu.com' tag -m 'release version ${releaseVersion}' ${releaseVersion}"
}
}
stage('Build') {
mvn 'clean install -DskipTests'
}
2018-05-31 12:34:34 +02:00
stage('Unit Test') {
mvn 'test -Pcoverage -Dmaven.test.failure.ignore=true'
2020-03-11 11:05:54 +01:00
junit allowEmptyResults: true, testResults: '**/target/surefire-reports/TEST-*.xml,**/target/jest-reports/TEST-*.xml'
}
stage('Integration Test') {
2020-03-11 11:05:54 +01:00
mvn 'verify -Pit -pl :scm-webapp,:scm-it -Dmaven.test.failure.ignore=true -Dscm.git.core.supportsatomicfilecreation=false'
junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml'
}
2018-08-06 16:37:22 +02:00
stage('SonarQube') {
analyzeWith(mvn)
if (!waitForQualityGateWebhookToBeCalled()) {
currentBuild.result = 'UNSTABLE'
}
}
2018-09-24 13:03:02 +02:00
2020-03-11 11:05:54 +01:00
if (isMainBranch() || isReleaseBranch()) {
2019-07-31 13:26:58 +02:00
stage('Lifecycle') {
try {
// failBuildOnNetworkError -> so we can catch the exception and neither fail nor make our build unstable
nexusPolicyEvaluation iqApplication: selectedApplication('scm'), iqScanPatterns: [[scanPattern: 'scm-server/target/scm-server-app.zip']], iqStage: 'build', failBuildOnNetworkError: true
} catch (Exception e) {
echo "ERROR: iQ Server policy eval failed. Not marking build unstable for now."
echo "ERROR: iQ Server Exception: ${e.getMessage()}"
}
2019-07-31 13:26:58 +02:00
}
2020-03-11 11:05:54 +01:00
if (isBuildSuccessful()) {
def commitHash = git.getCommitHash()
2020-03-11 11:05:54 +01:00
def imageVersion = mvn.getVersion()
if (imageVersion.endsWith('-SNAPSHOT')) {
imageVersion = imageVersion.replace('-SNAPSHOT', "${commitHash.substring(0,7)}-${BUILD_NUMBER}")
}
stage('Archive') {
archiveArtifacts 'scm-webapp/target/scm-webapp.war'
archiveArtifacts 'scm-server/target/scm-server-app.*'
}
stage('Maven Deployment') {
// TODO why is the server recreated
// delete appassembler target, because the maven plugin fails to recreate the tar
sh "rm -rf scm-server/target/appassembler"
// deploy java artifacts
mvn.useRepositoryCredentials([id: 'maven.scm-manager.org', url: 'https://maven.scm-manager.org/nexus', credentialsId: 'maven.scm-manager.org', type: 'Nexus2'])
2020-03-11 11:05:54 +01:00
mvn.deployToNexusRepository()
// deploy frontend bits
withCredentials([string(credentialsId: 'cesmarvin_npm_token', variable: 'NPM_TOKEN')]) {
writeFile encoding: 'UTF-8', file: '.npmrc', text: "//registry.npmjs.org/:_authToken='${NPM_TOKEN}'"
writeFile encoding: 'UTF-8', file: '.yarnrc', text: '''
registry "https://registry.npmjs.org/"
always-auth true
email cesmarvin@cloudogu.com
'''.trim()
// we are tricking lerna by pretending that we are not a git repository
sh "mv .git .git.disabled"
try {
mvn "-pl :scm-ui buildfrontend:run@deploy"
} finally {
sh "mv .git.disabled .git"
}
2020-03-11 11:05:54 +01:00
}
}
stage('Docker') {
docker.withRegistry('', 'hub.docker.com-cesmarvin') {
def image = docker.build('cloudogu/scm-manager')
image.push(imageVersion)
if (isReleaseBranch()) {
image = docker.build('scmmanager/scm-manager')
image.push(imageVersion)
}
}
}
stage('Presentation Environment') {
build job: 'scm-manager/next-scm.cloudogu.com', propagate: false, wait: false, parameters: [
string(name: 'changeset', value: commitHash),
string(name: 'imageTag', value: imageVersion)
]
}
if (isReleaseBranch()) {
stage('Update Repository') {
// merge changes into develop
sh "git checkout develop"
// TODO what if we have an conflict
// e.g.: someone has edit the changelog durring the release
sh "git merge master"
// set versions for maven packages
mvn "build-helper:parse-version versions:set -DgenerateBackupPoms=false -DnewVersion='\${parsedVersion.majorVersion}.\${parsedVersion.nextMinorVersion}.0-SNAPSHOT'"
// set versions for ui packages
mvn "-pl :scm-ui buildfrontend:run@set-version"
// stage pom changes
sh "git status --porcelain | sed s/^...// | grep pom.xml | xargs git add"
// stage package.json changes
sh "git status --porcelain | sed s/^...// | grep package.json | xargs git add"
// stage lerna.json changes
sh "git add lerna.json"
// commit changes
sh "git -c user.name='CES Marvin' -c user.email='cesmarvin@cloudogu.com' commit -m 'prepare for next development iteration'"
// push changes back to remote repository
withCredentials([usernamePassword(credentialsId: 'cesmarvin-github', usernameVariable: 'GIT_AUTH_USR', passwordVariable: 'GIT_AUTH_PSW')]) {
sh "git -c credential.helper=\"!f() { echo username='\$GIT_AUTH_USR'; echo password='\$GIT_AUTH_PSW'; }; f\" push origin master --tags"
sh "git -c credential.helper=\"!f() { echo username='\$GIT_AUTH_USR'; echo password='\$GIT_AUTH_PSW'; }; f\" push origin develop --tags"
sh "git -c credential.helper=\"!f() { echo username='\$GIT_AUTH_USR'; echo password='\$GIT_AUTH_PSW'; }; f\" push origin :${env.BRANCH_NAME}"
}
2019-08-06 11:32:05 +02:00
}
}
}
}
2018-05-31 12:34:34 +02:00
}
mailIfStatusChanged(git.commitAuthorEmail)
}
2018-05-31 12:34:34 +02:00
}
String mainBranch
Maven setupMavenBuild() {
2020-03-03 11:16:12 +01:00
Maven mvn = new MavenWrapperInDocker(this, "scmmanager/java-build:11.0.6_10")
2020-03-11 11:05:54 +01:00
if (isMainBranch() || isReleaseBranch()) {
// Release starts javadoc, which takes very long, so do only for certain branches
mvn.additionalArgs += ' -DperformRelease'
// JDK8 is more strict, we should fix this before the next release. Right now, this is just not the focus, yet.
mvn.additionalArgs += ' -Dmaven.javadoc.failOnError=false'
}
return mvn
}
void analyzeWith(Maven mvn) {
withSonarQubeEnv('sonarcloud.io-scm') {
String mvnArgs = "${env.SONAR_MAVEN_GOAL} " +
"-Dsonar.host.url=${env.SONAR_HOST_URL} " +
"-Dsonar.login=${env.SONAR_AUTH_TOKEN} "
if (isPullRequest()) {
echo "Analysing SQ in PR mode"
mvnArgs += "-Dsonar.pullrequest.base=${env.CHANGE_TARGET} " +
"-Dsonar.pullrequest.branch=${env.CHANGE_BRANCH} " +
"-Dsonar.pullrequest.key=${env.CHANGE_ID} " +
"-Dsonar.pullrequest.provider=bitbucketcloud " +
"-Dsonar.pullrequest.bitbucketcloud.owner=sdorra " +
2018-12-04 15:52:02 +01:00
"-Dsonar.pullrequest.bitbucketcloud.repository=scm-manager " +
"-Dsonar.cpd.exclusions=**/*StoreFactory.java,**/*UserPassword.js "
} else {
mvnArgs += " -Dsonar.branch.name=${env.BRANCH_NAME} "
if (!isMainBranch()) {
// Avoid exception "The main branch must not have a target" on main branch
mvnArgs += " -Dsonar.branch.target=${mainBranch} "
}
}
mvn "${mvnArgs}"
}
}
2020-03-11 11:05:54 +01:00
boolean isReleaseBranch() {
return env.BRANCH_NAME.startsWith("release/");
}
String getReleaseVersion() {
return env.BRANCH_NAME.substring("release/".length());
}
boolean isMainBranch() {
return mainBranch.equals(env.BRANCH_NAME)
}
boolean waitForQualityGateWebhookToBeCalled() {
boolean isQualityGateSucceeded = true
timeout(time: 5, unit: 'MINUTES') { // Needed when there is no webhook for example
def qGate = waitForQualityGate()
echo "SonarQube Quality Gate status: ${qGate.status}"
if (qGate.status != 'OK') {
isQualityGateSucceeded = false
}
}
return isQualityGateSucceeded
}