From 55939eff1e69bfee3c77d7ced8b0d642ca7cb34a Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Thu, 9 Aug 2018 18:37:02 -0400 Subject: [PATCH 1/4] Auto build gradle lib-project dependencies Search through all configurations for dependencies of the style 'configurationName project(":path")' and have jib depend on the 'assemble' task of that project. This ensure jar dependencies are built before jib starts to package the project. --- .../cloud/tools/jib/gradle/JibPlugin.java | 38 +++++++++- .../cloud/tools/jib/gradle/JibPluginTest.java | 73 +++++++++++++++++++ 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java index 336c8e88be..cc089024ec 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java @@ -17,11 +17,17 @@ package com.google.cloud.tools.jib.gradle; import com.google.common.annotations.VisibleForTesting; +import java.util.List; +import java.util.stream.Collectors; import org.gradle.api.GradleException; import org.gradle.api.Plugin; import org.gradle.api.Project; import org.gradle.api.Task; import org.gradle.api.UnknownTaskException; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.artifacts.DependencySet; +import org.gradle.api.artifacts.ProjectDependency; +import org.gradle.api.plugins.BasePlugin; import org.gradle.util.GradleVersion; public class JibPlugin implements Plugin { @@ -66,12 +72,14 @@ public void apply(Project project) { project.afterEvaluate( projectAfterEvaluation -> { try { + List taskDependencies = getProjectDependencyAssembleTasks(projectAfterEvaluation); Task classesTask = projectAfterEvaluation.getTasks().getByPath("classes"); + taskDependencies.add(classesTask); - buildImageTask.dependsOn(classesTask); - dockerContextTask.dependsOn(classesTask); - buildDockerTask.dependsOn(classesTask); - buildTarTask.dependsOn(classesTask); + buildImageTask.dependsOn(taskDependencies.toArray()); + dockerContextTask.dependsOn(taskDependencies.toArray()); + buildDockerTask.dependsOn(taskDependencies.toArray()); + buildTarTask.dependsOn(taskDependencies.toArray()); } catch (UnknownTaskException ex) { throw new GradleException( @@ -83,6 +91,28 @@ public void apply(Project project) { }); } + /** + * Collects all assemble tasks for project dependencies of the style "compile project(':mylib')" + * for any kind of configuration [compile, runtime, etc]. It potentially will collect common test + * libraries in configs like [test, integrationTest, etc], but it's either that or filter based on + * a configuration containing the word "test" which feels dangerous. + * + * @param project this project we are containerizing + * @return a list of "assemble" tasks associated with projects that this project depends on. + */ + static List getProjectDependencyAssembleTasks(Project project) { + return project + .getConfigurations() + .stream() + .map(Configuration::getDependencies) + .flatMap(DependencySet::stream) + .filter(ProjectDependency.class::isInstance) + .map(ProjectDependency.class::cast) + .map(ProjectDependency::getDependencyProject) + .map(subProject -> subProject.getTasks().getByPath(BasePlugin.ASSEMBLE_TASK_NAME)) + .collect(Collectors.toList()); + } + private static void checkGradleVersion() { if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) { throw new GradleException( diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java index c92a4d7276..92842077a0 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java @@ -16,10 +16,19 @@ package com.google.cloud.tools.jib.gradle; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Collectors; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.internal.project.ProjectInternal; +import org.gradle.testfixtures.ProjectBuilder; import org.gradle.testkit.runner.GradleRunner; import org.gradle.testkit.runner.UnexpectedBuildFailure; import org.junit.Assert; @@ -68,4 +77,68 @@ public void testCheckGradleVersion_fail() throws IOException { + "'.")); } } + + @Test + public void testGetProjectDependencyAssembleTasks() { + // root project is our jib packaged service + Project rootProject = + ProjectBuilder.builder().withProjectDir(testProjectRoot.getRoot()).withName("root").build(); + rootProject.getPluginManager().apply("java"); + + // our service DOES depend on this, and jib should trigger an assemble from this project + Project subProject = + ProjectBuilder.builder() + .withParent(rootProject) + .withProjectDir(testProjectRoot.getRoot()) + .withName("sub") + .build(); + subProject.getPluginManager().apply("java"); + + // our service doesn't depend on this, and jib should NOT trigger an assemble from this project + Project unrelatedSubProject = + ProjectBuilder.builder() + .withParent(rootProject) + .withProjectDir(testProjectRoot.getRoot()) + .withName("unrelated") + .build(); + unrelatedSubProject.getPluginManager().apply("java"); + + // equivalent of "compile project(':sub')" on the root(jib) project + rootProject + .getConfigurations() + .getByName("compile") + .getDependencies() + .add(rootProject.getDependencies().project(ImmutableMap.of("path", subProject.getPath()))); + + // programmatic check + Assert.assertEquals( + Collections.singletonList(":sub:assemble"), + JibPlugin.getProjectDependencyAssembleTasks(rootProject) + .stream() + .map(Task::getPath) + .collect(Collectors.toList())); + + // check by applying the jib plugin and inspect the task dependencies + rootProject.getPluginManager().apply("com.google.cloud.tools.jib"); + ((ProjectInternal) rootProject).evaluate(); + + Arrays.asList( + JibPlugin.BUILD_IMAGE_TASK_NAME, + JibPlugin.DOCKER_CONTEXT_TASK_NAME, + JibPlugin.BUILD_DOCKER_TASK_NAME, + JibPlugin.BUILD_TAR_TASK_NAME) + .forEach( + taskName -> { + Assert.assertEquals( + ImmutableSet.of(":sub:assemble", ":classes"), + rootProject + .getTasks() + .getByPath(taskName) + .getDependsOn() + .stream() + .map(Task.class::cast) + .map(Task::getPath) + .collect(Collectors.toSet())); + }); + } } From 43c466984bbe52a8efe4db75000a5dd0cc303e33 Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Thu, 9 Aug 2018 18:53:34 -0400 Subject: [PATCH 2/4] Update changelog --- jib-gradle-plugin/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 1638e4f333..a4fae6857f 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -11,6 +11,8 @@ All notable changes to this project will be documented in this file. ### Fixed +- Gradle project dependencies have their `assemble` task run before running a jib task ([#815](https://github.com/GoogleContainerTools/jib/issues/815)) + ## 0.9.8 ### Added From 5538a650e9b01a15e614f8e9ea0c79e4154775ab Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Fri, 10 Aug 2018 13:41:33 -0400 Subject: [PATCH 3/4] fix ordering, make test better --- .../cloud/tools/jib/gradle/JibPlugin.java | 90 ++++++++++--------- .../cloud/tools/jib/gradle/JibPluginTest.java | 47 ++++++---- 2 files changed, 76 insertions(+), 61 deletions(-) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java index cc089024ec..b65fdbb324 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java @@ -40,6 +40,42 @@ public class JibPlugin implements Plugin { @VisibleForTesting static final String BUILD_DOCKER_TASK_NAME = "jibDockerBuild"; @VisibleForTesting static final String DOCKER_CONTEXT_TASK_NAME = "jibExportDockerContext"; + private static void checkGradleVersion() { + if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) { + throw new GradleException( + "Detected " + + GradleVersion.current() + + ", but jib requires " + + GRADLE_MIN_VERSION + + " or higher. You can upgrade by running 'gradle wrapper --gradle-version=" + + GRADLE_MIN_VERSION.getVersion() + + "'."); + } + } + + /** + * Collects all assemble tasks for project dependencies of the style "compile project(':mylib')" + * for any kind of configuration [compile, runtime, etc]. It potentially will collect common test + * libraries in configs like [test, integrationTest, etc], but it's either that or filter based on + * a configuration containing the word "test" which feels dangerous. + * + * @param project this project we are containerizing + * @return a list of "assemble" tasks associated with projects that this project depends on. + */ + @VisibleForTesting + static List getProjectDependencyAssembleTasks(Project project) { + return project + .getConfigurations() + .stream() + .map(Configuration::getDependencies) + .flatMap(DependencySet::stream) + .filter(ProjectDependency.class::isInstance) + .map(ProjectDependency.class::cast) + .map(ProjectDependency::getDependencyProject) + .map(subProject -> subProject.getTasks().getByPath(BasePlugin.ASSEMBLE_TASK_NAME)) + .collect(Collectors.toList()); + } + @Override public void apply(Project project) { checkGradleVersion(); @@ -68,18 +104,23 @@ public void apply(Project project) { .create(BUILD_TAR_TASK_NAME, BuildTarTask.class) .setJibExtension(jibExtension); - // Has all tasks depend on the 'classes' task. project.afterEvaluate( projectAfterEvaluation -> { try { - List taskDependencies = getProjectDependencyAssembleTasks(projectAfterEvaluation); + // Find project dependencies + List computedDependencies = + getProjectDependencyAssembleTasks(projectAfterEvaluation); + // Has all tasks depend on the 'classes' task. Task classesTask = projectAfterEvaluation.getTasks().getByPath("classes"); - taskDependencies.add(classesTask); + computedDependencies.add(classesTask); + + // dependsOn takes an Object... type + Object[] dependenciesArray = computedDependencies.toArray(); - buildImageTask.dependsOn(taskDependencies.toArray()); - dockerContextTask.dependsOn(taskDependencies.toArray()); - buildDockerTask.dependsOn(taskDependencies.toArray()); - buildTarTask.dependsOn(taskDependencies.toArray()); + buildImageTask.dependsOn(dependenciesArray); + dockerContextTask.dependsOn(dependenciesArray); + buildDockerTask.dependsOn(dependenciesArray); + buildTarTask.dependsOn(dependenciesArray); } catch (UnknownTaskException ex) { throw new GradleException( @@ -90,39 +131,4 @@ public void apply(Project project) { } }); } - - /** - * Collects all assemble tasks for project dependencies of the style "compile project(':mylib')" - * for any kind of configuration [compile, runtime, etc]. It potentially will collect common test - * libraries in configs like [test, integrationTest, etc], but it's either that or filter based on - * a configuration containing the word "test" which feels dangerous. - * - * @param project this project we are containerizing - * @return a list of "assemble" tasks associated with projects that this project depends on. - */ - static List getProjectDependencyAssembleTasks(Project project) { - return project - .getConfigurations() - .stream() - .map(Configuration::getDependencies) - .flatMap(DependencySet::stream) - .filter(ProjectDependency.class::isInstance) - .map(ProjectDependency.class::cast) - .map(ProjectDependency::getDependencyProject) - .map(subProject -> subProject.getTasks().getByPath(BasePlugin.ASSEMBLE_TASK_NAME)) - .collect(Collectors.toList()); - } - - private static void checkGradleVersion() { - if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) { - throw new GradleException( - "Detected " - + GradleVersion.current() - + ", but jib requires " - + GRADLE_MIN_VERSION - + " or higher. You can upgrade by running 'gradle wrapper --gradle-version=" - + GRADLE_MIN_VERSION.getVersion() - + "'."); - } - } } diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java index 92842077a0..f34e2f2996 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java @@ -16,14 +16,15 @@ package com.google.cloud.tools.jib.gradle; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.stream.Collectors; import org.gradle.api.Project; import org.gradle.api.Task; @@ -39,6 +40,12 @@ /** Tests for {@link JibPlugin}. */ public class JibPluginTest { + private static final List KNOWN_JIB_TASKS = + ImmutableList.of( + JibPlugin.BUILD_IMAGE_TASK_NAME, + JibPlugin.BUILD_DOCKER_TASK_NAME, + JibPlugin.DOCKER_CONTEXT_TASK_NAME, + JibPlugin.BUILD_TAR_TASK_NAME); @Rule public TemporaryFolder testProjectRoot = new TemporaryFolder(); @Test @@ -120,25 +127,27 @@ public void testGetProjectDependencyAssembleTasks() { // check by applying the jib plugin and inspect the task dependencies rootProject.getPluginManager().apply("com.google.cloud.tools.jib"); + + // add a custom task that our jib tasks depend on to ensure we do not overwrite this dependsOn + Task dependencyTask = + rootProject.getTasks().create("myCustomTask", task -> System.out.println("test")); + KNOWN_JIB_TASKS.forEach( + taskName -> rootProject.getTasks().getByPath(taskName).dependsOn(dependencyTask)); + ((ProjectInternal) rootProject).evaluate(); - Arrays.asList( - JibPlugin.BUILD_IMAGE_TASK_NAME, - JibPlugin.DOCKER_CONTEXT_TASK_NAME, - JibPlugin.BUILD_DOCKER_TASK_NAME, - JibPlugin.BUILD_TAR_TASK_NAME) - .forEach( - taskName -> { - Assert.assertEquals( - ImmutableSet.of(":sub:assemble", ":classes"), - rootProject - .getTasks() - .getByPath(taskName) - .getDependsOn() - .stream() - .map(Task.class::cast) - .map(Task::getPath) - .collect(Collectors.toSet())); - }); + KNOWN_JIB_TASKS.forEach( + taskName -> { + Assert.assertEquals( + ImmutableSet.of(":sub:assemble", ":classes", ":myCustomTask"), + rootProject + .getTasks() + .getByPath(taskName) + .getDependsOn() + .stream() + .map(Task.class::cast) + .map(Task::getPath) + .collect(Collectors.toSet())); + }); } } From 371b7cbc388a7329c0b3c5786ee0aec8cc43e353 Mon Sep 17 00:00:00 2001 From: Appu Goundan Date: Fri, 10 Aug 2018 15:15:03 -0400 Subject: [PATCH 4/4] ordering --- .../cloud/tools/jib/gradle/JibPlugin.java | 26 +++++++++---------- .../cloud/tools/jib/gradle/JibPluginTest.java | 6 ++--- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java index b65fdbb324..c22ea8199a 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/JibPlugin.java @@ -40,19 +40,6 @@ public class JibPlugin implements Plugin { @VisibleForTesting static final String BUILD_DOCKER_TASK_NAME = "jibDockerBuild"; @VisibleForTesting static final String DOCKER_CONTEXT_TASK_NAME = "jibExportDockerContext"; - private static void checkGradleVersion() { - if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) { - throw new GradleException( - "Detected " - + GradleVersion.current() - + ", but jib requires " - + GRADLE_MIN_VERSION - + " or higher. You can upgrade by running 'gradle wrapper --gradle-version=" - + GRADLE_MIN_VERSION.getVersion() - + "'."); - } - } - /** * Collects all assemble tasks for project dependencies of the style "compile project(':mylib')" * for any kind of configuration [compile, runtime, etc]. It potentially will collect common test @@ -76,6 +63,19 @@ static List getProjectDependencyAssembleTasks(Project project) { .collect(Collectors.toList()); } + private static void checkGradleVersion() { + if (GRADLE_MIN_VERSION.compareTo(GradleVersion.current()) > 0) { + throw new GradleException( + "Detected " + + GradleVersion.current() + + ", but jib requires " + + GRADLE_MIN_VERSION + + " or higher. You can upgrade by running 'gradle wrapper --gradle-version=" + + GRADLE_MIN_VERSION.getVersion() + + "'."); + } + } + @Override public void apply(Project project) { checkGradleVersion(); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java index f34e2f2996..4e49a0aaa1 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/JibPluginTest.java @@ -24,7 +24,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.Collections; -import java.util.List; import java.util.stream.Collectors; import org.gradle.api.Project; import org.gradle.api.Task; @@ -40,7 +39,7 @@ /** Tests for {@link JibPlugin}. */ public class JibPluginTest { - private static final List KNOWN_JIB_TASKS = + private static final ImmutableList KNOWN_JIB_TASKS = ImmutableList.of( JibPlugin.BUILD_IMAGE_TASK_NAME, JibPlugin.BUILD_DOCKER_TASK_NAME, @@ -129,8 +128,7 @@ public void testGetProjectDependencyAssembleTasks() { rootProject.getPluginManager().apply("com.google.cloud.tools.jib"); // add a custom task that our jib tasks depend on to ensure we do not overwrite this dependsOn - Task dependencyTask = - rootProject.getTasks().create("myCustomTask", task -> System.out.println("test")); + Task dependencyTask = rootProject.getTasks().create("myCustomTask", task -> {}); KNOWN_JIB_TASKS.forEach( taskName -> rootProject.getTasks().getByPath(taskName).dependsOn(dependencyTask));