Add Spring Build Conventions Gradle Plugins.

Resolves #623.
This commit is contained in:
John Blum
2022-09-21 16:46:04 -07:00
parent 7bfdd4e3d9
commit 518f38b8b5
68 changed files with 3814 additions and 0 deletions

47
build.gradle Normal file
View File

@@ -0,0 +1,47 @@
import io.spring.gradle.convention.Utils
buildscript {
ext {
snapshotBuild = Utils.isSnapshot(project)
milestoneBuild = Utils.isMilestone(project)
releaseBuild = Utils.isRelease(project)
}
repositories {
mavenCentral()
gradlePluginPortal()
maven { url 'https://repo.spring.io/plugins-release' }
maven {
url 'https://repo.spring.io/plugins-snapshot'
if (project.hasProperty('artifactoryUsername')) {
credentials {
username "$artifactoryUsername"
password "$artifactoryPassword"
}
}
}
}
}
apply plugin: 'io.spring.convention.root'
description = 'Spring Data for Apache Geode Build'
allprojects {
group = 'org.springframework.data'
repositories {
if (version.contains('-')) {
maven { url "https://repo.spring.io/milestone" }
}
if (version.endsWith('-SNAPSHOT')) {
maven { url "https://repo.spring.io/snapshot" }
}
}
}
nohttp {
source.excludes = [ "**/.gradle/**", "**/.m2/**", "**/build/**", "**/target/**" ]
}

72
buildSrc/build.gradle Normal file
View File

@@ -0,0 +1,72 @@
plugins {
id "java-gradle-plugin"
id "java"
id "groovy"
}
repositories {
mavenCentral()
gradlePluginPortal()
maven {
url 'https://repo.spring.io/plugins-release/'
}
}
sourceCompatibility = JavaVersion.VERSION_1_8
sourceSets {
main {
java {
srcDirs = []
}
groovy {
srcDirs += [ "src/main/java" ]
}
}
}
gradlePlugin {
plugins {
managementConfiguration {
id = "io.spring.convention.management-configuration"
implementationClass = "io.spring.gradle.convention.ManagementConfigurationPlugin"
}
githubMilestone {
id = "org.springframework.github.milestone"
implementationClass = "org.springframework.gradle.github.milestones.GitHubMilestonePlugin"
}
propdeps {
id = "org.springframework.propdeps"
implementationClass = "org.springframework.gradle.propdeps.PropDepsPlugin"
}
sagan {
id = "org.springframework.sagan"
implementationClass = "org.springframework.gradle.sagan.SaganPlugin"
}
}
}
configurations {
implementation {
exclude module: 'groovy-all'
}
}
dependencies {
implementation localGroovy()
implementation 'com.apollographql.apollo:apollo-runtime:2.4.5'
implementation 'com.google.code.gson:gson:2.8.8'
implementation 'io.github.gradle-nexus:publish-plugin:1.1.0'
implementation 'io.spring.gradle:dependency-management-plugin:1.0.11.RELEASE'
implementation 'io.spring.javaformat:spring-javaformat-checkstyle:0.0.29'
implementation 'io.spring.nohttp:nohttp-checkstyle:0.0.10'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.10'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm:3.3.2'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:3.3.2'
implementation 'org.jfrog.buildinfo:build-info-extractor-gradle:4.27.1'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'
implementation 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.7.1'
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.GroovyPlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.PluginManager
import org.gradle.plugins.ide.eclipse.EclipsePlugin
import org.gradle.plugins.ide.idea.IdeaPlugin
import org.springframework.gradle.CopyPropertiesPlugin
import org.springframework.gradle.propdeps.PropDepsEclipsePlugin
import org.springframework.gradle.propdeps.PropDepsIdeaPlugin
import org.springframework.gradle.propdeps.PropDepsPlugin
/**
* Abstract base Gradle {@link Plugin} for all Spring Java & Groovy Gradle Plugins used by SBDG.
*
* This abstract base Gradle {@link Plugin} primarily serves to apply a common set of Gradle {@link Plugin Plugins),
* such as the {@link JavaPlugin} and {@link GroovyPlugin} for the various SBDG project Spring modules as well as other
* Spring Gradle {@link Plugin Plugins} to manage builds, IDE integration, releases and so on.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
@Override
final void apply(Project project) {
applyPlugins(project)
setJarManifestAttributes(project)
project.test {
useJUnitPlatform()
}
applyAdditionalPlugins(project)
}
private void applyPlugins(Project project) {
PluginManager pluginManager = project.getPluginManager()
applyJavaPlugin(pluginManager)
applyGroovyPlugin(project)
applyIdePlugins(pluginManager)
applySpringPlugins(pluginManager)
}
@SuppressWarnings("all")
private void applyGroovyPlugin(Project project) {
if (project.file("src/main/groovy").exists()
|| project.file("src/test/groovy").exists()
|| project.file("src/integration-test/groovy").exists()) {
project.getPluginManager().apply(GroovyPlugin.class)
}
}
@SuppressWarnings("all")
private void applyIdePlugins(PluginManager pluginManager) {
pluginManager.apply(EclipsePlugin)
pluginManager.apply(IdeaPlugin)
}
@SuppressWarnings("all")
private void applyJavaPlugin(PluginManager pluginManager) {
pluginManager.apply(JavaPlugin.class)
}
@SuppressWarnings("all")
private void applySpringPlugins(PluginManager pluginManager) {
pluginManager.apply(ManagementConfigurationPlugin)
pluginManager.apply(RepositoryConventionPlugin)
pluginManager.apply(PropDepsPlugin)
pluginManager.apply(PropDepsEclipsePlugin)
pluginManager.apply(PropDepsIdeaPlugin)
pluginManager.apply(SpringDependencyManagementConventionsPlugin)
pluginManager.apply(DependencySetPlugin)
pluginManager.apply(TestsConfigurationPlugin)
pluginManager.apply(IntegrationTestPlugin)
pluginManager.apply(JacocoPlugin);
pluginManager.apply(JavadocOptionsPlugin)
pluginManager.apply(CheckstylePlugin)
pluginManager.apply(CopyPropertiesPlugin)
}
private void setJarManifestAttributes(Project project) {
project.jar {
manifest.attributes["Created-By"] = "${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})"
manifest.attributes["Implementation-Title"] = project.name
manifest.attributes["Implementation-Version"] = project.version
manifest.attributes["Automatic-Module-Name"] = project.name.replace('-', '.')
}
}
protected abstract void applyAdditionalPlugins(Project project);
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* Applies and configures the JFrag Artifactory Gradle {@link Plugin} to publish Gradle {@link Project} artifacts
* to the Spring {@literal snapshot}, {@literal milestone} and {@literal release} repositories in Artifactory.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class ArtifactoryPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.plugins.apply('com.jfrog.artifactory')
// (Externally-defined) Methods cannot be invoked inside the Groovy/Gradle DSL.
def artifactoryRepoKey = resolveRepositoryKey(project)
def authRequired = isAuthRequired(project)
project.artifactory {
contextUrl = 'https://repo.spring.io'
publish {
repository {
repoKey = artifactoryRepoKey
if (authRequired) {
username = artifactoryUsername
password = artifactoryPassword
}
}
defaults {
publications('mavenJava')
}
}
}
}
@SuppressWarnings("all")
private boolean isAuthRequired(Project project) {
project?.hasProperty('artifactoryUsername')
}
@SuppressWarnings("all")
private String resolveRepositoryKey(Project project) {
boolean isSnapshot = Utils.isSnapshot(project);
boolean isMilestone = Utils.isMilestone(project);
return isSnapshot ? 'libs-snapshot-local'
: isMilestone ? 'libs-milestone-local'
: 'libs-release-local'
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
/**
* Configures and applies the Checkstyle Gradle {@link Plugin}.
*
* @author Vedran Pavic
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class CheckstylePlugin implements Plugin<Project> {
static final String CHECKSTYLE_PATHNAME = 'etc/checkstyle'
static final String CHECKSTYLE_VERSION = '8.21'
@Override
void apply(Project project) {
project.plugins.withType(JavaPlugin) {
def checkstyleDirectory = project.rootProject.file(CHECKSTYLE_PATHNAME)
if (checkstyleDirectory?.isDirectory()) {
project.getPluginManager().apply('checkstyle')
project.dependencies.add('checkstyle', 'io.spring.javaformat:spring-javaformat-checkstyle')
project.dependencies.add('checkstyle', 'io.spring.nohttp:nohttp-checkstyle')
project.checkstyle {
configDirectory = checkstyleDirectory
toolVersion = CHECKSTYLE_VERSION
}
}
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.
*/
package io.spring.gradle.convention
import org.gradle.api.DefaultTask
import org.gradle.api.artifacts.component.ModuleComponentSelector
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.TaskAction
/**
* Gradle API Task to output all the configured project &amp; subproject (runtime) dependencies.
*
* @author Rob Winch
* @author John Blum
*/
class DependencyManagementExportTask extends DefaultTask {
@Internal
def projects;
@Input
String getProjectNames() {
return this.projects*.name
}
@TaskAction
void dependencyManagementExport() throws IOException {
def projects = this.projects ?: project.subprojects + project
def configurations = projects*.configurations*.findAll {
[ 'testRuntimeOnly', 'integrationTestRuntime', 'grettyRunnerTomcat10', 'ajtools' ].contains(it.name)
}
def dependencyResults = configurations*.incoming*.resolutionResult*.allDependencies.flatten()
def moduleVersionVersions = dependencyResults
.findAll { r -> r.requested instanceof ModuleComponentSelector }
.collect { r -> r.selected.moduleVersion }
def projectDependencies = projects.collect { p ->
"${p.group}:${p.name}:${p.version}".toString()
} as Set
def dependencies = moduleVersionVersions
.collect { d -> "${d.group}:${d.name}:${d.version}".toString() }
.sort() as Set
println ''
println ''
println 'dependencyManagement {'
println '\tdependencies {'
dependencies
.findAll { d -> !projectDependencies.contains(d) }
.each { println "\t\tdependency '$it'" }
println '\t}'
println '}'
println ''
println ''
println 'TIP Use this to find duplicates:\n$ sort gradle/dependency-management.gradle| uniq -c | grep -v \'^\\s*1\''
println ''
println ''
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
/**
* Defines sets of dependencies to make it easy to add a related group of dependencies to a Gradle {@link Project}.
*
* The dependencies set defined include:
*
* <ul>
* <li>jstlDependencies</li>
* <li>seleniumDependencies</li>
* <li>slf4jDependencies</li>
* <li>testDependencies</li>
* </ul>
*
*{@literal testDependencies} are automatically added to Java projects
* ({@lin Project Projects} with the {@link JavaPlugin} applied).
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class DependencySetPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.ext.jstlDependencies = [
"jakarta.servlet.jsp.jstl:jakarta.servlet.jsp.jstl-api",
"org.glassfish.web:jakarta.servlet.jsp.jstl"
]
project.ext.seleniumDependencies = [
"org.seleniumhq.selenium:htmlunit-driver",
"org.seleniumhq.selenium:selenium-support"
]
project.ext.slf4jDependencies = [
"org.slf4j:slf4j-api",
"org.slf4j:jcl-over-slf4j",
"org.slf4j:jul-over-slf4j",
"org.slf4j:log4j-over-slf4j",
"ch.qos.logback:logback-classic"
]
project.ext.testDependencies = [
"junit:junit",
"org.junit.jupiter:junit-jupiter-api",
"org.junit.vintage:junit-vintage-engine",
"org.assertj:assertj-core",
"org.mockito:mockito-core",
"org.projectlombok:lombok",
"org.springframework:spring-test",
"org.springframework.data:spring-data-geode-test",
"edu.umd.cs.mtc:multithreadedtc"
]
project.plugins.withType(JavaPlugin) {
project.dependencies {
testImplementation project.testDependencies
}
}
}
}

View File

@@ -0,0 +1,96 @@
/*
* Copyright 2002-2017 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* @author Rob Winch
* @author John Blum
*/
class DeployDocsPlugin implements Plugin<Project> {
static final String DEFAULT_SPRING_DOCS_HOST = 'docs-ip.spring.io';
@Override
void apply(Project project) {
project.getPluginManager().apply('org.hidetake.ssh')
project.ssh.settings {
knownHosts = allowAnyHosts
}
project.remotes {
docs {
retryCount = 5 // retry 5 times (default is 0)
retryWaitSec = 10 // wait 10 seconds between retries (default is 0)
role 'docs'
host = project.hasProperty('deployDocsHost')
? project.findProperty('deployDocsHost')
: DEFAULT_SPRING_DOCS_HOST
user = project.findProperty('deployDocsSshUsername')
identity = project.hasProperty('deployDocsSshKeyPath')
? project.file(project.findProperty('deployDocsSshKeyPath'))
: project.hasProperty('deployDocsSshKey')
? project.findProperty('deployDocsSshKey')
: null
passphrase = project.hasProperty('deployDocsSshPassphrase')
? project.findProperty('deployDocsSshPassphrase')
: null
}
}
project.task('deployDocs') {
dependsOn 'docs'
doLast {
project.ssh.run {
session(project.remotes.docs) {
def now = System.currentTimeMillis()
def name = project.rootProject.name
def version = project.rootProject.version
def tempPath = "/tmp/${name}-${now}-docs/".replaceAll(' ', '_')
execute "mkdir -p $tempPath"
project.tasks.docsZip.outputs.each { out ->
put from: out.files, into: tempPath
}
execute "unzip $tempPath*.zip -d $tempPath"
def extractPath =
"/var/www/domains/spring.io/docs/htdocs/autorepo/docs/${name}/${version}/"
execute "rm -rf $extractPath"
execute "mkdir -p $extractPath"
execute "mv $tempPath/docs/* $extractPath"
execute "chmod -R g+w $extractPath"
}
}
}
}
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2002-2017 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.plugins.PluginManager
import org.gradle.api.tasks.bundling.Zip
/**
* Aggregates Asciidoc, Javadoc, and deploying of the docs into a single Gradle Plugin.
*
* @author Rob Winch
* @author John Blum
*/
class DocsPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
PluginManager pluginManager = project.getPluginManager()
pluginManager.apply("org.asciidoctor.jvm.convert")
pluginManager.apply("org.asciidoctor.jvm.pdf")
pluginManager.apply(AsciidoctorConventionPlugin)
pluginManager.apply(DeployDocsPlugin)
pluginManager.apply(JavadocApiPlugin)
def projectName = Utils.getProjectName(project);
def pdfFilename = projectName + '-reference.pdf';
Task docsZip = project.tasks.create('docsZip', Zip) {
archiveBaseName = project.rootProject.name
archiveClassifier = 'docs'
group = 'Distribution'
description = "Builds -${archiveClassifier} archive containing all documenation for deployment to docs-ip.spring.io."
dependsOn 'api', 'asciidoctor'
from(project.tasks.api.outputs) {
into 'api'
}
from(project.tasks.asciidoctor.outputs) {
into 'reference/html5'
include '**'
}
from(project.tasks.asciidoctorPdf.outputs) {
into 'reference/pdf'
include '**'
rename "index.pdf", pdfFilename
}
into 'docs'
duplicatesStrategy DuplicatesStrategy.EXCLUDE
}
Task docs = project.tasks.create("docs") {
group = 'Documentation'
description 'Aggregator Task to generate all documentation.'
dependsOn docsZip
}
project.tasks.assemble.dependsOn docs
}
}

View File

@@ -0,0 +1,133 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.GroovyPlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.testing.Test
import org.gradle.plugins.ide.eclipse.EclipsePlugin
import org.gradle.plugins.ide.idea.IdeaPlugin
import org.springframework.gradle.propdeps.PropDepsPlugin
/**
* Adds Integration Test support to Java projects.
*
* <ul>
* <li>Adds integrationTestCompile and integrationTestRuntimeOnly configurations</li>
* <li>Adds new source test folder of src/integration-test/java</li>
* <li>Adds a task to run integration tests named integrationTest</li>
* <li>Adds a new source test folder src/integration-test/groovy if the Groovy Plugin was added</li>
* </ul>
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.Task
* @see org.gradle.api.tasks.testing.Test
*/
class IntegrationTestPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.plugins.withType(JavaPlugin.class) {
applyJava(project)
}
}
private void applyJava(Project project) {
// Do not add any configuration if there are no (integration) tests to avoid adding Gretty.
if (isIntegrationTestSourceAvailable(project)) {
project.configurations {
integrationTestCompile {
extendsFrom testCompileClasspath
}
integrationTestRuntime {
extendsFrom integrationTestCompile, testRuntimeOnly
}
}
project.sourceSets {
integrationTest {
java.srcDir project.file('src/integration-test/java')
resources.srcDir project.file('src/integration-test/resources')
compileClasspath = project.sourceSets.main.output + project.sourceSets.test.output + project.configurations.integrationTestCompile
runtimeClasspath = output + compileClasspath + project.configurations.integrationTestRuntime
}
}
Task integrationTestTask = project.tasks.create("integrationTest", Test) {
group = 'Verification'
description = 'Runs Integration Tests'
dependsOn 'jar'
testClassesDirs = project.sourceSets.integrationTest.output.classesDirs
classpath = project.sourceSets.integrationTest.runtimeClasspath
shouldRunAfter project.tasks.test
useJUnitPlatform()
}
project.tasks.check.dependsOn integrationTestTask
project.plugins.withType(EclipsePlugin) {
project.eclipse.classpath {
plusConfigurations += [ project.configurations.integrationTestCompile ]
}
}
project.plugins.withType(IdeaPlugin) {
project.idea {
module {
testSourceDirs += project.file('src/integration-test/java')
scopes.TEST.plus += [ project.configurations.integrationTestCompile ]
}
}
}
project.plugins.withType(GroovyPlugin) {
project.sourceSets {
integrationTest {
groovy.srcDirs project.file('src/integration-test/groovy')
}
}
project.plugins.withType(IdeaPlugin) {
project.idea {
module {
testSourceDirs += project.file('src/integration-test/groovy')
}
}
}
}
project.plugins.withType(PropDepsPlugin) {
project.configurations {
integrationTestCompile {
extendsFrom optional, provided
}
}
}
}
}
@SuppressWarnings("all")
private boolean isIntegrationTestSourceAvailable(Project project) {
return project.file('src/integration-test/').exists()
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
/**
* Applies the Jacoco Gradle {@link Plugin} to the target Gradle {@link Project}
* and configures {@literal check} Gradle Task to depend on the {@literal jacocoTestReport} Gradle Task.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class JacocoPlugin implements Plugin<Project> {
private static final String JACOCO_VERSION = '0.8.7';
@Override
void apply(Project project) {
project.plugins.withType(JavaPlugin) {
project.getPluginManager().apply("jacoco")
project.tasks.check.dependsOn project.tasks.jacocoTestReport
project.jacoco {
toolVersion = JACOCO_VERSION
}
}
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.JavaVersion
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.javadoc.Javadoc
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.regex.Pattern
/**
* Generates Javadoc API documentation for {@literal this} {@link Project}.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.plugins.JavaPluginExtension
* @see org.gradle.api.tasks.javadoc.Javadoc
*/
class JavadocApiPlugin implements Plugin<Project> {
Logger logger = LoggerFactory.getLogger(getClass())
Set<Pattern> excludes = Collections.singleton(Pattern.compile("test"))
@Override
void apply(Project project) {
Project rootProject = project.getRootProject()
Javadoc api = project.tasks.create("api", Javadoc)
api.setGroup("Documentation")
api.setDescription("Generates Javadoc API documentation.")
api.setDestinationDir(new File(project.getBuildDir(), "api"))
api.setMaxMemory("1024m")
api.doLast {
if (JavaVersion.current().isJava11Compatible()) {
project.copy({ copy -> copy
.from(api.destinationDir)
.into(api.destinationDir)
.include("element-list")
.rename("element-list", "package-list")
})
}
}
Set<Project> subprojects = rootProject.getSubprojects()
if (subprojects.isEmpty()) {
addProject(api, project)
}
for (Project subproject : subprojects) {
addProject(api, subproject)
}
project.getPluginManager().apply("io.spring.convention.javadoc-options")
}
@SuppressWarnings("unused")
void setExcludes(String... excludes) {
excludes ?= new String[0]
this.excludes = new HashSet<>(excludes.length)
excludes.each {this.excludes.add(Pattern.compile(it)) }
}
private void addProject(Javadoc javadoc, Project project) {
if (isProjectIncluded(project)) {
logInfo("Add sources for project {}", project)
project.getPlugins().withType(SpringModulePlugin).all { plugin ->
JavaPluginExtension java = project.getExtensions().getByType(JavaPluginExtension)
SourceSet mainSourceSet = java.getSourceSets().getByName("main")
javadoc.setSource(javadoc.getSource() + mainSourceSet.getAllJava())
project.getTasks().withType(Javadoc).all((Javadoc javadocTask) ->
javadoc.setClasspath(javadoc.getClasspath() + javadocTask.getClasspath()))
}
}
}
private boolean isProjectIncluded(Project project) {
for (Pattern exclude : this.excludes) {
if (exclude.matcher(project.getName()).matches()) {
logInfo("Skipping project {} because it was excluded by {}", project, exclude)
return false
}
}
return true
}
private void logInfo(String message, Object... arguments) {
this.logger.info(message, arguments)
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.javadoc.Javadoc
/**
* Configures Javadoc (Gradle Task) to disable the DocLint tool by setting the {@literal -Xdoclint} JVM extension option
* to {@literal none} as well as setting the {@literal -quiet} Javadoc option thereby suppressing the output from
* the Javadoc tool.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.tasks.javadoc.Javadoc
*/
class JavadocOptionsPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.getTasks().withType(Javadoc).all { task ->
task.options.addStringOption('Xdoclint:none', '-quiet')
}
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 2017-present 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.
*/
package io.spring.gradle.convention;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaTestFixturesPlugin;
import org.gradle.api.plugins.PluginContainer;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.VariantVersionMappingStrategy;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.springframework.gradle.propdeps.PropDepsPlugin;
/**
* Creates a {@literal Management} Gradle {@link Configuration} that is appropriate for adding a platform
* that it is not exposed externally.
*
* If the {@link JavaPlugin} is applied, then the {@literal compileClasspath}, {@literal runtimeClasspath},
* {@literal testCompileClasspath}, and {@literal testRuntimeClasspath} will extend from it.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
public class ManagementConfigurationPlugin implements Plugin<Project> {
public static final String MANAGEMENT_CONFIGURATION_NAME = "management";
// TODO: Understand why we don't want certain Configurations to be consumed, resolved or visible???
@Override
public void apply(Project project) {
ConfigurationContainer configurations = project.getConfigurations();
configurations.create(MANAGEMENT_CONFIGURATION_NAME, management -> {
management.setCanBeConsumed(false);
management.setCanBeResolved(false);
management.setVisible(false);
PluginContainer plugins = project.getPlugins();
plugins.withType(JavaPlugin.class, javaPlugin -> {
configurations.getByName(JavaPlugin.COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
configurations.getByName(JavaPlugin.TEST_COMPILE_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
configurations.getByName(JavaPlugin.TEST_RUNTIME_CLASSPATH_CONFIGURATION_NAME).extendsFrom(management);
});
plugins.withType(JavaTestFixturesPlugin.class, javaTestFixturesPlugin -> {
configurations.getByName("testFixturesCompileClasspath").extendsFrom(management);
configurations.getByName("testFixturesRuntimeClasspath").extendsFrom(management);
});
plugins.withType(MavenPublishPlugin.class, mavenPublishPlugin -> {
PublishingExtension publishingExtension = project.getExtensions().getByType(PublishingExtension.class);
publishingExtension.getPublications().withType(MavenPublication.class, mavenPublication ->
mavenPublication.versionMapping(versions ->
versions.allVariants(VariantVersionMappingStrategy::fromResolutionResult)));
});
plugins.withType(PropDepsPlugin.class, propDepsPlugin -> {
configurations.getByName("optional").extendsFrom(management);
configurations.getByName("provided").extendsFrom(management);
});
});
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlatformPlugin
import org.gradle.api.plugins.PluginManager
import org.springframework.gradle.CopyPropertiesPlugin
import org.springframework.gradle.maven.SpringMavenPlugin
/**
* Gradle {@link Plugin} used to generate a Maven BOM for the Gradle {@link Project}.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class MavenBomPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaPlatformPlugin)
pluginManager.apply(SpringMavenPlugin)
pluginManager.apply(CopyPropertiesPlugin)
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention;
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* Declares Maven Repositories (for example: mavenLocal(), mavenCentral(), jcenter(), Spring Repositories, etc)
* based on a {@link Project Project's} release artifact(s).
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class RepositoryConventionPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
String[] forceMavenRepositories =
((String) project.findProperty("forceMavenRepositories"))?.split(',')
boolean isImplicitSnapshotRepository = forceMavenRepositories == null && Utils.isSnapshot(project)
boolean isImplicitMilestoneRepository = forceMavenRepositories == null && Utils.isMilestone(project)
boolean isSnapshot = isImplicitSnapshotRepository || forceMavenRepositories?.contains('snapshot')
boolean isMilestone = isImplicitMilestoneRepository || forceMavenRepositories?.contains('milestone')
project.repositories {
if (forceMavenRepositories?.contains('local')) {
mavenLocal()
}
mavenCentral()
jcenter() {
content {
includeGroup "org.gretty"
}
}
if (isSnapshot) {
maven {
name = 'artifactory-snapshot'
if (project.hasProperty('artifactoryUsername')) {
credentials {
username project.artifactoryUsername
password project.artifactoryPassword
}
}
url = 'https://repo.spring.io/snapshot/'
}
}
if (isSnapshot || isMilestone) {
maven {
name = 'artifactory-milestone'
if (project.hasProperty('artifactoryUsername')) {
credentials {
username project.artifactoryUsername
password project.artifactoryPassword
}
}
url = 'https://repo.spring.io/milestone/'
}
}
maven {
name = 'artifactory-release'
if (project.hasProperty('artifactoryUsername')) {
credentials {
username project.artifactoryUsername
password project.artifactoryPassword
}
}
url = 'https://repo.spring.io/release/'
}
maven {
name = 'shibboleth'
url = 'https://build.shibboleth.net/nexus/content/repositories/releases/'
}
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import io.spring.nohttp.gradle.NoHttpPlugin
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.PluginManager
import org.springframework.gradle.maven.SpringNexusPublishPlugin
/**
* The Gradle {@link Plugin} applied to the {@literal root} Gradle {@link Project} with functionality inherited by
* all Gradle {@link Project Projects} ({@literal sub-projects} in a multi-module project.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class RootProjectPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
applyPlugins(project)
configureMavenCentralRepository(project)
configureResolutionStrategy(project)
configureSonarQube(project)
createDependencyManagementExportTask(project)
createReleasePublishedArtifactsTask(project)
}
@SuppressWarnings("all")
private void applyPlugins(Project project) {
PluginManager pluginManager = project.getPluginManager()
pluginManager.apply(BasePlugin)
pluginManager.apply(NoHttpPlugin)
pluginManager.apply(SchemaPlugin)
pluginManager.apply(SpringNexusPublishPlugin)
pluginManager.apply("org.sonarqube")
}
/**
* Adds the Maven Central Repository to the list of repositories used by this Gradle {@link Project} build
* to resolve dependencies.
*
* @param project Gradle {@link Project}.
* @see org.gradle.api.Project
*/
@SuppressWarnings("all")
private void configureMavenCentralRepository(Project project) {
project.repositories.mavenCentral()
}
private void configureResolutionStrategy(Project project) {
project.allprojects {
configurations.all {
resolutionStrategy {
cacheChangingModulesFor 0, 'seconds'
cacheDynamicVersionsFor 0, 'seconds'
}
}
}
}
private void configureSonarQube(Project project) {
String projectName = Utils.getProjectName(project)
project.sonarqube {
properties {
property "sonar.projectName", projectName
property "sonar.java.coveragePlugin", "jacoco"
property "sonar.jacoco.reportPath", "${project.buildDir.name}/jacoco.exec"
property "sonar.links.homepage", "https://spring.io/${projectName}"
property "sonar.links.ci", "https://jenkins.spring.io/job/${projectName}/"
property "sonar.links.issue", "https://github.com/spring-projects/${projectName}/issues"
property "sonar.links.scm", "https://github.com/spring-projects/${projectName}"
property "sonar.links.scm_dev", "https://github.com/spring-projects/${projectName}.git"
}
}
}
@SuppressWarnings("all")
private void createDependencyManagementExportTask(Project project) {
project.tasks.create("dependencyManagementExport", DependencyManagementExportTask)
}
private void createReleasePublishedArtifactsTask(Project project) {
project.task("releasePublishedArtifacts", { Task releasePublishedArtifacts ->
if (isReleasingToMavenCentral(project)) {
releasePublishedArtifacts.dependsOn project.tasks.closeAndReleaseOssrhStagingRepository
}
})
}
@SuppressWarnings("all")
private boolean isReleasingToMavenCentral(Project project) {
Utils.isRelease(project) && project.hasProperty("ossrhUsername")
}
}

View File

@@ -0,0 +1,100 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* Deploys the Spring XML schema (XSD) files to the spring.io server.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class SchemaDeployPlugin implements Plugin<Project> {
static final String DEFAULT_SPRING_DOCS_HOST = 'docs-ip.spring.io';
@Override
void apply(Project project) {
project.getPluginManager().apply('org.hidetake.ssh')
project.ssh.settings {
knownHosts = allowAnyHosts
}
project.remotes {
docs {
retryCount = 5 // Retry 5 times (default is 0)
retryWaitSec = 10 // Wait 10 seconds between retries (default is 0)
role 'docs'
host = project.hasProperty('deployDocsHost')
? project.findProperty('deployDocsHost')
: DEFAULT_SPRING_DOCS_HOST
user = project.findProperty('deployDocsSshUsername')
identity = project.hasProperty('deployDocsSshKeyPath')
? project.file(project.findProperty('deployDocsSshKeyPath'))
: project.hasProperty('deployDocsSshKey')
? project.findProperty('deployDocsSshKey')
: null
passphrase = project.hasProperty('deployDocsSshPassphrase')
? project.findProperty('deployDocsSshPassphrase')
: null
}
}
project.task('deploySchema') {
dependsOn 'schemaZip'
doFirst {
project.ssh.run {
session(project.remotes.docs) {
def now = System.currentTimeMillis()
def name = project.rootProject.name
def version = project.rootProject.version
def tempPath = "/tmp/${name}-${now}-schema/".replaceAll(' ', '_')
execute "mkdir -p $tempPath"
project.tasks.schemaZip.outputs.each { out ->
println "Putting $out.files"
put from: out.files, into: tempPath
}
execute "unzip $tempPath*.zip -d $tempPath"
def extractPath = "/var/www/domains/spring.io/docs/htdocs/autorepo/schema/${name}/${version}/"
execute "rm -rf $extractPath"
execute "mkdir -p $extractPath"
execute "rm -f $tempPath*.zip"
execute "rm -rf $extractPath*"
execute "mv $tempPath/* $extractPath"
execute "chmod -R g+w $extractPath"
}
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* Gradle {@link Plugin} to ZIP and deploy Spring XML schemas (XSDK) files.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class SchemaPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.getPluginManager().apply(SchemaZipPlugin)
project.getPluginManager().apply(SchemaDeployPlugin)
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2016-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. 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.bundling.Zip
/**
* Zips all Spring XML schemas (XSD) files.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class SchemaZipPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
Zip schemaZip = project.tasks.create('schemaZip', Zip)
schemaZip.archiveBaseName = project.rootProject.name
schemaZip.archiveClassifier = 'schema'
schemaZip.description = "Builds -${schemaZip.archiveClassifier} archive containing all XSDs" +
" for deployment to static.springframework.org/schema."
schemaZip.group = 'Distribution'
project.rootProject.subprojects.each { module ->
module.getPlugins().withType(JavaPlugin.class).all {
Properties schemas = new Properties();
module.sourceSets.main.resources
.find { it.path.endsWith('META-INF/spring.schemas') }
?.withInputStream { schemas.load(it) }
for (def key : schemas.keySet()) {
def zipEntryName = key.replaceAll(/http.*schema.(.*).spring-.*/, '$1')
assert zipEntryName != key
File xsdFile = module.sourceSets.main.resources.find {
it.path.endsWith(schemas.get(key))
}
assert xsdFile != null
schemaZip.into(zipEntryName) {
duplicatesStrategy DuplicatesStrategy.EXCLUDE
from xsdFile.path
}
}
}
}
}
}

View File

@@ -0,0 +1,73 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import io.spring.gradle.dependencymanagement.DependencyManagementPlugin
import org.gradle.api.Plugin
import org.gradle.api.Project
/**
* Applies and configures the Spring Gradle {@link DependencyManagementPlugin}.
*
* Additionally, if a {@literal gradle/dependency-management.gradle} file is present in a Gradle {@link Project},
* then this file will be automatically applied in order to configure {@link Project} additional dependencies.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.plugins.PluginManager
*/
class SpringDependencyManagementConventionsPlugin implements Plugin<Project> {
static final String DEPENDENCY_MANAGEMENT_RESOURCE = "gradle/dependency-management.gradle"
@Override
void apply(Project project) {
applyAndConfigureDependencyManagementPlugin(project)
applyDependencyManagementResources(project)
}
private void applyAndConfigureDependencyManagementPlugin(Project project) {
project.getPluginManager().apply(DependencyManagementPlugin)
project.dependencyManagement {
resolutionStrategy {
cacheChangingModulesFor 0, "seconds"
}
}
}
@SuppressWarnings("all")
private void applyDependencyManagementResources(Project project) {
File rootDir = project.rootDir
List<File> dependencyManagementFiles = [ project.rootProject.file(DEPENDENCY_MANAGEMENT_RESOURCE) ]
for (File dir = project.projectDir; dir != rootDir; dir = dir.parentFile) {
dependencyManagementFiles.add(new File(dir, DEPENDENCY_MANAGEMENT_RESOURCE))
}
dependencyManagementFiles.each { file ->
if (file.exists()) {
project.apply from: file.absolutePath
}
}
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.PluginManager
import org.springframework.gradle.maven.SpringMavenPlugin
/**
* Defines a Gradle {@link Project} as a Spring module.
*
* @author Rob Winch
* @author John Blum
* @see io.spring.gradle.convention.AbstractSpringJavaPlugin
* @see org.springframework.gradle.maven.SpringMavenPlugin
* @see org.gradle.api.plugins.JavaLibraryPlugin
* @see org.gradle.api.Project
*/
class SpringModulePlugin extends AbstractSpringJavaPlugin {
@Override
void applyAdditionalPlugins(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaLibraryPlugin.class)
pluginManager.apply(SpringMavenPlugin.class);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
/**
* @author Rob Winch
* @author John Blum
*/
class SpringSampleBootPlugin extends SpringSamplePlugin {
@Override
void applyAdditionalPlugins(Project project) {
project.getPluginManager().apply("org.springframework.boot");
super.applyAdditionalPlugins(project);
project.repositories {
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
/**
* Gradle Spring Java Plugin used to identify a Gradle {@link Project} as a {@literal Sample} and add configuration
* to skip Sonar Qube inspections.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Project
*/
class SpringSamplePlugin extends AbstractSpringJavaPlugin {
@Override
void applyAdditionalPlugins(Project project) {
Utils.skipProjectWithSonarQubePlugin(project)
}
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.PluginManager
import org.gradle.api.tasks.testing.Test
/**
* Spring Sample Gradle Plugin used to build Samples as a Java Web Application (WAR archive).
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Project
* @see org.gradle.api.Task
*/
class SpringSampleWarPlugin extends SpringSamplePlugin {
@Override
void applyAdditionalPlugins(Project project) {
super.applyAdditionalPlugins(project);
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply("war");
pluginManager.apply("org.gretty");
project.gretty {
servletContainer = 'tomcat10'
contextPath = '/'
fileLogEnabled = false
}
Task prepareAppServerForIntegrationTests = project.tasks.create('prepareAppServerForIntegrationTests') {
group = 'Verification'
description = 'Prepares the Web application server for Integration Testing'
doFirst {
project.gretty {
httpPort = getRandomPort()
httpsPort = getRandomPort()
}
}
}
project.tasks.matching { it.name == "appBeforeIntegrationTest" }.all { task ->
task.dependsOn prepareAppServerForIntegrationTests
}
project.tasks.withType(Test).all { task ->
if ("integrationTest".equals(task.name)) {
applyForIntegrationTest(project, task)
}
}
}
def applyForIntegrationTest(Project project, Task integrationTest) {
project.gretty.integrationTestTask = integrationTest.name
integrationTest.doFirst {
def gretty = project.gretty
boolean isHttps = gretty.httpsEnabled
Integer httpPort = integrationTest.systemProperties['gretty.httpPort']
Integer httpsPort = integrationTest.systemProperties['gretty.httpsPort']
int port = isHttps ? httpsPort : httpPort
String host = gretty.host ?: 'localhost'
String contextPath = gretty.contextPath
String httpBaseUrl = "http://${host}:${httpPort}${contextPath}"
String httpsBaseUrl = "https://${host}:${httpsPort}${contextPath}"
String baseUrl = isHttps ? httpsBaseUrl : httpBaseUrl
integrationTest.systemProperty 'app.port', port
integrationTest.systemProperty 'app.httpPort', httpPort
integrationTest.systemProperty 'app.httpsPort', httpsPort
integrationTest.systemProperty 'app.baseURI', baseUrl
integrationTest.systemProperty 'app.httpBaseURI', httpBaseUrl
integrationTest.systemProperty 'app.httpsBaseURI', httpsBaseUrl
integrationTest.systemProperty 'geb.build.baseUrl', baseUrl
integrationTest.systemProperty 'geb.build.reportsDir', 'build/geb-reports'
}
}
def getRandomPort() {
ServerSocket serverSocket = new ServerSocket(0)
int port = serverSocket.localPort
serverSocket.close()
return port
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
/**
* Gradle Plugin used to disable Sonar Qube inspection(s) during Spring project tests.
* @author Rob Winch
* @author John Blum
*/
class SpringTestPlugin extends AbstractSpringJavaPlugin {
@Override
void applyAdditionalPlugins(Project project) {
Utils.skipProjectWithSonarQubePlugin(project)
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention;
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaPlugin
import org.gradle.jvm.tasks.Jar
/**
* Adds ability to depend on the test JAR within other Gradle {@link Project Projects} using:
*
* <code>
* testImplementation project(path: ':foo', configuration: 'tests')
* </code>
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
class TestsConfigurationPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
project.plugins.withType(JavaPlugin) {
project.configurations {
tests.extendsFrom testRuntimeClasspath
}
project.tasks.create('testJar', Jar) {
archiveClassifier = 'test'
from project.sourceSets.test.output
}
project.artifacts {
tests project.testJar
}
}
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2022-present 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.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
import org.sonarqube.gradle.SonarQubePlugin
/**
* Utility class encapsulating common operations on Gradle {@link Project Projects}.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Project
*/
class Utils {
private Utils() {}
static String getProjectName(Project project) {
String projectName = project.getRootProject().getName()
if (projectName.endsWith("-build")) {
projectName = projectName.substring(0, projectName.length() - "-build".length())
}
return projectName
}
static boolean isMilestone(Project project) {
return projectVersion(project).matches('^.*[.-]M\\d+$')
|| projectVersion(project).matches('^.*[.-]RC\\d+$')
}
static boolean isRelease(Project project) {
return !(isSnapshot(project) || isMilestone(project))
}
static boolean isSnapshot(Project project) {
return projectVersion(project).matches('^.*([.-]BUILD)?-SNAPSHOT$')
}
private static String projectVersion(Project project) {
return String.valueOf(project.version)
}
static String findPropertyAsString(Project project, String propertyName) {
return (String) project.findProperty(propertyName)
}
static void skipProjectWithSonarQubePlugin(Project project) {
project.plugins.withType(SonarQubePlugin) {
project.sonarqube.skipProject = true
}
}
}

View File

@@ -0,0 +1,230 @@
/*
* Copyright 2017-present 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.
*/
package io.spring.gradle.convention;
import java.io.File;
import java.net.URI;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask;
import org.asciidoctor.gradle.jvm.AsciidoctorJExtension;
import org.asciidoctor.gradle.jvm.AsciidoctorJPlugin;
import org.asciidoctor.gradle.jvm.AsciidoctorTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.file.DuplicatesStrategy;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Sync;
/**
* Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}.
*
* When the plugin is applied:
*
* <ul>
* <li>All warnings are made fatal.
* <li>A task is created to resolve and unzip our documentation resources (CSS and Javascript).
* <li>For each {@link AsciidoctorTask} (HTML only):
* <ul>
* <li>A configuration named asciidoctorExtensions is ued to add the
* <a href="https://github.com/spring-io/spring-asciidoctor-extensions#block-switch">block switch</a> extension
* <li>{@code doctype} {@link AsciidoctorTask#options(Map) option} is configured.
* <li>{@link AsciidoctorTask#attributes(Map) Attributes} are configured for syntax highlighting, CSS styling,
* docinfo, etc.
* </ul>
* <li>For each {@link AbstractAsciidoctorTask} (HTML and PDF):
* <ul>
* <li>{@link AsciidoctorTask#attributes(Map) Attributes} are configured to enable warnings for references to
* missing attributes, the year is added as @{code today-year}, etc
* <li>{@link AbstractAsciidoctorTask#baseDirFollowsSourceDir() baseDirFollowsSourceDir()} is enabled.
* </ul>
* </ul>
*
* @author Andy Wilkinson
* @author Rob Winch
*/
public class AsciidoctorConventionPlugin implements Plugin<Project> {
private static final String SPRING_ASCIIDOCTOR_EXTENSIONS_BLOCK_SWITCH_VERSION = "0.4.2.RELEASE";
private static final String SPRING_DOC_RESOURCES_VERSION = "0.2.5";
private static final String SPRING_ASCIIDOCTOR_EXTENSION_BLOCK_SWITCH_DEPENDENCY =
String.format("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:%s",
SPRING_ASCIIDOCTOR_EXTENSIONS_BLOCK_SWITCH_VERSION);
private static final String SPRING_DOC_RESOURCES_DEPENDENCY =
String.format("io.spring.docresources:spring-doc-resources:%s", SPRING_DOC_RESOURCES_VERSION);
@Override
public void apply(Project project) {
project.getPlugins().withType(AsciidoctorJPlugin.class, asciidoctorPlugin -> {
createDefaultAsciidoctorRepository(project);
makeAllWarningsFatal(project);
Sync unzipResources = createUnzipDocumentationResourcesTask(project);
project.getTasks().withType(AbstractAsciidoctorTask.class, asciidoctorTask -> {
asciidoctorTask.dependsOn(unzipResources);
configureAttributes(project, asciidoctorTask);
configureExtensions(project, asciidoctorTask);
configureOptions(asciidoctorTask);
asciidoctorTask.baseDirFollowsSourceDir();
asciidoctorTask.useIntermediateWorkDir();
asciidoctorTask.resources(resourcesSpec -> {
resourcesSpec.setDuplicatesStrategy(DuplicatesStrategy.INCLUDE);
resourcesSpec.from(unzipResources);
resourcesSpec.from(asciidoctorTask.getSourceDir(), resourcesSrcDirSpec -> {
// https://github.com/asciidoctor/asciidoctor-gradle-plugin/issues/523
// For now copy the entire sourceDir over so that include files are
// available in the intermediateWorkDir
// resourcesSrcDirSpec.include("images/**");
});
});
if (asciidoctorTask instanceof AsciidoctorTask) {
configureHtmlOnlyAttributes(project, asciidoctorTask);
}
});
});
}
private void createDefaultAsciidoctorRepository(Project project) {
project.getGradle().afterProject(it -> {
RepositoryHandler repositories = it.getRepositories();
if (repositories.isEmpty()) {
repositories.mavenCentral();
repositories.maven(repo -> repo.setUrl(URI.create("https://repo.spring.io/release")));
}
});
}
/**
* Requests the base Spring Documentation Resources from {@literal https://repo.spring.io/release} and uses it
* to format and render documentation.
*
* @param project {@literal this} Gradle {@link Project}.
* @return a {@link Sync} task used to copy the Spring Documentation Resources to a build directory
* used to generate documentation.
* @see <a href="https://repo.spring.io/ui/native/release/io/spring/docresources/spring-doc-resources">spring-doc-resources</a>
* @see org.gradle.api.tasks.Sync
* @see org.gradle.api.Project
*/
@SuppressWarnings("all")
private Sync createUnzipDocumentationResourcesTask(Project project) {
Configuration documentationResources = project.getConfigurations().maybeCreate("documentationResources");
documentationResources.getDependencies()
.add(project.getDependencies().create(SPRING_DOC_RESOURCES_DEPENDENCY));
Sync unzipResources = project.getTasks().create("unzipDocumentationResources", Sync.class, sync -> {
sync.dependsOn(documentationResources);
Callable<List<FileTree>> source = () -> {
List<FileTree> result = new ArrayList<>();
documentationResources.getAsFileTree().forEach(file -> result.add(project.zipTree(file)));
return result;
};
sync.from(source);
File destination = new File(project.getBuildDir(), "docs/resources");
sync.into(project.relativePath(destination));
});
return unzipResources;
}
@SuppressWarnings("unused")
private void configureAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("attribute-missing", "warn");
attributes.put("icons", "font");
attributes.put("idprefix", "");
attributes.put("idseparator", "-");
attributes.put("docinfo", "shared");
attributes.put("sectanchors", "");
attributes.put("sectnums", "");
attributes.put("today-year", LocalDate.now().getYear());
asciidoctorTask.attributes(attributes);
}
private void configureExtensions(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Configuration extensionsConfiguration = project.getConfigurations().maybeCreate("asciidoctorExtensions");
extensionsConfiguration.defaultDependencies(dependencies -> dependencies.add(project.getDependencies()
.create(SPRING_ASCIIDOCTOR_EXTENSION_BLOCK_SWITCH_DEPENDENCY)));
asciidoctorTask.configurations(extensionsConfiguration);
}
private void configureHtmlOnlyAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("source-highlighter", "highlight.js");
attributes.put("highlightjsdir", "js/highlight");
attributes.put("highlightjs-theme", "github");
attributes.put("linkcss", true);
attributes.put("icons", "font");
attributes.put("stylesheet", "css/spring.css");
asciidoctorTask.getAttributeProviders().add(() -> {
Object version = project.getVersion();
Map<String, Object> localAttributes = new HashMap<>();
if (version != null && !Project.DEFAULT_VERSION.equals(version)) {
localAttributes.put("revnumber", version);
}
return localAttributes;
});
asciidoctorTask.attributes(attributes);
}
private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
}
private void makeAllWarningsFatal(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).fatalWarnings(".*");
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* Copies {@literal root} {@link Project} properties to the target ({@literal this}) {@link Project},
* the {@link Project} for which {@literal this} Gradle {@link Plugin} is applied.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
*/
public class CopyPropertiesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
copyPropertyFromRootProjectTo("group", project);
copyPropertyFromRootProjectTo("version", project);
copyPropertyFromRootProjectTo("description", project);
}
private void copyPropertyFromRootProjectTo(String propertyName, Project project) {
Object propertyValue = project.getRootProject().findProperty(propertyName);
if (propertyValue != null) {
project.setProperty(propertyName, propertyValue);
}
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.github.milestones;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import java.io.IOException;
import java.util.List;
public class GitHubMilestoneApi {
private String baseUrl = "https://api.github.com";
private OkHttpClient client;
private Gson gson = new Gson();
public GitHubMilestoneApi() {
this.client = new OkHttpClient.Builder().build();
}
public GitHubMilestoneApi(String gitHubToken) {
this.client = new OkHttpClient.Builder()
.addInterceptor(new AuthorizationInterceptor(gitHubToken))
.build();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public long findMilestoneNumberByTitle(RepositoryRef repositoryRef, String milestoneTitle) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/milestones?per_page=100";
Request request = new Request.Builder().get().url(url)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not find milestone with title " + milestoneTitle + " for repository " + repositoryRef + ". Response " + response);
}
List<Milestone> milestones = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Milestone>>(){}.getType());
for (Milestone milestone : milestones) {
if (milestoneTitle.equals(milestone.getTitle())) {
return milestone.getNumber();
}
}
if (milestones.size() <= 100) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
}
throw new RuntimeException("It is possible there are too many open milestones open (only 100 are supported). Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef + " Got " + milestones);
} catch (IOException e) {
throw new RuntimeException("Could not find open milestone with title " + milestoneTitle + " for repository " + repositoryRef, e);
}
}
public boolean isOpenIssuesForMilestoneNumber(RepositoryRef repositoryRef, long milestoneNumber) {
String url = this.baseUrl + "/repos/" + repositoryRef.getOwner() + "/" + repositoryRef.getName() + "/issues?per_page=1&milestone=" + milestoneNumber;
Request request = new Request.Builder().get().url(url)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef + ". Response " + response);
}
List<Object> issues = this.gson.fromJson(response.body().charStream(), new TypeToken<List<Object>>(){}.getType());
return !issues.isEmpty();
} catch (IOException e) {
throw new RuntimeException("Could not find issues for milestone number " + milestoneNumber + " for repository " + repositoryRef, e);
}
}
// public boolean isOpenIssuesForMilestoneName(String owner, String repository, String milestoneName) {
//
// }
private static class AuthorizationInterceptor implements Interceptor {
private final String token;
public AuthorizationInterceptor(String token) {
this.token = token;
}
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Bearer " + this.token).build();
return chain.proceed(request);
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.TaskAction;
public class GitHubMilestoneHasNoOpenIssuesTask extends DefaultTask {
@Input
private RepositoryRef repository = new RepositoryRef();
@Input
private String milestoneTitle;
@Input @Optional
private String gitHubAccessToken;
private GitHubMilestoneApi milestones = new GitHubMilestoneApi();
@TaskAction
public void checkHasNoOpenIssues() {
long milestoneNumber = this.milestones.findMilestoneNumberByTitle(this.repository, this.milestoneTitle);
boolean isOpenIssues = this.milestones.isOpenIssuesForMilestoneNumber(this.repository, milestoneNumber);
if (isOpenIssues) {
throw new IllegalStateException("The repository " + this.repository + " has open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
System.out.println("The repository " + this.repository + " has no open issues for milestone with the title " + this.milestoneTitle + " and number " + milestoneNumber);
}
public RepositoryRef getRepository() {
return repository;
}
public void repository(Action<RepositoryRef> repository) {
repository.execute(this.repository);
}
public void setRepository(RepositoryRef repository) {
this.repository = repository;
}
public String getMilestoneTitle() {
return milestoneTitle;
}
public void setMilestoneTitle(String milestoneTitle) {
this.milestoneTitle = milestoneTitle;
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
this.milestones = new GitHubMilestoneApi(gitHubAccessToken);
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.github.milestones;
import org.gradle.api.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
public class GitHubMilestonePlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getTasks().register("gitHubCheckMilestoneHasNoOpenIssues", GitHubMilestoneHasNoOpenIssuesTask.class, new Action<GitHubMilestoneHasNoOpenIssuesTask>() {
@Override
public void execute(GitHubMilestoneHasNoOpenIssuesTask githubCheckMilestoneHasNoOpenIssues) {
githubCheckMilestoneHasNoOpenIssues.setGroup("Release");
githubCheckMilestoneHasNoOpenIssues.setDescription("Checks if there are any open issues for the specified repository and milestone");
githubCheckMilestoneHasNoOpenIssues.setMilestoneTitle((String) project.findProperty("nextVersion"));
if (project.hasProperty("githubAccessToken")) {
githubCheckMilestoneHasNoOpenIssues.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
}
});
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.github.milestones;
public class Milestone {
private String title;
private long number;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public long getNumber() {
return number;
}
public void setNumber(long number) {
this.number = number;
}
@Override
public String toString() {
return "Milestone{" +
"title='" + title + '\'' +
", number=" + number +
'}';
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.github.milestones;
public class RepositoryRef {
private String owner;
private String name;
RepositoryRef() {
}
public RepositoryRef(String owner, String name) {
this.owner = owner;
this.name = name;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "RepositoryRef{" +
"owner='" + owner + '\'' +
", name='" + name + '\'' +
'}';
}
public static RepositoryRefBuilder owner(String owner) {
return new RepositoryRefBuilder().owner(owner);
}
public static final class RepositoryRefBuilder {
private String owner;
private String repository;
private RepositoryRefBuilder() {
}
private RepositoryRefBuilder owner(String owner) {
this.owner = owner;
return this;
}
public RepositoryRefBuilder repository(String repository) {
this.repository = repository;
return this;
}
public RepositoryRef build() {
return new RepositoryRef(owner, repository);
}
}
}

View File

@@ -0,0 +1,119 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPom;
import org.gradle.api.publish.maven.MavenPomDeveloperSpec;
import org.gradle.api.publish.maven.MavenPomIssueManagement;
import org.gradle.api.publish.maven.MavenPomLicenseSpec;
import org.gradle.api.publish.maven.MavenPomOrganization;
import org.gradle.api.publish.maven.MavenPomScm;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
/**
* Customizes the Maven POM generated from the Gradle {@link Project}.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.publish.PublishingExtension
* @see org.gradle.api.publish.maven.MavenPom
* @see org.gradle.api.publish.maven.MavenPublication
* @see org.gradle.api.publish.maven.plugins.MavenPublishPlugin
*/
public class MavenPublishConventionsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().withType(MavenPublishPlugin.class).all(mavenPublishPlugin -> {
customizeJavaPlugin(project);
PublishingExtension publishingExtension = project.getExtensions().getByType(PublishingExtension.class);
publishingExtension.getPublications().withType(MavenPublication.class).all(mavenPublication ->
customizeMavenPom(project, mavenPublication.getPom()));
});
}
private void customizeJavaPlugin(Project project) {
project.getPlugins().withType(JavaPlugin.class).all(javaPlugin -> {
JavaPluginExtension extension = project.getExtensions().getByType(JavaPluginExtension.class);
extension.withJavadocJar();
extension.withSourcesJar();
});
}
private void customizeMavenPom(Project project, MavenPom pom) {
pom.getName().set(project.provider(project::getName));
pom.getDescription().set(project.provider(project::getDescription));
pom.getUrl().set("https://github.com/spring-projects/spring-boot-data-geode");
pom.licenses(this::customizeLicences);
pom.organization(this::customizeOrganization);
pom.developers(this::customizeDevelopers);
pom.scm(this::customizeScm);
pom.issueManagement(this::customizeIssueManagement);
}
private void customizeDevelopers(MavenPomDeveloperSpec developers) {
developers.developer(developer -> {
developer.getName().set("VMware");
developer.getEmail().set("info@vmware.com");
developer.getOrganization().set("VMware, Inc.");
developer.getOrganizationUrl().set("https://www.spring.io");
});
}
private void customizeIssueManagement(MavenPomIssueManagement issueManagement) {
issueManagement.getSystem().set("GitHub");
issueManagement.getUrl().set("https://github.com/spring-projects/spring-boot-data-geode/issues");
}
private void customizeLicences(MavenPomLicenseSpec licences) {
licences.license(licence -> {
licence.getName().set("Apache License, Version 2.0");
licence.getUrl().set("https://www.apache.org/licenses/LICENSE-2.0");
});
}
private void customizeOrganization(MavenPomOrganization organization) {
organization.getName().set("VMware, Inc.");
organization.getUrl().set("https://spring.io");
}
private void customizeScm(MavenPomScm scm) {
scm.getConnection().set("scm:git:git://github.com/spring-projects/spring-boot-data-geode.git");
scm.getDeveloperConnection().set("scm:git:ssh://git@github.com/spring-projects/spring-boot-data-geode.git");
scm.getUrl().set("https://github.com/spring-projects/spring-boot-data-geode");
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaPlatformPlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
/**
* Adds Java and JavaPlatform based Gradle {@link Project Pojects} to be published by Maven.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.plugins.JavaPlatformPlugin
* @see org.gradle.api.plugins.JavaPlugin
* @see org.gradle.api.publish.PublishingExtension
* @see org.gradle.api.publish.maven.MavenPublication
* @see org.gradle.api.publish.maven.plugins.MavenPublishPlugin
*/
public class PublishAllJavaComponentsPlugin implements Plugin<Project> {
private static final String JAVA_COMPONENT_NAME = "java";
private static final String JAVA_PLATFORM_COMPONENT_NAME = "javaPlatform";
@Override
public void apply(Project project) {
project.getPlugins().withType(MavenPublishPlugin.class).all(mavenPublish -> {
PublishingExtension publishingExtension = project.getExtensions().getByType(PublishingExtension.class);
publishingExtension.getPublications().create("mavenJava", MavenPublication.class, mavenPublication -> {
project.getPlugins().withType(JavaPlugin.class, javaPlugin ->
mavenPublication.from(project.getComponents().getByName(JAVA_COMPONENT_NAME)));
project.getPlugins().withType(JavaPlatformPlugin.class, javaPlatformPlugin ->
mavenPublication.from(project.getComponents().getByName(JAVA_PLATFORM_COMPONENT_NAME)));
});
});
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import io.spring.gradle.convention.Utils;
/**
* Publishes Gradle {@link Project} artifacts to either Artifactory or Maven Central.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see <a href="https://www.jfrog.com/confluence/display/JFROG/Gradle+Artifactory+Plugin">Artifatory Gradle Plugin</a>
* @see <a href="https://central.sonatype.org/publish/publish-gradle/">Maven Central Sonatype Gradle Support</a>
*/
public class PublishArtifactsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getTasks().register("publishArtifacts", publishArtifactsTask -> {
publishArtifactsTask.setGroup("Publishing");
publishArtifactsTask.setDescription("Publish project artifacts to either Artifactory or Maven Central"
+ " based on the project version.");
if (Utils.isRelease(project)) {
publishArtifactsTask.dependsOn("publishToOssrh");
}
else {
publishArtifactsTask.dependsOn("artifactoryPublish");
}
});
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import java.io.File;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
/**
* Gradle Plugin used to publish all {@link Project} artifacts locally
* under {@literal rootProject/buildDir/publications/repos}.
*
* This is useful for inspecting the generated {@link Project} artifacts to ensure they are correct
* before publishing the {@link Project} artifacts to Artifactory or Maven Central.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @since 2.0.0
*/
public class PublishLocalPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().withType(MavenPublishPlugin.class).all(mavenPublish -> {
PublishingExtension publishing = project.getExtensions().getByType(PublishingExtension.class);
publishing.getRepositories().maven(maven -> {
maven.setName("local");
maven.setUrl(new File(project.getRootProject().getBuildDir(), "publications/repos"));
});
});
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import io.spring.gradle.convention.ArtifactoryPlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.PluginManager;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
/**
* Enables publishing to Maven for a Spring module Gradle {@link Project}.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.api.publish.maven.plugins.MavenPublishPlugin
*/
public class SpringMavenPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(MavenPublishPlugin.class);
pluginManager.apply(MavenPublishConventionsPlugin.class);
pluginManager.apply(PublishAllJavaComponentsPlugin.class);
pluginManager.apply(PublishArtifactsPlugin.class);
pluginManager.apply(PublishLocalPlugin.class);
pluginManager.apply(SpringSigningPlugin.class);
pluginManager.apply(ArtifactoryPlugin.class);
}
}

View File

@@ -0,0 +1,61 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import java.net.URI;
import java.time.Duration;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import io.github.gradlenexus.publishplugin.NexusPublishExtension;
import io.github.gradlenexus.publishplugin.NexusPublishPlugin;
/**
* Enables a Gradle {@link Project} to publish to Maven Central using Sonatype's Nexus Repository Manager.
*
* @author Rob Winch
* @author John Blum
* @see <a href="https://github.com/gradle-nexus/publish-plugin">Nexus Publish Gradle Plugin</a>
*/
public class SpringNexusPublishPlugin implements Plugin<Project> {
private static final String SONATYPE_NEXUS_URL = "https://s01.oss.sonatype.org/service/local/";
private static final String SONATYPE_SNAPSHOT_REPOSITORY_URL = "https://s01.oss.sonatype.org/content/repositories/snapshots/";
@Override
public void apply(Project project) {
project.getPlugins().apply(NexusPublishPlugin.class);
NexusPublishExtension nexusPublishExtension = project.getExtensions().findByType(NexusPublishExtension.class);
// TODO: Why did we not simply use/configure the 'sonatype' repository and instead add a repo ('ossrh')?
// See here: https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh
// NOTE: Careful, the keyword 'ossrh' is referred to in names in the Spring Build Conventions Gradle Plugins,
// such as, but not limited to:
// * 'ossrhUsername'
// * 'publishToOssrh'
// * 'closeAndReleaseOssrhStagingRepository'
nexusPublishExtension.getRepositories().create("ossrh", nexusRepository -> {
nexusRepository.getNexusUrl().set(URI.create(SONATYPE_NEXUS_URL));
nexusRepository.getSnapshotRepositoryUrl().set(URI.create(SONATYPE_SNAPSHOT_REPOSITORY_URL));
});
nexusPublishExtension.getClientTimeout().set(Duration.ofMinutes(3));
nexusPublishExtension.getConnectTimeout().set(Duration.ofMinutes(3));
}
}

View File

@@ -0,0 +1,115 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.maven;
import java.util.concurrent.Callable;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.publish.Publication;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.plugins.signing.SigningExtension;
import org.gradle.plugins.signing.SigningPlugin;
import io.spring.gradle.convention.Utils;
/**
* Signs all Gradle {@link Project} artifacts.
*
* @author Rob Winch
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.plugins.signing.SigningPlugin
*/
public class SpringSigningPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
if (isSigningRequired(project)) {
project.getPluginManager().apply(SigningPlugin.class);
sign(project);
}
}
private boolean isSigningRequired(Project project) {
return isSigningKeyPresent(project) && isRelease(project);
}
private boolean isSigningKeyPresent(Project project) {
return project.hasProperty("signing.keyId")
|| project.hasProperty("signingKeyId")
|| project.hasProperty("signingKey");
}
private boolean isRelease(Project project) {
return Utils.isRelease(project);
}
private void sign(Project project) {
SigningExtension signing = findAndConfigureSigningExtension(project);
project.getPlugins().withType(PublishAllJavaComponentsPlugin.class).all(publishJavaComponentsPlugin -> {
PublishingExtension publishing = project.getExtensions().findByType(PublishingExtension.class);
Publication maven = publishing.getPublications().getByName("mavenJava");
signing.sign(maven);
});
}
private SigningExtension findAndConfigureSigningExtension(Project project) {
SigningExtension signingExtension = project.getExtensions().findByType(SigningExtension.class);
return configurePgpKeys(project, configureSigningRequired(project, signingExtension));
}
private SigningExtension configureSigningRequired(Project project, SigningExtension signing) {
Callable<Boolean> signingRequired =
() -> project.getGradle().getTaskGraph().hasTask("publishArtifacts");
signing.setRequired(signingRequired);
return signing;
}
private SigningExtension configurePgpKeys(Project project, SigningExtension signing) {
String signingKey = Utils.findPropertyAsString(project, "signingKey");
String signingKeyId = resolveSigningKeyId(project);
String signingPassword = Utils.findPropertyAsString(project, "signingPassword");
if (signingKeyId != null) {
signing.useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword);
}
else {
signing.useInMemoryPgpKeys(signingKey, signingPassword);
}
return signing;
}
private String resolveSigningKeyId(Project project) {
String signingKeyId = Utils.findPropertyAsString(project, "signingKeyId");
return signingKeyId != null ? signingKeyId
: Utils.findPropertyAsString(project, "signing.keyId");
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2002-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.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.plugins.ide.eclipse.EclipsePlugin
/**
* Gradle {@link Plugin} to allow {@literal optional} and {@literal provided} dependency configurations
* to work with the standard Gradle {@link EclipsePlugin}.
*
* @author Phillip Webb
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.plugins.ide.eclipse.EclipsePlugin
*/
class PropDepsEclipsePlugin implements Plugin<Project> {
void apply(Project project) {
project.plugins.apply(PropDepsPlugin)
project.plugins.apply(EclipsePlugin)
project.eclipse {
classpath {
plusConfigurations += [ project.configurations.provided, project.configurations.optional ]
}
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2022-present 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.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.plugins.ide.idea.IdeaPlugin
/**
* Gradle {@link Plugin} to allow {@literal optional} and {@literal provided} dependency configurations
* to work with the standard Gradle {@link IdeaPlugin}.
*
* @author Phillip Webb
* @author Brian Clozel
* @author John Blum
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.gradle.plugins.ide.idea.IdeaPlugin
* @link https://youtrack.jetbrains.com/issue/IDEA-107046
* @link https://youtrack.jetbrains.com/issue/IDEA-117668
*/
class PropDepsIdeaPlugin implements Plugin<Project> {
void apply(Project project) {
project.plugins.apply(PropDepsPlugin)
project.plugins.apply(IdeaPlugin)
project.idea.module {
// IntelliJ IDEA internally deals with 4 scopes : COMPILE, TEST, PROVIDED, RUNTIME
// but only PROVIDED seems to be picked up
scopes.PROVIDED.plus += [ project.configurations.provided ]
scopes.PROVIDED.plus += [ project.configurations.optional ]
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 2022-present 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.
*/
package org.springframework.gradle.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.JavaLibraryPlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.javadoc.Javadoc
/**
* Gradle {@link Plugin} to allow {@literal optional} and {@literal provided} dependency configurations.
*
* As stated in the Maven documentation, {@literal provided} scope {@literal "is only available on the compilation
* and test classpath, and is not transitive"}.
*
* This {@link Plugin} creates two new configurations, and each one:
*
* <ul>
* <li>is a parent of the compile configuration</li>
* <li>is not visible, not transitive</li>
* <li>all dependencies are excluded from the default configuration</li>
* </ul>
*
* @author Phillip Webb
* @author Brian Clozel
* @author Rob Winch
* @author John Blum
*
* @see org.gradle.api.Plugin
* @see org.gradle.api.Project
* @see org.springframework.gradle.propdeps.PropDepsEclipsePlugin
* @see org.springframework.gradle.propdeps.PropDepsIdeaPlugin
* @see <a href="https://www.gradle.org/docs/current/userguide/java_plugin.html#N121CF">Maven documentation</a>
* @see <a href="https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope">Gradle configurations</a>
*/
class PropDepsPlugin implements Plugin<Project> {
void apply(Project project) {
project.plugins.apply(JavaPlugin)
Configuration optional = addConfiguration(project, "optional")
Configuration provided = addConfiguration(project, "provided")
Javadoc javadoc = project.tasks.getByName(JavaPlugin.JAVADOC_TASK_NAME)
javadoc.classpath = javadoc.classpath + provided + optional
}
private Configuration addConfiguration(Project project, String name) {
Configuration configuration = project.configurations.create(name)
configuration.extendsFrom(project.configurations.implementation)
project.plugins.withType(JavaLibraryPlugin, {
configuration.extendsFrom(project.configurations.api)
})
project.sourceSets.all {
compileClasspath += configuration
runtimeClasspath += configuration
}
return configuration
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.sagan;
import java.util.regex.Pattern;
/**
* Domain object for creating a new release version.
*/
public class Release {
private String version;
private ReleaseStatus status;
private boolean current;
private String referenceDocUrl;
private String apiDocUrl;
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public ReleaseStatus getStatus() {
return status;
}
public void setStatus(ReleaseStatus status) {
this.status = status;
}
public boolean isCurrent() {
return current;
}
public void setCurrent(boolean current) {
this.current = current;
}
public String getReferenceDocUrl() {
return referenceDocUrl;
}
public void setReferenceDocUrl(String referenceDocUrl) {
this.referenceDocUrl = referenceDocUrl;
}
public String getApiDocUrl() {
return apiDocUrl;
}
public void setApiDocUrl(String apiDocUrl) {
this.apiDocUrl = apiDocUrl;
}
@Override
public String toString() {
return "Release{" +
"version='" + version + '\'' +
", status=" + status +
", current=" + current +
", referenceDocUrl='" + referenceDocUrl + '\'' +
", apiDocUrl='" + apiDocUrl + '\'' +
'}';
}
public enum ReleaseStatus {
/**
* Unstable version with limited support
*/
SNAPSHOT,
/**
* Pre-Release version meant to be tested by the community
*/
PRERELEASE,
/**
* Release Generally Available on public artifact repositories and enjoying full support from maintainers
*/
GENERAL_AVAILABILITY;
private static final Pattern PRERELEASE_PATTERN = Pattern.compile("[A-Za-z0-9\\.\\-]+?(M|RC)\\d+");
private static final String SNAPSHOT_SUFFIX = "SNAPSHOT";
/**
* Parse the ReleaseStatus from a String
* @param version a project version
* @return the release status for this version
*/
public static ReleaseStatus parse(String version) {
if (version == null) {
throw new IllegalArgumentException("version cannot be null");
}
if (version.endsWith(SNAPSHOT_SUFFIX)) {
return SNAPSHOT;
}
if (PRERELEASE_PATTERN.matcher(version).matches()) {
return PRERELEASE;
}
return GENERAL_AVAILABILITY;
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.sagan;
import com.google.gson.Gson;
import okhttp3.*;
import java.io.IOException;
import java.util.Base64;
/**
* Implements necessary calls to the Sagan API See https://spring.io/restdocs/index.html
*/
public class SaganApi {
private String baseUrl = "https://spring.io/api";
private OkHttpClient client;
private Gson gson = new Gson();
public SaganApi(String gitHubToken) {
this.client = new OkHttpClient.Builder()
.addInterceptor(new BasicInterceptor("not-used", gitHubToken))
.build();
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public void createReleaseForProject(Release release, String projectName) {
String url = this.baseUrl + "/projects/" + projectName + "/releases";
String releaseJsonString = gson.toJson(release);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), releaseJsonString);
Request request = new Request.Builder()
.url(url)
.post(body)
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not create release " + release + ". Got response " + response);
}
} catch (IOException fail) {
throw new RuntimeException("Could not create release " + release, fail);
}
}
public void deleteReleaseForProject(String release, String projectName) {
String url = this.baseUrl + "/projects/" + projectName + "/releases/" + release;
Request request = new Request.Builder()
.url(url)
.delete()
.build();
try {
Response response = this.client.newCall(request).execute();
if (!response.isSuccessful()) {
throw new RuntimeException("Could not delete release " + release + ". Got response " + response);
}
} catch (IOException fail) {
throw new RuntimeException("Could not delete release " + release, fail);
}
}
private static class BasicInterceptor implements Interceptor {
private final String token;
public BasicInterceptor(String username, String token) {
this.token = Base64.getEncoder().encodeToString((username + ":" + token).getBytes());
}
@Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request().newBuilder()
.addHeader("Authorization", "Basic " + this.token).build();
return chain.proceed(request);
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.sagan;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
public class SaganCreateReleaseTask extends DefaultTask {
@Input
private String gitHubAccessToken;
@Input
private String version;
@Input
private String apiDocUrl;
@Input
private String referenceDocUrl;
@Input
private String projectName;
@TaskAction
public void saganCreateRelease() {
SaganApi sagan = new SaganApi(this.gitHubAccessToken);
Release release = new Release();
release.setVersion(this.version);
release.setApiDocUrl(this.apiDocUrl);
release.setReferenceDocUrl(this.referenceDocUrl);
sagan.createReleaseForProject(release, this.projectName);
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getApiDocUrl() {
return apiDocUrl;
}
public void setApiDocUrl(String apiDocUrl) {
this.apiDocUrl = apiDocUrl;
}
public String getReferenceDocUrl() {
return referenceDocUrl;
}
public void setReferenceDocUrl(String referenceDocUrl) {
this.referenceDocUrl = referenceDocUrl;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.sagan;
import org.gradle.api.DefaultTask;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
public class SaganDeleteReleaseTask extends DefaultTask {
@Input
private String gitHubAccessToken;
@Input
private String version;
@Input
private String projectName;
@TaskAction
public void saganCreateRelease() {
SaganApi sagan = new SaganApi(this.gitHubAccessToken);
sagan.deleteReleaseForProject(this.version, this.projectName);
}
public String getGitHubAccessToken() {
return gitHubAccessToken;
}
public void setGitHubAccessToken(String gitHubAccessToken) {
this.gitHubAccessToken = gitHubAccessToken;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getProjectName() {
return projectName;
}
public void setProjectName(String projectName) {
this.projectName = projectName;
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2017-present 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.
*/
package org.springframework.gradle.sagan;
import io.spring.gradle.convention.Utils;
import org.gradle.api.*;
public class SaganPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getTasks().register("saganCreateRelease", SaganCreateReleaseTask.class, new Action<SaganCreateReleaseTask>() {
@Override
public void execute(SaganCreateReleaseTask saganCreateVersion) {
saganCreateVersion.setGroup("Release");
saganCreateVersion.setDescription("Creates a new version for the specified project on spring.io");
saganCreateVersion.setVersion((String) project.findProperty("nextVersion"));
saganCreateVersion.setProjectName(Utils.getProjectName(project));
saganCreateVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
});
project.getTasks().register("saganDeleteRelease", SaganDeleteReleaseTask.class, new Action<SaganDeleteReleaseTask>() {
@Override
public void execute(SaganDeleteReleaseTask saganDeleteVersion) {
saganDeleteVersion.setGroup("Release");
saganDeleteVersion.setDescription("Delete a version for the specified project on spring.io");
saganDeleteVersion.setVersion((String) project.findProperty("previousVersion"));
saganDeleteVersion.setProjectName(Utils.getProjectName(project));
saganDeleteVersion.setGitHubAccessToken((String) project.findProperty("gitHubAccessToken"));
}
});
}
}

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.ArtifactoryPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.CheckstylePlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.DependencySetPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.DocsPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.IntegrationTestPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.JacocoPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.JavadocApiPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.JavadocOptionsPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.MavenBomPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.RepositoryConventionPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.RootProjectPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringModulePlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringSampleBootPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringSampleWarPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringSamplePlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringTestPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.SpringDependencyManagementConventionsPlugin

View File

@@ -0,0 +1 @@
implementation-class=io.spring.gradle.convention.TestsConfigurationPlugin