diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..434ca3c --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,275 @@ +pipeline { + agent none + + triggers { + pollSCM 'H/10 * * * *' + } + + options { + disableConcurrentBuilds() + buildDiscarder(logRotator(numToKeepStr: '14')) + } + + stages { + stage("test: baseline (jdk8)") { + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=none ci/test.sh' + } + } + + stage("Test other configurations") { + parallel { + stage("test: baseline (jdk11)") { + agent { + docker { + image 'adoptopenjdk/openjdk11:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=none ci/test.sh' + } + } + stage("test: baseline (jdk13)") { + agent { + docker { + image 'adoptopenjdk/openjdk13:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=none ci/test.sh' + } + } + stage("test: spring-next (jdk8)") { + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=spring5-next ci/test.sh' + } + } + stage("test: spring-next (jdk11)") { + agent { + docker { + image 'adoptopenjdk/openjdk11:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=spring5-next ci/test.sh' + } + } + stage("test: spring-next (jdk13)") { + agent { + docker { + image 'adoptopenjdk/openjdk13:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 30, unit: 'MINUTES') } + steps { + sh 'rm -rf ?' + sh 'PROFILE=spring5-next ci/test.sh' + } + } + } + } + + stage('Deploy to Artifactory') { + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 20, unit: 'MINUTES') } + + environment { + ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + } + + steps { + script { + sh 'rm -rf ?' + + // Warm up this plugin quietly before using it. + sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -q org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version' + + // Extract project's version number + PROJECT_VERSION = sh( + script: 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version -o | grep -v INFO', + returnStdout: true + ).trim() + + RELEASE_TYPE = 'milestone' // .RC? or .M? + + if (PROJECT_VERSION.endsWith('SNAPSHOT')) { + RELEASE_TYPE = 'snapshot' + } else if (PROJECT_VERSION.endsWith('RELEASE')) { + RELEASE_TYPE = 'release' + } + + // Capture build output... + OUTPUT = sh( + script: "PROFILE=ci,${RELEASE_TYPE} ci/build.sh", + returnStdout: true + ).trim() + + echo "$OUTPUT" + + // ...to extract artifactory build info + build_info_path = OUTPUT.split('\n') + .find { it.contains('Artifactory Build Info Recorder') } + .split('Saving Build Info to ')[1] + .trim()[1..-2] + + // Stash the JSON build info to support promotion to bintray + dir(build_info_path + '/..') { + stash name: 'build_info', includes: "*.json" + } + } + } + } + stage('Release documentation') { + when { + anyOf { + branch '2.0.x' + branch 'release-2.0' + } + } + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 20, unit: 'MINUTES') } + + environment { + ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + } + + steps { + script { + sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -Pci,distribute ' + + '-Dartifactory.server=https://repo.spring.io ' + + "-Dartifactory.username=${ARTIFACTORY_USR} " + + "-Dartifactory.password=${ARTIFACTORY_PSW} " + + "-Dartifactory.distribution-repository=temp-private-local " + + '-Dmaven.test.skip=true deploy -B' + } + } + } + stage('Promote to Bintray') { + when { + branch 'release' + } + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 20, unit: 'MINUTES') } + + environment { + ARTIFACTORY = credentials('02bd1690-b54f-4c9f-819d-a77cb7a9822c') + } + + steps { + script { + sh 'rm -rf ?' + + // Warm up this plugin quietly before using it. + sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -q org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version' + + PROJECT_VERSION = sh( + script: 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version -o | grep -v INFO', + returnStdout: true + ).trim() + + if (PROJECT_VERSION.endsWith('RELEASE')) { + unstash name: 'build_info' + sh "ci/promote-to-bintray.sh" + } else { + echo "${PROJECT_VERSION} is not a candidate for promotion to Bintray." + } + } + } + } + stage('Sync to Maven Central') { + when { + branch 'release' + } + agent { + docker { + image 'adoptopenjdk/openjdk8:latest' + args '-v $HOME/.m2:/tmp/jenkins-home/.m2' + } + } + options { timeout(time: 20, unit: 'MINUTES') } + + environment { + BINTRAY = credentials('Bintray-spring-operator') + SONATYPE = credentials('oss-token') + } + + steps { + script { + sh 'rm -rf ?' + + // Warm up this plugin quietly before using it. + sh 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw -q org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version' + + PROJECT_VERSION = sh( + script: 'MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/jenkins-home" ./mvnw org.apache.maven.plugins:maven-help-plugin:2.1.1:evaluate -Dexpression=project.version -o | grep -v INFO', + returnStdout: true + ).trim() + + if (PROJECT_VERSION.endsWith('RELEASE')) { + unstash name: 'build_info' + sh "ci/sync-to-maven-central.sh" + } else { + echo "${PROJECT_VERSION} is not a candidate for syncing to Maven Central." + } + } + } + } + } + + post { + changed { + script { + slackSend( + color: (currentBuild.currentResult == 'SUCCESS') ? 'good' : 'danger', + channel: '#spring-hateoas', + message: "${currentBuild.fullDisplayName} - `${currentBuild.currentResult}`\n${env.BUILD_URL}") + emailext( + subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}", + mimeType: 'text/html', + recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']], + body: "${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}") + } + } + } +} diff --git a/ci/build.sh b/ci/build.sh new file mode 100755 index 0000000..51a1241 --- /dev/null +++ b/ci/build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -euo pipefail + +MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/spring-plugin-maven-repository" ./mvnw -P${PROFILE} -Dmaven.test.skip=true clean deploy -B diff --git a/ci/create-release.sh b/ci/create-release.sh new file mode 100755 index 0000000..0fd9c43 --- /dev/null +++ b/ci/create-release.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +set -euo pipefail + +ISSUE=$1 +RELEASE=$2 +SNAPSHOT=$3 + +# Bump up the version in pom.xml to the desired version and commit the change +./mvnw versions:set -DnewVersion=$RELEASE -DgenerateBackupPoms=false +git add . +git commit --message "#$ISSUE - Releasing Spring Plugin $RELEASE." + +# Tag the release +git tag -s $RELEASE -m "$RELEASE" + +# Bump up the version in pom.xml to the next snapshot +./mvnw versions:set -DnewVersion=$SNAPSHOT -DgenerateBackupPoms=false +git add . +git commit --message "#$ISSUE - Continue development on $SNAPSHOT." + + diff --git a/ci/promote-to-bintray.sh b/ci/promote-to-bintray.sh new file mode 100755 index 0000000..a00bb8d --- /dev/null +++ b/ci/promote-to-bintray.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +set -e -u + +buildName=`jq -r '.name' build-info.json` +buildNumber=`jq -r '.number' build-info.json` +groupId=`jq -r '.modules[0].id' build-info.json | sed 's/\(.*\):.*:.*/\1/'` +version=`jq -r '.modules[0].id' build-info.json | sed 's/.*:.*:\(.*\)/\1/'` + +echo "Promoting ${buildName}/${buildNumber}/${groupId}/${version} to libs-release-local" + +curl \ + -s \ + --connect-timeout 240 \ + --max-time 2700 \ + -u ${ARTIFACTORY_USR}:${ARTIFACTORY_PSW} \ + -H 'Content-type:application/json' \ + -d '{"sourceRepos": ["libs-release-local"], "targetRepo" : "spring-distributions", "async":"true"}' \ + -f \ + -X \ + POST "https://repo.spring.io/api/build/distribute/${buildName}/${buildNumber}" > /dev/null || { echo "Failed to distribute" >&2; exit 1; } + +echo "Waiting for artifacts to be published" + +ARTIFACTS_PUBLISHED=false +WAIT_TIME=10 +COUNTER=0 + +while [ $ARTIFACTS_PUBLISHED == "false" ] && [ $COUNTER -lt 120 ]; do + + result=$( curl -s https://api.bintray.com/packages/spring/jars/"${groupId}" ) + versions=$( echo "$result" | jq -r '.versions' ) + exists=$( echo "$versions" | grep "$version" -o || true ) + + if [ "$exists" = "$version" ]; then + ARTIFACTS_PUBLISHED=true + fi + + COUNTER=$(( COUNTER + 1 )) + sleep $WAIT_TIME + +done diff --git a/ci/sync-to-maven-central.sh b/ci/sync-to-maven-central.sh new file mode 100755 index 0000000..7150ca7 --- /dev/null +++ b/ci/sync-to-maven-central.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +set -e -u + +buildName=`jq -r '.name' build-info.json` +buildNumber=`jq -r '.number' build-info.json` +groupId=`jq -r '.modules[0].id' build-info.json | sed 's/\(.*\):.*:.*/\1/'` +version=`jq -r '.modules[0].id' build-info.json | sed 's/.*:.*:\(.*\)/\1/'` + +echo "Syncing ${buildName}/${buildNumber}/${groupId}/${version} to Maven Central..." + +curl \ + -s \ + --connect-timeout 240 \ + --max-time 2700 \ + -u ${BINTRAY_USR}:${BINTRAY_PSW} \ + -H 'Content-Type: application/json' \ + -d "{ \"username\": \"${SONATYPE_USR}\", \"password\": \"${SONATYPE_PSW}\"}" \ + -f \ + -X \ + POST "https://api.bintray.com/maven_central_sync/spring/jars/${groupId}/versions/${version}" > /dev/null || { echo "Failed to sync" >&2; exit 1; } + +echo "Sync complete" diff --git a/ci/test.sh b/ci/test.sh new file mode 100755 index 0000000..d635abd --- /dev/null +++ b/ci/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -euo pipefail + +MAVEN_OPTS="-Duser.name=jenkins -Duser.home=/tmp/spring-plugin-maven-repository" ./mvnw -P${PROFILE} clean dependency:list test -Dsort -B diff --git a/pom.xml b/pom.xml index 2bafffc..e1cd4f7 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0 - Copyright 2010 the original author or authors. + Copyright 2010-2019 the original author or authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -65,10 +65,11 @@ + spring5-next - 5.2.0.BUILD-SNAPSHOT + 5.2.1.BUILD-SNAPSHOT @@ -77,6 +78,155 @@ + + + + ci + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + create-javadoc-jar + + jar + + package + + + + + + + + + + snapshot + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + {{BUILD_URL}} + + + spring-plugin + spring-plugin + false + *:*:*:*@zip + + + https://repo.spring.io + {{ARTIFACTORY_USR}} + {{ARTIFACTORY_PSW}} + libs-snapshot-local + libs-snapshot-local + + + + + + + + + + + milestone + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + {{BUILD_URL}} + + + spring-plugin + spring-plugin + false + *:*:*:*@zip + + + https://repo.spring.io + {{ARTIFACTORY_USR}} + {{ARTIFACTORY_PSW}} + libs-milestone-local + libs-milestone-local + + + + + + + + + + + release + + + + + org.jfrog.buildinfo + artifactory-maven-plugin + 2.6.1 + false + + + build-info + + publish + + + + {{BUILD_URL}} + + + spring-plugin + spring-plugin + false + *:*:*:*@zip + + + https://repo.spring.io + {{ARTIFACTORY_USR}} + {{ARTIFACTORY_PSW}} + libs-release-local + libs-release-local + + + + + + + + +