You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by sl...@apache.org on 2026/10/13 21:50:21 UTC
(maven-dependency-plugin) 01/01: [MDEP-758] Skip test scoped unused dependencies with maven.test.skip, tolerate unneeded forced usage, add analyze-report-only
This is an automated email from the ASF dual-hosted git repository.
slachiewicz pushed a commit to branch agent/analyze-test-skip-report-only
in repository https://gitbox.apache.org/repos/asf/maven-dependency-plugin.git
commit 2490af6a86e3db1ee4ee278ec2ddddcca680ba1f
Author: Sylwester Lachiewicz <sl...@apache.org>
AuthorDate: Tue Oct 13 23:48:00 2026 +0200
[MDEP-758] Skip test scoped unused dependencies with maven.test.skip, tolerate unneeded forced usage, add analyze-report-only
Also covers MDEP-973 and MDEP-879.
AnalyzeReportOnly overrides the inherited @Execute with LifecyclePhase.NONE.
Without it the generated descriptor gives analyze-report-only the same
test-compile executePhase as analyze-report, because plugin-tools inherits
class-level @Execute from the superclass.
---
.../invoker.properties | 18 +++++
.../pom.xml | 62 +++++++++++++++
.../src/main/java/Main.java | 25 ++++++
.../verify.groovy | 26 ++++++
.../invoker.properties | 18 +++++
.../pom.xml | 62 +++++++++++++++
.../src/main/java/Main.java | 25 ++++++
.../verify.groovy | 27 +++++++
.../invoker.properties | 18 +++++
.../projects/analyze-report-only-mdep-879/pom.xml | 57 ++++++++++++++
.../src/main/java/Main.java | 25 ++++++
.../src/test/java/MainTest.java | 23 ++++++
.../analyze-report-only-mdep-879/verify.groovy | 27 +++++++
.../analyze-test-skip-mdep-758/invoker.properties | 18 +++++
src/it/projects/analyze-test-skip-mdep-758/pom.xml | 67 ++++++++++++++++
.../src/main/java/Main.java | 23 ++++++
.../analyze-test-skip-mdep-758/verify.groovy | 31 ++++++++
.../dependency/analyze/AbstractAnalyzeMojo.java | 32 +++++++-
.../plugins/dependency/analyze/AnalyzeReport.java | 6 +-
.../dependency/analyze/AnalyzeReportOnly.java | 47 +++++++++++
.../plugins/dependency/analyze/ForcedUsage.java | 74 +++++++++++++++++
src/site/markdown/index.md | 1 +
src/site/markdown/usage.md.vm | 6 ++
.../analyze/AbstractAnalyzeMojoTest.java | 92 +++++++++++++++++++++-
24 files changed, 807 insertions(+), 3 deletions(-)
diff --git a/src/it/projects/analyze-forced-usage-already-used-mdep-973/invoker.properties b/src/it/projects/analyze-forced-usage-already-used-mdep-973/invoker.properties
new file mode 100644
index 00000000..e6028302
--- /dev/null
+++ b/src/it/projects/analyze-forced-usage-already-used-mdep-973/invoker.properties
@@ -0,0 +1,18 @@
+# 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.
+
+invoker.goals = clean ${project.groupId}:${project.artifactId}:${project.version}:analyze
diff --git a/src/it/projects/analyze-forced-usage-already-used-mdep-973/pom.xml b/src/it/projects/analyze-forced-usage-already-used-mdep-973/pom.xml
new file mode 100644
index 00000000..ed2ec84d
--- /dev/null
+++ b/src/it/projects/analyze-forced-usage-already-used-mdep-973/pom.xml
@@ -0,0 +1,62 @@
+<?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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>Test</name>
+ <description>
+ Test that forcing the usage of an already used dependency is a warning (MDEP-973)
+ </description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-model</artifactId>
+ <version>3.9.16</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <usedDependencies>
+ <usedDependency>org.apache.maven:maven-model</usedDependency>
+ </usedDependencies>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/src/it/projects/analyze-forced-usage-already-used-mdep-973/src/main/java/Main.java b/src/it/projects/analyze-forced-usage-already-used-mdep-973/src/main/java/Main.java
new file mode 100644
index 00000000..967d85f3
--- /dev/null
+++ b/src/it/projects/analyze-forced-usage-already-used-mdep-973/src/main/java/Main.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+import org.apache.maven.model.Model;
+
+public class Main
+{
+ public Model model = null;
+}
diff --git a/src/it/projects/analyze-forced-usage-already-used-mdep-973/verify.groovy b/src/it/projects/analyze-forced-usage-already-used-mdep-973/verify.groovy
new file mode 100644
index 00000000..01b1fabc
--- /dev/null
+++ b/src/it/projects/analyze-forced-usage-already-used-mdep-973/verify.groovy
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+String log = new File( basedir, "build.log" ).getText( "UTF-8" );
+
+assert log.contains( "Unneeded forced usage of org.apache.maven:maven-model" ) :
+ "expected a warning about the unneeded forced usage";
+assert !log.contains( "Cannot analyze dependencies" ) : "the analysis must not fail";
+
+return true;
diff --git a/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/invoker.properties b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/invoker.properties
new file mode 100644
index 00000000..ab68bf1c
--- /dev/null
+++ b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/invoker.properties
@@ -0,0 +1,18 @@
+# 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.
+
+invoker.goals = clean ${project.groupId}:${project.artifactId}:${project.version}:analyze-report
diff --git a/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/pom.xml b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/pom.xml
new file mode 100644
index 00000000..bcb28b0a
--- /dev/null
+++ b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/pom.xml
@@ -0,0 +1,62 @@
+<?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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>Test</name>
+ <description>
+ Test that analyze-report survives forcing the usage of an already used dependency (MDEP-973)
+ </description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-model</artifactId>
+ <version>3.9.16</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <usedDependencies>
+ <usedDependency>org.apache.maven:maven-model</usedDependency>
+ </usedDependencies>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/src/main/java/Main.java b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/src/main/java/Main.java
new file mode 100644
index 00000000..967d85f3
--- /dev/null
+++ b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/src/main/java/Main.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+import org.apache.maven.model.Model;
+
+public class Main
+{
+ public Model model = null;
+}
diff --git a/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/verify.groovy b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/verify.groovy
new file mode 100644
index 00000000..29b9d0b4
--- /dev/null
+++ b/src/it/projects/analyze-report-forced-usage-already-used-mdep-973/verify.groovy
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+File htmlFile = new File( basedir, "target/reports/dependency-analysis.html" );
+assert htmlFile.isFile() && htmlFile.length() > 0 : "Dependency analysis report missing " + htmlFile;
+
+String log = new File( basedir, "build.log" ).getText( "UTF-8" );
+assert log.contains( "Unneeded forced usage of org.apache.maven:maven-model" ) :
+ "expected a warning about the unneeded forced usage";
+
+return true;
diff --git a/src/it/projects/analyze-report-only-mdep-879/invoker.properties b/src/it/projects/analyze-report-only-mdep-879/invoker.properties
new file mode 100644
index 00000000..139e6319
--- /dev/null
+++ b/src/it/projects/analyze-report-only-mdep-879/invoker.properties
@@ -0,0 +1,18 @@
+# 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.
+
+invoker.goals = clean compile ${project.groupId}:${project.artifactId}:${project.version}:analyze-report-only
diff --git a/src/it/projects/analyze-report-only-mdep-879/pom.xml b/src/it/projects/analyze-report-only-mdep-879/pom.xml
new file mode 100644
index 00000000..54318727
--- /dev/null
+++ b/src/it/projects/analyze-report-only-mdep-879/pom.xml
@@ -0,0 +1,57 @@
+<?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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>Test</name>
+ <description>
+ Test that analyze-report-only does not fork test-compile (MDEP-879)
+ </description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven</groupId>
+ <artifactId>maven-model</artifactId>
+ <version>3.9.16</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>@project.version@</version>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/src/it/projects/analyze-report-only-mdep-879/src/main/java/Main.java b/src/it/projects/analyze-report-only-mdep-879/src/main/java/Main.java
new file mode 100644
index 00000000..967d85f3
--- /dev/null
+++ b/src/it/projects/analyze-report-only-mdep-879/src/main/java/Main.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+import org.apache.maven.model.Model;
+
+public class Main
+{
+ public Model model = null;
+}
diff --git a/src/it/projects/analyze-report-only-mdep-879/src/test/java/MainTest.java b/src/it/projects/analyze-report-only-mdep-879/src/test/java/MainTest.java
new file mode 100644
index 00000000..069bf121
--- /dev/null
+++ b/src/it/projects/analyze-report-only-mdep-879/src/test/java/MainTest.java
@@ -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.
+ */
+
+
+public class MainTest
+{
+}
diff --git a/src/it/projects/analyze-report-only-mdep-879/verify.groovy b/src/it/projects/analyze-report-only-mdep-879/verify.groovy
new file mode 100644
index 00000000..a448cf7e
--- /dev/null
+++ b/src/it/projects/analyze-report-only-mdep-879/verify.groovy
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+File htmlFile = new File( basedir, "target/reports/dependency-analysis.html" );
+assert htmlFile.isFile() && htmlFile.length() > 0 : "Dependency analysis report missing " + htmlFile;
+
+String log = new File( basedir, "build.log" ).getText( "UTF-8" );
+assert log.contains( ":compile (default-compile)" ) : "expected the explicitly requested compile phase to run";
+assert !log.contains( ":testCompile (default-testCompile)" ) : "analyze-report-only must not fork test-compile";
+
+return true;
diff --git a/src/it/projects/analyze-test-skip-mdep-758/invoker.properties b/src/it/projects/analyze-test-skip-mdep-758/invoker.properties
new file mode 100644
index 00000000..5c72f8a2
--- /dev/null
+++ b/src/it/projects/analyze-test-skip-mdep-758/invoker.properties
@@ -0,0 +1,18 @@
+# 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.
+
+invoker.goals = clean ${project.groupId}:${project.artifactId}:${project.version}:analyze -Dmaven.test.skip=true
diff --git a/src/it/projects/analyze-test-skip-mdep-758/pom.xml b/src/it/projects/analyze-test-skip-mdep-758/pom.xml
new file mode 100644
index 00000000..69f1517e
--- /dev/null
+++ b/src/it/projects/analyze-test-skip-mdep-758/pom.xml
@@ -0,0 +1,67 @@
+<?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 xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>test</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>Test</name>
+ <description>
+ Test that test scoped dependencies are not reported as unused when maven.test.skip is set (MDEP-758)
+ </description>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>scope-leaf</artifactId>
+ <version>1.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.its.dependency</groupId>
+ <artifactId>scope-root</artifactId>
+ <version>1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <version>@project.version@</version>
+ <configuration>
+ <verbose>true</verbose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
+ </build>
+</project>
diff --git a/src/it/projects/analyze-test-skip-mdep-758/src/main/java/Main.java b/src/it/projects/analyze-test-skip-mdep-758/src/main/java/Main.java
new file mode 100644
index 00000000..5e405ff1
--- /dev/null
+++ b/src/it/projects/analyze-test-skip-mdep-758/src/main/java/Main.java
@@ -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.
+ */
+
+
+public class Main
+{
+}
diff --git a/src/it/projects/analyze-test-skip-mdep-758/verify.groovy b/src/it/projects/analyze-test-skip-mdep-758/verify.groovy
new file mode 100644
index 00000000..542c847d
--- /dev/null
+++ b/src/it/projects/analyze-test-skip-mdep-758/verify.groovy
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+String log = new File( basedir, "build.log" ).getText( "UTF-8" );
+
+int unused = log.indexOf( "Unused declared dependencies found:" );
+assert unused >= 0 : "expected an unused declared dependencies warning in build.log";
+String report = log.substring( unused );
+assert report.contains( "org.apache.maven.its.dependency:scope-root:jar:1.0:provided" ) :
+ "the provided scoped dependency must still be reported";
+assert !report.contains( "org.apache.maven.its.dependency:scope-leaf:jar:1.0:test" ) :
+ "the test scoped dependency must not be reported when maven.test.skip is set";
+assert log.contains( "maven.test.skip is set" ) : "expected the info line explaining why";
+
+return true;
diff --git a/src/main/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojo.java b/src/main/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojo.java
index f5758f55..9c577138 100644
--- a/src/main/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojo.java
+++ b/src/main/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojo.java
@@ -20,6 +20,7 @@ package org.apache.maven.plugins.dependency.analyze;
import java.io.File;
import java.io.StringWriter;
+import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
@@ -158,6 +159,16 @@ public abstract class AbstractAnalyzeMojo extends AbstractMojo {
@Parameter(property = "mdep.analyze.skip", defaultValue = "false")
private boolean skip;
+ /**
+ * Whether test compilation is skipped, as set by <code>maven.test.skip</code>. When <code>true</code>, test scoped
+ * dependencies are left out of the "declared but unused" list, because no test class is analyzed. Dependencies of
+ * other scopes are still analyzed.
+ *
+ * @since 3.12.0
+ */
+ @Parameter(property = "maven.test.skip", defaultValue = "false", readonly = true)
+ private boolean testSkip;
+
/**
* List of dependencies that will be ignored. Any dependency on this list will be excluded from the "declared but
* unused", the "used but undeclared", and the "non-test scoped" list. The filter syntax is:
@@ -329,11 +340,16 @@ public abstract class AbstractAnalyzeMojo extends AbstractMojo {
private boolean checkDependencies() throws MojoExecutionException {
ProjectDependencyAnalysis analysis;
+ List<String> unneededForcedUsage = Collections.emptyList();
try {
analysis = createProjectDependencyAnalyzer().analyze(project, excludedClasses);
if (usedDependencies != null) {
- analysis = analysis.forceDeclaredDependenciesUsage(usedDependencies);
+ ForcedUsage forced = new ForcedUsage(analysis, usedDependencies);
+ unneededForcedUsage = forced.getUnneeded();
+ if (forced.getToForce().length > 0) {
+ analysis = analysis.forceDeclaredDependenciesUsage(forced.getToForce());
+ }
}
} catch (ProjectDependencyAnalyzerException exception) {
throw new MojoExecutionException("Cannot analyze dependencies", exception);
@@ -353,6 +369,14 @@ public abstract class AbstractAnalyzeMojo extends AbstractMojo {
Set<Artifact> ignoredUnusedDeclared = new LinkedHashSet<>();
Set<Artifact> ignoredNonTestScope = new LinkedHashSet<>();
+ if (testSkip) {
+ int before = unusedDeclared.size();
+ unusedDeclared.removeIf(artifact -> Artifact.SCOPE_TEST.equals(artifact.getScope()));
+ if (unusedDeclared.size() < before) {
+ getLog().info("maven.test.skip is set: test scoped dependencies are not analyzed for being unused");
+ }
+ }
+
if (ignoreUnusedRuntime) {
filterArtifactsByScope(unusedDeclared, Artifact.SCOPE_RUNTIME);
}
@@ -383,6 +407,12 @@ public abstract class AbstractAnalyzeMojo extends AbstractMojo {
boolean reported = false;
boolean warning = false;
+ for (String entry : unneededForcedUsage) {
+ logDependencyWarning(ForcedUsage.message(entry));
+ reported = true;
+ warning = true;
+ }
+
if (verbose && !usedDeclared.isEmpty()) {
getLog().info("Used declared dependencies found:");
diff --git a/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReport.java b/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReport.java
index 03ffadd8..dfa6bfd4 100644
--- a/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReport.java
+++ b/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReport.java
@@ -108,7 +108,11 @@ public class AnalyzeReport extends AbstractMavenReport {
analysis = analyzer.analyze(project, excludedClasses);
if (usedDependencies != null) {
- analysis = analysis.forceDeclaredDependenciesUsage(usedDependencies);
+ ForcedUsage forced = new ForcedUsage(analysis, usedDependencies);
+ forced.getUnneeded().forEach(entry -> getLog().warn(ForcedUsage.message(entry)));
+ if (forced.getToForce().length > 0) {
+ analysis = analysis.forceDeclaredDependenciesUsage(forced.getToForce());
+ }
}
} catch (ProjectDependencyAnalyzerException exception) {
throw new MavenReportException("Cannot analyze dependencies", exception);
diff --git a/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReportOnly.java b/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReportOnly.java
new file mode 100644
index 00000000..4757abdc
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/dependency/analyze/AnalyzeReportOnly.java
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+package org.apache.maven.plugins.dependency.analyze;
+
+import javax.inject.Inject;
+
+import org.apache.maven.plugins.annotations.Execute;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalyzer;
+import org.codehaus.plexus.i18n.I18N;
+
+/**
+ * Analyzes the dependencies of this project and produces the same report as the <code>dependency:analyze-report</code>
+ * goal. Unlike that goal, it does not fork the <code>test-compile</code> phase, so it assumes that the project was
+ * already compiled, for example by an earlier phase of the same build.
+ *
+ * @see AnalyzeReport
+ * @since 3.12.0
+ */
+@Mojo(name = "analyze-report-only", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true)
+@Execute(phase = LifecyclePhase.NONE)
+public class AnalyzeReportOnly extends AnalyzeReport {
+ // subclassed to provide annotations, without the forked test-compile of analyze-report
+
+ @Inject
+ public AnalyzeReportOnly(ProjectDependencyAnalyzer analyzer, I18N i18n) {
+ super(analyzer, i18n);
+ }
+}
diff --git a/src/main/java/org/apache/maven/plugins/dependency/analyze/ForcedUsage.java b/src/main/java/org/apache/maven/plugins/dependency/analyze/ForcedUsage.java
new file mode 100644
index 00000000..216b3647
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/dependency/analyze/ForcedUsage.java
@@ -0,0 +1,74 @@
+/*
+ * 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.
+ */
+package org.apache.maven.plugins.dependency.analyze;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.maven.artifact.Artifact;
+import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalysis;
+
+/**
+ * Splits the <code>usedDependencies</code> entries into those the analysis already reports as used and declared, which
+ * {@link ProjectDependencyAnalysis#forceDeclaredDependenciesUsage(String[])} rejects with an exception, and the rest.
+ */
+final class ForcedUsage {
+
+ private final List<String> unneeded = new ArrayList<>();
+
+ private final List<String> toForce = new ArrayList<>();
+
+ ForcedUsage(ProjectDependencyAnalysis analysis, String[] usedDependencies) {
+ Set<String> usedDeclared = new HashSet<>();
+ for (Artifact artifact : analysis.getUsedDeclaredArtifacts()) {
+ usedDeclared.add(key(artifact));
+ }
+ // the analyzer first matches an entry against the unused declared artifacts, so such an entry is needed
+ for (Artifact artifact : analysis.getUnusedDeclaredArtifacts()) {
+ usedDeclared.remove(key(artifact));
+ }
+ for (String entry : usedDependencies) {
+ (usedDeclared.contains(entry) ? unneeded : toForce).add(entry);
+ }
+ }
+
+ /**
+ * @return the entries that are already detected as used
+ */
+ List<String> getUnneeded() {
+ return unneeded;
+ }
+
+ /**
+ * @return the entries that must still be passed to the analyzer
+ */
+ String[] getToForce() {
+ return toForce.toArray(new String[0]);
+ }
+
+ static String message(String entry) {
+ return "Unneeded forced usage of " + entry + ": the dependency is already detected as used";
+ }
+
+ private static String key(Artifact artifact) {
+ return artifact.getGroupId() + ":" + artifact.getArtifactId();
+ }
+}
diff --git a/src/site/markdown/index.md b/src/site/markdown/index.md
index 88b783f1..1efd1fb0 100644
--- a/src/site/markdown/index.md
+++ b/src/site/markdown/index.md
@@ -38,6 +38,7 @@ The Dependency plugin has several goals:
- [dependency:analyze-exclusions](./analyze-exclusions-mojo.html) analyzes the exclusions on dependencies and checks if the artifact actually brings in the given dependency.
- [dependency:analyze-only](./analyze-only-mojo.html) is the same as analyze, but is meant to be bound in a pom. It does not fork the build and execute test-compile.
- [dependency:analyze-report](./analyze-report-mojo.html) analyzes the dependencies of this project and produces a report that summarises which are: used and declared; used and undeclared; unused and declared.
+- [dependency:analyze-report-only](./analyze-report-only-mojo.html) is the same as analyze-report, but does not fork the build and execute test-compile.
- [dependency:analyze-duplicate](./analyze-duplicate-mojo.html) analyzes the `<dependencies/>` and `<dependencyManagement/>` tags in the pom.xml and determines the duplicate declared dependencies.
- [dependency:build-classpath](./build-classpath-mojo.html) tells Maven to output the path of the dependencies from the local repository in a classpath format to be used in java -cp. The classpath file may also be attached and installed/deployed along with the main artifact.
- [dependency:collect](./collect-mojo.html) collects the project dependencies from the repository. It lists the groupId:artifactId:version information by downloading the pom files without downloading the actual artifacts such as jar files.
diff --git a/src/site/markdown/usage.md.vm b/src/site/markdown/usage.md.vm
index 662862c5..693b90f7 100644
--- a/src/site/markdown/usage.md.vm
+++ b/src/site/markdown/usage.md.vm
@@ -490,6 +490,12 @@ This goal is used to include a report of the dependencies in the output of the `
</reporting>
```
+Use `analyze-report-only` instead of `analyze-report` to render the same report without forking the `test-compile` phase, for example in a build that has already compiled the project:
+
+```xml
+ <report>analyze-report-only</report>
+```
+
`dependency:tree`
-----------------
diff --git a/src/test/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojoTest.java b/src/test/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojoTest.java
index 556d58b4..83008246 100644
--- a/src/test/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojoTest.java
+++ b/src/test/java/org/apache/maven/plugins/dependency/analyze/AbstractAnalyzeMojoTest.java
@@ -29,6 +29,7 @@ import java.util.stream.Collectors;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DefaultArtifact;
import org.apache.maven.artifact.handler.DefaultArtifactHandler;
+import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.dependency.analyzer.ProjectDependencyAnalysis;
@@ -40,9 +41,11 @@ import org.junit.jupiter.api.io.TempDir;
import org.mockito.ArgumentCaptor;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -55,6 +58,8 @@ class AbstractAnalyzeMojoTest {
private final Artifact commonsIo = artifact("commons-io", "commons-io", Artifact.SCOPE_COMPILE);
+ private ProjectDependencyAnalyzer analyzer;
+
private Log log;
private AnalyzeOnlyMojo mojo;
@@ -81,7 +86,7 @@ class AbstractAnalyzeMojoTest {
*/
@BeforeEach
void setUp() throws Exception {
- ProjectDependencyAnalyzer analyzer = mock(ProjectDependencyAnalyzer.class);
+ analyzer = mock(ProjectDependencyAnalyzer.class);
when(analyzer.analyze(any(MavenProject.class), any()))
.thenReturn(new ProjectDependencyAnalysis(
Collections.emptySet(), setOf(jodaTime, commonsIo), Collections.emptySet(), setOf(jodaTime)));
@@ -126,4 +131,89 @@ class AbstractAnalyzeMojoTest {
assertThat(warnings()).doesNotContain("Non-test scoped test only dependencies found:");
}
+
+ private void analysisIs(ProjectDependencyAnalysis analysis) throws Exception {
+ when(analyzer.analyze(any(MavenProject.class), any())).thenReturn(analysis);
+ }
+
+ @Test
+ void testSkipDropsTestScopedUnusedDeclared() throws Exception {
+ Artifact junit = artifact("junit", "junit", Artifact.SCOPE_TEST);
+ Artifact provided = artifact("javax.servlet", "servlet-api", Artifact.SCOPE_PROVIDED);
+ analysisIs(new ProjectDependencyAnalysis(
+ Collections.emptySet(), Collections.emptySet(), setOf(junit, provided), Collections.emptySet()));
+ set(mojo, "testSkip", true);
+
+ mojo.execute();
+
+ assertThat(warnings()).contains("Unused declared dependencies found:", " " + provided);
+ assertThat(warnings()).doesNotContain(" " + junit);
+ ArgumentCaptor<CharSequence> info = ArgumentCaptor.forClass(CharSequence.class);
+ verify(log, atLeast(1)).info(info.capture());
+ assertThat(info.getAllValues())
+ .filteredOn(m -> m.toString().contains("maven.test.skip"))
+ .hasSize(1);
+ }
+
+ @Test
+ void testScopedUnusedDeclaredIsReportedWithoutTestSkip() throws Exception {
+ Artifact junit = artifact("junit", "junit", Artifact.SCOPE_TEST);
+ analysisIs(new ProjectDependencyAnalysis(
+ Collections.emptySet(), Collections.emptySet(), setOf(junit), Collections.emptySet()));
+
+ mojo.execute();
+
+ assertThat(warnings()).contains(" " + junit);
+ }
+
+ @Test
+ void unneededForcedUsageIsAWarningNotAFailure() throws Exception {
+ Artifact logback = artifact("ch.qos.logback", "logback-classic", Artifact.SCOPE_TEST);
+ analysisIs(new ProjectDependencyAnalysis(
+ setOf(logback), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()));
+ set(mojo, "usedDependencies", new String[] {"ch.qos.logback:logback-classic"});
+
+ mojo.execute();
+
+ assertThat(warnings())
+ .anyMatch(m -> m.contains("ch.qos.logback:logback-classic") && m.contains("already detected as used"));
+ }
+
+ @Test
+ void unneededForcedUsageFailsTheBuildWithFailOnWarning() throws Exception {
+ Artifact logback = artifact("ch.qos.logback", "logback-classic", Artifact.SCOPE_TEST);
+ analysisIs(new ProjectDependencyAnalysis(
+ setOf(logback), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()));
+ set(mojo, "usedDependencies", new String[] {"ch.qos.logback:logback-classic"});
+ set(mojo, "failOnWarning", true);
+
+ assertThatThrownBy(mojo::execute)
+ .isInstanceOf(MojoExecutionException.class)
+ .hasMessage("Dependency problems found");
+ verify(log, atLeast(1)).error(any(CharSequence.class));
+ }
+
+ @Test
+ void neededForcedUsageIsStillApplied() throws Exception {
+ Artifact logback = artifact("ch.qos.logback", "logback-classic", Artifact.SCOPE_TEST);
+ analysisIs(new ProjectDependencyAnalysis(
+ Collections.emptySet(), Collections.emptySet(), setOf(logback), Collections.emptySet()));
+ set(mojo, "usedDependencies", new String[] {"ch.qos.logback:logback-classic"});
+ set(mojo, "failOnWarning", true);
+
+ mojo.execute();
+
+ verify(log, never()).error(any(CharSequence.class));
+ }
+
+ @Test
+ void forcingAnUndeclaredDependencyStillFails() throws Exception {
+ analysisIs(new ProjectDependencyAnalysis(
+ Collections.emptySet(), Collections.emptySet(), Collections.emptySet(), Collections.emptySet()));
+ set(mojo, "usedDependencies", new String[] {"not.declared:anywhere"});
+
+ assertThatThrownBy(mojo::execute)
+ .isInstanceOf(MojoExecutionException.class)
+ .hasMessage("Cannot analyze dependencies");
+ }
}