Skip to content

Commit 6389fc6

Browse files
Move version range check to check-buildplan
1 parent fa26f53 commit 6389fc6

10 files changed

Lines changed: 186 additions & 130 deletions

File tree

src/it/compare-version-range-no-fail/invoker.properties renamed to src/it/check-buildplan-version-range-fail/invoker.properties

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,5 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
# initial reference build: install
19-
invoker.goals.1=clean install
20-
# second build: verify (could be package, but not install to avoid overriding reference)
21-
invoker.goals.2=clean verify artifact:compare
22-
18+
invoker.goals=artifact:check-buildplan
19+
invoker.buildResult=failure

src/it/compare-version-range-fail/pom.xml renamed to src/it/check-buildplan-version-range-fail/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
<properties>
3131
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
32+
<project.build.outputTimestamp>0</project.build.outputTimestamp>
3233
</properties>
3334

3435
<dependencies>

src/it/compare-version-range-no-fail/verify.groovy renamed to src/it/check-buildplan-version-range-fail/verify.groovy

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
def buildLog = new File(basedir, 'build.log').text
2222

23-
assert buildLog =~ /(?m)^\[WARNING] Dependency io\.cucumber:messages:jar:.+ \(compile\) via io\.cucumber:gherkin:jar:.+ is referenced with a range version \[32\.0\.0,33\.0\.0\)\s*$/
24-
assert buildLog =~ /(?m)^\[WARNING] Dependency commons-io:commons-io:jar:.+ \(compile\) is referenced with a range version \[2.20.0,\)\s*$/
25-
assert buildLog =~ /(?m)^\[WARNING] Dependency commons-collections:commons-collections:jar:LATEST \(compile\) is referenced with a range version LATEST\s*$/
23+
assert buildLog.contains('[ERROR] Version with range found in dependencies, project can be non-reproducible')
24+
assert buildLog.contains(' - Dependency io.cucumber:messages:jar:32.2.0 (compile) via io.cucumber:gherkin:jar:38.0.0 is referenced with a range version [32.0.0,33.0.0)')
25+
assert buildLog.contains(' - Dependency commons-io:commons-io:jar:2.21.0 (compile) is referenced with a range version [2.20.0,)')
26+
assert buildLog.contains(' - Dependency commons-collections:commons-collections:jar:LATEST (compile) is referenced with a range version LATEST')

src/it/compare-version-range-fail/invoker.properties renamed to src/it/check-buildplan-version-range-no-fail/invoker.properties

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,4 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
# initial reference build: install
19-
invoker.goals.1=clean install
20-
# second build: verify (could be package, but not install to avoid overriding reference)
21-
invoker.goals.2=clean verify artifact:compare
22-
invoker.buildResult.2=failure
23-
18+
invoker.goals=artifact:check-buildplan

src/it/compare-version-range-no-fail/pom.xml renamed to src/it/check-buildplan-version-range-no-fail/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
<artifactId>@project.artifactId@</artifactId>
6464
<version>@project.version@</version>
6565
<configuration>
66-
<failVersionRange>false</failVersionRange>
66+
<failOnNonReproducible>false</failOnNonReproducible>
6767
</configuration>
6868
</plugin>
6969
</plugins>

src/it/compare-version-range-fail/verify.groovy renamed to src/it/check-buildplan-version-range-no-fail/verify.groovy

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
def buildLog = new File(basedir, 'build.log').text
2222

23-
assert buildLog =~ /(?m)^\[ERROR] Dependency io\.cucumber:messages:jar:.+ \(compile\) via io\.cucumber:gherkin:jar:.+ is referenced with a range version \[32\.0\.0,33\.0\.0\)\s*$/
24-
assert buildLog =~ /(?m)^\[ERROR] Dependency commons-io:commons-io:jar:.+ \(compile\) is referenced with a range version \[2.20.0,\)\s*$/
25-
assert buildLog =~ /(?m)^\[ERROR] Dependency commons-collections:commons-collections:jar:LATEST \(compile\) is referenced with a range version LATEST\s*$/
23+
assert buildLog.contains('[WARNING] Version with range found in dependencies, project can be non-reproducible')
24+
assert buildLog.contains(' - Dependency io.cucumber:messages:jar:32.2.0 (compile) via io.cucumber:gherkin:jar:38.0.0 is referenced with a range version [32.0.0,33.0.0)')
25+
assert buildLog.contains(' - Dependency commons-io:commons-io:jar:2.21.0 (compile) is referenced with a range version [2.20.0,)')
26+
assert buildLog.contains(' - Dependency commons-collections:commons-collections:jar:LATEST (compile) is referenced with a range version LATEST')

src/it/compare-version-range-no-fail-depMan/invoker.properties

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,5 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
# initial reference build: install
19-
invoker.goals.1=clean install
20-
# second build: verify (could be package, but not install to avoid overriding reference)
21-
invoker.goals.2=clean verify artifact:compare
18+
invoker.goals=artifact:check-buildplan
2219

src/main/java/org/apache/maven/plugins/artifact/buildinfo/CheckBuildPlanMojo.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.Map;
2929
import java.util.Properties;
3030
import java.util.Set;
31+
import java.util.stream.Collectors;
3132

3233
import org.apache.maven.execution.MavenSession;
3334
import org.apache.maven.lifecycle.LifecycleExecutor;
@@ -39,6 +40,7 @@
3940
import org.apache.maven.plugins.annotations.Mojo;
4041
import org.apache.maven.plugins.annotations.Parameter;
4142
import org.apache.maven.project.MavenProject;
43+
import org.eclipse.aether.graph.DependencyNode;
4244
import org.eclipse.aether.util.version.GenericVersionScheme;
4345
import org.eclipse.aether.version.InvalidVersionSpecificationException;
4446
import org.eclipse.aether.version.Version;
@@ -91,11 +93,15 @@ public class CheckBuildPlanMojo extends AbstractMojo {
9193

9294
private final VersionScheme versionScheme = new GenericVersionScheme();
9395

96+
private final RangesUtil rangesUtil;
97+
9498
@Inject
95-
public CheckBuildPlanMojo(MavenProject project, MavenSession session, LifecycleExecutor lifecycleExecutor) {
99+
public CheckBuildPlanMojo(
100+
MavenProject project, MavenSession session, LifecycleExecutor lifecycleExecutor, RangesUtil rangesUtil) {
96101
this.project = project;
97102
this.session = session;
98103
this.lifecycleExecutor = lifecycleExecutor;
104+
this.rangesUtil = rangesUtil;
99105
}
100106

101107
protected MavenExecutionPlan calculateExecutionPlan() throws MojoExecutionException {
@@ -164,6 +170,8 @@ public void execute() throws MojoExecutionException {
164170
getLog().info("No known issue in " + okCount + " plugins");
165171
}
166172

173+
fail = checkVersionRangeInDependencies();
174+
167175
if (fail) {
168176
getLog().info("current module pom.xml is " + project.getBasedir() + "/pom.xml");
169177
MavenProject parent = project;
@@ -183,6 +191,23 @@ public void execute() throws MojoExecutionException {
183191
}
184192
}
185193

194+
private boolean checkVersionRangeInDependencies() throws MojoExecutionException {
195+
Map<DependencyNode, String> versionRangeDependencies =
196+
rangesUtil.findVersionRangeDependencies(session, project);
197+
if (!versionRangeDependencies.isEmpty()) {
198+
String message = "Version with range found in dependencies, project can be non-reproducible"
199+
+ versionRangeDependencies.values().stream()
200+
.collect(Collectors.joining(
201+
System.lineSeparator() + " - ", System.lineSeparator() + " - ", ""));
202+
if (failOnNonReproducible) {
203+
getLog().error(message);
204+
} else {
205+
getLog().warn(message);
206+
}
207+
}
208+
return !versionRangeDependencies.isEmpty();
209+
}
210+
186211
private Properties loadIssues() throws MojoExecutionException {
187212
try (InputStream in = (pluginIssues == null)
188213
? getClass().getResourceAsStream("not-reproducible-plugins.properties")

src/main/java/org/apache/maven/plugins/artifact/buildinfo/CompareMojo.java

Lines changed: 0 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,9 @@
3232
import java.util.Collections;
3333
import java.util.List;
3434
import java.util.Map;
35-
import java.util.Objects;
3635
import java.util.Properties;
37-
import java.util.stream.Collectors;
3836

39-
import org.apache.maven.RepositoryUtils;
4037
import org.apache.maven.execution.MavenSession;
41-
import org.apache.maven.model.DependencyManagement;
4238
import org.apache.maven.plugin.MojoExecutionException;
4339
import org.apache.maven.plugins.annotations.Mojo;
4440
import org.apache.maven.plugins.annotations.Parameter;
@@ -49,17 +45,9 @@
4945
import org.eclipse.aether.RepositorySystem;
5046
import org.eclipse.aether.RepositorySystemSession;
5147
import org.eclipse.aether.artifact.Artifact;
52-
import org.eclipse.aether.artifact.ArtifactTypeRegistry;
53-
import org.eclipse.aether.collection.CollectRequest;
54-
import org.eclipse.aether.collection.DependencyCollectionException;
55-
import org.eclipse.aether.graph.Dependency;
56-
import org.eclipse.aether.graph.DependencyNode;
5748
import org.eclipse.aether.repository.RemoteRepository;
5849
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
59-
import org.eclipse.aether.util.graph.visitor.PathRecordingDependencyVisitor;
60-
import org.eclipse.aether.version.VersionConstraint;
6150

62-
import static java.util.Optional.ofNullable;
6351
import static org.apache.maven.plugins.artifact.buildinfo.BuildInfoWriter.getArtifactFilename;
6452

6553
/**
@@ -110,14 +98,6 @@ public class CompareMojo extends AbstractBuildinfoMojo {
11098
@Parameter(property = "compare.fail", defaultValue = "true")
11199
private boolean fail;
112100

113-
/**
114-
* Fail the build if dependencies with version range are found in project or transitive dependencies.
115-
*
116-
* @since 3.6.2
117-
*/
118-
@Parameter(property = "compare.failVersionRange", defaultValue = "true")
119-
private boolean failVersionRange;
120-
121101
/**
122102
* The entry point to Maven Artifact Resolver, i.e. the component doing all the work.
123103
*/
@@ -137,8 +117,6 @@ public CompareMojo(
137117
@Override
138118
public void execute(Map<Artifact, String> artifacts) throws MojoExecutionException {
139119
getLog().info("Checking against reference build from " + referenceRepo + "...");
140-
141-
checkVersionRangeInDependencies();
142120
checkAgainstReference(artifacts, session.getProjects().size() == 1);
143121
}
144122

@@ -148,8 +126,6 @@ protected void skip(MavenProject last) throws MojoExecutionException {
148126
return;
149127
}
150128

151-
checkVersionRangeInDependencies();
152-
153129
// try to download reference artifacts for current project and check if there are issues to give early feedback
154130
checkAgainstReference(generateBuildinfo(true), true);
155131
}
@@ -393,87 +369,4 @@ private RemoteRepository createDeploymentArtifactRepository(String id, String ur
393369
repoSystem.newResolutionRepositories(repoSession, Collections.singletonList(repository));
394370
return repositories.isEmpty() ? repository : repositories.get(0);
395371
}
396-
397-
private void checkVersionRangeInDependencies() throws MojoExecutionException {
398-
DependencyNode rootNode = collectDependencies();
399-
List<String> versionRangeDependencies = collectVersionRangeDependencies(rootNode);
400-
if (!versionRangeDependencies.isEmpty()) {
401-
if (failVersionRange) {
402-
versionRangeDependencies.forEach(getLog()::error);
403-
throw new MojoExecutionException("Version range dependencies found: " + versionRangeDependencies.size()
404-
+ ". Please fix them to have a fixed version for better reproducibility");
405-
} else {
406-
versionRangeDependencies.forEach(getLog()::warn);
407-
}
408-
}
409-
}
410-
411-
private DependencyNode collectDependencies() throws MojoExecutionException {
412-
ArtifactTypeRegistry artifactTypeRegistry =
413-
session.getRepositorySession().getArtifactTypeRegistry();
414-
415-
List<Dependency> dependencies = project.getDependencies().stream()
416-
.map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
417-
.collect(Collectors.toList());
418-
419-
List<Dependency> managedDependencies = ofNullable(project.getDependencyManagement())
420-
.map(DependencyManagement::getDependencies)
421-
.map(list -> list.stream()
422-
.map(d -> RepositoryUtils.toDependency(d, artifactTypeRegistry))
423-
.collect(Collectors.toList()))
424-
.orElse(null);
425-
426-
CollectRequest collectRequest =
427-
new CollectRequest(dependencies, managedDependencies, project.getRemoteProjectRepositories());
428-
collectRequest.setRootArtifact(RepositoryUtils.toArtifact(project.getArtifact()));
429-
430-
try {
431-
return repoSystem.collectDependencies(repoSession, collectRequest).getRoot();
432-
} catch (DependencyCollectionException e) {
433-
throw new MojoExecutionException("Cannot build dependency tree: " + e.getMessage(), e);
434-
}
435-
}
436-
437-
private List<String> collectVersionRangeDependencies(DependencyNode rootNode) {
438-
List<String> result = new ArrayList<>();
439-
440-
rootNode.accept(new PathRecordingDependencyVisitor((node, parents) -> {
441-
VersionConstraint versionConstraint = node.getVersionConstraint();
442-
if (isVersionRange(versionConstraint)) {
443-
String path = "";
444-
if (parents.size() > 1) {
445-
path = " via "
446-
+ parents.stream()
447-
.limit(parents.size() - 1)
448-
.map(n -> n.getDependency().getArtifact().toString())
449-
.collect(Collectors.joining(" --> "));
450-
}
451-
result.add("Dependency " + node.getDependency() + path + " is referenced with a range version "
452-
+ versionConstraint);
453-
}
454-
455-
// track all dependencies
456-
return false;
457-
}));
458-
459-
return result;
460-
}
461-
462-
private boolean isVersionRange(VersionConstraint versionConstraint) {
463-
if (versionConstraint == null) {
464-
return false;
465-
}
466-
467-
if (versionConstraint.getVersion() != null) {
468-
String version = versionConstraint.getVersion().toString();
469-
return version.equals("LATEST") || version.equals("RELEASE");
470-
}
471-
472-
if (versionConstraint.getRange() != null) {
473-
return !Objects.equals(
474-
versionConstraint.getRange().getLowerBound(),
475-
versionConstraint.getRange().getUpperBound());
476-
}
477-
return false;
478-
}
479372
}

0 commit comments

Comments
 (0)