Skip to content

Commit 5895ff2

Browse files
[MENFORCER-467] banDynamicVersions excludedScopes on project level (#262)
Co-authored-by: Konrad Windszus <[email protected]>
1 parent 7848853 commit 5895ff2

File tree

3 files changed

+48
-60
lines changed

3 files changed

+48
-60
lines changed

enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/BanDynamicVersions.java renamed to enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/dependency/BanDynamicVersions.java

+30-57
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
* specific language governing permissions and limitations
1717
* under the License.
1818
*/
19-
package org.apache.maven.enforcer.rules;
19+
package org.apache.maven.enforcer.rules.dependency;
2020

2121
import javax.inject.Inject;
2222
import javax.inject.Named;
@@ -32,25 +32,16 @@
3232
import java.util.function.Predicate;
3333
import java.util.stream.Collectors;
3434

35-
import org.apache.maven.RepositoryUtils;
3635
import org.apache.maven.enforcer.rule.api.EnforcerRuleException;
36+
import org.apache.maven.enforcer.rules.AbstractStandardEnforcerRule;
3737
import org.apache.maven.enforcer.rules.utils.ArtifactMatcher;
3838
import org.apache.maven.enforcer.rules.utils.ArtifactUtils;
3939
import org.apache.maven.execution.MavenSession;
4040
import org.apache.maven.project.MavenProject;
41-
import org.eclipse.aether.DefaultRepositorySystemSession;
4241
import org.eclipse.aether.RepositorySystem;
43-
import org.eclipse.aether.RepositorySystemSession;
44-
import org.eclipse.aether.collection.CollectRequest;
45-
import org.eclipse.aether.collection.CollectResult;
4642
import org.eclipse.aether.collection.DependencyCollectionException;
47-
import org.eclipse.aether.collection.DependencySelector;
48-
import org.eclipse.aether.graph.Dependency;
4943
import org.eclipse.aether.graph.DependencyNode;
5044
import org.eclipse.aether.graph.DependencyVisitor;
51-
import org.eclipse.aether.util.graph.selector.AndDependencySelector;
52-
import org.eclipse.aether.util.graph.selector.OptionalDependencySelector;
53-
import org.eclipse.aether.util.graph.selector.ScopeDependencySelector;
5445
import org.eclipse.aether.util.graph.visitor.TreeDependencyVisitor;
5546
import org.eclipse.aether.version.VersionConstraint;
5647

@@ -108,7 +99,7 @@ public final class BanDynamicVersions extends AbstractStandardEnforcerRule {
10899
/**
109100
* the scopes of dependencies which should be excluded from this rule
110101
*/
111-
private String[] excludedScopes;
102+
private List<String> excludedScopes;
112103

113104
/**
114105
* Specify the ignored dependencies. This can be a list of artifacts in the format
@@ -119,17 +110,12 @@ public final class BanDynamicVersions extends AbstractStandardEnforcerRule {
119110
*/
120111
private List<String> ignores = null;
121112

122-
private final MavenProject project;
123-
124-
private final RepositorySystem repoSystem;
125-
126-
private final MavenSession mavenSession;
113+
private final ResolverUtil resolverUtil;
127114

128115
@Inject
129-
public BanDynamicVersions(MavenProject project, RepositorySystem repoSystem, MavenSession mavenSession) {
130-
this.project = Objects.requireNonNull(project);
131-
this.repoSystem = Objects.requireNonNull(repoSystem);
132-
this.mavenSession = Objects.requireNonNull(mavenSession);
116+
public BanDynamicVersions(
117+
MavenProject project, RepositorySystem repoSystem, MavenSession mavenSession, ResolverUtil resolverUtil) {
118+
this.resolverUtil = Objects.requireNonNull(resolverUtil);
133119
}
134120

135121
private final class BannedDynamicVersionCollector implements DependencyVisitor {
@@ -138,19 +124,19 @@ private final class BannedDynamicVersionCollector implements DependencyVisitor {
138124

139125
private boolean isRoot = true;
140126

141-
private int numViolations;
127+
private List<String> violations;
142128

143129
private final Predicate<DependencyNode> predicate;
144130

145-
public int getNumViolations() {
146-
return numViolations;
131+
public List<String> getViolations() {
132+
return violations;
147133
}
148134

149135
BannedDynamicVersionCollector(Predicate<DependencyNode> predicate) {
150-
nodeStack = new ArrayDeque<>();
136+
this.nodeStack = new ArrayDeque<>();
151137
this.predicate = predicate;
152138
this.isRoot = true;
153-
numViolations = 0;
139+
this.violations = new ArrayList<>();
154140
}
155141

156142
private boolean isBannedDynamicVersion(VersionConstraint versionConstraint) {
@@ -183,13 +169,11 @@ public boolean visitEnter(DependencyNode node) {
183169
} else {
184170
getLog().debug("Found node " + node + " with version constraint " + node.getVersionConstraint());
185171
if (predicate.test(node) && isBannedDynamicVersion(node.getVersionConstraint())) {
186-
getLog().warnOrError(() -> new StringBuilder()
187-
.append("Dependency ")
188-
.append(node.getDependency())
189-
.append(dumpIntermediatePath(nodeStack))
190-
.append(" is referenced with a banned dynamic version ")
191-
.append(node.getVersionConstraint()));
192-
numViolations++;
172+
violations.add("Dependency "
173+
+ node.getDependency()
174+
+ dumpIntermediatePath(nodeStack)
175+
+ " is referenced with a banned dynamic version "
176+
+ node.getVersionConstraint());
193177
return false;
194178
}
195179
nodeStack.addLast(node);
@@ -209,26 +193,17 @@ public boolean visitLeave(DependencyNode node) {
209193
@Override
210194
public void execute() throws EnforcerRuleException {
211195

212-
// get a new session to be able to tweak the dependency selector
213-
DefaultRepositorySystemSession newRepoSession =
214-
new DefaultRepositorySystemSession(mavenSession.getRepositorySession());
215-
216-
Collection<DependencySelector> depSelectors = new ArrayList<>();
217-
depSelectors.add(new ScopeDependencySelector(excludedScopes));
218-
if (excludeOptionals) {
219-
depSelectors.add(new OptionalDependencySelector());
220-
}
221-
newRepoSession.setDependencySelector(new AndDependencySelector(depSelectors));
222-
223-
Dependency rootDependency = RepositoryUtils.toDependency(project.getArtifact(), null);
224196
try {
225-
// use root dependency with unresolved direct dependencies
226-
int numViolations = emitDependenciesWithBannedDynamicVersions(rootDependency, newRepoSession);
227-
if (numViolations > 0) {
197+
DependencyNode rootDependency =
198+
resolverUtil.resolveTransitiveDependencies(excludeOptionals, excludedScopes);
199+
200+
List<String> violations = collectDependenciesWithBannedDynamicVersions(rootDependency);
201+
if (!violations.isEmpty()) {
228202
ChoiceFormat dependenciesFormat = new ChoiceFormat("1#dependency|1<dependencies");
229-
throw new EnforcerRuleException("Found " + numViolations + " "
230-
+ dependenciesFormat.format(numViolations)
231-
+ " with dynamic versions. Look at the warnings emitted above for the details.");
203+
throw new EnforcerRuleException("Found " + violations.size() + " "
204+
+ dependenciesFormat.format(violations.size())
205+
+ " with dynamic versions." + System.lineSeparator()
206+
+ String.join(System.lineSeparator(), violations));
232207
}
233208
} catch (DependencyCollectionException e) {
234209
throw new EnforcerRuleException("Could not retrieve dependency metadata for project", e);
@@ -256,10 +231,8 @@ public boolean test(DependencyNode depNode) {
256231
}
257232
}
258233

259-
private int emitDependenciesWithBannedDynamicVersions(
260-
Dependency rootDependency, RepositorySystemSession repoSession) throws DependencyCollectionException {
261-
CollectRequest collectRequest = new CollectRequest(rootDependency, project.getRemoteProjectRepositories());
262-
CollectResult collectResult = repoSystem.collectDependencies(repoSession, collectRequest);
234+
private List<String> collectDependenciesWithBannedDynamicVersions(DependencyNode rootDependency)
235+
throws DependencyCollectionException {
263236
Predicate<DependencyNode> predicate;
264237
if (ignores != null && !ignores.isEmpty()) {
265238
predicate = new ExcludeArtifactPatternsPredicate(ignores);
@@ -268,8 +241,8 @@ private int emitDependenciesWithBannedDynamicVersions(
268241
}
269242
BannedDynamicVersionCollector bannedDynamicVersionCollector = new BannedDynamicVersionCollector(predicate);
270243
DependencyVisitor depVisitor = new TreeDependencyVisitor(bannedDynamicVersionCollector);
271-
collectResult.getRoot().accept(depVisitor);
272-
return bannedDynamicVersionCollector.getNumViolations();
244+
rootDependency.accept(depVisitor);
245+
return bannedDynamicVersionCollector.getViolations();
273246
}
274247

275248
@Override

enforcer-rules/src/main/java/org/apache/maven/enforcer/rules/dependency/ResolverUtil.java

+16-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ class ResolverUtil {
7777
* Please consult {@link ConflictResolver} and {@link DependencyManagerUtils}>
7878
* </p>
7979
*
80-
* @param excludedScopes a project dependency scope to excluded
80+
* @param excludedScopes the scopes of direct dependencies to ignore
8181
* @return a Dependency Node which is the root of the project's dependency tree
8282
* @throws EnforcerRuleException thrown if the lookup fails
8383
*/
@@ -96,6 +96,20 @@ DependencyNode resolveTransitiveDependencies() throws EnforcerRuleException {
9696
return resolveTransitiveDependencies(false, true, Arrays.asList(SCOPE_TEST, SCOPE_PROVIDED));
9797
}
9898

99+
/**
100+
* Retrieves the {@link DependencyNode} instance containing the result of the transitive dependency
101+
* for the current {@link MavenProject}.
102+
*
103+
* @param excludeOptional ignore optional project artifacts
104+
* @param excludedScopes the scopes of direct dependencies to ignore
105+
* @return a Dependency Node which is the root of the project's dependency tree
106+
* @throws EnforcerRuleException thrown if the lookup fails
107+
*/
108+
DependencyNode resolveTransitiveDependencies(boolean excludeOptional, List<String> excludedScopes)
109+
throws EnforcerRuleException {
110+
return resolveTransitiveDependencies(false, excludeOptional, excludedScopes);
111+
}
112+
99113
private DependencyNode resolveTransitiveDependencies(
100114
boolean verbose, boolean excludeOptional, List<String> excludedScopes) throws EnforcerRuleException {
101115

@@ -134,6 +148,7 @@ private DependencyNode resolveTransitiveDependencies(
134148
return repositorySystem
135149
.collectDependencies(repositorySystemSession, collectRequest)
136150
.getRoot();
151+
137152
} catch (DependencyCollectionException e) {
138153
throw new EnforcerRuleException("Could not build dependency tree " + e.getLocalizedMessage(), e);
139154
}

maven-enforcer-plugin/src/it/projects/ban-dynamic-versions/verify.groovy

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@ assert buildLog.text.contains( '[ERROR] Dependency org.apache.maven.plugins.enfo
2121
assert buildLog.text.contains( '[ERROR] Dependency org.apache.maven.plugins.enforcer.its:menforcer138_io:jar:LATEST (compile) is referenced with a banned dynamic version LATEST' )
2222
assert buildLog.text.contains( '[ERROR] Dependency org.apache.maven.plugins.enforcer.its:menforcer134_model:jar:1.0-SNAPSHOT (compile) is referenced with a banned dynamic version 1.0-SNAPSHOT' )
2323
assert buildLog.text.contains( '[ERROR] Dependency org.apache.maven.plugins.enforcer.its:menforcer427-a:jar:1.0 (compile) via org.apache.maven.plugins.enforcer.its:menforcer427:jar:1.0 is referenced with a banned dynamic version [1.0,2)' )
24-
assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.BanDynamicVersions failed with message' )
25-
assert buildLog.text.contains( 'Found 4 dependencies with dynamic versions. Look at the warnings emitted above for the details.' )
24+
assert buildLog.text.contains( '[ERROR] Rule 0: org.apache.maven.enforcer.rules.dependency.BanDynamicVersions failed with message' )
25+
assert buildLog.text.contains( 'ERROR] Found 4 dependencies with dynamic versions.' )

0 commit comments

Comments
 (0)