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());
+    }
 }

Reply via email to