Isolate Maven Plugin's integration tests from repo.spring.io

Previously, the Maven plugin integration tests used a settings.xml file
that defined https://repo.spring.io/snapshot as a repository. This
allowed them to resolve snapshots of the plugin's Spring Framework
dependencies but it had the unfortunate side-effect of also allowing
them to resolve snapshots of other Spring Boot modules from Artifactory
rather than using those currently being built.

This commit replaces the repositories in settings.xml with a Gradle
task that resolves the necessary dependencies and populates a local
repository with the dependencies' jars and pom files. This is achieved
using a ComponentMetadataRule that creates a custom variant of each
dependency that includes its pom file, inspired by the example in
gradle/gradle/#11449. A configuration that extends the
runtimeClasspath configuration and select the custom variant via its
attribute is then used to resolve the jars and pom files of the runtime
classpath such that they can then be used to populate the local
repository.

Closes gh-22828
pull/22996/head
Andy Wilkinson 4 years ago
parent fea535d176
commit 181e3b34ba

@ -17,9 +17,11 @@
package org.springframework.boot.build.mavenplugin;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import io.spring.javaformat.formatter.FileEdit;
@ -28,13 +30,23 @@ import org.gradle.api.DefaultTask;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.Task;
import org.gradle.api.artifacts.ComponentMetadataContext;
import org.gradle.api.artifacts.ComponentMetadataRule;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ModuleVersionIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
import org.gradle.api.attributes.DocsType;
import org.gradle.api.file.CopySpec;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginConvention;
import org.gradle.api.publish.PublishingExtension;
import org.gradle.api.publish.maven.MavenPublication;
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Copy;
import org.gradle.api.tasks.JavaExec;
import org.gradle.api.tasks.OutputDirectory;
@ -85,16 +97,30 @@ public class MavenPluginPlugin implements Plugin<Project> {
}
private void addPopulateIntTestMavenRepositoryTask(Project project) {
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository = project.getTasks()
.create("runtimeClasspathMavenRepository", RuntimeClasspathMavenRepository.class);
runtimeClasspathMavenRepository.getOutputDirectory()
.set(new File(project.getBuildDir(), "runtime-classpath-repository"));
Configuration runtimeClasspathWithMetadata = project.getConfigurations().create("runtimeClasspathWithMetadata");
runtimeClasspathWithMetadata
.extendsFrom(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
runtimeClasspathWithMetadata.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,
project.getObjects().named(DocsType.class, "maven-repository")));
project.getDependencies()
.components((components) -> components.all(MavenRepositoryComponentMetadataRule.class));
Copy task = project.getTasks().create("populateIntTestMavenRepository", Copy.class);
task.setDestinationDir(project.getBuildDir());
task.into("int-test-maven-repository", (copy) -> copyIntTestMavenRepositoryFiles(project, copy));
task.into("int-test-maven-repository",
(copy) -> copyIntTestMavenRepositoryFiles(project, copy, runtimeClasspathMavenRepository));
task.dependsOn(project.getTasks().getByName(MavenRepositoryPlugin.PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME));
project.getTasks().getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME).dependsOn(task);
}
private void copyIntTestMavenRepositoryFiles(Project project, CopySpec copy) {
private void copyIntTestMavenRepositoryFiles(Project project, CopySpec copy,
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository) {
copy.from(project.getConfigurations().getByName(MavenRepositoryPlugin.MAVEN_REPOSITORY_CONFIGURATION_NAME));
copy.from(new File(project.getBuildDir(), "maven-repository"));
copy.from(runtimeClasspathMavenRepository);
}
private void addDocumentPluginGoalsTask(Project project, MavenExec generatePluginDescriptorTask) {
@ -252,4 +278,72 @@ public class MavenPluginPlugin implements Plugin<Project> {
}
public static class MavenRepositoryComponentMetadataRule implements ComponentMetadataRule {
private final ObjectFactory objects;
@javax.inject.Inject
public MavenRepositoryComponentMetadataRule(ObjectFactory objects) {
this.objects = objects;
}
@Override
public void execute(ComponentMetadataContext context) {
context.getDetails().maybeAddVariant("compileWithMetadata", "compile", (variant) -> {
variant.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,
this.objects.named(DocsType.class, "maven-repository")));
variant.withFiles((files) -> {
ModuleVersionIdentifier id = context.getDetails().getId();
files.addFile(id.getName() + "-" + id.getVersion() + ".pom");
});
});
}
}
public static class RuntimeClasspathMavenRepository extends DefaultTask {
private final Configuration runtimeClasspath;
private final DirectoryProperty outputDirectory;
public RuntimeClasspathMavenRepository() {
this.runtimeClasspath = getProject().getConfigurations()
.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
this.outputDirectory = getProject().getObjects().directoryProperty();
}
@OutputDirectory
public DirectoryProperty getOutputDirectory() {
return this.outputDirectory;
}
@Classpath
public Configuration getRuntimeClasspath() {
return this.runtimeClasspath;
}
@TaskAction
public void createRepository() {
for (ResolvedArtifactResult result : this.runtimeClasspath.getIncoming().getArtifacts()) {
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier identifier = (ModuleComponentIdentifier) result.getId()
.getComponentIdentifier();
File repositoryLocation = this.outputDirectory.dir(identifier.getGroup().replace('.', '/') + "/"
+ identifier.getModule() + "/" + identifier.getVersion() + "/" + result.getFile().getName())
.get().getAsFile();
repositoryLocation.getParentFile().mkdirs();
try {
Files.copy(result.getFile().toPath(), repositoryLocation.toPath(),
StandardCopyOption.REPLACE_EXISTING);
}
catch (IOException ex) {
throw new RuntimeException("Failed to copy artifact '" + result + "'", ex);
}
}
}
}
}
}

@ -18,26 +18,6 @@
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
@ -50,26 +30,6 @@
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
</profiles>

Loading…
Cancel
Save