You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ant.apache.org by ja...@apache.org on 2019/09/07 12:57:22 UTC

[ant-ivy] branch master updated: IVY-1580 Resolve any implicit artifacts when one among multiple dependencies of the same module has an explicit artifact/includes declaration

This is an automated email from the ASF dual-hosted git repository.

jaikiran pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ant-ivy.git


The following commit(s) were added to refs/heads/master by this push:
     new d714d9d  IVY-1580 Resolve any implicit artifacts when one among multiple dependencies of the same module has an explicit artifact/includes declaration
d714d9d is described below

commit d714d9dffbaa2c91855297a7df1c5d9ddfe6d0b0
Author: Jaikiran Pai <ja...@apache.org>
AuthorDate: Sat Sep 7 13:21:40 2019 +0530

    IVY-1580 Resolve any implicit artifacts when one among multiple dependencies of the same module has an explicit artifact/includes declaration
---
 asciidoc/release-notes.adoc                        |   1 +
 .../org/apache/ivy/core/resolve/IvyNodeUsage.java  |  54 +++++++++++---
 .../org/apache/ivy/core/resolve/ResolveTest.java   |  79 +++++++++++++++++++++
 test/repositories/1/ivy-1580/ivy-1580.xml          |  27 +++++++
 .../1.2.3/1580-foo-api-1.2.3-tests.jar             | Bin 0 -> 452 bytes
 .../1580-foo-api/1.2.3/1580-foo-api-1.2.3.jar      | Bin 0 -> 442 bytes
 .../1580-foo-api/1.2.3/1580-foo-api-1.2.3.pom      |  29 ++++++++
 .../1.2.3/test-ivy-1580-foo-api-1.2.3.pom          |  29 ++++++++
 .../1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.jar    | Bin 0 -> 444 bytes
 .../1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.pom    |  45 ++++++++++++
 .../1580-foo-impl/1580-foo-impl-1.2.3.jar          |   1 +
 .../1580-foo-impl/test-ivy-1580-foo-impl-1.2.3.pom |  45 ++++++++++++
 12 files changed, 300 insertions(+), 10 deletions(-)

diff --git a/asciidoc/release-notes.adoc b/asciidoc/release-notes.adoc
index 0fe816a..4f19284 100644
--- a/asciidoc/release-notes.adoc
+++ b/asciidoc/release-notes.adoc
@@ -87,6 +87,7 @@ For details about the following changes, check our JIRA install at link:https://
 - FIX: ModuleDescriptorMemoryCache didn't detect outdated entries when Ivy file was updated in the cache by another process
 - FIX: Store ArtifactOrigin's location as a URL
 - FIX: Retrieve task, with symlink enabled, would not create symlinks for artifacts in certain specific cases (jira:IVY-1594[])
+- FIX: Generated ivy.xml from pom with multiple dependencies with different classifier does not contain the main dependency (jira:IVY-1580[])
 
 
 - IMPROVEMENT: Throw an IllegalStateException when retrieving the resolutionCacheRoot on the DefaultResolutionCacheManager if the basedir (or IvySettings) is not set (jira:IVY-1482[])
diff --git a/src/java/org/apache/ivy/core/resolve/IvyNodeUsage.java b/src/java/org/apache/ivy/core/resolve/IvyNodeUsage.java
index 85a522b..f96beb9 100644
--- a/src/java/org/apache/ivy/core/resolve/IvyNodeUsage.java
+++ b/src/java/org/apache/ivy/core/resolve/IvyNodeUsage.java
@@ -24,10 +24,15 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import org.apache.ivy.core.module.descriptor.DefaultIncludeRule;
 import org.apache.ivy.core.module.descriptor.DependencyArtifactDescriptor;
 import org.apache.ivy.core.module.descriptor.DependencyDescriptor;
 import org.apache.ivy.core.module.descriptor.IncludeRule;
 import org.apache.ivy.core.module.descriptor.WorkspaceModuleDescriptor;
+import org.apache.ivy.core.module.id.ArtifactId;
+import org.apache.ivy.core.module.id.ModuleId;
+import org.apache.ivy.plugins.matcher.ExactPatternMatcher;
+import org.apache.ivy.plugins.matcher.PatternMatcher;
 
 /**
  * Class collecting usage data for an IvyNode.
@@ -233,20 +238,40 @@ public class IvyNodeUsage {
         return dependencyArtifacts;
     }
 
-    protected Set<IncludeRule> getDependencyIncludesSet(String rootModuleConf) {
-        Collection<Depender> dependersInConf = dependers.get(rootModuleConf);
+    protected Set<IncludeRule> getDependencyIncludesSet(final String rootModuleConf) {
+        final Collection<Depender> dependersInConf = dependers.get(rootModuleConf);
         if (dependersInConf == null) {
             return null;
         }
-        Set<IncludeRule> dependencyIncludes = new HashSet<>();
-        for (Depender depender : dependersInConf) {
-            IncludeRule[] rules = depender.dd.getIncludeRules(depender.dependerConf);
-            if (rules == null || rules.length == 0) {
-                // no include rule in at least one depender -> we must include everything,
-                // and so return no include rule at all
-                return null;
+        final Set<IncludeRule> dependencyIncludes = new HashSet<>();
+        // true if the depedency descriptor of any of the depender *doesn't* have an explicit
+        // "<artifact>" or an "<include>". false otherwise
+        boolean atLeastOneDependerNeedsAllArtifacts = false;
+        // true if the dependency descriptor of any of the depender either has an explicit "<artifact>"
+        // or an "<include>". false otherwise
+        boolean atLeastOneDependerHasSpecificArtifactSelection = false;
+        for (final Depender depender : dependersInConf) {
+            final DependencyArtifactDescriptor dads[] = depender.dd.getDependencyArtifacts(depender.dd.getModuleConfigurations());
+            final boolean declaresArtifacts = dads != null && dads.length > 0;
+            final IncludeRule[] rules = depender.dd.getIncludeRules(depender.dependerConf);
+            final boolean hasIncludeRule = rules != null && rules.length > 0;
+            if (hasIncludeRule) {
+                dependencyIncludes.addAll(Arrays.asList(rules));
+            }
+            if (declaresArtifacts || hasIncludeRule) {
+                atLeastOneDependerHasSpecificArtifactSelection = true;
+            }
+            if (!hasIncludeRule && !declaresArtifacts) {
+                atLeastOneDependerNeedsAllArtifacts = true;
             }
-            dependencyIncludes.addAll(Arrays.asList(rules));
+        }
+        // so there's at least one depender D1 which has a specific artifact dependency and at the
+        // same time there's a depender D2 which doesn't have any explicit artifact/includes.
+        // so it is expected that an implicit "include all artifacts" is applied so that dependencies
+        // such as D2 get (all) the artifacts that are published by the dependency's module
+        if (atLeastOneDependerHasSpecificArtifactSelection && atLeastOneDependerNeedsAllArtifacts) {
+            // add a "include all artifacts" rule
+            dependencyIncludes.add(includeAllArtifacts());
         }
         return dependencyIncludes;
     }
@@ -313,4 +338,13 @@ public class IvyNodeUsage {
         return false;
     }
 
+    private static IncludeRule includeAllArtifacts() {
+        final ArtifactId aid = new ArtifactId(
+                new ModuleId(PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION),
+                PatternMatcher.ANY_EXPRESSION, PatternMatcher.ANY_EXPRESSION,
+                PatternMatcher.ANY_EXPRESSION);
+        return new DefaultIncludeRule(aid, ExactPatternMatcher.INSTANCE, null);
+    }
+
+
 }
diff --git a/test/java/org/apache/ivy/core/resolve/ResolveTest.java b/test/java/org/apache/ivy/core/resolve/ResolveTest.java
index 32cf9c5..8d2fea3 100644
--- a/test/java/org/apache/ivy/core/resolve/ResolveTest.java
+++ b/test/java/org/apache/ivy/core/resolve/ResolveTest.java
@@ -6444,6 +6444,85 @@ public class ResolveTest {
         assertTrue("Missing artifact(s) with classifiers " + classifiers, classifiers.isEmpty());
     }
 
+
+    /**
+     * Tests the issue noted in IVY-1580.
+     * <pre>
+     *  org.apache:1580:1.0.0 depends on (Maven modules):
+     *      -> org.apache:1580-foo-api:1.2.3
+     *      -> org.apache:1580-foo-impl:1.2.3 which in turn depends on:
+     *          -> org.apache:1580-foo-api:1.2.3 (in compile scope)
+     *          -> org.apache:1580-foo-api:1.2.3 (type = test-jar, in test scope)
+     * </pre>
+     * It's expected that the resolution of org.apache:1580:1.0.0, correctly gets both the regular
+     * jar of org.apache:1580-foo-api as well as the test-jar of the same org.apache:1580-foo-api.
+     *
+     * @see <a href="https://issues.apache.org/jira/browse/IVY-1580">IVY-1580</a>
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testIvy1580() throws Exception {
+        final File ivyXML = new File("test/repositories/1/ivy-1580/ivy-1580.xml");
+        final ResolveReport resolveReport = ivy.resolve(ivyXML.toURI().toURL(),
+                new ResolveOptions().setConfs(new String[]{"*"}));
+        assertFalse("Resolution report has failures", resolveReport.hasError());
+        final String rootModuleConf = "default";
+        // get the "default" conf, resolution report for the org.apache:1580:1.0.0 module (represented by the
+        // ivy-1580.xml module descriptor)
+        final ConfigurationResolveReport confReport = resolveReport.getConfigurationReport(rootModuleConf);
+        assertNotNull(rootModuleConf + " conf resolution report for " +
+                resolveReport.getModuleDescriptor().getModuleRevisionId() + " is null", confReport);
+
+        final ModuleRevisionId apiDependencyId = ModuleRevisionId.newInstance("org.apache", "1580-foo-api", "1.2.3");
+        final IvyNode apiDepNode = confReport.getDependency(apiDependencyId);
+        assertNotNull("Dependency " + apiDependencyId + " not found in conf resolve report", apiDepNode);
+        final Artifact[] apiArtifacts = apiDepNode.getArtifacts(rootModuleConf);
+        assertNotNull("No artifacts available for dependency " + apiDependencyId, apiArtifacts);
+        assertEquals("Unexpected number of artifacts for dependency " + apiDependencyId, 2, apiArtifacts.length);
+        boolean foundTestJarType = false;
+        boolean foundJarType = false;
+        for (final Artifact apiArtifact : apiArtifacts) {
+            assertEquals("Unexpected artifact name", "1580-foo-api", apiArtifact.getName());
+            assertNotNull("Artifact type is null for " + apiArtifact, apiArtifact.getType());
+            ArtifactDownloadReport apiDownloadReport = null;
+            for (final ArtifactDownloadReport artifactDownloadReport : confReport.getAllArtifactsReports()) {
+                if (artifactDownloadReport.getArtifact().equals(apiArtifact)) {
+                    apiDownloadReport = artifactDownloadReport;
+                    break;
+                }
+            }
+            assertNotNull("No download report found for artifact " + apiArtifact, apiDownloadReport);
+            final File apiJar = apiDownloadReport.getLocalFile();
+            assertNotNull("artifact jar file is null for " + apiArtifact, apiJar);
+            switch (apiArtifact.getType()) {
+                case "test-jar" : {
+                    assertFalse("More than 1 test-jar artifact found", foundTestJarType);
+                    foundTestJarType = true;
+                    assertJarContains(apiJar, "api-test-file.txt");
+                    break;
+                }
+                case "jar" : {
+                    assertFalse("More than 1 jar artifact found", foundJarType);
+                    foundJarType = true;
+                    assertJarContains(apiJar, "api-file.txt");
+                    break;
+                }
+                default: {
+                    fail("unexpected artifact type " + apiArtifact.getType() + " for artifact " + apiArtifact);
+                }
+            }
+        }
+        assertTrue("No test-jar artifact found for dependency " + apiDependencyId, foundTestJarType);
+        assertTrue("No jar artifact found for dependency " + apiDependencyId, foundJarType);
+
+        // just do some basic check on the impl module as well
+        final ModuleRevisionId implDepId = ModuleRevisionId.newInstance("org.apache", "1580-foo-impl", "1.2.3");
+        final IvyNode implDepNode = confReport.getDependency(implDepId);
+        assertNotNull("Dependency " + implDepId + " not found in conf resolve report", implDepNode);
+
+    }
+
     private void assertJarContains(final File jar, final String jarEntryPath) throws IOException {
         try (final JarFile jarFile = new JarFile(jar)) {
             final JarEntry entry = jarFile.getJarEntry(jarEntryPath);
diff --git a/test/repositories/1/ivy-1580/ivy-1580.xml b/test/repositories/1/ivy-1580/ivy-1580.xml
new file mode 100644
index 0000000..23d962a
--- /dev/null
+++ b/test/repositories/1/ivy-1580/ivy-1580.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!--
+  ~ 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.
+  -->
+<ivy-module version="2.0"
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:noNamespaceSchemaLocation="http://ant.apache.org/ivy/schemas/ivy.xsd">
+    <info organisation="org.apache" module="1580" revision="1.0.0"/>
+    <dependencies>
+        <!-- These modules are Maven based artifacts (available in test/repositories/m2/) -->
+        <dependency org="org.apache" name="1580-foo-api" rev="1.2.3" />
+        <dependency org="org.apache" name="1580-foo-impl" rev="1.2.3" />
+    </dependencies>
+</ivy-module>
diff --git a/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3-tests.jar b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3-tests.jar
new file mode 100644
index 0000000..b809c27
Binary files /dev/null and b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3-tests.jar differ
diff --git a/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.jar b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.jar
new file mode 100644
index 0000000..c5b4fb3
Binary files /dev/null and b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.jar differ
diff --git a/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.pom b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.pom
new file mode 100644
index 0000000..8d18cae
--- /dev/null
+++ b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/1580-foo-api-1.2.3.pom
@@ -0,0 +1,29 @@
+<?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</groupId>
+    <artifactId>1580-foo-api</artifactId>
+    <version>1.2.3</version>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/test/repositories/m2/org/apache/1580-foo-api/1.2.3/test-ivy-1580-foo-api-1.2.3.pom b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/test-ivy-1580-foo-api-1.2.3.pom
new file mode 100644
index 0000000..8d18cae
--- /dev/null
+++ b/test/repositories/m2/org/apache/1580-foo-api/1.2.3/test-ivy-1580-foo-api-1.2.3.pom
@@ -0,0 +1,29 @@
+<?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</groupId>
+    <artifactId>1580-foo-api</artifactId>
+    <version>1.2.3</version>
+    <packaging>jar</packaging>
+
+</project>
\ No newline at end of file
diff --git a/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.jar b/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.jar
new file mode 100644
index 0000000..5281e28
Binary files /dev/null and b/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.jar differ
diff --git a/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.pom b/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.pom
new file mode 100644
index 0000000..9b2a7ea
--- /dev/null
+++ b/test/repositories/m2/org/apache/1580-foo-impl/1.2.3/1580-foo-impl-1.2.3.pom
@@ -0,0 +1,45 @@
+<?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</groupId>
+    <artifactId>1580-foo-impl</artifactId>
+    <version>1.2.3</version>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache</groupId>
+            <artifactId>1580-foo-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache</groupId>
+            <artifactId>1580-foo-api</artifactId>
+            <type>test-jar</type>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/1580-foo-impl-1.2.3.jar b/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/1580-foo-impl-1.2.3.jar
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/1580-foo-impl-1.2.3.jar
@@ -0,0 +1 @@
+ 
diff --git a/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/test-ivy-1580-foo-impl-1.2.3.pom b/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/test-ivy-1580-foo-impl-1.2.3.pom
new file mode 100644
index 0000000..9b2a7ea
--- /dev/null
+++ b/test/repositories/m2/org/apache/test-ivy-1580-foo-impl/1580-foo-impl/test-ivy-1580-foo-impl-1.2.3.pom
@@ -0,0 +1,45 @@
+<?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</groupId>
+    <artifactId>1580-foo-impl</artifactId>
+    <version>1.2.3</version>
+    <packaging>jar</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache</groupId>
+            <artifactId>1580-foo-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache</groupId>
+            <artifactId>1580-foo-api</artifactId>
+            <type>test-jar</type>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file