diff --git a/ci/README.adoc b/ci/README.adoc new file mode 100644 index 0000000..f65e070 --- /dev/null +++ b/ci/README.adoc @@ -0,0 +1,16 @@ +== CI Pipeline + +Set up the Concourse target and login: + +[source] +---- +$ fly -t spring-cloud-connectors login -n spring-cloud-connectors -c https://runway-ci.eng.vmware.com +---- + +Deploy the pipelines + +[source] +---- +$ ./set-pipelines.sh +---- + diff --git a/ci/config-concourse.yml b/ci/config-concourse.yml new file mode 100644 index 0000000..4163106 --- /dev/null +++ b/ci/config-concourse.yml @@ -0,0 +1,2 @@ +artifactory-server: https://repo.spring.io +build-name: spring-cloud-connectors diff --git a/ci/config/release-scripts.yml b/ci/config/release-scripts.yml new file mode 100644 index 0000000..d31f8cb --- /dev/null +++ b/ci/config/release-scripts.yml @@ -0,0 +1,10 @@ +logging: + level: + io.spring.concourse: DEBUG +spring: + main: + banner-mode: off +sonatype: + exclude: + - 'build-info\.json' + - '.*\.zip' diff --git a/ci/images/spring-cloud-connectors-ci/Dockerfile b/ci/images/spring-cloud-connectors-ci/Dockerfile new file mode 100644 index 0000000..a6e7310 --- /dev/null +++ b/ci/images/spring-cloud-connectors-ci/Dockerfile @@ -0,0 +1,14 @@ +FROM harbor-repo.vmware.com/dockerhub-proxy-cache/library/ubuntu:bionic + +RUN apt-get update && apt-get install --no-install-recommends -y ca-certificates net-tools git curl jq gnupg + +RUN rm -rf /var/lib/apt/lists/* + +ENV JAVA_HOME /opt/openjdk +ENV PATH $JAVA_HOME/bin:$PATH +RUN mkdir -p /opt/openjdk && \ + cd /opt/openjdk && \ + curl -L https://github.com/AdoptOpenJDK/openjdk8-binaries/releases/download/jdk8u292-b10/OpenJDK8U-jdk_x64_linux_hotspot_8u292b10.tar.gz | tar xz --strip-components=1 + +ADD https://raw.githubusercontent.com/spring-io/concourse-java-scripts/v0.0.4/concourse-java.sh /opt/ +ADD https://repo.spring.io/libs-snapshot/io/spring/concourse/releasescripts/concourse-release-scripts/0.3.4-SNAPSHOT/concourse-release-scripts-0.3.4-SNAPSHOT.jar /opt/ diff --git a/ci/pipeline.yml b/ci/pipeline.yml new file mode 100644 index 0000000..2f12824 --- /dev/null +++ b/ci/pipeline.yml @@ -0,0 +1,220 @@ +--- +jobs: + - name: build-ci-images + plan: + - get: ci-images-git-repo + trigger: true + - put: spring-cloud-connectors-ci-image + params: + build: ci-images-git-repo/ci/images/spring-cloud-connectors-ci + get_params: + skip_download: "true" + + - name: build + serial: true + public: true + plan: + - get: git-repo + trigger: true + - task: build-project + timeout: 1h30m + file: git-repo/ci/tasks/build-project.yml + vars: + ci-image-tag: ((ci-image-tag)) + - put: artifactory-repo + params: &artifactory-params + signing_key: ((signing-key)) + signing_passphrase: ((signing-passphrase)) + repo: libs-snapshot-local + folder: distribution-repository + build_uri: "${ATC_EXTERNAL_URL}/teams/${BUILD_TEAM_NAME}/pipelines/${BUILD_PIPELINE_NAME}/jobs/${BUILD_JOB_NAME}/builds/${BUILD_NAME}" + build_number: "${BUILD_PIPELINE_NAME}-${BUILD_JOB_NAME}-${BUILD_NAME}" + disable_checksum_uploads: true + artifact_set: + - include: + - "/**/*-docs.zip" + properties: + "zip.type": "docs" + "zip.deployed": "false" + + - name: stage-milestone + serial: true + plan: + - get: git-repo + - task: stage + file: git-repo/ci/tasks/stage.yml + vars: + release-type: M + ci-image-tag: ((ci-image-tag)) + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo-staging + params: + repository: stage-git-repo + + - name: stage-rc + serial: true + plan: + - get: git-repo + - task: stage + file: git-repo/ci/tasks/stage.yml + vars: + release-type: RC + ci-image-tag: ((ci-image-tag)) + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo-staging + params: + repository: stage-git-repo + + - name: stage-release + serial: true + plan: + - get: git-repo + - task: stage + file: git-repo/ci/tasks/stage.yml + vars: + release-type: RELEASE + ci-image-tag: ((ci-image-tag)) + - put: artifactory-repo + params: + <<: *artifactory-params + repo: libs-staging-local + - put: git-repo-staging + params: + repository: stage-git-repo + + - name: promote-milestone + serial: true + plan: + - get: git-repo + - get: artifactory-repo + passed: [stage-milestone] + params: + save_build_info: true + - task: promote + file: git-repo/ci/tasks/promote.yml + vars: + release-type: M + ci-image-tag: ((ci-image-tag)) + + - name: promote-rc + serial: true + plan: + - in_parallel: + - get: git-repo + - get: artifactory-repo + passed: [stage-rc] + params: + save_build_info: true + - task: promote + file: git-repo/ci/tasks/promote.yml + vars: + release-type: RC + ci-image-tag: ((ci-image-tag)) + + - name: promote-release + serial: true + plan: + - in_parallel: + - get: git-repo + - get: artifactory-repo + passed: [stage-release] + params: + save_build_info: true + - task: promote + file: git-repo/ci/tasks/promote.yml + vars: + release-type: RELEASE + ci-image-tag: ((ci-image-tag)) + + - name: sync-to-maven-central + serial: true + plan: + - in_parallel: + - get: git-repo + - get: artifactory-repo + passed: [promote-release] + params: + save_build_info: true + - task: sync-to-maven-central + file: git-repo/ci/tasks/sync-to-maven-central.yml + vars: + ci-image-tag: ((ci-image-tag)) + +resource_types: + - name: artifactory-resource + type: registry-image + source: + repository: ((dockerhub-mirror-registry))/springio/artifactory-resource + tag: 0.0.14 + + - name: slack-notification + type: registry-image + source: + repository: ((dockerhub-mirror-registry))/cfcommunity/slack-notification-resource + tag: latest + +resources: + - name: git-repo + type: git + source: + uri: ((github-repo)) + username: ((github-token)) + password: ((github-password)) + branch: ((branch)) + ignore_paths: ["ci/images/*"] + fetch_tags: true + + - name: git-repo-staging + type: git + source: + uri: ((github-repo)) + username: ((github-token)) + password: ((github-password)) + branch: ((github-username))/staging + + - name: ci-images-git-repo + type: git + source: + uri: ((github-repo)) + branch: ((branch)) + paths: ["ci/images/*"] + + - name: spring-cloud-connectors-ci-image + type: docker-image + source: + repository: ((corporate-harbor-registry))/((dockerhub-organization))/spring-cloud-connectors-ci + username: ((corporate-harbor-robot-account.username)) + password: ((corporate-harbor-robot-account.password)) + tag: ((ci-image-tag)) + + - name: artifactory-repo + type: artifactory-resource + source: + uri: ((artifactory-server)) + username: ((artifactory-username)) + password: ((artifactory-password)) + build_name: ((build-name)) + +groups: + - name: "builds" + jobs: + - build + - name: "releases" + jobs: + - stage-milestone + - promote-milestone + - stage-rc + - promote-rc + - stage-release + - promote-release + - sync-to-maven-central + - name: "ci-images" + jobs: + - build-ci-images + diff --git a/ci/scripts/build-project.sh b/ci/scripts/build-project.sh new file mode 100755 index 0000000..4c1276b --- /dev/null +++ b/ci/scripts/build-project.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +set -euo pipefail + +readonly SKIP_TESTS="${SKIP_TESTS:-false}" + +# shellcheck source=common.sh +source "$(dirname "$0")/common.sh" +repository=$(pwd)/distribution-repository +if [ "$SKIP_TESTS" == "true" ]; then + build_task=assemble +else + build_task=build matrixTests +fi + +pushd git-repo >/dev/null +./gradlew clean "${build_task}" dist publish -PpublicationRepository="${repository}" +popd >/dev/null diff --git a/ci/scripts/common.sh b/ci/scripts/common.sh new file mode 100755 index 0000000..51716ce --- /dev/null +++ b/ci/scripts/common.sh @@ -0,0 +1,3 @@ +source /opt/concourse-java.sh +export TERM=xterm-256color +setup_symlinks diff --git a/ci/scripts/promote.sh b/ci/scripts/promote.sh new file mode 100755 index 0000000..97e0e22 --- /dev/null +++ b/ci/scripts/promote.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -euo pipefail + +# shellcheck source=scripts/common.sh +source $(dirname $0)/common.sh + +version=$( cat artifactory-repo/build-info.json | jq -r '.buildInfo.modules[0].id' | sed 's/.*:.*:\(.*\)/\1/' ) +export BUILD_INFO_LOCATION=$(pwd)/artifactory-repo/build-info.json + +java -jar /opt/concourse-release-scripts*.jar promote $RELEASE_TYPE $BUILD_INFO_LOCATION + +echo "Promotion complete" +echo $version > version/version diff --git a/ci/scripts/stage.sh b/ci/scripts/stage.sh new file mode 100755 index 0000000..68b6e7e --- /dev/null +++ b/ci/scripts/stage.sh @@ -0,0 +1,54 @@ +#!/bin/bash +set -eo pipefail + +# shellcheck source=scripts/common.sh +source "$(dirname "$0")/common.sh" +repository=$(pwd)/distribution-repository + +git clone git-repo stage-git-repo +echo + +pushd stage-git-repo >/dev/null + +git config user.name $USER_NAME +git config user.email $USER_EMAIL + +snapshotVersion=$(awk -F '=' '$1 == "version" { print $2 }' gradle.properties) +if [[ $RELEASE_TYPE == "M" ]]; then + stageVersion=$(get_next_milestone_release "$snapshotVersion") + nextVersion="$snapshotVersion" +elif [[ $RELEASE_TYPE == "RC" ]]; then + stageVersion=$(get_next_rc_release "$snapshotVersion") + nextVersion="$snapshotVersion" +elif [[ $RELEASE_TYPE == "RELEASE" ]]; then + stageVersion=$(get_next_release "$snapshotVersion") + nextVersion=$(bump_version_number "$snapshotVersion") +else + echo "Unknown release type $RELEASE_TYPE" >&2 + exit 1 +fi + +echo "Current version is v$snapshotVersion" +echo "Version to stage is v$stageVersion" +echo "Next development version will be v$nextVersion" +echo + +echo "Tagging version being staged (v$stageVersion)" +sed -i "s/version=$snapshotVersion/version=$stageVersion/" gradle.properties +git add gradle.properties +git commit -m "Release v$stageVersion" +git tag -a "v$stageVersion" -m "Release v$stageVersion" +echo + +./gradlew clean publish -PpublicationRepository="${repository}" +echo + +echo "Setting next development version (v$nextVersion)" +sed -i "s/version=$stageVersion/version=$nextVersion/" gradle.properties +git add gradle.properties +git commit -m "Next development version (v$nextVersion)" +echo + +echo "DONE" + +popd >/dev/null diff --git a/ci/scripts/sync-to-maven-central.sh b/ci/scripts/sync-to-maven-central.sh new file mode 100755 index 0000000..ef5269f --- /dev/null +++ b/ci/scripts/sync-to-maven-central.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -euo pipefail + +readonly BUILD_INFO_LOCATION="$(pwd)/artifactory-repo/build-info.json" +readonly CONFIG_DIR="$(pwd)/git-repo/ci/config" + +java -jar /opt/concourse-release-scripts*.jar \ + --spring.config.location="${CONFIG_DIR}/release-scripts.yml" \ + publishToCentral 'RELEASE' "$BUILD_INFO_LOCATION" "artifactory-repo" + +echo "Sync complete" diff --git a/ci/set-pipelines.sh b/ci/set-pipelines.sh new file mode 100755 index 0000000..a41eb4c --- /dev/null +++ b/ci/set-pipelines.sh @@ -0,0 +1,47 @@ +#!/usr/bin/env bash + +# +# Copyright 2016-2021 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. +# You may obtain a copy of the License at +# +# https://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. +# + +set -euo pipefail + +readonly FLY_TARGET="spring-cloud-connectors" +readonly GITHUB_REPO="https://github.com/spring-cloud/spring-cloud-connectors" + +set_pipeline() { + local pipeline_name pipeline_definition branch ci_image_tag + pipeline_name="${1:?pipeline name must be provided}" + pipeline_definition="${2:?pipeline definition file must be provided}" + branch="${3:?branch must be provided}" + ci_image_tag="${4:-$branch}" + + echo "Setting $pipeline_name pipeline..." + fly --target "$FLY_TARGET" set-pipeline \ + --pipeline "$pipeline_name" \ + --config "$pipeline_definition" \ + --load-vars-from config-concourse.yml \ + --var "github-repo=$GITHUB_REPO" \ + --var "branch=$branch" \ + --var "ci-image-tag=$ci_image_tag" +} + +set_pipelines() { + fly -t "$FLY_TARGET" sync + + set_pipeline spring-cloud-connectors-2.0.x pipeline.yml main spring-cloud-connectors-ci +} + +set_pipelines diff --git a/ci/tasks/build-project.yml b/ci/tasks/build-project.yml new file mode 100644 index 0000000..bcefed0 --- /dev/null +++ b/ci/tasks/build-project.yml @@ -0,0 +1,21 @@ +--- +platform: linux +image_resource: + type: registry-image + source: + repository: ((corporate-harbor-registry))/((dockerhub-organization))/spring-cloud-connectors-ci + username: ((corporate-harbor-robot-account.username)) + password: ((corporate-harbor-robot-account.password)) + tag: ((ci-image-tag)) +inputs: + - name: git-repo +outputs: + - name: distribution-repository +caches: + - path: maven + - path: gradle +run: + path: git-repo/ci/scripts/build-project.sh +params: + ARTIFACTORY_USERNAME: ((artifactory-username)) + ARTIFACTORY_PASSWORD: ((artifactory-password)) diff --git a/ci/tasks/promote.yml b/ci/tasks/promote.yml new file mode 100644 index 0000000..84e0c57 --- /dev/null +++ b/ci/tasks/promote.yml @@ -0,0 +1,21 @@ +--- +platform: linux +image_resource: + type: registry-image + source: + repository: ((corporate-harbor-registry))/((dockerhub-organization))/spring-cloud-connectors-ci + username: ((corporate-harbor-robot-account.username)) + password: ((corporate-harbor-robot-account.password)) + tag: ((ci-image-tag)) +inputs: + - name: git-repo + - name: artifactory-repo +outputs: + - name: version +params: + RELEASE_TYPE: ((release-type)) + ARTIFACTORY_SERVER: ((artifactory-server)) + ARTIFACTORY_USERNAME: ((artifactory-username)) + ARTIFACTORY_PASSWORD: ((artifactory-password)) +run: + path: git-repo/ci/scripts/promote.sh diff --git a/ci/tasks/stage.yml b/ci/tasks/stage.yml new file mode 100644 index 0000000..09f36ec --- /dev/null +++ b/ci/tasks/stage.yml @@ -0,0 +1,23 @@ +--- +platform: linux +image_resource: + type: registry-image + source: + repository: ((corporate-harbor-registry))/((dockerhub-organization))/spring-cloud-connectors-ci + username: ((corporate-harbor-robot-account.username)) + password: ((corporate-harbor-robot-account.password)) + tag: ((ci-image-tag)) +inputs: + - name: git-repo +outputs: + - name: stage-git-repo + - name: distribution-repository +params: + RELEASE_TYPE: ((release-type)) + USER_NAME: ((git-username)) + USER_EMAIL: ((git-email)) +caches: + - path: maven + - path: gradle +run: + path: git-repo/ci/scripts/stage.sh diff --git a/ci/tasks/sync-to-maven-central.yml b/ci/tasks/sync-to-maven-central.yml new file mode 100644 index 0000000..12779e9 --- /dev/null +++ b/ci/tasks/sync-to-maven-central.yml @@ -0,0 +1,19 @@ +--- +platform: linux +image_resource: + type: registry-image + source: + repository: ((corporate-harbor-registry))/((dockerhub-organization))/spring-cloud-connectors-ci + username: ((corporate-harbor-robot-account.username)) + password: ((corporate-harbor-robot-account.password)) + tag: ((ci-image-tag)) +inputs: + - name: git-repo + - name: artifactory-repo +params: + SONATYPE_URL: ((sonatype-url)) + SONATYPE_USERNAME: ((sonatype-user-token)) + SONATYPE_PASSWORD: ((sonatype-user-token-password)) + SONATYPE_STAGING_PROFILE: ((sonatype-staging-profile)) +run: + path: git-repo/ci/scripts/sync-to-maven-central.sh diff --git a/publish-maven.gradle b/publish-maven.gradle index 34d8aa8..511f243 100644 --- a/publish-maven.gradle +++ b/publish-maven.gradle @@ -1,66 +1,59 @@ -apply plugin: 'maven' +apply plugin: 'maven-publish' -install { - repositories.mavenInstaller { - customizePom(pom, project) + +publishing { + repositories { + maven { + url = project.properties.getOrDefault('publicationRepository', "${System.getenv('HOME')}/.m2/repository") + } } -} - -def customizePom(pom, gradleProject) { - pom.whenConfigured { generatedPom -> - // eliminate test-scoped dependencies (no need in maven central poms) - generatedPom.dependencies.removeAll { dep -> - dep.scope == 'test' - } - - // Ensure consistent ordering of dependencies to ease comparison with older poms - generatedPom.dependencies = generatedPom.dependencies.sort { dep -> - "$dep.scope:$dep.groupId:$dep.artifactId" - } - - // add all items necessary for maven central publication - generatedPom.project { - name = gradleProject.description - description = gradleProject.description - url = 'https://projects.spring.io/spring-cloud' - organization { - name = 'Spring IO' - url = 'https://spring.io' - } - licenses { - license { - name 'The Apache Software License, Version 2.0' - url 'https://www.apache.org/licenses/LICENSE-2.0.txt' - distribution 'repo' + publications { + mavenJava(MavenPublication) { + from components.java + pom { + afterEvaluate { + name = project.description + description = project.description } - } - - scm { - url = 'https://github.com/spring-projects/spring-cloud' - connection = 'scm:git:https://github.com/spring-projects/spring-cloud.git' - developerConnection = 'scm:git:https://github.com/spring-projects/spring-cloud.git' - } - - issueManagement { - system = 'GitHub' - url = 'https://github.com/spring-projects/spring-cloud/issues' - } - - developers { - developer { - id = 'ramnivas' - name = 'Ramnivas Laddad' - email = 'rladdad@gopivotal.com' + url = 'https://projects.spring.io/spring-cloud' + organization { + name = 'Spring IO' + url = 'https://spring.io' } - developer { - id = 'sfrederick' - name = 'Scott Frederick' - email = 'sfrederick@pivotal.io' + licenses { + license { + name = 'The Apache Software License, Version 2.0' + url = 'https://www.apache.org/licenses/LICENSE-2.0.txt' + distribution = 'repo' + } } - developer { - id = 'cschaefer' - name = 'Chris Schaefer' - email = 'cschaefer@pivotal.io' + scm { + url = 'https://github.com/spring-projects/spring-cloud' + connection = 'scm:git:https://github.com/spring-projects/spring-cloud.git' + developerConnection = 'scm:git:https://github.com/spring-projects/spring-cloud.git' + } + + issueManagement { + system = 'GitHub' + url = 'https://github.com/spring-projects/spring-cloud/issues' + } + + developers { + developer { + id = 'ramnivas' + name = 'Ramnivas Laddad' + email = 'rladdad@gopivotal.com' + } + developer { + id = 'sfrederick' + name = 'Scott Frederick' + email = 'sfrederick@pivotal.io' + } + developer { + id = 'cschaefer' + name = 'Chris Schaefer' + email = 'cschaefer@pivotal.io' + } } } }