This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-shade-plugin.git
The following commit(s) were added to refs/heads/master by this push:
new 6b94fed9 [#870] Warn when an artifactSet include or exclude matches no
artifact
6b94fed9 is described below
commit 6b94fed9081627a6e6102bf079f8a3beb8e9c081
Author: Sylwester Lachiewicz <[email protected]>
AuthorDate: Tue Oct 27 21:43:36 2026 +0000
[#870] Warn when an artifactSet include or exclude matches no artifact
A typo in an include, or one left behind after a dependency is removed,
went unnoticed. Unmatched includes and filters are now logged at WARN and
unmatched excludes at INFO.
---
.../projects/artifactset-unmatched-pattern/pom.xml | 77 ++++++++++++++++++++++
.../artifactset-unmatched-pattern/verify.groovy | 23 +++++++
.../maven/plugins/shade/mojo/ArtifactSelector.java | 59 +++++++++++++++--
.../apache/maven/plugins/shade/mojo/ShadeMojo.java | 9 ++-
.../plugins/shade/mojo/ArtifactSelectorTest.java | 36 ++++++++++
5 files changed, 196 insertions(+), 8 deletions(-)
diff --git a/src/it/projects/artifactset-unmatched-pattern/pom.xml
b/src/it/projects/artifactset-unmatched-pattern/pom.xml
new file mode 100644
index 00000000..bf35c4b6
--- /dev/null
+++ b/src/it/projects/artifactset-unmatched-pattern/pom.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+<project>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.shade.asup</groupId>
+ <artifactId>test</artifactId>
+ <version>1.0</version>
+ <packaging>jar</packaging>
+
+ <name>artifactset-unmatched-pattern</name>
+ <description>
+ Test that artifactSet patterns matching no artifact are reported.
+ </description>
+
+ <properties>
+ <slf4j.version>1.7.36</slf4j.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <version>@project.version@</version>
+ <executions>
+ <execution>
+ <id>attach-shade</id>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ <configuration>
+ <shadedArtifactAttached>true</shadedArtifactAttached>
+ <artifactSet>
+ <includes>
+ <include>org.slf4j:slf4j-api</include>
+ <include>no.such:artifact</include>
+ </includes>
+ <excludes>
+ <exclude>no.such:other</exclude>
+ </excludes>
+ </artifactSet>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/src/it/projects/artifactset-unmatched-pattern/verify.groovy
b/src/it/projects/artifactset-unmatched-pattern/verify.groovy
new file mode 100644
index 00000000..73bfc033
--- /dev/null
+++ b/src/it/projects/artifactset-unmatched-pattern/verify.groovy
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+def buildLog = new File(basedir, 'build.log').text
+assert buildLog.contains('[WARNING] No artifact matching artifactSet include
no.such:artifact')
+assert buildLog.contains('[INFO] No artifact matching artifactSet exclude
no.such:other')
+assert !buildLog.contains('artifactSet include org.slf4j:slf4j-api')
diff --git
a/src/main/java/org/apache/maven/plugins/shade/mojo/ArtifactSelector.java
b/src/main/java/org/apache/maven/plugins/shade/mojo/ArtifactSelector.java
index 502a10c2..359f5b91 100644
--- a/src/main/java/org/apache/maven/plugins/shade/mojo/ArtifactSelector.java
+++ b/src/main/java/org/apache/maven/plugins/shade/mojo/ArtifactSelector.java
@@ -18,8 +18,15 @@
*/
package org.apache.maven.plugins.shade.mojo;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
import org.apache.maven.artifact.Artifact;
@@ -32,6 +39,13 @@ class ArtifactSelector {
private Collection<ArtifactId> excludes;
+ /** The patterns as configured, by the id parsed from each; the patterns
added here are not in it. */
+ private final Map<ArtifactId, String> configuredIncludes = new
LinkedHashMap<>();
+
+ private final Map<ArtifactId, String> configuredExcludes = new
LinkedHashMap<>();
+
+ private final Set<ArtifactId> matchedPatterns =
Collections.newSetFromMap(new IdentityHashMap<>());
+
ArtifactSelector(Artifact projectArtifact, ArtifactSet artifactSet, String
groupPrefix) {
this(
(artifactSet != null) ? artifactSet.getIncludes() : null,
@@ -44,20 +58,22 @@ class ArtifactSelector {
}
ArtifactSelector(Collection<String> includes, Collection<String> excludes,
String groupPrefix) {
- this.includes = toIds(includes);
- this.excludes = toIds(excludes);
+ this.includes = toIds(includes, configuredIncludes);
+ this.excludes = toIds(excludes, configuredExcludes);
if (groupPrefix != null && groupPrefix.length() > 0) {
this.includes.add(new ArtifactId(groupPrefix + "*", "*", "*",
"*"));
}
}
- private static Collection<ArtifactId> toIds(Collection<String> patterns) {
+ private static Collection<ArtifactId> toIds(Collection<String> patterns,
Map<ArtifactId, String> configured) {
Collection<ArtifactId> result = new HashSet<>();
if (patterns != null) {
for (String pattern : patterns) {
- result.add(new ArtifactId(pattern));
+ ArtifactId id = new ArtifactId(pattern);
+ result.add(id);
+ configured.put(id, pattern);
}
}
@@ -69,15 +85,44 @@ class ArtifactSelector {
}
boolean isSelected(ArtifactId id) {
- return (includes.isEmpty() || matches(includes, id)) &&
!matches(excludes, id);
+ // Both sets are always evaluated, so that every pattern that matches
anything is recorded.
+ boolean includeMatched = matches(includes, id);
+ boolean excluded = matches(excludes, id);
+ return (includes.isEmpty() || includeMatched) && !excluded;
}
private boolean matches(Collection<ArtifactId> patterns, ArtifactId id) {
+ boolean matched = false;
for (ArtifactId pattern : patterns) {
if (id.matches(pattern)) {
- return true;
+ matchedPatterns.add(pattern);
+ matched = true;
+ }
+ }
+ return matched;
+ }
+
+ /**
+ * @return the configured include patterns that have not matched any
artifact passed to {@link #isSelected}
+ */
+ List<String> getUnmatchedIncludes() {
+ return unmatched(configuredIncludes);
+ }
+
+ /**
+ * @return the configured exclude patterns that have not matched any
artifact passed to {@link #isSelected}
+ */
+ List<String> getUnmatchedExcludes() {
+ return unmatched(configuredExcludes);
+ }
+
+ private List<String> unmatched(Map<ArtifactId, String> configured) {
+ List<String> result = new ArrayList<>();
+ for (Map.Entry<ArtifactId, String> entry : configured.entrySet()) {
+ if (!matchedPatterns.contains(entry.getKey())) {
+ result.add(entry.getValue());
}
}
- return false;
+ return result;
}
}
diff --git a/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
b/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
index db06e938..eb000c1e 100644
--- a/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
+++ b/src/main/java/org/apache/maven/plugins/shade/mojo/ShadeMojo.java
@@ -532,6 +532,13 @@ public class ShadeMojo extends AbstractMojo {
List<Artifact> processedArtifacts = processArtifactSelectors(
artifacts, artifactIds, sourceArtifacts, testArtifacts,
testSourceArtifacts, artifactSelector);
+ for (String pattern : artifactSelector.getUnmatchedIncludes()) {
+ getLog().warn("No artifact matching artifactSet include " +
pattern);
+ }
+ for (String pattern : artifactSelector.getUnmatchedExcludes()) {
+ getLog().info("No artifact matching artifactSet exclude " +
pattern);
+ }
+
File outputJar = (outputFile != null) ? outputFile :
shadedArtifactFileWithClassifier();
File sourcesJar = shadedSourceArtifactFileWithClassifier();
File testJar = shadedTestArtifactFileWithClassifier();
@@ -1033,7 +1040,7 @@ public class ShadeMojo extends AbstractMojo {
}
if (jars.isEmpty()) {
- getLog().debug("No artifact matching filter " +
filter.getArtifact());
+ getLog().warn("No artifact matching filter " +
filter.getArtifact());
continue;
}
diff --git
a/src/test/java/org/apache/maven/plugins/shade/mojo/ArtifactSelectorTest.java
b/src/test/java/org/apache/maven/plugins/shade/mojo/ArtifactSelectorTest.java
index 204ea4fb..76ae6635 100644
---
a/src/test/java/org/apache/maven/plugins/shade/mojo/ArtifactSelectorTest.java
+++
b/src/test/java/org/apache/maven/plugins/shade/mojo/ArtifactSelectorTest.java
@@ -18,11 +18,13 @@
*/
package org.apache.maven.plugins.shade.mojo;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -66,4 +68,38 @@ public class ArtifactSelectorTest {
assertFalse(selector.isSelected(new ArtifactId("gid", "aid", "type",
"cls")));
assertFalse(selector.isSelected(new ArtifactId("gid.test", "id",
"type", "cls")));
}
+
+ @Test
+ public void testUnmatchedPatterns() {
+ ArtifactSelector selector = newSelector(
+ Arrays.asList("gid:aid", "gid:typo", "other:*"),
Arrays.asList("gid:aid:jar:tests", "nope:*"), "gid");
+
+ selector.isSelected(new ArtifactId("gid", "aid", "jar", ""));
+ selector.isSelected(new ArtifactId("gid", "aid", "jar", "tests"));
+ selector.isSelected(new ArtifactId("other", "lib", "jar", ""));
+
+ assertEquals(Collections.singletonList("gid:typo"),
selector.getUnmatchedIncludes());
+ assertEquals(Collections.singletonList("nope:*"),
selector.getUnmatchedExcludes());
+ }
+
+ @Test
+ public void testExcludedArtifactStillCountsAsMatchingTheInclude() {
+ ArtifactSelector selector =
newSelector(Collections.singleton("gid:*"), Collections.singleton("gid:aid"),
null);
+
+ assertFalse(selector.isSelected(new ArtifactId("gid", "aid", "jar",
"")));
+
+ assertTrue(selector.getUnmatchedIncludes().isEmpty());
+ assertTrue(selector.getUnmatchedExcludes().isEmpty());
+ }
+
+ @Test
+ public void testNothingConfiguredReportsNothing() {
+ ArtifactSelector selector = newSelector(null, null, "gid");
+
+ selector.isSelected(new ArtifactId("other", "aid", "jar", ""));
+
+ assertTrue(
+ selector.getUnmatchedIncludes().isEmpty(), "the
shadedGroupFilter prefix is not a configured include");
+ assertTrue(selector.getUnmatchedExcludes().isEmpty());
+ }
}