Allow to customize how build writers sort dependencies

Closes gh-1098
This commit is contained in:
Stephane Nicoll 2020-11-19 11:50:02 +01:00
parent d665620a91
commit eed9c3876f
5 changed files with 137 additions and 10 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2020 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -142,6 +142,14 @@ public abstract class GradleBuildWriter {
return (scope) -> Arrays.asList(validScopes).contains(scope); return (scope) -> Arrays.asList(validScopes).contains(scope);
} }
/**
* Return the {@link Comparator} to use to sort dependencies.
* @return a dependency comparator
*/
protected Comparator<Dependency> getDependencyComparator() {
return DependencyComparator.INSTANCE;
}
protected abstract void writeDependency(IndentingWriter writer, Dependency dependency); protected abstract void writeDependency(IndentingWriter writer, Dependency dependency);
protected String configurationForDependency(Dependency dependency) { protected String configurationForDependency(Dependency dependency) {
@ -242,9 +250,9 @@ public abstract class GradleBuildWriter {
protected abstract void writeProperty(IndentingWriter writer, String name, String value); protected abstract void writeProperty(IndentingWriter writer, String name, String value);
private static Collection<Dependency> filterDependencies(DependencyContainer dependencies, private Collection<Dependency> filterDependencies(DependencyContainer dependencies,
Predicate<DependencyScope> filter) { Predicate<DependencyScope> filter) {
return dependencies.items().filter((dep) -> filter.test(dep.getScope())).sorted(DependencyComparator.INSTANCE) return dependencies.items().filter((dep) -> filter.test(dep.getScope())).sorted(getDependencyComparator())
.collect(Collectors.toList()); .collect(Collectors.toList());
} }

View File

@ -83,6 +83,14 @@ public class MavenBuildWriter {
}); });
} }
/**
* Return the {@link Comparator} to use to sort dependencies.
* @return a dependency comparator
*/
protected Comparator<Dependency> getDependencyComparator() {
return DependencyComparator.INSTANCE;
}
private void writeProject(IndentingWriter writer, Runnable whenWritten) { private void writeProject(IndentingWriter writer, Runnable whenWritten) {
writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>"); writer.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
writer.println( writer.println(
@ -214,7 +222,7 @@ public class MavenBuildWriter {
private Collection<Dependency> writeDependencies(IndentingWriter writer, DependencyContainer dependencies, private Collection<Dependency> writeDependencies(IndentingWriter writer, DependencyContainer dependencies,
Predicate<DependencyScope> filter) { Predicate<DependencyScope> filter) {
Collection<Dependency> candidates = dependencies.items().filter((dep) -> filter.test(dep.getScope())) Collection<Dependency> candidates = dependencies.items().filter((dep) -> filter.test(dep.getScope()))
.sorted(DependencyComparator.INSTANCE).collect(Collectors.toList()); .sorted(getDependencyComparator()).collect(Collectors.toList());
writeCollection(writer, candidates, this::writeDependency); writeCollection(writer, candidates, this::writeDependency);
return candidates; return candidates;
} }

View File

@ -18,6 +18,7 @@ package io.spring.initializr.generator.buildsystem.gradle;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
import io.spring.initializr.generator.buildsystem.BillOfMaterials; import io.spring.initializr.generator.buildsystem.BillOfMaterials;
@ -415,6 +416,41 @@ class GroovyDslGradleBuildWriterTests {
"}"); "}");
} }
@Test
void gradleBuildWithOrderedDependencies() {
GradleBuild build = new GradleBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
List<String> lines = generateBuild(build);
assertThat(lines).containsSequence(" implementation 'org.springframework.boot:spring-boot-starter'",
" implementation 'org.springframework.boot:spring-boot-starter-web'",
" implementation 'com.example:alpha'", " implementation 'com.example:beta'");
}
@Test
void gradleBuildWithOrderedDependenciesAndCustomComparator() {
GradleBuild build = new GradleBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
GroovyDslGradleBuildWriter writer = new GroovyDslGradleBuildWriter() {
@Override
protected Comparator<Dependency> getDependencyComparator() {
return Comparator.comparing(Dependency::getArtifactId);
}
};
List<String> lines = generateBuild(writer, build);
assertThat(lines).containsSequence(" implementation 'com.example:alpha'",
" implementation 'com.example:beta'",
" implementation 'org.springframework.boot:spring-boot-starter'",
" implementation 'org.springframework.boot:spring-boot-starter-web'");
}
@Test @Test
void gradleBuildWithBom() { void gradleBuildWithBom() {
GradleBuild build = new GradleBuild(); GradleBuild build = new GradleBuild();
@ -447,7 +483,10 @@ class GroovyDslGradleBuildWriterTests {
} }
private List<String> generateBuild(GradleBuild build) { private List<String> generateBuild(GradleBuild build) {
GradleBuildWriter writer = new GroovyDslGradleBuildWriter(); return generateBuild(new GroovyDslGradleBuildWriter(), build);
}
private List<String> generateBuild(GroovyDslGradleBuildWriter writer, GradleBuild build) {
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
writer.writeTo(new IndentingWriter(out), build); writer.writeTo(new IndentingWriter(out), build);
String[] lines = out.toString().split("\\r?\\n"); String[] lines = out.toString().split("\\r?\\n");

View File

@ -18,6 +18,7 @@ package io.spring.initializr.generator.buildsystem.gradle;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Arrays; import java.util.Arrays;
import java.util.Comparator;
import java.util.List; import java.util.List;
import io.spring.initializr.generator.buildsystem.BillOfMaterials; import io.spring.initializr.generator.buildsystem.BillOfMaterials;
@ -424,6 +425,41 @@ class KotlinDslGradleBuildWriterTests {
"}"); "}");
} }
@Test
void gradleBuildWithOrderedDependencies() {
GradleBuild build = new GradleBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
List<String> lines = generateBuild(build);
assertThat(lines).containsSequence(" implementation(\"org.springframework.boot:spring-boot-starter\")",
" implementation(\"org.springframework.boot:spring-boot-starter-web\")",
" implementation(\"com.example:alpha\")", " implementation(\"com.example:beta\")");
}
@Test
void gradleBuildWithOrderedDependenciesAndCustomComparator() {
GradleBuild build = new GradleBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
KotlinDslGradleBuildWriter writer = new KotlinDslGradleBuildWriter() {
@Override
protected Comparator<Dependency> getDependencyComparator() {
return Comparator.comparing(Dependency::getArtifactId);
}
};
List<String> lines = generateBuild(writer, build);
assertThat(lines).containsSequence(" implementation(\"com.example:alpha\")",
" implementation(\"com.example:beta\")",
" implementation(\"org.springframework.boot:spring-boot-starter\")",
" implementation(\"org.springframework.boot:spring-boot-starter-web\")");
}
@Test @Test
void gradleBuildWithBom() { void gradleBuildWithBom() {
GradleBuild build = new GradleBuild(); GradleBuild build = new GradleBuild();
@ -456,7 +492,10 @@ class KotlinDslGradleBuildWriterTests {
} }
private List<String> generateBuild(GradleBuild build) { private List<String> generateBuild(GradleBuild build) {
GradleBuildWriter writer = new KotlinDslGradleBuildWriter(); return generateBuild(new KotlinDslGradleBuildWriter(), build);
}
private List<String> generateBuild(KotlinDslGradleBuildWriter writer, GradleBuild build) {
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
writer.writeTo(new IndentingWriter(out), build); writer.writeTo(new IndentingWriter(out), build);
String[] lines = out.toString().split("\\r?\\n"); String[] lines = out.toString().split("\\r?\\n");

View File

@ -17,6 +17,7 @@
package io.spring.initializr.generator.buildsystem.maven; package io.spring.initializr.generator.buildsystem.maven;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.Comparator;
import java.util.function.Consumer; import java.util.function.Consumer;
import io.spring.initializr.generator.buildsystem.BillOfMaterials; import io.spring.initializr.generator.buildsystem.BillOfMaterials;
@ -420,6 +421,39 @@ class MavenBuildWriterTests {
}); });
} }
@Test
void pomWithOrderedDependencies() {
MavenBuild build = new MavenBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
String pom = writePom(new MavenBuildWriter(), build);
assertThat(pom).containsSubsequence("<artifactId>spring-boot-starter</artifactId>",
"<artifactId>spring-boot-starter-web</artifactId>", "<artifactId>alpha</artifactId>",
"<artifactId>beta</artifactId>");
}
@Test
void pomWithOrderedDependenciesAndCustomComparator() {
MavenBuild build = new MavenBuild();
build.dependencies().add("beta", Dependency.withCoordinates("com.example", "beta"));
build.dependencies().add("alpha", Dependency.withCoordinates("com.example", "alpha"));
build.dependencies().add("web",
Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter-web"));
build.dependencies().add("root", Dependency.withCoordinates("org.springframework.boot", "spring-boot-starter"));
MavenBuildWriter writer = new MavenBuildWriter() {
@Override
protected Comparator<Dependency> getDependencyComparator() {
return Comparator.comparing(Dependency::getArtifactId);
}
};
String pom = writePom(writer, build);
assertThat(pom).containsSubsequence("<artifactId>alpha</artifactId>", "<artifactId>beta</artifactId>",
"<artifactId>spring-boot-starter</artifactId>", "<artifactId>spring-boot-starter-web</artifactId>");
}
@Test @Test
void pomWithBom() { void pomWithBom() {
MavenBuild build = new MavenBuild(); MavenBuild build = new MavenBuild();
@ -822,17 +856,16 @@ class MavenBuildWriterTests {
MavenBuild build = new MavenBuild(); MavenBuild build = new MavenBuild();
build.settings().coordinates("com.example.demo", "demo").name("<demo project>") build.settings().coordinates("com.example.demo", "demo").name("<demo project>")
.description("A \"demo\" project for 'developers' & 'testers'"); .description("A \"demo\" project for 'developers' & 'testers'");
String pom = writePom(build); String pom = writePom(new MavenBuildWriter(), build);
assertThat(pom).contains("<name>&lt;demo project&gt;</name>").contains( assertThat(pom).contains("<name>&lt;demo project&gt;</name>").contains(
"<description>A &quot;demo&quot; project for &apos;developers&apos; &amp; &apos;testers&apos;</description>"); "<description>A &quot;demo&quot; project for &apos;developers&apos; &amp; &apos;testers&apos;</description>");
} }
private void generatePom(MavenBuild mavenBuild, Consumer<NodeAssert> consumer) { private void generatePom(MavenBuild mavenBuild, Consumer<NodeAssert> consumer) {
consumer.accept(new NodeAssert(writePom(mavenBuild))); consumer.accept(new NodeAssert(writePom(new MavenBuildWriter(), mavenBuild)));
} }
private String writePom(MavenBuild mavenBuild) { private String writePom(MavenBuildWriter writer, MavenBuild mavenBuild) {
MavenBuildWriter writer = new MavenBuildWriter();
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
writer.writeTo(new IndentingWriter(out), mavenBuild); writer.writeTo(new IndentingWriter(out), mavenBuild);
return out.toString(); return out.toString();