Skip to content

Commit 181e3b3

Browse files
committed
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
1 parent fea535d commit 181e3b3

File tree

2 files changed

+96
-42
lines changed
  • buildSrc/src/main/java/org/springframework/boot/build/mavenplugin
  • spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects

2 files changed

+96
-42
lines changed

buildSrc/src/main/java/org/springframework/boot/build/mavenplugin/MavenPluginPlugin.java

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
package org.springframework.boot.build.mavenplugin;
1818

1919
import java.io.File;
20+
import java.io.IOException;
2021
import java.nio.charset.StandardCharsets;
2122
import java.nio.file.Files;
2223
import java.nio.file.Path;
24+
import java.nio.file.StandardCopyOption;
2325
import java.util.Arrays;
2426

2527
import io.spring.javaformat.formatter.FileEdit;
@@ -28,13 +30,23 @@
2830
import org.gradle.api.Plugin;
2931
import org.gradle.api.Project;
3032
import org.gradle.api.Task;
33+
import org.gradle.api.artifacts.ComponentMetadataContext;
34+
import org.gradle.api.artifacts.ComponentMetadataRule;
35+
import org.gradle.api.artifacts.Configuration;
36+
import org.gradle.api.artifacts.ModuleVersionIdentifier;
37+
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
38+
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
39+
import org.gradle.api.attributes.DocsType;
3140
import org.gradle.api.file.CopySpec;
41+
import org.gradle.api.file.DirectoryProperty;
42+
import org.gradle.api.model.ObjectFactory;
3243
import org.gradle.api.plugins.JavaLibraryPlugin;
3344
import org.gradle.api.plugins.JavaPlugin;
3445
import org.gradle.api.plugins.JavaPluginConvention;
3546
import org.gradle.api.publish.PublishingExtension;
3647
import org.gradle.api.publish.maven.MavenPublication;
3748
import org.gradle.api.publish.maven.plugins.MavenPublishPlugin;
49+
import org.gradle.api.tasks.Classpath;
3850
import org.gradle.api.tasks.Copy;
3951
import org.gradle.api.tasks.JavaExec;
4052
import org.gradle.api.tasks.OutputDirectory;
@@ -85,16 +97,30 @@ private void setPackaging(MavenPublication mavenPublication) {
8597
}
8698

8799
private void addPopulateIntTestMavenRepositoryTask(Project project) {
100+
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository = project.getTasks()
101+
.create("runtimeClasspathMavenRepository", RuntimeClasspathMavenRepository.class);
102+
runtimeClasspathMavenRepository.getOutputDirectory()
103+
.set(new File(project.getBuildDir(), "runtime-classpath-repository"));
104+
Configuration runtimeClasspathWithMetadata = project.getConfigurations().create("runtimeClasspathWithMetadata");
105+
runtimeClasspathWithMetadata
106+
.extendsFrom(project.getConfigurations().getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
107+
runtimeClasspathWithMetadata.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,
108+
project.getObjects().named(DocsType.class, "maven-repository")));
109+
project.getDependencies()
110+
.components((components) -> components.all(MavenRepositoryComponentMetadataRule.class));
88111
Copy task = project.getTasks().create("populateIntTestMavenRepository", Copy.class);
89112
task.setDestinationDir(project.getBuildDir());
90-
task.into("int-test-maven-repository", (copy) -> copyIntTestMavenRepositoryFiles(project, copy));
113+
task.into("int-test-maven-repository",
114+
(copy) -> copyIntTestMavenRepositoryFiles(project, copy, runtimeClasspathMavenRepository));
91115
task.dependsOn(project.getTasks().getByName(MavenRepositoryPlugin.PUBLISH_TO_PROJECT_REPOSITORY_TASK_NAME));
92116
project.getTasks().getByName(IntegrationTestPlugin.INT_TEST_TASK_NAME).dependsOn(task);
93117
}
94118

95-
private void copyIntTestMavenRepositoryFiles(Project project, CopySpec copy) {
119+
private void copyIntTestMavenRepositoryFiles(Project project, CopySpec copy,
120+
RuntimeClasspathMavenRepository runtimeClasspathMavenRepository) {
96121
copy.from(project.getConfigurations().getByName(MavenRepositoryPlugin.MAVEN_REPOSITORY_CONFIGURATION_NAME));
97122
copy.from(new File(project.getBuildDir(), "maven-repository"));
123+
copy.from(runtimeClasspathMavenRepository);
98124
}
99125

100126
private void addDocumentPluginGoalsTask(Project project, MavenExec generatePluginDescriptorTask) {
@@ -252,4 +278,72 @@ private void save(File output, FileEdit edit) {
252278

253279
}
254280

281+
public static class MavenRepositoryComponentMetadataRule implements ComponentMetadataRule {
282+
283+
private final ObjectFactory objects;
284+
285+
@javax.inject.Inject
286+
public MavenRepositoryComponentMetadataRule(ObjectFactory objects) {
287+
this.objects = objects;
288+
}
289+
290+
@Override
291+
public void execute(ComponentMetadataContext context) {
292+
context.getDetails().maybeAddVariant("compileWithMetadata", "compile", (variant) -> {
293+
variant.attributes((attributes) -> attributes.attribute(DocsType.DOCS_TYPE_ATTRIBUTE,
294+
this.objects.named(DocsType.class, "maven-repository")));
295+
variant.withFiles((files) -> {
296+
ModuleVersionIdentifier id = context.getDetails().getId();
297+
files.addFile(id.getName() + "-" + id.getVersion() + ".pom");
298+
});
299+
});
300+
}
301+
302+
}
303+
304+
public static class RuntimeClasspathMavenRepository extends DefaultTask {
305+
306+
private final Configuration runtimeClasspath;
307+
308+
private final DirectoryProperty outputDirectory;
309+
310+
public RuntimeClasspathMavenRepository() {
311+
this.runtimeClasspath = getProject().getConfigurations()
312+
.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME);
313+
this.outputDirectory = getProject().getObjects().directoryProperty();
314+
}
315+
316+
@OutputDirectory
317+
public DirectoryProperty getOutputDirectory() {
318+
return this.outputDirectory;
319+
}
320+
321+
@Classpath
322+
public Configuration getRuntimeClasspath() {
323+
return this.runtimeClasspath;
324+
}
325+
326+
@TaskAction
327+
public void createRepository() {
328+
for (ResolvedArtifactResult result : this.runtimeClasspath.getIncoming().getArtifacts()) {
329+
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier) {
330+
ModuleComponentIdentifier identifier = (ModuleComponentIdentifier) result.getId()
331+
.getComponentIdentifier();
332+
File repositoryLocation = this.outputDirectory.dir(identifier.getGroup().replace('.', '/') + "/"
333+
+ identifier.getModule() + "/" + identifier.getVersion() + "/" + result.getFile().getName())
334+
.get().getAsFile();
335+
repositoryLocation.getParentFile().mkdirs();
336+
try {
337+
Files.copy(result.getFile().toPath(), repositoryLocation.toPath(),
338+
StandardCopyOption.REPLACE_EXISTING);
339+
}
340+
catch (IOException ex) {
341+
throw new RuntimeException("Failed to copy artifact '" + result + "'", ex);
342+
}
343+
}
344+
}
345+
}
346+
347+
}
348+
255349
}

spring-boot-project/spring-boot-tools/spring-boot-maven-plugin/src/intTest/projects/settings.xml

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,6 @@
1818
<enabled>true</enabled>
1919
</snapshots>
2020
</repository>
21-
<repository>
22-
<id>spring-snapshot</id>
23-
<url>https://repo.spring.io/snapshot</url>
24-
<releases>
25-
<enabled>false</enabled>
26-
</releases>
27-
<snapshots>
28-
<enabled>true</enabled>
29-
</snapshots>
30-
</repository>
31-
<repository>
32-
<id>spring-milestone</id>
33-
<url>https://repo.spring.io/milestone</url>
34-
<releases>
35-
<enabled>true</enabled>
36-
</releases>
37-
<snapshots>
38-
<enabled>false</enabled>
39-
</snapshots>
40-
</repository>
4121
</repositories>
4222
<pluginRepositories>
4323
<pluginRepository>
@@ -50,26 +30,6 @@
5030
<enabled>true</enabled>
5131
</snapshots>
5232
</pluginRepository>
53-
<pluginRepository>
54-
<id>spring-snapshot</id>
55-
<url>https://repo.spring.io/snapshot</url>
56-
<releases>
57-
<enabled>false</enabled>
58-
</releases>
59-
<snapshots>
60-
<enabled>true</enabled>
61-
</snapshots>
62-
</pluginRepository>
63-
<pluginRepository>
64-
<id>spring-milestone</id>
65-
<url>https://repo.spring.io/milestone</url>
66-
<releases>
67-
<enabled>true</enabled>
68-
</releases>
69-
<snapshots>
70-
<enabled>false</enabled>
71-
</snapshots>
72-
</pluginRepository>
7333
</pluginRepositories>
7434
</profile>
7535
</profiles>

0 commit comments

Comments
 (0)