Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace assemble task dependency with runtimeClasspath #2247

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,29 @@

package com.google.cloud.tools.jib.gradle;

import static org.gradle.api.tasks.SourceSet.MAIN_SOURCE_SET_NAME;

import com.google.cloud.tools.jib.ProjectInfo;
import com.google.cloud.tools.jib.gradle.skaffold.CheckJibVersionTask;
import com.google.cloud.tools.jib.gradle.skaffold.FilesTaskV2;
import com.google.cloud.tools.jib.gradle.skaffold.InitTask;
import com.google.cloud.tools.jib.gradle.skaffold.SyncMapTask;
import com.google.cloud.tools.jib.plugins.common.VersionChecker;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
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.api.plugins.JavaPluginConvention;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
import org.gradle.jvm.tasks.Jar;
Expand Down Expand Up @@ -162,68 +166,49 @@ public void apply(Project project) {
SyncMapTask.class,
task -> task.setJibExtension(jibExtension));

Set<TaskProvider<?>> jibTaskProviders =
ImmutableSet.of(buildImageTask, buildDockerTask, buildTarTask, syncMapTask);

// A check to catch older versions of Jib. This can be removed once we are certain people
// are using Jib 1.3.1 or later.
tasks.register(SKAFFOLD_CHECK_REQUIRED_VERSION_TASK_NAME, CheckJibVersionTask.class);

project.afterEvaluate(
projectAfterEvaluation -> {
try {
TaskProvider<Task> warTask = TaskCommon.getWarTaskProvider(projectAfterEvaluation);
TaskProvider<Task> bootWarTask =
TaskCommon.getBootWarTaskProvider(projectAfterEvaluation);
List<TaskProvider<?>> dependsOnTask = new ArrayList<>();
if (warTask != null || bootWarTask != null) {
// Have all tasks depend on the 'war' and/or 'bootWar' task.
if (warTask != null) {
dependsOnTask.add(warTask);
}
if (bootWarTask != null) {
dependsOnTask.add(bootWarTask);
}
} else if ("packaged".equals(jibExtension.getContainerizingMode())) {
// Have all tasks depend on the 'jar' task.
TaskProvider<Task> jarTask = projectAfterEvaluation.getTasks().named("jar");
dependsOnTask.add(jarTask);

if (projectAfterEvaluation.getPlugins().hasPlugin("org.springframework.boot")) {
Jar jar = (Jar) jarTask.get();
jar.setEnabled(true);
jar.getArchiveClassifier().set("original");
}
} else {
// Have all tasks depend on the 'classes' task.
dependsOnTask.add(projectAfterEvaluation.getTasks().named("classes"));
TaskProvider<Task> warTask = TaskCommon.getWarTaskProvider(projectAfterEvaluation);
TaskProvider<Task> bootWarTask =
TaskCommon.getBootWarTaskProvider(projectAfterEvaluation);
List<Object> jibDependencies = new ArrayList<>();
if (warTask != null || bootWarTask != null) {
// Have all tasks depend on the 'war' and/or 'bootWar' task.
if (warTask != null) {
jibDependencies.add(warTask);
}
if (bootWarTask != null) {
jibDependencies.add(bootWarTask);
}
buildImageTask.configure(task -> task.dependsOn(dependsOnTask));
buildDockerTask.configure(task -> task.dependsOn(dependsOnTask));
buildTarTask.configure(task -> task.dependsOn(dependsOnTask));
syncMapTask.configure(task -> task.dependsOn(dependsOnTask));

// Find project dependencies and add a dependency to their assemble task. We make sure
// to only add the dependency after BasePlugin is evaluated as otherwise the assemble
// task may not be available yet.
List<Project> computedDependencies = getProjectDependencies(projectAfterEvaluation);
for (Project dependencyProject : computedDependencies) {
dependencyProject
.getPlugins()
.withType(
BasePlugin.class,
unused -> {
TaskProvider<Task> assembleTask =
dependencyProject.getTasks().named(BasePlugin.ASSEMBLE_TASK_NAME);
buildImageTask.configure(task -> task.dependsOn(assembleTask));
buildDockerTask.configure(task -> task.dependsOn(assembleTask));
buildTarTask.configure(task -> task.dependsOn(assembleTask));
});
} else if ("packaged".equals(jibExtension.getContainerizingMode())) {
// Have all tasks depend on the 'jar' task.
TaskProvider<Task> jarTask = projectAfterEvaluation.getTasks().named("jar");
jibDependencies.add(jarTask);

if (projectAfterEvaluation.getPlugins().hasPlugin("org.springframework.boot")) {
Jar jar = (Jar) jarTask.get();
jar.setEnabled(true);
jar.getArchiveClassifier().set("original");
}
} catch (UnknownTaskException ex) {
throw new GradleException(
"Could not find task 'classes' on project "
+ projectAfterEvaluation.getDisplayName()
+ " - perhaps you did not apply the 'java' plugin?",
ex);
}

SourceSet mainSourceSet =
project
.getConvention()
.getPlugin(JavaPluginConvention.class)
.getSourceSets()
.getByName(MAIN_SOURCE_SET_NAME);
jibDependencies.add(mainSourceSet.getRuntimeClasspath());

jibTaskProviders.forEach(
provider -> provider.configure(task -> task.setDependsOn(jibDependencies)));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,12 @@
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.Set;
import java.util.stream.Collectors;
import org.gradle.api.GradleException;
import org.gradle.api.Project;
Expand Down Expand Up @@ -136,72 +133,6 @@ public void testCheckJibVersionInvoked() {
}
}

@SuppressWarnings("unchecked")
@Test
public void testProjectDependencyAssembleTasksAreRun() {
// root project is our jib packaged service
Project rootProject = createProject("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"),
JibPlugin.getProjectDependencies(rootProject)
.stream()
.map(Project::getPath)
.collect(Collectors.toList()));

// check by applying the jib plugin and inspect the task dependencies
rootProject.getPluginManager().apply("com.google.cloud.tools.jib");

TaskContainer tasks = rootProject.getTasks();
// add a custom task that our jib tasks depend on to ensure we do not overwrite this dependsOn
TaskProvider<Task> dependencyTask = rootProject.getTasks().register("myCustomTask", task -> {});
KNOWN_JIB_TASKS.forEach(taskName -> tasks.getByPath(taskName).dependsOn(dependencyTask));

((ProjectInternal) rootProject).evaluate();

KNOWN_JIB_TASKS.forEach(
taskName ->
Assert.assertEquals(
ImmutableSet.of(":sub:assemble", ":classes", ":myCustomTask"),
tasks
.getByPath(taskName)
.getDependsOn()
.stream()
.map(
object ->
object instanceof List ? object : Collections.singletonList(object))
.map(List.class::cast)
.flatMap(List::stream)
.map(object -> ((TaskProvider<Task>) object).get().getPath())
.collect(Collectors.toSet())));
}

@SuppressWarnings("unchecked")
@Test
public void testWebAppProject() {
Expand All @@ -213,10 +144,16 @@ public void testWebAppProject() {
Assert.assertNotNull(warTask);

for (String taskName : KNOWN_JIB_TASKS) {
List<TaskProvider<?>> taskProviders =
(List<TaskProvider<?>>) tasks.getByPath(taskName).getDependsOn().iterator().next();
Assert.assertEquals(1, taskProviders.size());
Assert.assertEquals(warTask, taskProviders.get(0).get());
Set<Task> taskDependencies =
tasks
.getByPath(taskName)
.getDependsOn()
.stream()
.filter(TaskProvider.class::isInstance)
.map(it -> ((TaskProvider<?>) it).get())
.collect(Collectors.toSet());

Assert.assertTrue(taskDependencies.contains(warTask));
}
}

Expand All @@ -234,11 +171,16 @@ public void testWebAppProject_bootWar() {
Assert.assertNotNull(bootWarTask);

for (String taskName : KNOWN_JIB_TASKS) {
List<TaskProvider<?>> taskProviders =
(List<TaskProvider<?>>) tasks.getByPath(taskName).getDependsOn().iterator().next();
Assert.assertEquals(
ImmutableSet.of(warTask, bootWarTask),
taskProviders.stream().map(TaskProvider::get).collect(Collectors.toSet()));
Set<Task> taskDependencies =
tasks
.getByPath(taskName)
.getDependsOn()
.stream()
.filter(TaskProvider.class::isInstance)
.map(it -> ((TaskProvider<?>) it).get())
.collect(Collectors.toSet());

Assert.assertTrue(taskDependencies.containsAll(Arrays.asList(warTask, bootWarTask)));
}
}

Expand All @@ -257,11 +199,16 @@ public void testWebAppProject_bootWarDisabled() {
bootWarTask.setEnabled(false); // should depend on bootWar even if disabled

for (String taskName : KNOWN_JIB_TASKS) {
List<TaskProvider<?>> taskProviders =
(List<TaskProvider<?>>) tasks.getByPath(taskName).getDependsOn().iterator().next();
Assert.assertEquals(
ImmutableSet.of(warTask, bootWarTask),
taskProviders.stream().map(TaskProvider::get).collect(Collectors.toSet()));
Set<Task> taskDependencies =
tasks
.getByPath(taskName)
.getDependsOn()
.stream()
.filter(TaskProvider.class::isInstance)
.map(it -> ((TaskProvider<?>) it).get())
.collect(Collectors.toSet());

Assert.assertTrue(taskDependencies.containsAll(Arrays.asList(warTask, bootWarTask)));
}
}

Expand Down