Rework Antora Gradle Infrastructure
Closes gh-40572 Co-authored-by: Phillip Webb <phil.webb@broadcom.com>
This commit is contained in:
parent
6470748d6d
commit
f9281a61ff
|
@ -70,6 +70,14 @@ gradlePlugin {
|
||||||
id = "org.springframework.boot.annotation-processor"
|
id = "org.springframework.boot.annotation-processor"
|
||||||
implementationClass = "org.springframework.boot.build.processors.AnnotationProcessorPlugin"
|
implementationClass = "org.springframework.boot.build.processors.AnnotationProcessorPlugin"
|
||||||
}
|
}
|
||||||
|
antoraAggregatedPlugin {
|
||||||
|
id = "org.springframework.boot.antora-contributor"
|
||||||
|
implementationClass = "org.springframework.boot.build.antora.AntoraContributorPlugin"
|
||||||
|
}
|
||||||
|
antoraAggregatorPlugin {
|
||||||
|
id = "org.springframework.boot.antora-dependencies"
|
||||||
|
implementationClass = "org.springframework.boot.build.antora.AntoraDependenciesPlugin"
|
||||||
|
}
|
||||||
architecturePlugin {
|
architecturePlugin {
|
||||||
id = "org.springframework.boot.architecture"
|
id = "org.springframework.boot.architecture"
|
||||||
implementationClass = "org.springframework.boot.build.architecture.ArchitecturePlugin"
|
implementationClass = "org.springframework.boot.build.architecture.ArchitecturePlugin"
|
||||||
|
|
|
@ -58,10 +58,18 @@ public class AntoraConventions {
|
||||||
|
|
||||||
private static final String DEPENDENCIES_PATH = ":spring-boot-project:spring-boot-dependencies";
|
private static final String DEPENDENCIES_PATH = ":spring-boot-project:spring-boot-dependencies";
|
||||||
|
|
||||||
private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
|
|
||||||
|
|
||||||
private static final List<String> NAV_FILES = List.of("nav.adoc", "local-nav.adoc");
|
private static final List<String> NAV_FILES = List.of("nav.adoc", "local-nav.adoc");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Antora source directory.
|
||||||
|
*/
|
||||||
|
public static final String ANTORA_SOURCE_DIR = "src/docs/antora";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the {@link GenerateAntoraPlaybook} task.
|
||||||
|
*/
|
||||||
|
public static final String GENERATE_ANTORA_PLAYBOOK_TASK_NAME = "generateAntoraPlaybook";
|
||||||
|
|
||||||
void apply(Project project) {
|
void apply(Project project) {
|
||||||
project.getPlugins().withType(AntoraPlugin.class, (antoraPlugin) -> apply(project, antoraPlugin));
|
project.getPlugins().withType(AntoraPlugin.class, (antoraPlugin) -> apply(project, antoraPlugin));
|
||||||
}
|
}
|
||||||
|
@ -70,7 +78,7 @@ public class AntoraConventions {
|
||||||
ExtractVersionConstraints dependencyVersionsTask = addDependencyVersionsTask(project);
|
ExtractVersionConstraints dependencyVersionsTask = addDependencyVersionsTask(project);
|
||||||
project.getPlugins().apply(GenerateAntoraYmlPlugin.class);
|
project.getPlugins().apply(GenerateAntoraYmlPlugin.class);
|
||||||
TaskContainer tasks = project.getTasks();
|
TaskContainer tasks = project.getTasks();
|
||||||
GenerateAntoraPlaybook generateAntoraPlaybookTask = tasks.create("generateAntoraPlaybook",
|
GenerateAntoraPlaybook generateAntoraPlaybookTask = tasks.create(GENERATE_ANTORA_PLAYBOOK_TASK_NAME,
|
||||||
GenerateAntoraPlaybook.class);
|
GenerateAntoraPlaybook.class);
|
||||||
configureGenerateAntoraPlaybookTask(project, generateAntoraPlaybookTask);
|
configureGenerateAntoraPlaybookTask(project, generateAntoraPlaybookTask);
|
||||||
Copy copyAntoraPackageJsonTask = tasks.create("copyAntoraPackageJson", Copy.class);
|
Copy copyAntoraPackageJsonTask = tasks.create("copyAntoraPackageJson", Copy.class);
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of aggregate content.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class AggregateContentContribution extends ConsumableContentContribution {
|
||||||
|
|
||||||
|
protected AggregateContentContribution(Project project, String name) {
|
||||||
|
super(project, "aggregate", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.antora.gradle.AntoraPlugin;
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.NamedDomainObjectContainer;
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.file.CopySpec;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Plugin} for a project that contributes to Antora-based documentation that is
|
||||||
|
* {@link AntoraDependenciesPlugin depended upon} by another project.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class AntoraContributorPlugin implements Plugin<Project> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(Project project) {
|
||||||
|
project.getPlugins().apply(AntoraPlugin.class);
|
||||||
|
NamedDomainObjectContainer<Contribution> antoraContributions = project.getObjects()
|
||||||
|
.domainObjectContainer(Contribution.class,
|
||||||
|
(name) -> project.getObjects().newInstance(Contribution.class, name, project));
|
||||||
|
project.getExtensions().add("antoraContributions", antoraContributions);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Contribution {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final Project project;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public Contribution(String name, Project project) {
|
||||||
|
this.name = name;
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void source() {
|
||||||
|
new SourceContribution(this.project, this.name).produce();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void catalogContent(Action<CopySpec> action) {
|
||||||
|
CopySpec copySpec = this.project.copySpec();
|
||||||
|
action.execute(copySpec);
|
||||||
|
new CatalogContentContribution(this.project, this.name).produceFrom(copySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void aggregateContent(Action<CopySpec> action) {
|
||||||
|
CopySpec copySpec = this.project.copySpec();
|
||||||
|
action.execute(copySpec);
|
||||||
|
new AggregateContentContribution(this.project, this.name).produceFrom(copySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void localAggregateContent(Action<CopySpec> action) {
|
||||||
|
CopySpec copySpec = this.project.copySpec();
|
||||||
|
action.execute(copySpec);
|
||||||
|
new LocalAggregateContentContribution(this.project, this.name).produceFrom(copySpec);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.NamedDomainObjectContainer;
|
||||||
|
import org.gradle.api.Plugin;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link Plugin} for a project that depends on {@link AntoraContributorPlugin
|
||||||
|
* contributed} Antora-based documentation.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class AntoraDependenciesPlugin implements Plugin<Project> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void apply(Project project) {
|
||||||
|
NamedDomainObjectContainer<AntoraDependency> antoraDependencies = project.getObjects()
|
||||||
|
.domainObjectContainer(AntoraDependency.class);
|
||||||
|
project.getExtensions().add("antoraDependencies", antoraDependencies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AntoraDependency {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
private final Project project;
|
||||||
|
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AntoraDependency(String name, Project project) {
|
||||||
|
this.name = name;
|
||||||
|
this.project = project;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return this.path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void catalogContent() {
|
||||||
|
new CatalogContentContribution(this.project, this.name).consumeFrom(this.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void aggregateContent() {
|
||||||
|
new AggregateContentContribution(this.project, this.name).consumeFrom(this.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void source() {
|
||||||
|
new SourceContribution(this.project, this.name).consumeFrom(this.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of catalog content.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class CatalogContentContribution extends ConsumableContentContribution {
|
||||||
|
|
||||||
|
CatalogContentContribution(Project project, String name) {
|
||||||
|
super(project, "catalog", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Task;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.dsl.DependencyHandler;
|
||||||
|
import org.gradle.api.file.CopySpec;
|
||||||
|
import org.gradle.api.file.Directory;
|
||||||
|
import org.gradle.api.file.RegularFile;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.publish.PublishingExtension;
|
||||||
|
import org.gradle.api.publish.maven.MavenPublication;
|
||||||
|
import org.gradle.api.tasks.TaskContainer;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of content to Antora that can be consumed by other projects.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class ConsumableContentContribution extends ContentContribution {
|
||||||
|
|
||||||
|
protected ConsumableContentContribution(Project project, String type, String name) {
|
||||||
|
super(project, name, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void produceFrom(CopySpec copySpec) {
|
||||||
|
TaskProvider<? extends Task> producer = super.configureProduction(copySpec);
|
||||||
|
Configuration configuration = createConfiguration(getName(),
|
||||||
|
"Configuration for %s Antora %s content artifacts.");
|
||||||
|
configuration.setCanBeConsumed(true);
|
||||||
|
configuration.setCanBeResolved(false);
|
||||||
|
getProject().getArtifacts().add(configuration.getName(), producer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consumeFrom(String path) {
|
||||||
|
Configuration configuration = createConfiguration(getName(), "Configuration for %s Antora %s content.");
|
||||||
|
configuration.setCanBeConsumed(false);
|
||||||
|
configuration.setCanBeResolved(true);
|
||||||
|
DependencyHandler dependencies = getProject().getDependencies();
|
||||||
|
dependencies.add(configuration.getName(),
|
||||||
|
getProject().provider(() -> projectDependency(path, configuration.getName())));
|
||||||
|
Provider<Directory> outputDirectory = outputDirectory("content", getName());
|
||||||
|
TaskContainer tasks = getProject().getTasks();
|
||||||
|
TaskProvider<?> copyAntoraContent = tasks.register(taskName("copy", "%s", configuration.getName()),
|
||||||
|
CopyAntoraContent.class, (task) -> configureCopyContent(task, path, configuration, outputDirectory));
|
||||||
|
configureAntora(addInputFrom(copyAntoraContent, configuration.getName()));
|
||||||
|
configurePlaybookGeneration(this::addToZipContentsCollectorDependencies);
|
||||||
|
getProject().getExtensions()
|
||||||
|
.getByType(PublishingExtension.class)
|
||||||
|
.getPublications()
|
||||||
|
.withType(MavenPublication.class)
|
||||||
|
.configureEach((mavenPublication) -> addPublishedMavenArtifact(mavenPublication, copyAntoraContent));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureCopyContent(CopyAntoraContent task, String path, Configuration configuration,
|
||||||
|
Provider<Directory> outputDirectory) {
|
||||||
|
task.setDescription(
|
||||||
|
"Syncs the %s Antora %s content from %s.".formatted(getName(), toDescription(getType()), path));
|
||||||
|
task.setSource(configuration);
|
||||||
|
task.getOutputFile().set(outputDirectory.map(this::getContentZipFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToZipContentsCollectorDependencies(GenerateAntoraPlaybook task) {
|
||||||
|
task.getAntoraExtensions().getZipContentsCollector().getDependencies().add(getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPublishedMavenArtifact(MavenPublication mavenPublication, TaskProvider<?> copyAntoraContent) {
|
||||||
|
if ("maven".equals(mavenPublication.getName())) {
|
||||||
|
String classifier = "%s-%s-content".formatted(getName(), getType());
|
||||||
|
mavenPublication.artifact(copyAntoraContent, (mavenArtifact) -> mavenArtifact.setClassifier(classifier));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private RegularFile getContentZipFile(Directory dir) {
|
||||||
|
Object version = getProject().getVersion();
|
||||||
|
return dir.file("spring-boot-docs-%s-%s-%s-content.zip".formatted(version, getName(), getType()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toDescription(String input) {
|
||||||
|
return input.replace("-", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration createConfiguration(String name, String description) {
|
||||||
|
return getProject().getConfigurations()
|
||||||
|
.create(configurationName(name, "Antora%sContent", getType()),
|
||||||
|
(configuration) -> configuration.setDescription(description.formatted(getName(), getType())));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.Task;
|
||||||
|
import org.gradle.api.file.CopySpec;
|
||||||
|
import org.gradle.api.tasks.TaskContainer;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import org.gradle.api.tasks.bundling.Zip;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of content to Antora.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
abstract class ContentContribution extends Contribution {
|
||||||
|
|
||||||
|
private final String type;
|
||||||
|
|
||||||
|
protected ContentContribution(Project project, String name, String type) {
|
||||||
|
super(project, name);
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getType() {
|
||||||
|
return this.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void produceFrom(CopySpec copySpec);
|
||||||
|
|
||||||
|
protected TaskProvider<? extends Task> configureProduction(CopySpec copySpec) {
|
||||||
|
TaskContainer tasks = getProject().getTasks();
|
||||||
|
TaskProvider<Zip> zipContent = tasks.register(taskName("zip", "%sAntora%sContent", getName(), this.type),
|
||||||
|
Zip.class, (zip) -> {
|
||||||
|
zip.getDestinationDirectory()
|
||||||
|
.set(getProject().getLayout().getBuildDirectory().dir("generated/docs/antora-content"));
|
||||||
|
zip.getArchiveClassifier().set("%s-%s-content".formatted(getName(), this.type));
|
||||||
|
zip.with(copySpec);
|
||||||
|
zip.setDescription("Creates a zip archive of the %s Antora %s content.".formatted(getName(),
|
||||||
|
toDescription(this.type)));
|
||||||
|
});
|
||||||
|
configureAntora(addInputFrom(zipContent, zipContent.getName()));
|
||||||
|
return zipContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toDescription(String input) {
|
||||||
|
return input.replace("-", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,115 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.antora.gradle.AntoraTask;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.gradle.api.Action;
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.artifacts.Dependency;
|
||||||
|
import org.gradle.api.file.Directory;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.PathSensitivity;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
|
||||||
|
import org.springframework.boot.build.AntoraConventions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution to Antora.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
abstract class Contribution {
|
||||||
|
|
||||||
|
private final Project project;
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
protected Contribution(Project project, String name) {
|
||||||
|
this.project = project;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Project getProject() {
|
||||||
|
return this.project;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Dependency projectDependency(String path, String configurationName) {
|
||||||
|
return getProject().getDependencies().project(Map.of("path", path, "configuration", configurationName));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Provider<Directory> outputDirectory(String dependencyType, String theName) {
|
||||||
|
return getProject().getLayout()
|
||||||
|
.getBuildDirectory()
|
||||||
|
.dir("generated/docs/antora-dependencies-" + dependencyType + "/" + theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String taskName(String verb, String object, String... args) {
|
||||||
|
return name(verb, object, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String configurationName(String name, String type, String... args) {
|
||||||
|
return name(toCamelCase(name), type, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void configurePlaybookGeneration(Action<GenerateAntoraPlaybook> action) {
|
||||||
|
this.project.getTasks()
|
||||||
|
.named(AntoraConventions.GENERATE_ANTORA_PLAYBOOK_TASK_NAME, GenerateAntoraPlaybook.class, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void configureAntora(Action<AntoraTask> action) {
|
||||||
|
this.project.getTasks().named("antora", AntoraTask.class, action);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Action<AntoraTask> addInputFrom(TaskProvider<?> task, String propertyName) {
|
||||||
|
return (antora) -> antora.getInputs()
|
||||||
|
.files(task)
|
||||||
|
.withPathSensitivity(PathSensitivity.RELATIVE)
|
||||||
|
.withPropertyName(propertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name(String prefix, String format, String... args) {
|
||||||
|
return prefix + format.formatted(Arrays.stream(args).map(this::toPascalCase).toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toPascalCase(String input) {
|
||||||
|
return StringUtils.capitalize(toCamelCase(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String toCamelCase(String input) {
|
||||||
|
StringBuilder output = new StringBuilder(input.length());
|
||||||
|
boolean capitalize = false;
|
||||||
|
for (char c : input.toCharArray()) {
|
||||||
|
if (c == '-') {
|
||||||
|
capitalize = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
output.append(capitalize ? Character.toUpperCase(c) : c);
|
||||||
|
capitalize = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.StandardCopyOption;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.api.tasks.OutputFile;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tasks to copy Antora content.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public abstract class CopyAntoraContent extends DefaultTask {
|
||||||
|
|
||||||
|
private FileCollection source;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public CopyAntoraContent() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
public FileCollection getSource() {
|
||||||
|
return this.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(FileCollection source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OutputFile
|
||||||
|
public abstract RegularFileProperty getOutputFile();
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
void copyAntoraContent() throws IllegalStateException, IOException {
|
||||||
|
Path source = this.source.getSingleFile().toPath();
|
||||||
|
Path target = getOutputFile().getAsFile().get().toPath();
|
||||||
|
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.build.antora;
|
package org.springframework.boot.build.antora;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -158,20 +158,24 @@ public final class Extensions {
|
||||||
customize("version_file", versionFile);
|
customize("version_file", versionFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
void locations(Path... locations) {
|
void locations(List<String> locations) {
|
||||||
locations(Arrays.stream(locations).map(Path::toString).toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void locations(List<String> locations) {
|
|
||||||
customize("locations", locations);
|
customize("locations", locations);
|
||||||
}
|
}
|
||||||
|
|
||||||
void alwaysInclude(Map<String, String> alwaysInclude) {
|
void alwaysInclude(List<AlwaysInclude> alwaysInclude) {
|
||||||
if (alwaysInclude != null && !alwaysInclude.isEmpty()) {
|
if (alwaysInclude != null && !alwaysInclude.isEmpty()) {
|
||||||
customize("always_include", List.of(new TreeMap<>(alwaysInclude)));
|
customize("always_include", alwaysInclude.stream().map(AlwaysInclude::asMap).toList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
record AlwaysInclude(String name, String classifier) implements Serializable {
|
||||||
|
|
||||||
|
private Map<String, String> asMap() {
|
||||||
|
return new TreeMap<>(Map.of("name", name(), "classifier", classifier()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class RootComponent extends Customizer {
|
class RootComponent extends Customizer {
|
||||||
|
|
|
@ -26,26 +26,31 @@ import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.gradle.api.DefaultTask;
|
import org.gradle.api.DefaultTask;
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.artifacts.Configuration;
|
import org.gradle.api.file.Directory;
|
||||||
import org.gradle.api.artifacts.ProjectDependency;
|
|
||||||
import org.gradle.api.file.RegularFileProperty;
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.model.ObjectFactory;
|
||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.MapProperty;
|
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.provider.SetProperty;
|
||||||
import org.gradle.api.tasks.Input;
|
import org.gradle.api.tasks.Input;
|
||||||
|
import org.gradle.api.tasks.Nested;
|
||||||
import org.gradle.api.tasks.Optional;
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.OutputFile;
|
import org.gradle.api.tasks.OutputFile;
|
||||||
import org.gradle.api.tasks.TaskAction;
|
import org.gradle.api.tasks.TaskAction;
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
import org.yaml.snakeyaml.DumperOptions;
|
||||||
import org.yaml.snakeyaml.Yaml;
|
import org.yaml.snakeyaml.Yaml;
|
||||||
|
|
||||||
|
import org.springframework.boot.build.AntoraConventions;
|
||||||
|
import org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Task to generate a local Antora playbook.
|
* Task to generate a local Antora playbook.
|
||||||
*
|
*
|
||||||
|
@ -53,35 +58,61 @@ import org.yaml.snakeyaml.Yaml;
|
||||||
*/
|
*/
|
||||||
public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
|
|
||||||
private static final String ANTORA_SOURCE_DIR = "src/docs/antora";
|
|
||||||
|
|
||||||
private static final String GENERATED_DOCS = "build/generated/docs/";
|
private static final String GENERATED_DOCS = "build/generated/docs/";
|
||||||
|
|
||||||
|
private final Path root;
|
||||||
|
|
||||||
|
private final Provider<String> playbookOutputDir;
|
||||||
|
|
||||||
|
private final String version;
|
||||||
|
|
||||||
|
private final AntoraExtensions antoraExtensions;
|
||||||
|
|
||||||
|
private final AsciidocExtensions asciidocExtensions;
|
||||||
|
|
||||||
|
private final ContentSource contentSource;
|
||||||
|
|
||||||
@OutputFile
|
@OutputFile
|
||||||
public abstract RegularFileProperty getOutputFile();
|
public abstract RegularFileProperty getOutputFile();
|
||||||
|
|
||||||
@Input
|
|
||||||
public abstract Property<String> getContentSourceConfiguration();
|
|
||||||
|
|
||||||
@Input
|
|
||||||
@Optional
|
|
||||||
public abstract ListProperty<String> getXrefStubs();
|
|
||||||
|
|
||||||
@Input
|
|
||||||
@Optional
|
|
||||||
public abstract MapProperty<String, String> getAlwaysInclude();
|
|
||||||
|
|
||||||
@Input
|
|
||||||
@Optional
|
|
||||||
public abstract Property<Boolean> getExcludeJavadocExtension();
|
|
||||||
|
|
||||||
public GenerateAntoraPlaybook() {
|
public GenerateAntoraPlaybook() {
|
||||||
|
this.root = toRealPath(getProject().getRootDir().toPath());
|
||||||
|
this.antoraExtensions = getProject().getObjects().newInstance(AntoraExtensions.class, this.root);
|
||||||
|
this.asciidocExtensions = getProject().getObjects().newInstance(AsciidocExtensions.class);
|
||||||
|
this.version = getProject().getVersion().toString();
|
||||||
|
this.playbookOutputDir = configurePlaybookOutputDir(getProject());
|
||||||
|
this.contentSource = getProject().getObjects().newInstance(ContentSource.class, this.root);
|
||||||
setGroup("Documentation");
|
setGroup("Documentation");
|
||||||
setDescription("Generates an Antora playbook.yml file for local use");
|
setDescription("Generates an Antora playbook.yml file for local use");
|
||||||
getOutputFile().convention(getProject().getLayout()
|
getOutputFile().convention(getProject().getLayout()
|
||||||
.getBuildDirectory()
|
.getBuildDirectory()
|
||||||
.file("generated/docs/antora-playbook/antora-playbook.yml"));
|
.file("generated/docs/antora-playbook/antora-playbook.yml"));
|
||||||
getContentSourceConfiguration().convention("antoraContent");
|
this.contentSource.addStartPath(getProject()
|
||||||
|
.provider(() -> getProject().getLayout().getProjectDirectory().dir(AntoraConventions.ANTORA_SOURCE_DIR)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public AntoraExtensions getAntoraExtensions() {
|
||||||
|
return this.antoraExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public AsciidocExtensions getAsciidocExtensions() {
|
||||||
|
return this.asciidocExtensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public ContentSource getContentSource() {
|
||||||
|
return this.contentSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Provider<String> configurePlaybookOutputDir(Project project) {
|
||||||
|
Path siteDirectory = getProject().getLayout().getBuildDirectory().dir("site").get().getAsFile().toPath();
|
||||||
|
return project.provider(() -> {
|
||||||
|
Path playbookDir = toRealPath(getOutputFile().get().getAsFile().toPath()).getParent();
|
||||||
|
Path outputDir = toRealPath(siteDirectory);
|
||||||
|
return "." + File.separator + playbookDir.relativize(outputDir).toString();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
|
@ -93,26 +124,14 @@ public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input
|
private Map<String, Object> getData() throws IOException {
|
||||||
final Map<String, Object> getData() throws IOException {
|
|
||||||
Map<String, Object> data = loadPlaybookTemplate();
|
Map<String, Object> data = loadPlaybookTemplate();
|
||||||
addExtensions(data);
|
addExtensions(data);
|
||||||
addSources(data);
|
addSources(data);
|
||||||
addDir(data);
|
addDir(data);
|
||||||
filterJavadocExtension(data);
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private void filterJavadocExtension(Map<String, Object> data) {
|
|
||||||
if (getExcludeJavadocExtension().getOrElse(Boolean.FALSE)) {
|
|
||||||
Map<String, Object> asciidoc = (Map<String, Object>) data.get("asciidoc");
|
|
||||||
List<String> extensions = new ArrayList<>((List<String>) asciidoc.get("extensions"));
|
|
||||||
extensions.remove("@springio/asciidoctor-extensions/javadoc-extension");
|
|
||||||
asciidoc.put("extensions", extensions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private Map<String, Object> loadPlaybookTemplate() throws IOException {
|
private Map<String, Object> loadPlaybookTemplate() throws IOException {
|
||||||
try (InputStream resource = getClass().getResourceAsStream("antora-playbook-template.yml")) {
|
try (InputStream resource = getClass().getResourceAsStream("antora-playbook-template.yml")) {
|
||||||
|
@ -124,21 +143,25 @@ public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
private void addExtensions(Map<String, Object> data) {
|
private void addExtensions(Map<String, Object> data) {
|
||||||
Map<String, Object> antora = (Map<String, Object>) data.get("antora");
|
Map<String, Object> antora = (Map<String, Object>) data.get("antora");
|
||||||
antora.put("extensions", Extensions.antora((extensions) -> {
|
antora.put("extensions", Extensions.antora((extensions) -> {
|
||||||
extensions.xref((xref) -> xref.stub(getXrefStubs().getOrElse(Collections.emptyList())));
|
extensions.xref(
|
||||||
|
(xref) -> xref.stub(this.antoraExtensions.getXref().getStubs().getOrElse(Collections.emptyList())));
|
||||||
extensions.zipContentsCollector((zipContentsCollector) -> {
|
extensions.zipContentsCollector((zipContentsCollector) -> {
|
||||||
zipContentsCollector.versionFile("gradle.properties");
|
zipContentsCollector.versionFile("gradle.properties");
|
||||||
String locationName = getProject().getName() + "-${version}-${name}-${classifier}.zip";
|
zipContentsCollector.locations(this.antoraExtensions.getZipContentsCollector()
|
||||||
Path antoraContent = getRelativeProjectPath()
|
.getLocations()
|
||||||
.resolve(GENERATED_DOCS + "antora-content/" + locationName);
|
.getOrElse(Collections.emptyList()));
|
||||||
Path antoraDependencies = getRelativeProjectPath()
|
zipContentsCollector
|
||||||
.resolve(GENERATED_DOCS + "antora-dependencies-content/" + locationName);
|
.alwaysInclude(this.antoraExtensions.getZipContentsCollector().getAlwaysInclude().getOrNull());
|
||||||
zipContentsCollector.locations(antoraContent, antoraDependencies);
|
|
||||||
zipContentsCollector.alwaysInclude(getAlwaysInclude().getOrNull());
|
|
||||||
});
|
});
|
||||||
extensions.rootComponent((rootComponent) -> rootComponent.name("boot"));
|
extensions.rootComponent((rootComponent) -> rootComponent.name("boot"));
|
||||||
}));
|
}));
|
||||||
Map<String, Object> asciidoc = (Map<String, Object>) data.get("asciidoc");
|
Map<String, Object> asciidoc = (Map<String, Object>) data.get("asciidoc");
|
||||||
asciidoc.put("extensions", Extensions.asciidoc());
|
List<String> asciidocExtensions = Extensions.asciidoc();
|
||||||
|
if (this.asciidocExtensions.getExcludeJavadocExtension().getOrElse(Boolean.FALSE)) {
|
||||||
|
asciidocExtensions = new ArrayList<>(asciidocExtensions);
|
||||||
|
asciidocExtensions.remove("@springio/asciidoctor-extensions/javadoc-extension");
|
||||||
|
}
|
||||||
|
asciidoc.put("extensions", asciidocExtensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addSources(Map<String, Object> data) {
|
private void addSources(Map<String, Object> data) {
|
||||||
|
@ -149,34 +172,17 @@ public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
private Map<String, Object> createContentSource() {
|
private Map<String, Object> createContentSource() {
|
||||||
Map<String, Object> source = new LinkedHashMap<>();
|
Map<String, Object> source = new LinkedHashMap<>();
|
||||||
Path playbookPath = getOutputFile().get().getAsFile().toPath().getParent();
|
Path playbookPath = getOutputFile().get().getAsFile().toPath().getParent();
|
||||||
Path antoraSrc = getProjectPath(getProject()).resolve(ANTORA_SOURCE_DIR);
|
|
||||||
StringBuilder url = new StringBuilder(".");
|
StringBuilder url = new StringBuilder(".");
|
||||||
relativizeFromRootProject(playbookPath).normalize().forEach((path) -> url.append(File.separator).append(".."));
|
this.root.relativize(playbookPath).normalize().forEach((path) -> url.append(File.separator).append(".."));
|
||||||
source.put("url", url.toString());
|
source.put("url", url.toString());
|
||||||
source.put("branches", "HEAD");
|
source.put("branches", "HEAD");
|
||||||
source.put("version", getProject().getVersion().toString());
|
source.put("version", this.version);
|
||||||
Set<String> startPaths = new LinkedHashSet<>();
|
source.put("start_paths", this.contentSource.getStartPaths().get());
|
||||||
addAntoraContentStartPaths(startPaths);
|
|
||||||
startPaths.add(relativizeFromRootProject(antoraSrc).toString());
|
|
||||||
source.put("start_paths", startPaths.stream().toList());
|
|
||||||
return source;
|
return source;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAntoraContentStartPaths(Set<String> startPaths) {
|
|
||||||
Configuration configuration = getProject().getConfigurations().findByName("antoraContent");
|
|
||||||
if (configuration != null) {
|
|
||||||
for (ProjectDependency dependency : configuration.getAllDependencies().withType(ProjectDependency.class)) {
|
|
||||||
Path path = dependency.getDependencyProject().getProjectDir().toPath();
|
|
||||||
startPaths.add(relativizeFromRootProject(path).resolve(ANTORA_SOURCE_DIR).toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDir(Map<String, Object> data) {
|
private void addDir(Map<String, Object> data) {
|
||||||
Path playbookDir = toRealPath(getOutputFile().get().getAsFile().toPath()).getParent();
|
data.put("output", Map.of("dir", this.playbookOutputDir.get()));
|
||||||
Path outputDir = toRealPath(
|
|
||||||
getProject().getLayout().getBuildDirectory().dir("site").get().getAsFile().toPath());
|
|
||||||
data.put("output", Map.of("dir", "." + File.separator + playbookDir.relativize(outputDir).toString()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -201,20 +207,7 @@ public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
return new Yaml(options);
|
return new Yaml(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path getRelativeProjectPath() {
|
private static Path toRealPath(Path path) {
|
||||||
return relativizeFromRootProject(getProjectPath(getProject()));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path relativizeFromRootProject(Path subPath) {
|
|
||||||
Path rootProjectPath = getProjectPath(getProject().getRootProject());
|
|
||||||
return rootProjectPath.relativize(subPath).normalize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path getProjectPath(Project project) {
|
|
||||||
return toRealPath(project.getProjectDir().toPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Path toRealPath(Path path) {
|
|
||||||
try {
|
try {
|
||||||
return Files.exists(path) ? path.toRealPath() : path;
|
return Files.exists(path) ? path.toRealPath() : path;
|
||||||
}
|
}
|
||||||
|
@ -223,4 +216,112 @@ public abstract class GenerateAntoraPlaybook extends DefaultTask {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract static class AntoraExtensions {
|
||||||
|
|
||||||
|
private final Xref xref;
|
||||||
|
|
||||||
|
private final ZipContentsCollector zipContentsCollector;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AntoraExtensions(ObjectFactory objects, Path root) {
|
||||||
|
this.xref = objects.newInstance(Xref.class);
|
||||||
|
this.zipContentsCollector = objects.newInstance(ZipContentsCollector.class, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public Xref getXref() {
|
||||||
|
return this.xref;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
public ZipContentsCollector getZipContentsCollector() {
|
||||||
|
return this.zipContentsCollector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class Xref {
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract ListProperty<String> getStubs();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class ZipContentsCollector {
|
||||||
|
|
||||||
|
private final Provider<List<String>> locations;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ZipContentsCollector(Project project, Path root) {
|
||||||
|
this.locations = configureZipContentCollectorLocations(project, root);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Provider<List<String>> configureZipContentCollectorLocations(Project project, Path root) {
|
||||||
|
ListProperty<String> locations = project.getObjects().listProperty(String.class);
|
||||||
|
Path relativeProjectPath = relativize(root, project.getProjectDir().toPath());
|
||||||
|
String locationName = project.getName() + "-${version}-${name}-${classifier}.zip";
|
||||||
|
locations.add(project
|
||||||
|
.provider(() -> relativeProjectPath.resolve(GENERATED_DOCS + "antora-content/" + locationName)
|
||||||
|
.toString()));
|
||||||
|
locations.addAll(getDependencies().map((dependencies) -> dependencies.stream()
|
||||||
|
.map((dependency) -> relativeProjectPath
|
||||||
|
.resolve(GENERATED_DOCS + "antora-dependencies-content/" + dependency + "/" + locationName))
|
||||||
|
.map(Path::toString)
|
||||||
|
.toList()));
|
||||||
|
return locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Path relativize(Path root, Path subPath) {
|
||||||
|
return toRealPath(root).relativize(toRealPath(subPath)).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract ListProperty<AlwaysInclude> getAlwaysInclude();
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public Provider<List<String>> getLocations() {
|
||||||
|
return this.locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract SetProperty<String> getDependencies();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class AsciidocExtensions {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AsciidocExtensions() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
@Optional
|
||||||
|
public abstract Property<Boolean> getExcludeJavadocExtension();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class ContentSource {
|
||||||
|
|
||||||
|
private final Path root;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ContentSource(Path root) {
|
||||||
|
this.root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Input
|
||||||
|
public abstract ListProperty<String> getStartPaths();
|
||||||
|
|
||||||
|
void addStartPath(Provider<Directory> startPath) {
|
||||||
|
getStartPaths()
|
||||||
|
.add(startPath.map((dir) -> this.root.relativize(toRealPath(dir.getAsFile().toPath())).toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.file.CopySpec;
|
||||||
|
|
||||||
|
import org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of aggregate content that cannot be consumed by other projects.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class LocalAggregateContentContribution extends ContentContribution {
|
||||||
|
|
||||||
|
protected LocalAggregateContentContribution(Project project, String name) {
|
||||||
|
super(project, name, "local-aggregate");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void produceFrom(CopySpec copySpec) {
|
||||||
|
super.configureProduction(copySpec);
|
||||||
|
configurePlaybookGeneration(this::addToAlwaysInclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToAlwaysInclude(GenerateAntoraPlaybook task) {
|
||||||
|
task.getAntoraExtensions()
|
||||||
|
.getZipContentsCollector()
|
||||||
|
.getAlwaysInclude()
|
||||||
|
.add(new AlwaysInclude(getName(), "local-aggregate-content"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
|
import org.gradle.api.artifacts.Configuration;
|
||||||
|
import org.gradle.api.artifacts.dsl.DependencyHandler;
|
||||||
|
import org.gradle.api.file.Directory;
|
||||||
|
import org.gradle.api.provider.Provider;
|
||||||
|
import org.gradle.api.tasks.TaskContainer;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import org.gradle.api.tasks.bundling.Zip;
|
||||||
|
|
||||||
|
import org.springframework.boot.build.AntoraConventions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A contribution of source to Antora.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class SourceContribution extends Contribution {
|
||||||
|
|
||||||
|
private static final String CONFIGURATION_NAME = "antoraSource";
|
||||||
|
|
||||||
|
SourceContribution(Project project, String name) {
|
||||||
|
super(project, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void produce() {
|
||||||
|
Configuration antoraSource = getProject().getConfigurations().create(CONFIGURATION_NAME);
|
||||||
|
TaskProvider<Zip> antoraSourceZip = getProject().getTasks().register("antoraSourceZip", Zip.class, (zip) -> {
|
||||||
|
zip.getDestinationDirectory().set(getProject().getLayout().getBuildDirectory().dir("antora-source"));
|
||||||
|
zip.from(AntoraConventions.ANTORA_SOURCE_DIR);
|
||||||
|
zip.setDescription(
|
||||||
|
"Creates a zip archive of the Antora source in %s.".formatted(AntoraConventions.ANTORA_SOURCE_DIR));
|
||||||
|
});
|
||||||
|
getProject().getArtifacts().add(antoraSource.getName(), antoraSourceZip);
|
||||||
|
}
|
||||||
|
|
||||||
|
void consumeFrom(String path) {
|
||||||
|
Configuration configuration = createConfiguration(getName());
|
||||||
|
DependencyHandler dependencies = getProject().getDependencies();
|
||||||
|
dependencies.add(configuration.getName(),
|
||||||
|
getProject().provider(() -> projectDependency(path, CONFIGURATION_NAME)));
|
||||||
|
Provider<Directory> outputDirectory = outputDirectory("source", getName());
|
||||||
|
TaskContainer tasks = getProject().getTasks();
|
||||||
|
TaskProvider<SyncAntoraSource> syncSource = tasks.register(taskName("sync", "%s", configuration.getName()),
|
||||||
|
SyncAntoraSource.class, (task) -> configureSyncSource(task, path, configuration, outputDirectory));
|
||||||
|
configureAntora(addInputFrom(syncSource, configuration.getName()));
|
||||||
|
configurePlaybookGeneration(
|
||||||
|
(generatePlaybook) -> generatePlaybook.getContentSource().addStartPath(outputDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configureSyncSource(SyncAntoraSource task, String path, Configuration configuration,
|
||||||
|
Provider<Directory> outputDirectory) {
|
||||||
|
task.setDescription("Syncs the %s Antora source from %s.".formatted(getName(), path));
|
||||||
|
task.setSource(configuration);
|
||||||
|
task.getOutputDirectory().set(outputDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration createConfiguration(String name) {
|
||||||
|
return getProject().getConfigurations().create(configurationName(name, "AntoraSource"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2024 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.boot.build.antora;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import org.gradle.api.DefaultTask;
|
||||||
|
import org.gradle.api.file.ArchiveOperations;
|
||||||
|
import org.gradle.api.file.CopySpec;
|
||||||
|
import org.gradle.api.file.DirectoryProperty;
|
||||||
|
import org.gradle.api.file.FileCollection;
|
||||||
|
import org.gradle.api.file.FileSystemOperations;
|
||||||
|
import org.gradle.api.tasks.InputFiles;
|
||||||
|
import org.gradle.api.tasks.OutputDirectory;
|
||||||
|
import org.gradle.api.tasks.TaskAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Task sync Antora source.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public abstract class SyncAntoraSource extends DefaultTask {
|
||||||
|
|
||||||
|
private final FileSystemOperations fileSystemOperations;
|
||||||
|
|
||||||
|
private final ArchiveOperations archiveOperations;
|
||||||
|
|
||||||
|
private FileCollection source;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public SyncAntoraSource(FileSystemOperations fileSystemOperations, ArchiveOperations archiveOperations) {
|
||||||
|
this.fileSystemOperations = fileSystemOperations;
|
||||||
|
this.archiveOperations = archiveOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OutputDirectory
|
||||||
|
public abstract DirectoryProperty getOutputDirectory();
|
||||||
|
|
||||||
|
@InputFiles
|
||||||
|
public FileCollection getSource() {
|
||||||
|
return this.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(FileCollection source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@TaskAction
|
||||||
|
void syncAntoraSource() {
|
||||||
|
this.fileSystemOperations.sync(this::syncAntoraSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncAntoraSource(CopySpec sync) {
|
||||||
|
sync.into(getOutputDirectory());
|
||||||
|
this.source.getFiles().forEach((file) -> sync.from(this.archiveOperations.zipTree(file)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -19,13 +19,15 @@ package org.springframework.boot.build.antora;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Map;
|
import java.util.List;
|
||||||
|
|
||||||
import org.gradle.api.Project;
|
import org.gradle.api.Project;
|
||||||
import org.gradle.testfixtures.ProjectBuilder;
|
import org.gradle.testfixtures.ProjectBuilder;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.io.TempDir;
|
import org.junit.jupiter.api.io.TempDir;
|
||||||
|
|
||||||
|
import org.springframework.boot.build.antora.Extensions.AntoraExtensionsConfiguration.ZipContentsCollector.AlwaysInclude;
|
||||||
|
import org.springframework.boot.build.antora.GenerateAntoraPlaybook.AntoraExtensions.ZipContentsCollector;
|
||||||
import org.springframework.util.function.ThrowingConsumer;
|
import org.springframework.util.function.ThrowingConsumer;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -43,23 +45,26 @@ class GenerateAntoraPlaybookTests {
|
||||||
@Test
|
@Test
|
||||||
void writePlaybookGeneratesExpectedContent() throws Exception {
|
void writePlaybookGeneratesExpectedContent() throws Exception {
|
||||||
writePlaybookYml((task) -> {
|
writePlaybookYml((task) -> {
|
||||||
task.getXrefStubs().addAll("appendix:.*", "api:.*", "reference:.*");
|
task.getAntoraExtensions().getXref().getStubs().addAll("appendix:.*", "api:.*", "reference:.*");
|
||||||
task.getAlwaysInclude().set(Map.of("name", "test", "classifier", "local-aggregate-content"));
|
ZipContentsCollector zipContentsCollector = task.getAntoraExtensions().getZipContentsCollector();
|
||||||
|
zipContentsCollector.getAlwaysInclude().set(List.of(new AlwaysInclude("test", "local-aggregate-content")));
|
||||||
|
zipContentsCollector.getDependencies().add("test-dependency");
|
||||||
});
|
});
|
||||||
String actual = Files.readString(this.temp.toPath()
|
String actual = Files.readString(this.temp.toPath()
|
||||||
.resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml"));
|
.resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml"));
|
||||||
String expected = Files
|
String expected = Files
|
||||||
.readString(Path.of("src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml"));
|
.readString(Path.of("src/test/resources/org/springframework/boot/build/antora/expected-playbook.yml"));
|
||||||
System.out.println(actual);
|
|
||||||
assertThat(actual.replace('\\', '/')).isEqualToNormalizingNewlines(expected.replace('\\', '/'));
|
assertThat(actual.replace('\\', '/')).isEqualToNormalizingNewlines(expected.replace('\\', '/'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void writePlaybookWhenHasJavadocExcludeGeneratesExpectedContent() throws Exception {
|
void writePlaybookWhenHasJavadocExcludeGeneratesExpectedContent() throws Exception {
|
||||||
writePlaybookYml((task) -> {
|
writePlaybookYml((task) -> {
|
||||||
task.getXrefStubs().addAll("appendix:.*", "api:.*", "reference:.*");
|
task.getAntoraExtensions().getXref().getStubs().addAll("appendix:.*", "api:.*", "reference:.*");
|
||||||
task.getAlwaysInclude().set(Map.of("name", "test", "classifier", "local-aggregate-content"));
|
ZipContentsCollector zipContentsCollector = task.getAntoraExtensions().getZipContentsCollector();
|
||||||
task.getExcludeJavadocExtension().set(true);
|
zipContentsCollector.getAlwaysInclude().set(List.of(new AlwaysInclude("test", "local-aggregate-content")));
|
||||||
|
zipContentsCollector.getDependencies().add("test-dependency");
|
||||||
|
task.getAsciidocExtensions().getExcludeJavadocExtension().set(true);
|
||||||
});
|
});
|
||||||
String actual = Files.readString(this.temp.toPath()
|
String actual = Files.readString(this.temp.toPath()
|
||||||
.resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml"));
|
.resolve("rootproject/project/build/generated/docs/antora-playbook/antora-playbook.yml"));
|
||||||
|
|
|
@ -13,7 +13,7 @@ antora:
|
||||||
name: test
|
name: test
|
||||||
locations:
|
locations:
|
||||||
- project/build/generated/docs/antora-content/test-${version}-${name}-${classifier}.zip
|
- project/build/generated/docs/antora-content/test-${version}-${name}-${classifier}.zip
|
||||||
- project/build/generated/docs/antora-dependencies-content/test-${version}-${name}-${classifier}.zip
|
- project/build/generated/docs/antora-dependencies-content/test-dependency/test-${version}-${name}-${classifier}.zip
|
||||||
version_file: gradle.properties
|
version_file: gradle.properties
|
||||||
- require: '@springio/antora-extensions/root-component-extension'
|
- require: '@springio/antora-extensions/root-component-extension'
|
||||||
root_component_name: boot
|
root_component_name: boot
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "java-library"
|
id "java-library"
|
||||||
id "org.antora"
|
id "org.springframework.boot.antora-contributor"
|
||||||
id "org.springframework.boot.auto-configuration"
|
id "org.springframework.boot.auto-configuration"
|
||||||
id "org.springframework.boot.configuration-properties"
|
id "org.springframework.boot.configuration-properties"
|
||||||
id "org.springframework.boot.deployed"
|
id "org.springframework.boot.deployed"
|
||||||
|
@ -9,10 +9,6 @@ plugins {
|
||||||
|
|
||||||
description = "Spring Boot Actuator AutoConfigure"
|
description = "Spring Boot Actuator AutoConfigure"
|
||||||
|
|
||||||
configurations {
|
|
||||||
antoraContent
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":spring-boot-project:spring-boot-actuator"))
|
api(project(":spring-boot-project:spring-boot-actuator"))
|
||||||
api(project(":spring-boot-project:spring-boot"))
|
api(project(":spring-boot-project:spring-boot"))
|
||||||
|
@ -215,36 +211,18 @@ def documentationTest = tasks.register("documentationTest", Test) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def antoraActuatorRestApiLocalAggregateContent = tasks.register("antoraActuatorRestApiLocalAggregateContent", Zip) {
|
antoraContributions {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
'actuator-rest-api' {
|
||||||
archiveClassifier = "actuator-rest-api-local-aggregate-content"
|
aggregateContent {
|
||||||
from(tasks.getByName("generateAntoraYml")) {
|
from(documentationTest.map { layout.buildDirectory.dir("generated-snippets") }) {
|
||||||
into "modules"
|
into "modules/api/partials/rest/actuator"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
localAggregateContent {
|
||||||
|
from(tasks.named("generateAntoraYml")) {
|
||||||
|
into "modules"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
source()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def antoraActuatorRestApiAggregateContent = tasks.register("antoraActuatorRestApiAggregateContent", Zip) {
|
|
||||||
dependsOn documentationTest
|
|
||||||
inputs.dir(layout.buildDirectory.dir("generated-snippets"))
|
|
||||||
.withPathSensitivity(PathSensitivity.RELATIVE)
|
|
||||||
.withPropertyName("generatedSnippets")
|
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
|
||||||
archiveClassifier = "actuator-rest-api-aggregate-content"
|
|
||||||
from(layout.buildDirectory.dir("generated-snippets")) {
|
|
||||||
into "modules/api/partials/rest/actuator"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("generateAntoraPlaybook") {
|
|
||||||
alwaysInclude = [name: "actuator-rest-api", classifier: "local-aggregate-content"]
|
|
||||||
dependsOn antoraActuatorRestApiLocalAggregateContent
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("antora") {
|
|
||||||
inputs.files(antoraActuatorRestApiAggregateContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
antoraContent antoraActuatorRestApiAggregateContent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ plugins {
|
||||||
id "dev.adamko.dokkatoo-html"
|
id "dev.adamko.dokkatoo-html"
|
||||||
id "java"
|
id "java"
|
||||||
id "org.antora"
|
id "org.antora"
|
||||||
|
id "org.springframework.boot.antora-contributor"
|
||||||
|
id "org.springframework.boot.antora-dependencies"
|
||||||
id "org.springframework.boot.deployed"
|
id "org.springframework.boot.deployed"
|
||||||
id 'org.jetbrains.kotlin.jvm'
|
id 'org.jetbrains.kotlin.jvm'
|
||||||
}
|
}
|
||||||
|
@ -14,7 +16,6 @@ configurations {
|
||||||
remoteSpringApplicationExample
|
remoteSpringApplicationExample
|
||||||
springApplicationExample
|
springApplicationExample
|
||||||
testSlices
|
testSlices
|
||||||
antoraContent
|
|
||||||
all {
|
all {
|
||||||
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
|
||||||
if (details.requested.module.group == "org.apache.kafka" && details.requested.module.name == "kafka-server-common") {
|
if (details.requested.module.group == "org.apache.kafka" && details.requested.module.name == "kafka-server-common") {
|
||||||
|
@ -179,10 +180,6 @@ dependencies {
|
||||||
springApplicationExample(platform(project(":spring-boot-project:spring-boot-dependencies")))
|
springApplicationExample(platform(project(":spring-boot-project:spring-boot-dependencies")))
|
||||||
springApplicationExample(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
springApplicationExample(project(path: ":spring-boot-project:spring-boot-starters:spring-boot-starter-web"))
|
||||||
|
|
||||||
antoraContent(project(path: ":spring-boot-project:spring-boot-actuator-autoconfigure", configuration: "antoraContent"))
|
|
||||||
antoraContent(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin", configuration: "antoraContent"))
|
|
||||||
antoraContent(project(path: ":spring-boot-project:spring-boot-tools:spring-boot-maven-plugin", configuration: "antoraContent"))
|
|
||||||
|
|
||||||
testImplementation(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
testImplementation(project(":spring-boot-project:spring-boot-actuator-autoconfigure"))
|
||||||
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
|
||||||
testImplementation("org.assertj:assertj-core")
|
testImplementation("org.assertj:assertj-core")
|
||||||
|
@ -308,86 +305,86 @@ def getRelativeExamplesPath(var outputs) {
|
||||||
'example$example-output/' + fileName
|
'example$example-output/' + fileName
|
||||||
}
|
}
|
||||||
|
|
||||||
def antoraRootAggregateContent = tasks.register("antoraRootAggregateContent", Zip) {
|
antoraDependencies {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
'actuator-rest-api' {
|
||||||
archiveClassifier = "root-aggregate-content"
|
path = ":spring-boot-project:spring-boot-actuator-autoconfigure"
|
||||||
from("src/main") {
|
source()
|
||||||
into "modules/ROOT/examples"
|
aggregateContent()
|
||||||
}
|
}
|
||||||
from(project.configurations.configurationProperties) {
|
'gradle-plugin' {
|
||||||
eachFile {
|
path = ":spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin"
|
||||||
it.path = rootProject
|
source()
|
||||||
.projectDir
|
catalogContent()
|
||||||
.toPath()
|
}
|
||||||
.relativize(it.file.toPath())
|
'maven-plugin' {
|
||||||
.toString()
|
path = ":spring-boot-project:spring-boot-tools:spring-boot-maven-plugin"
|
||||||
.replace('\\', '/')
|
source()
|
||||||
.replaceAll('.*/([^/]+)/build.*', 'modules/ROOT/partials/$1/spring-configuration-metadata.json')
|
catalogContent()
|
||||||
|
aggregateContent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
antoraContributions {
|
||||||
|
'api' {
|
||||||
|
catalogContent {
|
||||||
|
from(aggregatedJavadoc) {
|
||||||
|
into "java"
|
||||||
|
}
|
||||||
|
from(tasks.named("dokkatooGeneratePublicationHtml")) {
|
||||||
|
into "kotlin"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
from(runRemoteSpringApplicationExample) {
|
'root' {
|
||||||
into "modules/ROOT/examples"
|
aggregateContent {
|
||||||
}
|
from("src/main") {
|
||||||
from(documentDevtoolsPropertyDefaults) {
|
into "modules/ROOT/examples"
|
||||||
into "modules/ROOT/partials/propertydefaults"
|
}
|
||||||
}
|
from(project.configurations.configurationProperties) {
|
||||||
from(documentStarters) {
|
eachFile {
|
||||||
into "modules/ROOT/partials/starters"
|
it.path = rootProject
|
||||||
}
|
.projectDir
|
||||||
from(documentTestSlices) {
|
.toPath()
|
||||||
into "modules/appendix/partials/slices"
|
.relativize(it.file.toPath())
|
||||||
}
|
.toString()
|
||||||
from(runSpringApplicationExample) {
|
.replace('\\', '/')
|
||||||
into "modules/ROOT/partials/application"
|
.replaceAll('.*/([^/]+)/build.*', 'modules/ROOT/partials/$1/spring-configuration-metadata.json')
|
||||||
}
|
}
|
||||||
from(runLoggingFormatExample) {
|
}
|
||||||
into "modules/ROOT/partials/logging"
|
from(runRemoteSpringApplicationExample) {
|
||||||
}
|
into "modules/ROOT/examples"
|
||||||
from(documentDependencyVersionCoordinates) {
|
}
|
||||||
into "modules/appendix/partials/dependency-versions"
|
from(documentDevtoolsPropertyDefaults) {
|
||||||
}
|
into "modules/ROOT/partials/propertydefaults"
|
||||||
from(documentDependencyVersionProperties) {
|
}
|
||||||
into "modules/appendix/partials/dependency-versions"
|
from(documentStarters) {
|
||||||
}
|
into "modules/ROOT/partials/starters"
|
||||||
from(documentAutoConfigurationClasses) {
|
}
|
||||||
into "modules/appendix/partials/auto-configuration-classes"
|
from(documentTestSlices) {
|
||||||
}
|
into "modules/appendix/partials/slices"
|
||||||
from(documentConfigurationProperties) {
|
}
|
||||||
into "modules/appendix/partials/configuration-properties"
|
from(runSpringApplicationExample) {
|
||||||
}
|
into "modules/ROOT/partials/application"
|
||||||
from(tasks.getByName("generateAntoraYml")) {
|
}
|
||||||
into "modules"
|
from(runLoggingFormatExample) {
|
||||||
}
|
into "modules/ROOT/partials/logging"
|
||||||
}
|
}
|
||||||
|
from(documentDependencyVersionCoordinates) {
|
||||||
def antoraApiCatalogContent = tasks.register("antoraApiCatalogContent", Zip) {
|
into "modules/appendix/partials/dependency-versions"
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
}
|
||||||
archiveClassifier = "api-catalog-content"
|
from(documentDependencyVersionProperties) {
|
||||||
from(aggregatedJavadoc) {
|
into "modules/appendix/partials/dependency-versions"
|
||||||
into "java"
|
}
|
||||||
}
|
from(documentAutoConfigurationClasses) {
|
||||||
from(tasks.named("dokkatooGeneratePublicationHtml")) {
|
into "modules/appendix/partials/auto-configuration-classes"
|
||||||
into "kotlin"
|
}
|
||||||
}
|
from(documentConfigurationProperties) {
|
||||||
}
|
into "modules/appendix/partials/configuration-properties"
|
||||||
|
}
|
||||||
def copyAntoraContentDependencies = tasks.register("copyAntoraContentDependencies", Copy) {
|
from(tasks.getByName("generateAntoraYml")) {
|
||||||
into layout.buildDirectory.dir('generated/docs/antora-dependencies-content')
|
into "modules"
|
||||||
from(configurations.antoraContent)
|
}
|
||||||
rename("spring-boot-actuator-autoconfigure", "spring-boot-docs")
|
}
|
||||||
rename("spring-boot-maven-plugin", "spring-boot-docs")
|
|
||||||
rename("spring-boot-gradle-plugin", "spring-boot-docs")
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("antora") {
|
|
||||||
inputs.files(antoraRootAggregateContent, antoraApiCatalogContent, copyAntoraContentDependencies)
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.projectsEvaluated {
|
|
||||||
def mavenPublication = publishing.publications.getByName("maven");
|
|
||||||
configurations.antoraContent.dependencies.forEach { dependency ->
|
|
||||||
dependency.dependencyProject.configurations.getByName(dependency.targetConfiguration)
|
|
||||||
.artifacts.forEach(mavenPublication::artifact)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,12 +393,3 @@ dokkatoo {
|
||||||
includes.from("src/docs/dokkatoo/dokka-overview.md")
|
includes.from("src/docs/dokkatoo/dokka-overview.md")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
|
||||||
publications {
|
|
||||||
getByName("maven") {
|
|
||||||
artifact antoraRootAggregateContent
|
|
||||||
artifact antoraApiCatalogContent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import org.gradle.plugins.ide.eclipse.model.Library
|
||||||
plugins {
|
plugins {
|
||||||
id "java-gradle-plugin"
|
id "java-gradle-plugin"
|
||||||
id "maven-publish"
|
id "maven-publish"
|
||||||
id "org.antora"
|
id "org.springframework.boot.antora-contributor"
|
||||||
id "org.springframework.boot.docker-test"
|
id "org.springframework.boot.docker-test"
|
||||||
id "org.springframework.boot.maven-repository"
|
id "org.springframework.boot.maven-repository"
|
||||||
id "org.springframework.boot.optional-dependencies"
|
id "org.springframework.boot.optional-dependencies"
|
||||||
|
@ -14,7 +14,6 @@ plugins {
|
||||||
description = "Spring Boot Gradle Plugins"
|
description = "Spring Boot Gradle Plugins"
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
antoraContent
|
|
||||||
"testCompileClasspath" {
|
"testCompileClasspath" {
|
||||||
// Downgrade SLF4J is required for tests to run in Eclipse
|
// Downgrade SLF4J is required for tests to run in Eclipse
|
||||||
resolutionStrategy.force("org.slf4j:slf4j-api:1.7.36")
|
resolutionStrategy.force("org.slf4j:slf4j-api:1.7.36")
|
||||||
|
@ -166,35 +165,25 @@ javadoc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def antoraGradlePluginLocalAggregateContent = tasks.register("antoraGradlePluginLocalAggregateContent", Zip) {
|
antoraContributions {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
'gradle-plugin' {
|
||||||
archiveClassifier = "gradle-plugin-local-aggregate-content"
|
catalogContent {
|
||||||
from(tasks.getByName("generateAntoraYml")) {
|
from(javadoc) {
|
||||||
into "modules"
|
into("api/java")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
localAggregateContent {
|
||||||
def antoraGradlePluginCatalogContent = tasks.register("antoraGradlePluginCatalogContent", Zip) {
|
from(tasks.named("generateAntoraYml")) {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
into "modules"
|
||||||
archiveClassifier = "gradle-plugin-catalog-content"
|
}
|
||||||
from(javadoc) {
|
}
|
||||||
into "api/java"
|
source()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named("generateAntoraPlaybook") {
|
tasks.named("generateAntoraPlaybook") {
|
||||||
xrefStubs = ["appendix:.*", "api:.*", "reference:.*"]
|
antoraExtensions.xref.stubs = ["appendix:.*", "api:.*", "reference:.*"]
|
||||||
excludeJavadocExtension = true
|
asciidocExtensions.excludeJavadocExtension = true
|
||||||
alwaysInclude = [name: "gradle-plugin", classifier: "local-aggregate-content"]
|
|
||||||
dependsOn antoraGradlePluginLocalAggregateContent
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.named("antora") {
|
|
||||||
inputs.files(antoraGradlePluginLocalAggregateContent, antoraGradlePluginCatalogContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
antoraContent antoraGradlePluginCatalogContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toolchain {
|
toolchain {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
plugins {
|
plugins {
|
||||||
id "org.antora"
|
id "org.springframework.boot.antora-contributor"
|
||||||
id "org.springframework.boot.maven-plugin"
|
id "org.springframework.boot.maven-plugin"
|
||||||
id "org.springframework.boot.optional-dependencies"
|
id "org.springframework.boot.optional-dependencies"
|
||||||
id "org.springframework.boot.docker-test"
|
id "org.springframework.boot.docker-test"
|
||||||
|
@ -9,7 +9,6 @@ description = "Spring Boot Maven Plugin"
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
dependenciesBom
|
dependenciesBom
|
||||||
antoraContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
@ -148,45 +147,30 @@ tasks.named("documentPluginGoals") {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
def antoraMavenPluginLocalAggregateContent = tasks.register("antoraMavenPluginLocalAggregateContent", Zip) {
|
antoraContributions {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
'maven-plugin' {
|
||||||
archiveClassifier = "maven-plugin-local-aggregate-content"
|
aggregateContent {
|
||||||
from(tasks.getByName("generateAntoraYml")) {
|
from(documentPluginGoals) {
|
||||||
into "modules"
|
into "modules/maven-plugin/partials/goals"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catalogContent {
|
||||||
def antoraMavenPluginAggregateContent = tasks.register("antoraMavenPluginAggregateContent", Zip) {
|
from(javadoc) {
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
into "api/java"
|
||||||
archiveClassifier = "maven-plugin-aggregate-content"
|
}
|
||||||
from(documentPluginGoals) {
|
}
|
||||||
into "modules/maven-plugin/partials/goals"
|
localAggregateContent {
|
||||||
}
|
from(tasks.named("generateAntoraYml")) {
|
||||||
}
|
into "modules"
|
||||||
|
}
|
||||||
def antoraMavenPluginCatalogContent = tasks.register("antoraMavenPluginCatalogContent", Zip) {
|
}
|
||||||
destinationDirectory = layout.buildDirectory.dir('generated/docs/antora-content')
|
source()
|
||||||
archiveClassifier = "maven-plugin-catalog-content"
|
|
||||||
from(javadoc) {
|
|
||||||
into "api/java"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named("generateAntoraPlaybook") {
|
tasks.named("generateAntoraPlaybook") {
|
||||||
xrefStubs = ["appendix:.*", "api:.*", "reference:.*", "how-to:.*"]
|
antoraExtensions.xref.stubs = ["appendix:.*", "api:.*", "reference:.*", "how-to:.*"]
|
||||||
excludeJavadocExtension = true
|
asciidocExtensions.excludeJavadocExtension = true
|
||||||
alwaysInclude = [name: "maven-plugin", classifier: "local-aggregate-content"]
|
|
||||||
dependsOn antoraMavenPluginLocalAggregateContent
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
tasks.named("antora") {
|
|
||||||
inputs.files(antoraMavenPluginLocalAggregateContent, antoraMavenPluginAggregateContent, antoraMavenPluginCatalogContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
artifacts {
|
|
||||||
antoraContent antoraMavenPluginAggregateContent
|
|
||||||
antoraContent antoraMavenPluginCatalogContent
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.named("dockerTest").configure {
|
tasks.named("dockerTest").configure {
|
||||||
|
|
Loading…
Reference in New Issue