From 69c61d0e8e1755822c1d7c18d8fcd62b899eca68 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 20 Aug 2014 14:19:57 +0100 Subject: [PATCH] Include transitive file dependencies during Gradle repackaging Previously, ProjectLibraries only considered a configuration's direct file dependencies. This meant that a transitive file dependency that should have been pulled in via a project dependency was not included in the repackaged jar's lib directory. ProjectLibraries has been updated to walk down the tree of project dependencies and create libraries for any file dependencies that are found. Fixes gh-1368 --- .../gradle/MultiProjectRepackagingTests.java | 61 +++++++++++++++++++ .../boot/gradle/ProjectCreator.java | 12 +++- .../boot/gradle/RepackagingTests.java | 1 - .../multi-project-repackage/build.gradle | 40 ++++++++++++ .../multi-project-repackage/settings.gradle | 3 + .../gradle/repackage/ProjectLibraries.java | 16 ++++- 6 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java create mode 100644 spring-boot-integration-tests/src/test/resources/multi-project-repackage/build.gradle create mode 100644 spring-boot-integration-tests/src/test/resources/multi-project-repackage/settings.gradle diff --git a/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java new file mode 100644 index 00000000000..70977355899 --- /dev/null +++ b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java @@ -0,0 +1,61 @@ +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed 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.springframework.boot.gradle; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; + +import org.gradle.tooling.ProjectConnection; +import org.junit.BeforeClass; +import org.junit.Test; +import org.springframework.boot.dependency.tools.ManagedDependencies; +import org.springframework.util.FileCopyUtils; + +import static org.hamcrest.Matchers.notNullValue; +import static org.junit.Assert.assertThat; + +/** + * Integration tests for Gradle repackaging with a multi-project build. + * + * @author Andy Wilkinson + */ +public class MultiProjectRepackagingTests { + + private static final String BOOT_VERSION = ManagedDependencies.get() + .find("spring-boot").getVersion(); + + private static ProjectConnection project; + + @BeforeClass + public static void createProject() throws IOException { + project = new ProjectCreator().createProject("multi-project-repackage"); + } + + @Test + public void repackageWithTransitiveFileDependency() throws Exception { + FileCopyUtils.copy(new File("src/test/resources/foo.jar"), new File( + "target/multi-project-repackage/foo.jar")); + project.newBuild().forTasks("clean", "build") + .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); + File buildLibs = new File("target/multi-project-repackage/main/build/libs"); + JarFile jarFile = new JarFile(new File(buildLibs, "main.jar")); + assertThat(jarFile.getEntry("lib/commons-logging-1.1.3.jar"), notNullValue()); + assertThat(jarFile.getEntry("lib/foo.jar"), notNullValue()); + jarFile.close(); + } +} diff --git a/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java index 7a34a1be8a3..8fffb5677af 100644 --- a/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java +++ b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java @@ -23,6 +23,7 @@ import org.gradle.tooling.GradleConnector; import org.gradle.tooling.ProjectConnection; import org.gradle.tooling.internal.consumer.DefaultGradleConnector; import org.springframework.util.FileCopyUtils; +import org.springframework.util.FileSystemUtils; /** * @author Andy Wilkinson @@ -34,8 +35,15 @@ public class ProjectCreator { projectDirectory.mkdirs(); File gradleScript = new File(projectDirectory, "build.gradle"); - FileCopyUtils.copy(new File("src/test/resources/" + name + ".gradle"), - gradleScript); + + if (new File("src/test/resources", name).isDirectory()) { + FileSystemUtils.copyRecursively(new File("src/test/resources", name), + projectDirectory); + } + else { + FileCopyUtils.copy(new File("src/test/resources/" + name + ".gradle"), + gradleScript); + } GradleConnector gradleConnector = GradleConnector.newConnector(); ((DefaultGradleConnector) gradleConnector).embedded(true); diff --git a/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java index d4950c71fc4..0010d2188f3 100644 --- a/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java +++ b/spring-boot-integration-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java @@ -132,5 +132,4 @@ public class RepackagingTests { assertThat(jarFile.getEntry("lib/foo.jar"), notNullValue()); jarFile.close(); } - } diff --git a/spring-boot-integration-tests/src/test/resources/multi-project-repackage/build.gradle b/spring-boot-integration-tests/src/test/resources/multi-project-repackage/build.gradle new file mode 100644 index 00000000000..87ef48932c4 --- /dev/null +++ b/spring-boot-integration-tests/src/test/resources/multi-project-repackage/build.gradle @@ -0,0 +1,40 @@ +buildscript { + repositories { + mavenLocal() + } + dependencies { + classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" + } +} + +project('main') { + apply plugin: 'spring-boot' + apply plugin: 'java' + + repositories { + mavenLocal() + mavenCentral() + } + + dependencies { + compile project(':common') + } + + springBoot { + mainClass = 'foo.bar.Baz' + } +} + +project('common') { + apply plugin: 'java' + + repositories { + mavenLocal() + mavenCentral() + } + + dependencies { + compile "commons-logging:commons-logging:1.1.3" + compile files { "lib/foo.jar" } + } +} \ No newline at end of file diff --git a/spring-boot-integration-tests/src/test/resources/multi-project-repackage/settings.gradle b/spring-boot-integration-tests/src/test/resources/multi-project-repackage/settings.gradle new file mode 100644 index 00000000000..567c0652675 --- /dev/null +++ b/spring-boot-integration-tests/src/test/resources/multi-project-repackage/settings.gradle @@ -0,0 +1,3 @@ + +include 'main' +include 'common' \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java index 69e063633c6..b0ea449a1a9 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/groovy/org/springframework/boot/gradle/repackage/ProjectLibraries.java @@ -27,6 +27,7 @@ import org.gradle.api.artifacts.Configuration; import org.gradle.api.artifacts.Dependency; import org.gradle.api.artifacts.FileCollectionDependency; import org.gradle.api.artifacts.ModuleVersionIdentifier; +import org.gradle.api.artifacts.ProjectDependency; import org.gradle.api.artifacts.ResolvedArtifact; import org.springframework.boot.gradle.SpringBootPluginExtension; import org.springframework.boot.loader.tools.Libraries; @@ -109,6 +110,14 @@ class ProjectLibraries implements Libraries { .getResolvedArtifacts()) { libraries.add(new ResolvedArtifactLibrary(artifact, scope)); } + libraries.addAll(getLibrariesForFileDependencies(configuration, scope)); + + return libraries; + } + + private Set getLibrariesForFileDependencies(Configuration configuration, + LibraryScope scope) { + Set libraries = new LinkedHashSet(); for (Dependency dependency : configuration.getIncoming().getDependencies()) { if (dependency instanceof FileCollectionDependency) { FileCollectionDependency fileDependency = (FileCollectionDependency) dependency; @@ -116,6 +125,11 @@ class ProjectLibraries implements Libraries { libraries.add(new Library(file, scope)); } } + else if (dependency instanceof ProjectDependency) { + ProjectDependency projectDependency = (ProjectDependency) dependency; + libraries.addAll(getLibrariesForFileDependencies( + projectDependency.getProjectConfiguration(), scope)); + } } return libraries; } @@ -161,7 +175,7 @@ class ProjectLibraries implements Libraries { @Override public boolean isUnpackRequired() { if (ProjectLibraries.this.extension.getRequiresUnpack() != null) { - ModuleVersionIdentifier id = artifact.getModuleVersion().getId(); + ModuleVersionIdentifier id = this.artifact.getModuleVersion().getId(); return ProjectLibraries.this.extension.getRequiresUnpack().contains( id.getGroup() + ":" + id.getName()); }