Update local Spring Build Conventions Gradle Plugins (in buildSrc/) with latest, required infrastructure changes.

Required changes include, but are not limited to:

* Switching from spring-doc-resources:0.2.5 to spring-asciidoctor-backends used to build documewntation.
* Resolving build dependencies from Maven Central.
* Importing the Spring PropDeps Gradle Plugins locally.
* Refactoring the local Spring Build Conventions Gradle Plugins with the latest, state-of-art build and infrastructure practices.
This commit is contained in:
John Blum
2023-06-13 16:22:40 -07:00
parent 9b9957ec38
commit e5418a2410
14 changed files with 555 additions and 222 deletions

View File

@@ -12,13 +12,37 @@ group 'io.spring.gradle'
sourceCompatibility = 1.8
sourceSets {
main {
java {
srcDirs = []
}
groovy {
srcDirs += [ "src/main/java" ]
}
}
}
repositories {
jcenter()
gradlePluginPortal()
mavenCentral()
gradlePluginPortal()
jcenter()
maven { url 'https://repo.spring.io/plugins-release/' }
}
gradlePlugin {
plugins {
managementConfiguration {
id = "io.spring.convention.management-configuration"
implementationClass = "io.spring.gradle.convention.ManagementConfigurationPlugin"
}
propdeps {
id = "org.springframework.propdeps"
implementationClass = "io.spring.gradle.convention.propdeps.PropDepsPlugin"
}
}
}
configurations {
implementation {
exclude module: 'groovy-all'
@@ -29,13 +53,14 @@ dependencies {
implementation localGroovy()
runtimeOnly 'org.springframework.boot:spring-boot-loader-tools:2.7.12'
implementation 'com.github.ben-manes:gradle-versions-plugin:0.25.0'
implementation 'gradle.plugin.org.gretty:gretty:3.0.1'
implementation 'io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.21.1'
implementation 'io.spring.gradle:dependency-management-plugin:1.0.9.RELEASE'
implementation 'io.spring.gradle:propdeps-plugin:0.0.10.RELEASE'
implementation 'io.spring.gradle:dependency-management-plugin:1.0.15.RELEASE'
implementation 'io.spring.javaformat:spring-javaformat-gradle-plugin:0.0.15'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.3.RELEASE'
implementation 'io.spring.nohttp:nohttp-gradle:0.0.11'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm:3.1.0'
implementation 'org.asciidoctor:asciidoctor-gradle-jvm-pdf:3.1.0'
implementation 'org.hidetake:gradle-ssh-plugin:2.10.1'

View File

@@ -13,47 +13,52 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention
package io.spring.gradle.convention;
import io.spring.gradle.propdeps.PropDepsMavenPlugin;
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.MavenPlugin;
import org.gradle.api.plugins.PluginManager;
import org.gradle.internal.impldep.org.apache.maven.Maven;
import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin;
import org.gradle.plugins.ide.idea.IdeaPlugin;
import io.spring.gradle.propdeps.PropDepsEclipsePlugin;
import io.spring.gradle.propdeps.PropDepsIdeaPlugin;
import io.spring.gradle.propdeps.PropDepsPlugin;
import io.spring.gradle.propdeps.PropDepsEclipsePlugin
import io.spring.gradle.propdeps.PropDepsIdeaPlugin
import io.spring.gradle.propdeps.PropDepsMavenPlugin
import io.spring.gradle.propdeps.PropDepsPlugin
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.MavenPlugin
import org.gradle.api.plugins.PluginManager
import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin
import org.gradle.plugins.ide.idea.IdeaPlugin
/**
* @author Rob Winch
*/
public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
@Override
public final void apply(Project project) {
final void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaPlugin.class);
pluginManager.apply(ManagementConfigurationPlugin.class);
if (project.file("src/main/groovy").exists()
|| project.file("src/test/groovy").exists()
|| project.file("src/integration-test/groovy").exists()) {
pluginManager.apply(GroovyPlugin.class);
}
pluginManager.apply("io.spring.convention.repository");
pluginManager.apply(EclipseWtpPlugin);
pluginManager.apply(IdeaPlugin);
pluginManager.apply(PropDepsPlugin);
pluginManager.apply(PropDepsEclipsePlugin);
pluginManager.apply(PropDepsIdeaPlugin);
project.getPlugins().withType(MavenPlugin) {
pluginManager.apply(PropDepsMavenPlugin);
}
pluginManager.apply("io.spring.convention.tests-configuration");
pluginManager.apply("io.spring.convention.integration-test");
pluginManager.apply("io.spring.convention.springdependencymangement");
@@ -68,21 +73,25 @@ public abstract class AbstractSpringJavaPlugin implements Plugin<Project> {
project.jar {
manifest.attributes["Created-By"] =
"${System.getProperty("java.version")} (${System.getProperty("java.specification.vendor")})"
"${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('-', '.')
}
additionalPlugins(project);
}
private void copyPropertyFromRootProjectTo(String propertyName, Project project) {
Project rootProject = project.getRootProject();
Object property = rootProject.findProperty(propertyName);
if(property != null) {
if (property != null) {
project.setProperty(propertyName, property);
}
}
protected abstract void additionalPlugins(Project project);
}

View File

@@ -1,25 +1,22 @@
package io.spring.gradle.convention
import org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.DependencySet
import org.gradle.api.plugins.PluginManager
import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.bundling.Zip
/**
* Aggregates asciidoc, javadoc, and deploying of the docs into a single plugin
*/
public class DocsPlugin implements Plugin<Project> {
class DocsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply("org.asciidoctor.jvm.convert");
pluginManager.apply("org.asciidoctor.jvm.pdf");
pluginManager.apply(AsciidoctorConventionPlugin);
@@ -38,7 +35,6 @@ public class DocsPlugin implements Plugin<Project> {
}
}
Task docsZip = project.tasks.create('docsZip', Zip) {
dependsOn 'api', 'asciidoctor'
group = 'Distribution'
@@ -51,15 +47,19 @@ public class DocsPlugin implements Plugin<Project> {
into 'reference/html5'
include '**'
}
from(project.tasks.asciidoctorPdf.outputs) {
into 'reference/pdf'
include '**'
rename "index.pdf", pdfFilename
}
from(project.tasks.api.outputs) {
into 'api'
}
into 'docs'
duplicatesStrategy 'exclude'
}
@@ -68,6 +68,7 @@ public class DocsPlugin implements Plugin<Project> {
description 'An aggregator task to generate all the documentation'
dependsOn docsZip
}
project.tasks.assemble.dependsOn docs
}
}

View File

@@ -2,8 +2,6 @@ package io.spring.gradle.convention
import io.spring.gradle.dependencymanagement.DependencyManagementPlugin
import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension
import io.spring.gradle.dependencymanagement.dsl.GeneratedPomCustomizationHandler
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.XmlProvider
@@ -22,24 +20,32 @@ import org.gradle.plugins.signing.SigningPlugin
import org.slf4j.Logger
import org.slf4j.LoggerFactory
public class SpringMavenPlugin implements Plugin<Project> {
class SpringMavenPlugin implements Plugin<Project> {
private static final String ARCHIVES = "archives";
Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void apply(Project project) {
void apply(Project project) {
project.getPluginManager().apply(JavaPlugin.class);
project.getPluginManager().apply(MavenPlugin.class);
project.getPluginManager().apply(SigningPlugin.class);
Javadoc javadoc = (Javadoc) project.getTasks().findByPath("javadoc");
Jar javadocJar = project.getTasks().create("javadocJar", Jar.class);
javadocJar.setClassifier("javadoc");
javadocJar.from(javadoc);
JavaPluginConvention java = project.getConvention().getPlugin(JavaPluginConvention.class);
SourceSet mainSourceSet = java.getSourceSets().getByName("main");
Jar sourcesJar = project.getTasks().create("sourcesJar", Jar.class);
sourcesJar.setClassifier("sources");
sourcesJar.from(mainSourceSet.getAllSource());
@@ -51,6 +57,7 @@ public class SpringMavenPlugin implements Plugin<Project> {
configurePom(project, pom)
}
}
project.uploadArchives {
repositories.mavenDeployer {
configurePom(project, pom)
@@ -62,6 +69,7 @@ public class SpringMavenPlugin implements Plugin<Project> {
}
def hasSigningKey = project.hasProperty("signing.keyId") || project.findProperty("signingKey")
if(hasSigningKey && Utils.isRelease(project)) {
sign(project)
}
@@ -70,7 +78,9 @@ public class SpringMavenPlugin implements Plugin<Project> {
}
private void inlineDependencyManagement(Project project) {
final DependencyManagementExtension dependencyManagement = project.getExtensions().findByType(DependencyManagementExtension.class);
DependencyManagementExtension dependencyManagement = project.getExtensions().findByType(DependencyManagementExtension.class);
dependencyManagement.generatedPomCustomization( { handler -> handler.setEnabled(false) });
project.install {
@@ -78,6 +88,7 @@ public class SpringMavenPlugin implements Plugin<Project> {
configurePomForInlineDependencies(project, pom)
}
}
project.uploadArchives {
repositories.mavenDeployer {
configurePomForInlineDependencies(project, pom)
@@ -86,6 +97,7 @@ public class SpringMavenPlugin implements Plugin<Project> {
}
private void configurePomForInlineDependencies(Project project, MavenPom pom) {
pom.withXml { XmlProvider xml ->
project.plugins.withType(JavaBasePlugin) {
def dependencies = xml.asNode()?.dependencies?.dependency
@@ -118,6 +130,7 @@ public class SpringMavenPlugin implements Plugin<Project> {
}
private void sign(Project project) {
project.install {
repositories {
mavenDeployer {
@@ -136,19 +149,23 @@ public class SpringMavenPlugin implements Plugin<Project> {
project.signing {
required { project.gradle.taskGraph.hasTask("uploadArchives") }
def signingKeyId = project.findProperty("signingKeyId")
def signingKey = project.findProperty("signingKey")
def signingPassword = project.findProperty("signingPassword")
if (signingKeyId) {
useInMemoryPgpKeys(signingKeyId, signingKey, signingPassword)
} else if (signingKey) {
useInMemoryPgpKeys(signingKey, signingPassword)
}
sign project.configurations.archives
}
}
private static void configurePom(Project project, MavenPom pom) {
pom.whenConfigured { p ->
p.dependencies = p.dependencies.sort { dep ->
"$dep.scope:$dep.optional:$dep.groupId:$dep.artifactId"
@@ -156,50 +173,52 @@ public class SpringMavenPlugin implements Plugin<Project> {
}
pom.project {
boolean isWar = project.hasProperty("war");
String projectVersion = String.valueOf(project.getVersion());
String projectName = Utils.getProjectName(project);
if(isWar) {
boolean isWar = project.hasProperty("war");
String projectName = Utils.getProjectName(project);
String projectVersion = String.valueOf(project.getVersion());
if (isWar) {
packaging = "war"
}
name = project.name
description = project.name
url = 'https://spring.io/spring-security'
organization {
name = 'spring.io'
url = 'https://spring.io/'
}
url = 'https://spring.io/projects/spring-boot'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'https://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
scm {
url = 'https://github.com/spring-projects/spring-security'
connection = 'scm:git:git://github.com/spring-projects/spring-security'
developerConnection = 'scm:git:git://github.com/spring-projects/spring-security'
}
developers {
developer {
id = 'rwinch'
name = 'Rob Winch'
email = 'rwinch@pivotal.io'
}
developer {
id = 'jgrandja'
name = 'Joe Grandja'
email = 'jgrandja@pivotal.io'
}
}
if(isWar) {
organization {
name = 'spring.io'
url = 'https://spring.io/'
}
developers {
developer {
id = 'jblum'
name = 'John Blum'
}
}
scm {
url = 'https://github.com/spring-projects/spring-boot-data-geode'
connection = 'scm:git:git://github.com/spring-projects/spring-boot-data-geode'
developerConnection = 'scm:git:git://github.com/spring-projects/spring-boot-data-geode'
}
if (isWar) {
properties {
'm2eclipse.wtp.contextRoot' '/'
}
}
if (Utils.isSnapshot(project)) {
repositories {
repository {

View File

@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention;
import org.gradle.api.Project
@@ -28,17 +27,22 @@ class SpringModulePlugin extends AbstractSpringJavaPlugin {
@Override
void additionalPlugins(Project project) {
PluginManager pluginManager = project.getPluginManager();
pluginManager.apply(JavaLibraryPlugin.class)
pluginManager.apply(MavenPlugin.class);
pluginManager.apply("io.spring.convention.maven");
pluginManager.apply("io.spring.convention.artifactory");
pluginManager.apply("io.spring.convention.jacoco");
pluginManager.apply("io.spring.convention.merge");
def deployArtifacts = project.task("deployArtifacts")
deployArtifacts.group = 'Deploy tasks'
deployArtifacts.description = "Deploys the artifacts to either Artifactory or Maven Central"
if (Utils.isRelease(project)) {
deployArtifacts.dependsOn project.tasks.uploadArchives
}
@@ -46,5 +50,4 @@ class SpringModulePlugin extends AbstractSpringJavaPlugin {
deployArtifacts.dependsOn project.tasks.artifactoryPublish
}
}
}

View File

@@ -13,22 +13,19 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention
package io.spring.gradle.convention;
import org.gradle.api.Project;
import org.gradle.api.plugins.PluginManager;
import org.gradle.api.plugins.WarPlugin
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.tasks.testing.Test
import org.gradle.api.Project
import org.gradle.api.plugins.PluginManager
/**
* @author Rob Winch
*/
public class SpringSampleBootPlugin extends SpringSamplePlugin {
class SpringSampleBootPlugin extends SpringSamplePlugin {
@Override
public void additionalPlugins(Project project) {
void additionalPlugins(Project project) {
super.additionalPlugins(project);
PluginManager pluginManager = project.getPluginManager();

View File

@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention;
import org.gradle.api.Project
@@ -22,10 +21,11 @@ import org.sonarqube.gradle.SonarQubePlugin;
/**
* @author Rob Winch
*/
public class SpringSamplePlugin extends AbstractSpringJavaPlugin {
class SpringSamplePlugin extends AbstractSpringJavaPlugin {
@Override
public void additionalPlugins(Project project) {
void additionalPlugins(Project project) {
project.plugins.withType(SonarQubePlugin) {
project.sonarqube.skipProject = true
}

View File

@@ -13,7 +13,6 @@
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.spring.gradle.convention
import org.gradle.api.Project
@@ -24,10 +23,11 @@ import org.gradle.api.tasks.testing.Test
/**
* @author Rob Winch
*/
public class SpringSampleWarPlugin extends SpringSamplePlugin {
class SpringSampleWarPlugin extends SpringSamplePlugin {
@Override
public void additionalPlugins(Project project) {
void additionalPlugins(Project project) {
super.additionalPlugins(project);
PluginManager pluginManager = project.getPluginManager();
@@ -51,6 +51,7 @@ public class SpringSampleWarPlugin extends SpringSamplePlugin {
}
}
}
project.tasks.withType(org.akhikhl.gretty.AppBeforeIntegrationTestTask).all { task ->
task.dependsOn prepareAppServerForIntegrationTests
}
@@ -63,6 +64,7 @@ public class SpringSampleWarPlugin extends SpringSamplePlugin {
}
def applyForIntegrationTest(Project project, Task integrationTest) {
project.gretty.integrationTestTask = integrationTest.name
integrationTest.doFirst {
@@ -89,9 +91,9 @@ public class SpringSampleWarPlugin extends SpringSamplePlugin {
}
def getRandomPort() {
ServerSocket ss = new ServerSocket(0)
int port = ss.localPort
ss.close()
ServerSocket serverSocket = new ServerSocket(0)
int port = serverSocket.localPort
serverSocket.close()
return port
}
}

View File

@@ -0,0 +1,45 @@
/*
* 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.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 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.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,67 @@
/*
* Copyright 2002-2012 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.propdeps
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.artifacts.maven.Conf2ScopeMappingContainer
import org.gradle.api.artifacts.maven.MavenPom
import org.gradle.api.artifacts.maven.PomFilterContainer
import org.gradle.api.plugins.MavenPlugin
import org.gradle.api.tasks.Upload
/**
* Plugin to allow optional and provided dependency configurations to work with
* the standard gradle 'maven' plugin
*
* @author Phillip Webb
* @author John Blum
*/
class PropDepsMavenPlugin implements Plugin<Project> {
void apply(Project project) {
project.plugins.apply(PropDepsPlugin)
project.plugins.apply(MavenPlugin)
Conf2ScopeMappingContainer scopeMappings = project.conf2ScopeMappings
scopeMappings.addMapping(MavenPlugin.COMPILE_PRIORITY + 1,
project.configurations.getByName("provided"), Conf2ScopeMappingContainer.PROVIDED)
// Add a temporary new optional scope
scopeMappings.addMapping(MavenPlugin.COMPILE_PRIORITY + 2,
project.configurations.getByName("optional"), "optional")
// Add a hook to replace the optional scope
project.afterEvaluate {
project.tasks.withType(Upload).each { applyToUploadTask(project, it) }
}
}
private void applyToUploadTask(Project project, Upload upload) {
upload.repositories.withType(PomFilterContainer).each{ applyToPom(project, it) }
}
private void applyToPom(Project project, PomFilterContainer pomContainer) {
pomContainer.pom.whenConfigured { MavenPom pom ->
pom.dependencies.findAll{ it.scope == "optional" }.each {
it.scope = "compile"
it.optional = true
}
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.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 PropDepsEclipsePlugin
* @see 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

@@ -1,38 +1,21 @@
/*
* Copyright 2019-2020 the original author or authors.
* 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
* 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.
* 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.asciidoctor.gradle.base.AsciidoctorAttributeProvider;
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.Action;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.DependencySet;
import org.gradle.api.artifacts.dsl.RepositoryHandler;
import org.gradle.api.file.CopySpec;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.Sync;
import java.io.File;
import java.net.URI;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
@@ -40,169 +23,220 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Consumer;
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.JavaVersion;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
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:
* Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}.
* <p/>
* 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>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
* <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.
* <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.
* <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
* @author John Blum
*/
public class AsciidoctorConventionPlugin implements Plugin<Project> {
private static final String ASCIIDOCTORJ_VERSION = "2.4.3";
private static final String SPRING_ASCIIDOCTOR_BACKENDS_VERSION = "0.0.5";
private static final String SPRING_DOC_RESOURCES_VERSION = "0.2.5";
private static final String SPRING_ASCIIDOCTOR_BACKENDS_DEPENDENCY =
String.format("io.spring.asciidoctor.backends:spring-asciidoctor-backends:%s",
SPRING_ASCIIDOCTOR_BACKENDS_VERSION);
@SuppressWarnings("unused")
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);
project.getPlugins().withType(AsciidoctorJPlugin.class, asciidoctorPlugin -> {
setAsciidoctorJVersion(project);
makeAllWarningsFatal(project);
createAsciidoctorExtensionsConfiguration(project);
Sync unzipResources = createUnzipDocumentationResourcesTask(project);
project.getTasks().withType(AbstractAsciidoctorTask.class, (asciidoctorTask) -> {
project.getTasks().withType(AbstractAsciidoctorTask.class, asciidoctorTask -> {
asciidoctorTask.dependsOn(unzipResources);
configureExtensions(project, asciidoctorTask);
configureCommonAttributes(project, asciidoctorTask);
configureOptions(asciidoctorTask);
asciidoctorTask.baseDirFollowsSourceDir();
asciidoctorTask.useIntermediateWorkDir();
asciidoctorTask.resources(new Action<CopySpec>() {
@Override
public void execute(CopySpec resourcesSpec) {
resourcesSpec.from(unzipResources);
resourcesSpec.from(asciidoctorTask.getSourceDir(), new Action<CopySpec>() {
@Override
public void execute(CopySpec 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/**");
}
});
}
configureAsciidoctorTask(project, asciidoctorTask);
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(new Action<Project>() {
@Override
public void execute(Project project) {
RepositoryHandler repositories = project.getRepositories();
if (repositories.isEmpty()) {
repositories.mavenCentral();
repositories.maven(repo -> {
repo.setUrl(URI.create("https://repo.spring.io/release"));
});
}
}
});
private void setAsciidoctorJVersion(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).setVersion(ASCIIDOCTORJ_VERSION);
}
private void makeAllWarningsFatal(Project project) {
project.getExtensions().getByType(AsciidoctorJExtension.class).fatalWarnings(".*");
}
private void configureExtensions(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Configuration extensionsConfiguration = project.getConfigurations().maybeCreate("asciidoctorExtensions");
extensionsConfiguration.defaultDependencies(new Action<DependencySet>() {
@Override
public void execute(DependencySet dependencies) {
dependencies.add(project.getDependencies().create("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.2.RELEASE"));
}
private void createAsciidoctorExtensionsConfiguration(Project project) {
project.getConfigurations().create("asciidoctorExtensions", configuration -> {
project.getConfigurations()
.matching(it -> "dependencyManagement".equals(it.getName()))
.all(configuration::extendsFrom);
configuration.getDependencies()
.add(project.getDependencies().create(SPRING_ASCIIDOCTOR_BACKENDS_DEPENDENCY));
// TODO: Why is the asiidoctorj-pdf dependency needed?
configuration.getDependencies()
.add(project.getDependencies().create("org.asciidoctor:asciidoctorj-pdf:1.5.3"));
});
asciidoctorTask.configurations(extensionsConfiguration);
}
/**
* Requests the base Spring Documentation Resources from {@literal Maven Central} and uses it to format
* and render documentation.
*
* @param project {@literal this} Gradle {@link Project}.
* @return a {@link Sync} task that copies Spring Documentation Resources to the build directory
* used to generate documentation.
* @see org.gradle.api.tasks.Sync
* @see org.gradle.api.Project
*/
@SuppressWarnings("all")
private Sync createUnzipDocumentationResourcesTask(Project project) {
Configuration documentationResources = project.getConfigurations().maybeCreate("documentationResources");
Configuration documentationResources = project.getConfigurations().create("documentationResources");
documentationResources.getDependencies()
.add(project.getDependencies().create("io.spring.docresources:spring-doc-resources:0.2.5"));
Sync unzipResources = project.getTasks().create("unzipDocumentationResources",
Sync.class, new Action<Sync>() {
@Override
public void execute(Sync sync) {
sync.dependsOn(documentationResources);
sync.from(new Callable<List<FileTree>>() {
@Override
public List<FileTree> call() throws Exception {
List<FileTree> result = new ArrayList<>();
documentationResources.getAsFileTree().forEach(new Consumer<File>() {
@Override
public void accept(File file) {
result.add(project.zipTree(file));
}
});
return result;
}
});
File destination = new File(project.getBuildDir(), "docs/resources");
sync.into(project.relativePath(destination));
}
.add(project.getDependencies().create(SPRING_ASCIIDOCTOR_BACKENDS_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;
}
private void configureAsciidoctorTask(Project project, AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.baseDirFollowsSourceDir();
asciidoctorTask.configurations("asciidoctorExtensions");
//asciidoctorTask.useIntermediateWorkDir();
configureAttributes(project, asciidoctorTask);
configureForkOptions(asciidoctorTask);
configureOptions(asciidoctorTask);
if (asciidoctorTask instanceof AsciidoctorTask) {
boolean pdf = asciidoctorTask.getName().toLowerCase().contains("pdf");
String backend = pdf ? "spring-pdf" : "spring-html";
((AsciidoctorTask) asciidoctorTask).outputOptions((outputOptions) -> outputOptions.backends(backend));
configureHtmlOnlyAttributes(asciidoctorTask);
}
}
private void configureAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("attribute-missing", "warn");
attributes.put("docinfo", "shared");
attributes.put("idprefix", "");
attributes.put("idseparator", "-");
attributes.put("sectanchors", "");
attributes.put("sectnums", "");
attributes.put("today-year", LocalDate.now().getYear());
Object version = project.getVersion();
if (version != null && !Project.DEFAULT_VERSION.equals(version)) {
attributes.put("revnumber", version);
}
asciidoctorTask.attributes(attributes);
}
private void configureForkOptions(AbstractAsciidoctorTask asciidoctorTask) {
if (JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_16)) {
asciidoctorTask.forkOptions(options -> options.jvmArgs(
"--add-opens", "java.base/sun.nio.ch=ALL-UNNAMED",
"--add-opens", "java.base/java.io=ALL-UNNAMED")
);
}
}
private void configureHtmlOnlyAttributes(AbstractAsciidoctorTask asciidoctorTask) {
Map<String, Object> attributes = new HashMap<>();
attributes.put("highlightjsdir", "js/highlight");
attributes.put("highlightjs-theme", "github");
attributes.put("source-highlighter", "highlight.js");
attributes.put("icons", "font");
attributes.put("imagesdir", "./images");
attributes.put("linkcss", true);
attributes.put("stylesdir", "css/");
//attributes.put("stylesheet", "spring.css");
asciidoctorTask.attributes(attributes);
}
private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {
asciidoctorTask.options(Collections.singletonMap("doctype", "book"));
}
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(new AsciidoctorAttributeProvider() {
@Override
public Map<String, Object> getAttributes() {
Object version = project.getVersion();
Map<String, Object> attrs = new HashMap<>();
if (version != null && version.toString() != Project.DEFAULT_VERSION) {
attrs.put("revnumber", version);
}
return attrs;
}
});
asciidoctorTask.attributes(attributes);
}
private void configureCommonAttributes(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);
}
}

View File

@@ -0,0 +1 @@
implementation-class=build.GemFireServerPlugin