diff --git a/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencySetPlugin.groovy b/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencySetPlugin.groovy new file mode 100644 index 0000000..ce17158 --- /dev/null +++ b/buildSrc/src/main/groovy/io/spring/gradle/convention/DependencySetPlugin.groovy @@ -0,0 +1,71 @@ +/* + * 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.plugins.JavaPlugin + +/** + * Adds sets of dependencies to make it easy to add a grouping of dependencies. The + * dependencies added are: + * + * + * + * @author Rob Winch + */ +class DependencySetPlugin implements Plugin { + + @Override + void apply(Project project) { + + project.ext.jstlDependencies = [ + "javax.servlet.jsp.jstl:javax.servlet.jsp.jstl-api", + "org.apache.taglibs:taglibs-standard-jstlel" + ] + + 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:log4j-over-slf4j", + "ch.qos.logback:logback-classic" + ] + + project.ext.testDependencies = [ + "junit:junit", + "org.assertj:assertj-core", + "org.mockito:mockito-core", + "org.projectlombok:lombok", + "org.springframework:spring-test", + "edu.umd.cs.mtc:multithreadedtc" + ] + + project.plugins.withType(JavaPlugin) { + project.dependencies { + testImplementation project.testDependencies + } + } + } +} diff --git a/buildSrc/src/main/java/io/spring/gradle/convention/AsciidoctorConventionPlugin.java b/buildSrc/src/main/java/io/spring/gradle/convention/AsciidoctorConventionPlugin.java new file mode 100644 index 0000000..e51383d --- /dev/null +++ b/buildSrc/src/main/java/io/spring/gradle/convention/AsciidoctorConventionPlugin.java @@ -0,0 +1,209 @@ +/* + * Copyright 2019-2020 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 java.util.function.Consumer; + +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; + +/** + * Conventions that are applied in the presence of the {@link AsciidoctorJPlugin}. When + * the plugin is applied: + * + * + * + * @author Andy Wilkinson + * @author Rob Winch + */ +public class AsciidoctorConventionPlugin implements Plugin { + + 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); + configureExtensions(project, asciidoctorTask); + configureCommonAttributes(project, asciidoctorTask); + configureOptions(asciidoctorTask); + asciidoctorTask.baseDirFollowsSourceDir(); + asciidoctorTask.useIntermediateWorkDir(); + asciidoctorTask.resources(new Action() { + @Override + public void execute(CopySpec resourcesSpec) { + resourcesSpec.from(unzipResources); + resourcesSpec.from(asciidoctorTask.getSourceDir(), new Action() { + @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/**"); + } + }); + } + }); + if (asciidoctorTask instanceof AsciidoctorTask) { + configureHtmlOnlyAttributes(project, asciidoctorTask); + } + }); + }); + } + + private void createDefaultAsciidoctorRepository(Project project) { + project.getGradle().afterProject(new Action() { + @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 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() { + @Override + public void execute(DependencySet dependencies) { + dependencies.add(project.getDependencies().create("io.spring.asciidoctor:spring-asciidoctor-extensions-block-switch:0.4.2.RELEASE")); + } + }); + asciidoctorTask.configurations(extensionsConfiguration); + } + + private Sync createUnzipDocumentationResourcesTask(Project project) { + Configuration documentationResources = project.getConfigurations().maybeCreate("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() { + @Override + public void execute(Sync sync) { + sync.dependsOn(documentationResources); + sync.from(new Callable>() { + @Override + public List call() throws Exception { + List result = new ArrayList<>(); + documentationResources.getAsFileTree().forEach(new Consumer() { + @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)); + } + }); + return unzipResources; + } + + private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) { + asciidoctorTask.options(Collections.singletonMap("doctype", "book")); + } + + private void configureHtmlOnlyAttributes(Project project, AbstractAsciidoctorTask asciidoctorTask) { + Map 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 getAttributes() { + Object version = project.getVersion(); + Map 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 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); + } +} diff --git a/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.dependency-set.properties b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.dependency-set.properties new file mode 100644 index 0000000..12edaa4 --- /dev/null +++ b/buildSrc/src/main/resources/META-INF/gradle-plugins/io.spring.convention.dependency-set.properties @@ -0,0 +1 @@ +implementation-class=io.spring.gradle.convention.DependencySetPlugin