diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGenerator.java deleted file mode 100644 index c8fa25440f..0000000000 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGenerator.java +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.frontend; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; -import com.google.cloud.tools.jib.image.LayerEntry; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; -import com.google.common.io.MoreFiles; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.DirectoryNotEmptyException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.StringJoiner; -import javax.annotation.Nullable; - -/** - * Generates a Docker context for a Java application. - * - *

The image consists of a base image layer and 5 application layers under the directories: - * - *

- * - * Empty application layers are omitted. - */ -public class JavaDockerContextGenerator { - - private static final String DEPENDENCIES_LAYER_DIRECTORY = "libs"; - private static final String SNAPSHOT_DEPENDENCIES_LAYER_DIRECTORY = "snapshot-libs"; - private static final String RESOURCES_LAYER_DIRECTORY = "resources"; - private static final String CLASSES_LAYER_DIRECTORY = "classes"; - private static final String EXTRA_FILES_LAYER_DIRECTORY = "root"; - - private static final ObjectMapper objectMapper = new ObjectMapper(); - - /** Represents a Dockerfile {@code COPY} directive. */ - private static class CopyDirective { - - /** The layer entries to put into the context. */ - private final ImmutableList layerEntries; - - /** The directory in the context to put the source files for the layer */ - private final String directoryInContext; - - /** The extraction path in the image. */ - private final AbsoluteUnixPath extractionPath; - - private CopyDirective( - ImmutableList layerEntries, - String directoryInContext, - AbsoluteUnixPath extractionPath) { - this.layerEntries = layerEntries; - this.directoryInContext = directoryInContext; - this.extractionPath = extractionPath; - } - } - - /** - * Adds a copy directive for the {@code layerEntries} if it's not empty. - * - * @param listBuilder the {@link ImmutableList.Builder} to add to - * @param layerEntries the layer entries - * @param directoryInContext the directory in the context to put the source files for the layer - */ - private static void addIfNotEmpty( - ImmutableList.Builder listBuilder, - ImmutableList layerEntries, - String directoryInContext) { - if (layerEntries.isEmpty()) { - return; - } - - listBuilder.add(new CopyDirective(layerEntries, directoryInContext, AbsoluteUnixPath.get("/"))); - } - - /** - * Converts a map to a corresponding dockerfile string in the form of: - * - *
{@code
-   * command key1="value1" \
-   *     key2="value2" \
-   *     ...
-   * }
- * - * @param map the map to convert - * @param command the dockerfile command to prefix the map values with - * @return the new dockerfile command as a string - * @throws JsonProcessingException if getting the json string of a map value fails - */ - private static String mapToDockerfileString(Map map, String command) - throws JsonProcessingException { - if (map.isEmpty()) { - return ""; - } - - StringJoiner joiner = new StringJoiner(" \\\n ", "\n" + command + " ", ""); - for (Entry entry : map.entrySet()) { - joiner.add(entry.getKey() + "=" + objectMapper.writeValueAsString(entry.getValue())); - } - return joiner.toString(); - } - - private final ImmutableList copyDirectives; - - @Nullable private String baseImage; - @Nullable private List entrypoint; - @Nullable private List programArguments; - @Nullable private Map environment; - @Nullable private String user; - @Nullable private List exposedPorts; - @Nullable private Map labels; - - /** - * Constructs a Docker context generator for a Java application. - * - * @param javaLayerConfigurations the {@link JavaLayerConfigurations} - */ - public JavaDockerContextGenerator(JavaLayerConfigurations javaLayerConfigurations) { - ImmutableList.Builder copyDirectivesBuilder = ImmutableList.builder(); - addIfNotEmpty( - copyDirectivesBuilder, - javaLayerConfigurations.getDependencyLayerEntries(), - DEPENDENCIES_LAYER_DIRECTORY); - addIfNotEmpty( - copyDirectivesBuilder, - javaLayerConfigurations.getSnapshotDependencyLayerEntries(), - SNAPSHOT_DEPENDENCIES_LAYER_DIRECTORY); - addIfNotEmpty( - copyDirectivesBuilder, - javaLayerConfigurations.getResourceLayerEntries(), - RESOURCES_LAYER_DIRECTORY); - addIfNotEmpty( - copyDirectivesBuilder, - javaLayerConfigurations.getClassLayerEntries(), - CLASSES_LAYER_DIRECTORY); - addIfNotEmpty( - copyDirectivesBuilder, - javaLayerConfigurations.getExtraFilesLayerEntries(), - EXTRA_FILES_LAYER_DIRECTORY); - copyDirectives = copyDirectivesBuilder.build(); - } - - /** - * Sets the base image for the {@code FROM} directive. This must be called before {@link - * #generate}. - * - * @param baseImage the base image - * @return this - */ - public JavaDockerContextGenerator setBaseImage(String baseImage) { - this.baseImage = baseImage; - return this; - } - - /** - * Sets the entrypoint to be used as the {@code ENTRYPOINT}. - * - * @param entrypoint the entrypoint - * @return this - */ - public JavaDockerContextGenerator setEntrypoint(@Nullable List entrypoint) { - this.entrypoint = entrypoint; - return this; - } - - /** - * Sets the user for the {@code USER} directive. - * - * @param user the username/UID and optionally the groupname/GID - * @return this - */ - public JavaDockerContextGenerator setUser(@Nullable String user) { - this.user = user; - return this; - } - - /** - * Sets the arguments used in the {@code CMD}. - * - * @param programArguments the list of arguments to append to {@code ENTRYPOINT} - * @return this - */ - public JavaDockerContextGenerator setProgramArguments(@Nullable List programArguments) { - this.programArguments = programArguments; - return this; - } - - /** - * Sets the environment variables. - * - * @param environment map from the environment variable name to value - * @return this - */ - public JavaDockerContextGenerator setEnvironment(@Nullable Map environment) { - this.environment = environment; - return this; - } - - /** - * Sets the exposed ports. - * - * @param exposedPorts the list of port numbers/port ranges to expose - * @return this - */ - public JavaDockerContextGenerator setExposedPorts(@Nullable List exposedPorts) { - this.exposedPorts = exposedPorts; - return this; - } - - /** - * Sets the labels. - * - * @param labels the map of labels - * @return this - */ - public JavaDockerContextGenerator setLabels(@Nullable Map labels) { - this.labels = labels; - return this; - } - - /** - * Creates the Docker context in {@code #targetDirectory}. - * - * @param targetDirectory the directory to generate the Docker context in - * @throws IOException if the export fails - */ - public void generate(Path targetDirectory) throws IOException { - Preconditions.checkNotNull(baseImage); - - // Deletes the targetDir if it exists. - try { - Files.deleteIfExists(targetDirectory); - - } catch (DirectoryNotEmptyException ex) { - MoreFiles.deleteDirectoryContents(targetDirectory); - Files.delete(targetDirectory); - } - - Files.createDirectory(targetDirectory); - - for (CopyDirective copyDirective : copyDirectives) { - // Creates the directories. - Path directoryInContext = targetDirectory.resolve(copyDirective.directoryInContext); - Files.createDirectory(directoryInContext); - - // Copies the source files to the directoryInContext. - for (LayerEntry layerEntry : copyDirective.layerEntries) { - String noLeadingSlash = layerEntry.getExtractionPath().toString().substring(1); - Path destination = directoryInContext.resolve(noLeadingSlash); - - if (Files.isDirectory(layerEntry.getSourceFile())) { - Files.createDirectories(destination); - } else { - Files.createDirectories(destination.getParent()); - Files.copy(layerEntry.getSourceFile(), destination); - } - } - } - - // Creates the Dockerfile. - Files.write( - targetDirectory.resolve("Dockerfile"), makeDockerfile().getBytes(StandardCharsets.UTF_8)); - } - - /** - * Makes the contents of a {@code Dockerfile} using configuration data, in the following format: - * - *
{@code
-   * FROM [base image]
-   *
-   * COPY libs /
-   * COPY snapshot-libs /
-   * COPY resources /
-   * COPY classes /
-   * COPY root /
-   *
-   * EXPOSE [port]
-   * [More EXPOSE instructions, if necessary]
-   * ENV [key1]="[value1]" \
-   *     [key2]="[value2]" \
-   *     [...]
-   * LABEL [key1]="[value1]" \
-   *     [key2]="[value2]" \
-   *     [...]
-   * USER [user name (or UID) and optionally user group (or GID)]
-   * ENTRYPOINT java [jvm flags] -cp [classpaths] [main class]
-   * CMD [main class args]
-   * }
- * - * @return the {@code Dockerfile} contents - */ - @VisibleForTesting - String makeDockerfile() throws JsonProcessingException { - StringBuilder dockerfile = new StringBuilder(); - dockerfile.append("FROM ").append(Preconditions.checkNotNull(baseImage)).append("\n"); - for (CopyDirective copyDirective : copyDirectives) { - boolean hasTrailingSlash = copyDirective.extractionPath.toString().endsWith("/"); - dockerfile - .append("\nCOPY ") - .append(copyDirective.directoryInContext) - .append(" ") - .append(copyDirective.extractionPath) - .append(hasTrailingSlash ? "" : "/"); - } - - dockerfile.append("\n"); - if (exposedPorts != null) { - for (String port : exposedPorts) { - dockerfile.append("\nEXPOSE ").append(port); - } - } - - if (environment != null) { - dockerfile.append(mapToDockerfileString(environment, "ENV")); - } - if (labels != null) { - dockerfile.append(mapToDockerfileString(labels, "LABEL")); - } - if (entrypoint != null) { - dockerfile.append("\nENTRYPOINT ").append(objectMapper.writeValueAsString(entrypoint)); - } - if (programArguments != null) { - dockerfile.append("\nCMD ").append(objectMapper.writeValueAsString(programArguments)); - } - if (user != null) { - dockerfile.append("\nUSER ").append(user); - } - return dockerfile.toString(); - } -} diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGeneratorTest.java deleted file mode 100644 index 546e25e978..0000000000 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/frontend/JavaDockerContextGeneratorTest.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.frontend; - -import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; -import com.google.cloud.tools.jib.filesystem.DirectoryWalker; -import com.google.cloud.tools.jib.image.LayerEntry; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import com.google.common.io.Resources; -import java.io.IOException; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -/** Tests for {@link JavaDockerContextGenerator}. */ -@RunWith(MockitoJUnitRunner.class) -public class JavaDockerContextGeneratorTest { - - private static void assertSameFiles(Path directory1, Path directory2) throws IOException { - ImmutableList directory1Files = - new DirectoryWalker(directory1) - .walk() - .stream() - .map(directory1::relativize) - .collect(ImmutableList.toImmutableList()); - ImmutableList directory2Files = - new DirectoryWalker(directory2) - .walk() - .stream() - .map(directory2::relativize) - .collect(ImmutableList.toImmutableList()); - Assert.assertEquals(directory1Files, directory2Files); - } - - @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - - @Mock private JavaLayerConfigurations mockJavaLayerConfigurations; - - private ImmutableList filesToLayerEntries(Path directory, String extractionRootString) - throws IOException { - AbsoluteUnixPath extractionRoot = AbsoluteUnixPath.get(extractionRootString); - return new DirectoryWalker(directory) - .walk() - .stream() - .map( - sourceFile -> - new LayerEntry( - sourceFile, extractionRoot.resolve(directory.relativize(sourceFile)), null)) - .collect(ImmutableList.toImmutableList()); - } - - @Test - public void testGenerate() throws IOException, URISyntaxException { - Path testDependencies = Paths.get(Resources.getResource("application/dependencies").toURI()); - Path testSnapshotDependencies = - Paths.get(Resources.getResource("application/snapshot-dependencies").toURI()); - Path testResources = Paths.get(Resources.getResource("application/resources").toURI()); - Path testClasses = Paths.get(Resources.getResource("application/classes").toURI()); - Path testExtraFiles = Paths.get(Resources.getResource("layer").toURI()); - - Path targetDirectory = temporaryFolder.newFolder().toPath(); - - /* - * Deletes the directory so that JavaDockerContextGenerator#generate does not throw - * InsecureRecursiveDeleteException. - */ - Files.delete(targetDirectory); - - Mockito.when(mockJavaLayerConfigurations.getDependencyLayerEntries()) - .thenReturn(filesToLayerEntries(testDependencies, "/app/libs")); - Mockito.when(mockJavaLayerConfigurations.getSnapshotDependencyLayerEntries()) - .thenReturn(filesToLayerEntries(testSnapshotDependencies, "/snapshots")); - Mockito.when(mockJavaLayerConfigurations.getResourceLayerEntries()) - .thenReturn(filesToLayerEntries(testResources, "/more/resources")); - Mockito.when(mockJavaLayerConfigurations.getClassLayerEntries()) - .thenReturn(filesToLayerEntries(testClasses, "/my/classes")); - Mockito.when(mockJavaLayerConfigurations.getExtraFilesLayerEntries()) - .thenReturn(filesToLayerEntries(testExtraFiles, "/")); - - new JavaDockerContextGenerator(mockJavaLayerConfigurations) - .setBaseImage("somebaseimage") - .generate(targetDirectory); - - Assert.assertTrue(Files.exists(targetDirectory.resolve("Dockerfile"))); - assertSameFiles(targetDirectory.resolve("libs/app/libs"), testDependencies); - assertSameFiles(targetDirectory.resolve("snapshot-libs/snapshots"), testSnapshotDependencies); - assertSameFiles(targetDirectory.resolve("resources/more/resources"), testResources); - assertSameFiles(targetDirectory.resolve("classes/my/classes"), testClasses); - assertSameFiles(targetDirectory.resolve("root"), testExtraFiles); - } - - @Test - public void testMakeDockerfile() throws IOException { - String expectedBaseImage = "somebaseimage"; - List expectedJvmFlags = Arrays.asList("-flag", "another\"Flag"); - String expectedMainClass = "SomeMainClass"; - List expectedProgramArguments = Arrays.asList("arg1", "arg2"); - Map expectedEnv = ImmutableMap.of("key1", "value1", "key2", "value2"); - List exposedPorts = Arrays.asList("1000/tcp", "2000-2010/udp"); - Map expectedLabels = - ImmutableMap.of( - "key1", - "value", - "key2", - "value with\\backslashes\"and\\\\\"\"quotes\"\\", - "key3", - "value3"); - - Path ignored = Paths.get("ignored"); - Mockito.when(mockJavaLayerConfigurations.getDependencyLayerEntries()) - .thenReturn( - ImmutableList.of(new LayerEntry(ignored, AbsoluteUnixPath.get("/app/libs"), null))); - Mockito.when(mockJavaLayerConfigurations.getSnapshotDependencyLayerEntries()) - .thenReturn( - ImmutableList.of(new LayerEntry(ignored, AbsoluteUnixPath.get("/snapshots"), null))); - Mockito.when(mockJavaLayerConfigurations.getResourceLayerEntries()) - .thenReturn( - ImmutableList.of(new LayerEntry(ignored, AbsoluteUnixPath.get("/my/resources"), null))); - Mockito.when(mockJavaLayerConfigurations.getClassLayerEntries()) - .thenReturn( - ImmutableList.of(new LayerEntry(ignored, AbsoluteUnixPath.get("/my/classes/"), null))); - Mockito.when(mockJavaLayerConfigurations.getExtraFilesLayerEntries()) - .thenReturn(ImmutableList.of(new LayerEntry(ignored, AbsoluteUnixPath.get("/"), null))); - - String dockerfile = - new JavaDockerContextGenerator(mockJavaLayerConfigurations) - .setBaseImage(expectedBaseImage) - .setEntrypoint( - JavaEntrypointConstructor.makeDefaultEntrypoint( - AbsoluteUnixPath.get("/app"), expectedJvmFlags, expectedMainClass)) - .setProgramArguments(expectedProgramArguments) - .setEnvironment(expectedEnv) - .setExposedPorts(exposedPorts) - .setLabels(expectedLabels) - .makeDockerfile(); - - // Need to split/rejoin the string here to avoid cross-platform troubles - List sampleDockerfile = - Resources.readLines(Resources.getResource("sampleDockerfile"), StandardCharsets.UTF_8); - Assert.assertEquals(String.join("\n", sampleDockerfile), dockerfile); - } - - @Test - public void testMakeDockerfileWithWebApp() throws IOException { - String expectedBaseImage = "tomcat:8.5-jre8-alpine"; - AbsoluteUnixPath exepectedAppRoot = AbsoluteUnixPath.get("/usr/local/tomcat/webapps/ROOT/"); - - Mockito.when(mockJavaLayerConfigurations.getDependencyLayerEntries()) - .thenReturn( - ImmutableList.of( - new LayerEntry( - Paths.get("ignored"), exepectedAppRoot.resolve("WEB-INF/lib"), null))); - Mockito.when(mockJavaLayerConfigurations.getSnapshotDependencyLayerEntries()) - .thenReturn( - ImmutableList.of( - new LayerEntry( - Paths.get("ignored"), exepectedAppRoot.resolve("WEB-INF/lib"), null))); - Mockito.when(mockJavaLayerConfigurations.getResourceLayerEntries()) - .thenReturn(ImmutableList.of(new LayerEntry(Paths.get("ignored"), exepectedAppRoot, null))); - Mockito.when(mockJavaLayerConfigurations.getClassLayerEntries()) - .thenReturn( - ImmutableList.of( - new LayerEntry( - Paths.get("ignored"), exepectedAppRoot.resolve("WEB-INF/classes"), null))); - Mockito.when(mockJavaLayerConfigurations.getExtraFilesLayerEntries()) - .thenReturn( - ImmutableList.of( - new LayerEntry(Paths.get("ignored"), AbsoluteUnixPath.get("/"), null))); - String dockerfile = - new JavaDockerContextGenerator(mockJavaLayerConfigurations) - .setBaseImage(expectedBaseImage) - .setEntrypoint(ImmutableList.of("catalina.sh", "run")) - .makeDockerfile(); - - // Need to split/rejoin the string here to avoid cross-platform troubles - List sampleDockerfile = - Resources.readLines( - Resources.getResource("webAppSampleDockerfile"), StandardCharsets.UTF_8); - Assert.assertEquals(String.join("\n", sampleDockerfile), dockerfile); - } -} diff --git a/jib-core/src/test/resources/sampleDockerfile b/jib-core/src/test/resources/sampleDockerfile deleted file mode 100644 index c2eae1c103..0000000000 --- a/jib-core/src/test/resources/sampleDockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM somebaseimage - -COPY libs / -COPY snapshot-libs / -COPY resources / -COPY classes / -COPY root / - -EXPOSE 1000/tcp -EXPOSE 2000-2010/udp -ENV key1="value1" \ - key2="value2" -LABEL key1="value" \ - key2="value with\\backslashes\"and\\\\\"\"quotes\"\\" \ - key3="value3" -ENTRYPOINT ["java","-flag","another\"Flag","-cp","/app/resources:/app/classes:/app/libs/*","SomeMainClass"] -CMD ["arg1","arg2"] diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 303be7c02b..3b3ff5d715 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file. ### Changed +- Removed `jibExportDockerContext` task ([#1219](https://github.com/GoogleContainerTools/jib/issues/1219)) + ### Fixed - NullPointerException thrown with incomplete `auth` configuration ([#1177](https://github.com/GoogleContainerTools/jib/issues/1177)) diff --git a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/MultiProjectIntegrationTest.java b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/MultiProjectIntegrationTest.java deleted file mode 100644 index 297613b9e6..0000000000 --- a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/MultiProjectIntegrationTest.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.gradle; - -import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.BuildTask; -import org.gradle.testkit.runner.TaskOutcome; -import org.hamcrest.CoreMatchers; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Test; - -/** Integration tests for building multi-project images. */ -public class MultiProjectIntegrationTest { - - @ClassRule - public static final TestProject multiprojectTestProject = new TestProject("multiproject"); - - @Test - public void testMultiProject() { - BuildResult buildResult = - multiprojectTestProject.build("clean", ":a_packaged:jibExportDockerContext", "--info"); - - BuildTask classesTask = buildResult.task(":a_packaged:classes"); - BuildTask jibTask = buildResult.task(":a_packaged:jibExportDockerContext"); - Assert.assertNotNull(classesTask); - Assert.assertEquals(TaskOutcome.SUCCESS, classesTask.getOutcome()); - Assert.assertNotNull(jibTask); - Assert.assertEquals(TaskOutcome.SUCCESS, jibTask.getOutcome()); - Assert.assertThat( - buildResult.getOutput(), CoreMatchers.containsString("Created Docker context at ")); - } -} diff --git a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java index 31ee5c0a59..f1b8e191bc 100644 --- a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java +++ b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/SingleProjectIntegrationTest.java @@ -20,12 +20,9 @@ import com.google.cloud.tools.jib.IntegrationTestingConfiguration; import com.google.cloud.tools.jib.registry.LocalRegistry; import java.io.IOException; -import java.nio.file.Files; import java.security.DigestException; import java.time.Instant; import org.gradle.testkit.runner.BuildResult; -import org.gradle.testkit.runner.BuildTask; -import org.gradle.testkit.runner.TaskOutcome; import org.gradle.testkit.runner.UnexpectedBuildFailure; import org.hamcrest.CoreMatchers; import org.junit.Assert; @@ -180,61 +177,6 @@ public void testDockerDaemon_simple() throws IOException, InterruptedException, assertDockerInspect(targetImage); } - @Test - public void testDockerContext() throws IOException, InterruptedException { - BuildResult buildResult = simpleTestProject.build("clean", "jibExportDockerContext", "--info"); - - JibRunHelper.assertBuildSuccess( - buildResult, "jibExportDockerContext", "Created Docker context at "); - - String imageName = "jib-gradle-plugin/integration-test" + System.nanoTime(); - new Command( - "docker", - "build", - "-t", - imageName, - simpleTestProject - .getProjectRoot() - .resolve("build") - .resolve("jib-docker-context") - .toString()) - .run(); - - assertDockerInspect(imageName); - String output = new Command("docker", "run", "--rm", imageName).run(); - Assert.assertThat(output, CoreMatchers.startsWith("Hello, world. An argument.\n")); - Assert.assertThat(output, CoreMatchers.endsWith("foo\ncat\n")); - - // Checks that generating the Docker context again is skipped. - BuildTask upToDateJibDockerContextTask = - simpleTestProject.build("jibExportDockerContext").task(":jibExportDockerContext"); - Assert.assertNotNull(upToDateJibDockerContextTask); - Assert.assertEquals(TaskOutcome.UP_TO_DATE, upToDateJibDockerContextTask.getOutcome()); - - // Checks that adding a new file generates the Docker context again. - Files.createFile( - simpleTestProject - .getProjectRoot() - .resolve("src") - .resolve("main") - .resolve("resources") - .resolve("newfile")); - try { - BuildTask reexecutedJibDockerContextTask = - simpleTestProject.build("jibExportDockerContext").task(":jibExportDockerContext"); - Assert.assertNotNull(reexecutedJibDockerContextTask); - Assert.assertEquals(TaskOutcome.SUCCESS, reexecutedJibDockerContextTask.getOutcome()); - - } catch (UnexpectedBuildFailure ex) { - // This might happen on systems without SecureDirectoryStream, so we just ignore it. - // See com.google.common.io.MoreFiles#deleteDirectoryContents. - Assert.assertThat( - ex.getMessage(), - CoreMatchers.containsString( - "Export Docker context failed because cannot clear directory")); - } - } - @Test public void testBuildTar_simple() throws IOException, InterruptedException { String targetImage = "simpleimage:gradle" + System.nanoTime(); diff --git a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/WarProjectIntegrationTest.java b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/WarProjectIntegrationTest.java index 3aaef472d1..5a093ee96c 100644 --- a/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/WarProjectIntegrationTest.java +++ b/jib-gradle-plugin/src/integration-test/java/com/google/cloud/tools/jib/gradle/WarProjectIntegrationTest.java @@ -23,8 +23,6 @@ import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; import java.security.DigestException; import javax.annotation.Nullable; import org.junit.After; @@ -74,28 +72,6 @@ public void testBuild_tomcatServlet25() verifyBuildAndRun(servlet25Project, "war_tomcat_servlet25:gradle", "build-tomcat.gradle"); } - @Test - public void testDockerContext_jettyServlet25() throws IOException, InterruptedException { - String expectedDockerContext = - "FROM gcr.io/distroless/java/jetty\n" - + "\n" - + "COPY libs /\n" - + "COPY resources /\n" - + "COPY classes /"; - verifyDockerContextBuildAndRun(expectedDockerContext, "build.gradle"); - } - - @Test - public void testDockerContext_tomcatServlet25() throws IOException, InterruptedException { - String expectedDockerContext = - "FROM tomcat:8.5-jre8-alpine\n" - + "\n" - + "COPY libs /\n" - + "COPY resources /\n" - + "COPY classes /"; - verifyDockerContextBuildAndRun(expectedDockerContext, "build-tomcat.gradle"); - } - private void verifyBuildAndRun(TestProject project, String label, String gradleBuildFile) throws IOException, InterruptedException, DigestException { String nameBase = "gcr.io/" + IntegrationTestingConfiguration.getGCPProject() + '/'; @@ -106,22 +82,4 @@ private void verifyBuildAndRun(TestProject project, String label, String gradleB Assert.assertEquals("Hello world", getContent(new URL("http://localhost:8080/hello"))); } - - private void verifyDockerContextBuildAndRun(String expectedDockerfile, String gradleBuildFile) - throws IOException, InterruptedException { - servlet25Project.build("clean", "jibExportDockerContext", "-b=" + gradleBuildFile); - - Path dockerContext = - servlet25Project.getProjectRoot().resolve("build").resolve("jib-docker-context"); - Assert.assertTrue(Files.exists(dockerContext)); - String dockerfile = String.join("\n", Files.readAllLines(dockerContext.resolve("Dockerfile"))); - Assert.assertEquals(expectedDockerfile, dockerfile); - - String imageName = "jib/integration-test" + System.nanoTime(); - new Command("docker", "build", "-t", imageName, dockerContext.toString()).run(); - containerName = - new Command("docker", "run", "--rm", "--detach", "-p8080:8080", imageName).run().trim(); - - Assert.assertEquals("Hello world", getContent(new URL("http://localhost:8080/hello"))); - } } diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java deleted file mode 100644 index fa10f044de..0000000000 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/DockerContextTask.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.gradle; - -import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; -import com.google.cloud.tools.jib.frontend.ExposedPortsParser; -import com.google.cloud.tools.jib.frontend.JavaDockerContextGenerator; -import com.google.cloud.tools.jib.global.JibSystemProperties; -import com.google.cloud.tools.jib.plugins.common.AppRootInvalidException; -import com.google.cloud.tools.jib.plugins.common.HelpfulSuggestions; -import com.google.cloud.tools.jib.plugins.common.MainClassInferenceException; -import com.google.cloud.tools.jib.plugins.common.PluginConfigurationProcessor; -import com.google.cloud.tools.jib.plugins.common.RawConfiguration; -import com.google.common.base.Preconditions; -import com.google.common.io.InsecureRecursiveDeleteException; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.List; -import javax.annotation.Nullable; -import org.gradle.api.DefaultTask; -import org.gradle.api.GradleException; -import org.gradle.api.file.FileCollection; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputFiles; -import org.gradle.api.tasks.Nested; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.options.Option; - -public class DockerContextTask extends DefaultTask implements JibTask { - - @Nullable private String targetDir; - @Nullable private JibExtension jibExtension; - - /** - * This will call the property {@code "jib"} so that it is the same name as the extension. This - * way, the user would see error messages for missing configuration with the prefix {@code jib.}. - * - * @return the {@link JibExtension}. - */ - @Nested - @Nullable - public JibExtension getJib() { - return jibExtension; - } - - /** - * @return the input files to this task are all the output files for all the dependencies of the - * {@code classes} task. - */ - @InputFiles - public FileCollection getInputFiles() { - return GradleProjectProperties.getInputFiles( - Preconditions.checkNotNull(jibExtension).getExtraDirectory().getPath().toFile(), - getProject()); - } - - /** - * The output directory to check for task up-to-date. - * - * @return the output directory - */ - @OutputDirectory - public String getOutputDirectory() { - return getTargetDir(); - } - - /** - * Returns the output directory for the Docker context. By default, it is {@code - * build/jib-docker-context}. - * - * @return the output directory - */ - @Input - public String getTargetDir() { - if (targetDir == null) { - return getProject().getBuildDir().toPath().resolve("jib-docker-context").toString(); - } - return targetDir; - } - - /** - * The output directory can be overriden with the {@code --jibTargetDir} command line option. - * - * @param targetDir the output directory. - */ - @Option(option = "jibTargetDir", description = "Directory to output the Docker context to") - public void setTargetDir(String targetDir) { - this.targetDir = targetDir; - } - - @TaskAction - public void generateDockerContext() throws MainClassInferenceException { - Preconditions.checkNotNull(jibExtension); - JibSystemProperties.checkHttpTimeoutProperty(); - TaskCommon.disableHttpLogging(); - - if (!jibExtension.getExtraDirectory().getPermissions().isEmpty()) { - getLogger() - .warn( - "'jib.extraDirectory.permissions' configuration is not supported by Jib Docker " - + "context generator - building using Docker may produce unexpected results."); - } - - try { - AbsoluteUnixPath appRoot = TaskCommon.getAppRootChecked(jibExtension, getProject()); - - GradleProjectProperties projectProperties = - GradleProjectProperties.getForProject( - getProject(), - getLogger(), - jibExtension.getExtraDirectory().getPath(), - jibExtension.getExtraDirectory().getPermissions(), - appRoot); - RawConfiguration rawConfiguration = new GradleRawConfiguration(jibExtension); - String targetDir = getTargetDir(); - - List entrypoint = - PluginConfigurationProcessor.computeEntrypoint(rawConfiguration, projectProperties); - String baseImage = - PluginConfigurationProcessor.getBaseImage(rawConfiguration, projectProperties); - - // Validate port input, but don't save the output because we don't want the ranges expanded - // here. - ExposedPortsParser.parse(jibExtension.getContainer().getPorts()); - - new JavaDockerContextGenerator(projectProperties.getJavaLayerConfigurations()) - .setBaseImage(baseImage) - .setEntrypoint(entrypoint) - .setProgramArguments(jibExtension.getContainer().getArgs()) - .setExposedPorts(jibExtension.getContainer().getPorts()) - .setEnvironment(jibExtension.getContainer().getEnvironment()) - .setLabels(jibExtension.getContainer().getLabels()) - .setUser(jibExtension.getContainer().getUser()) - .generate(Paths.get(targetDir)); - - getLogger().lifecycle("Created Docker context at " + targetDir); - - } catch (InsecureRecursiveDeleteException ex) { - throw new GradleException( - HelpfulSuggestions.forDockerContextInsecureRecursiveDelete( - "Export Docker context failed because cannot clear directory '" - + getTargetDir() - + "' safely", - getTargetDir()), - ex); - - } catch (IOException ex) { - throw new GradleException( - HelpfulSuggestions.suggest( - "Export Docker context failed", - "check if the command-line option `--jibTargetDir` is set correctly"), - ex); - - } catch (AppRootInvalidException ex) { - throw new GradleException( - "container.appRoot is not an absolute Unix-style path: " + ex.getInvalidAppRoot()); - } - } - - @Override - public DockerContextTask setJibExtension(JibExtension jibExtension) { - this.jibExtension = jibExtension; - return this; - } -} 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 eba9879645..aa9af4f1a6 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 @@ -39,7 +39,6 @@ public class JibPlugin implements Plugin { @VisibleForTesting static final String BUILD_IMAGE_TASK_NAME = "jib"; @VisibleForTesting static final String BUILD_TAR_TASK_NAME = "jibBuildTar"; @VisibleForTesting static final String BUILD_DOCKER_TASK_NAME = "jibDockerBuild"; - @VisibleForTesting static final String DOCKER_CONTEXT_TASK_NAME = "jibExportDockerContext"; @VisibleForTesting static final String FILES_TASK_NAME = "_jibSkaffoldFiles"; @VisibleForTesting static final String EXPLODED_WAR_TASK_NAME = "jibExplodedWar"; @@ -90,11 +89,6 @@ public void apply(Project project) { .getTasks() .create(BUILD_IMAGE_TASK_NAME, BuildImageTask.class) .setJibExtension(jibExtension); - Task dockerContextTask = - project - .getTasks() - .create(DOCKER_CONTEXT_TASK_NAME, DockerContextTask.class) - .setJibExtension(jibExtension); Task buildDockerTask = project .getTasks() @@ -130,7 +124,6 @@ public void apply(Project project) { dependsOnTask = projectAfterEvaluation.getTasks().getByPath("classes"); } buildImageTask.dependsOn(dependsOnTask); - dockerContextTask.dependsOn(dependsOnTask); buildDockerTask.dependsOn(dependsOnTask); buildTarTask.dependsOn(dependsOnTask); @@ -147,7 +140,6 @@ public void apply(Project project) { Task assembleTask = dependencyProject.getTasks().getByPath(BasePlugin.ASSEMBLE_TASK_NAME); buildImageTask.dependsOn(assembleTask); - dockerContextTask.dependsOn(assembleTask); buildDockerTask.dependsOn(assembleTask); buildTarTask.dependsOn(assembleTask); }); diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java deleted file mode 100644 index 5751127b2c..0000000000 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/DockerContextTaskTest.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.gradle; - -import com.google.cloud.tools.jib.plugins.common.MainClassInferenceException; -import com.google.common.collect.ImmutableMap; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import javax.annotation.Nullable; -import org.gradle.api.GradleException; -import org.gradle.api.Project; -import org.gradle.testfixtures.ProjectBuilder; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -/** Test for {@link DockerContextTask}. */ -@RunWith(MockitoJUnitRunner.class) -public class DockerContextTaskTest { - - @Rule public final TemporaryFolder projectRoot = new TemporaryFolder(); - - @Mock private ContainerParameters containerParameters; - @Mock private BaseImageParameters baseImageParameters; - @Mock private ExtraDirectoryParameters extraDirectoryParameters; - - private DockerContextTask task; - private Project project; - - @Before - public void setUp() throws IOException { - projectRoot.newFolder("build", "jib-exploded-war", "WEB-INF", "lib"); - projectRoot.newFolder("build", "jib-exploded-war", "WEB-INF", "classes"); - projectRoot.newFolder("build", "jib-docker-context"); - - JibExtension jibExtension = Mockito.mock(JibExtension.class); - Mockito.when(jibExtension.getContainer()).thenReturn(containerParameters); - Mockito.when(containerParameters.getEnvironment()) - .thenReturn(ImmutableMap.of("envKey", "envVal")); - Mockito.when(containerParameters.getMainClass()).thenReturn("MainClass"); - Mockito.when(containerParameters.getAppRoot()).thenReturn("/app"); - Mockito.when(containerParameters.getArgs()).thenCallRealMethod(); - - Mockito.when(jibExtension.getFrom()).thenReturn(baseImageParameters); - Mockito.when(baseImageParameters.getImage()).thenReturn("base image"); - - Mockito.when(jibExtension.getExtraDirectory()).thenReturn(extraDirectoryParameters); - Mockito.when(extraDirectoryParameters.getPath()) - .thenReturn(projectRoot.newFolder("src", "main", "jib").toPath()); - - project = ProjectBuilder.builder().withProjectDir(projectRoot.getRoot()).build(); - project.getPluginManager().apply("java"); - - task = project.getTasks().create("jibExportDockerContext", DockerContextTask.class); - task.setJibExtension(jibExtension); - } - - @Test - public void testEntrypoint() throws IOException, MainClassInferenceException { - task.generateDockerContext(); - - Assert.assertEquals( - "ENTRYPOINT [\"java\",\"-cp\",\"/app/resources:/app/classes:/app/libs/*\",\"MainClass\"]", - getDockerfileLine("ENTRYPOINT")); - } - - @Test - public void testEntrypoint_nonDefaultAppRoot() throws IOException, MainClassInferenceException { - Mockito.when(containerParameters.getAppRoot()).thenReturn("/"); - task.generateDockerContext(); - - Assert.assertEquals( - "ENTRYPOINT [\"java\",\"-cp\",\"/resources:/classes:/libs/*\",\"MainClass\"]", - getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testEntrypoint_inheritedEntrypoint() throws IOException, MainClassInferenceException { - Mockito.when(containerParameters.getAppRoot()).thenReturn("/"); - Mockito.when(containerParameters.getArgs()).thenCallRealMethod(); - project.getPluginManager().apply("war"); - - task.generateDockerContext(); - - Assert.assertNull(getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testUser() throws IOException, MainClassInferenceException { - Mockito.when(containerParameters.getUser()).thenReturn("tomcat"); - task.generateDockerContext(); - - Assert.assertEquals("USER tomcat", getDockerfileLine("USER")); - } - - @Test - public void testUser_null() throws IOException, MainClassInferenceException { - Mockito.when(containerParameters.getUser()).thenReturn(null); - task.generateDockerContext(); - Assert.assertNull(getDockerfileLine("USER")); - } - - @Test - public void testGenerateDockerContext_errorOnNonAbsoluteAppRoot() - throws MainClassInferenceException { - Mockito.when(containerParameters.getAppRoot()).thenReturn("relative/path"); - - try { - task.generateDockerContext(); - Assert.fail(); - } catch (GradleException ex) { - Assert.assertEquals( - "container.appRoot is not an absolute Unix-style path: relative/path", ex.getMessage()); - } - } - - @Test - public void testGenerateDockerContext_errorOnWindowsAppRoot() throws MainClassInferenceException { - Mockito.when(containerParameters.getAppRoot()).thenReturn("\\windows\\path"); - - try { - task.generateDockerContext(); - Assert.fail(); - } catch (GradleException ex) { - Assert.assertEquals( - "container.appRoot is not an absolute Unix-style path: \\windows\\path", ex.getMessage()); - } - } - - @Test - public void testGenerateDockerContext_errorOnWindowsAppRootWithDriveLetter() - throws MainClassInferenceException { - Mockito.when(containerParameters.getAppRoot()).thenReturn("C:\\windows\\path"); - - try { - task.generateDockerContext(); - Assert.fail(); - } catch (GradleException ex) { - Assert.assertEquals( - "container.appRoot is not an absolute Unix-style path: C:\\windows\\path", - ex.getMessage()); - } - } - - @Test - public void testGenerateDockerContext_env() throws IOException, MainClassInferenceException { - task.generateDockerContext(); - Assert.assertEquals("ENV envKey=\"envVal\"", getDockerfileLine("ENV")); - } - - @Nullable - private String getDockerfileLine(String command) throws IOException { - Path dockerfile = projectRoot.getRoot().toPath().resolve("build/jib-docker-context/Dockerfile"); - List lines = Files.readAllLines(dockerfile); - return lines.stream().filter(line -> line.startsWith(command)).findFirst().orElse(null); - } -} 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 ffdf955094..060862c50f 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 @@ -46,7 +46,6 @@ public class JibPluginTest { ImmutableList.of( JibPlugin.BUILD_IMAGE_TASK_NAME, JibPlugin.BUILD_DOCKER_TASK_NAME, - JibPlugin.DOCKER_CONTEXT_TASK_NAME, JibPlugin.BUILD_TAR_TASK_NAME); @Rule public final TemporaryFolder testProjectRoot = new TemporaryFolder(); @@ -140,18 +139,17 @@ public void testProjectDependencyAssembleTasksAreRun() { ((ProjectInternal) rootProject).evaluate(); 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())); - }); + 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()))); } @Test @@ -193,14 +191,6 @@ public void testWebAppProject() { .getDependsOn() .iterator() .next()); - Assert.assertEquals( - explodedWarTask, - rootProject - .getTasks() - .getByPath(JibPlugin.DOCKER_CONTEXT_TASK_NAME) - .getDependsOn() - .iterator() - .next()); } @Test diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/TestProject.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/TestProject.java index 536024bb53..fd3b39fc76 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/TestProject.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/TestProject.java @@ -39,7 +39,6 @@ private static void copyProject(String projectName, Path destination) throws IOException, URISyntaxException { Path projectPathInResources = Paths.get(Resources.getResource(PROJECTS_PATH_IN_RESOURCES + projectName).toURI()); - // TODO: Consolidate with DockerContextMojo#copyFiles. new DirectoryWalker(projectPathInResources) .filterRoot() .walk( diff --git a/jib-maven-plugin/CHANGELOG.md b/jib-maven-plugin/CHANGELOG.md index 126a831001..fa0332dcd4 100644 --- a/jib-maven-plugin/CHANGELOG.md +++ b/jib-maven-plugin/CHANGELOG.md @@ -9,6 +9,8 @@ All notable changes to this project will be documented in this file. ### Changed +- Removed `jib:exportDockerContext` goal ([#1219](https://github.com/GoogleContainerTools/jib/issues/1219)) + ### Fixed - NullPointerException thrown with incomplete `auth` configuration ([#1177](https://github.com/GoogleContainerTools/jib/issues/1177)) diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/DockerContextMojo.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/DockerContextMojo.java deleted file mode 100644 index 6d9c783726..0000000000 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/DockerContextMojo.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.maven; - -import com.google.cloud.tools.jib.event.DefaultEventDispatcher; -import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; -import com.google.cloud.tools.jib.frontend.ExposedPortsParser; -import com.google.cloud.tools.jib.frontend.JavaDockerContextGenerator; -import com.google.cloud.tools.jib.global.JibSystemProperties; -import com.google.cloud.tools.jib.plugins.common.AppRootInvalidException; -import com.google.cloud.tools.jib.plugins.common.HelpfulSuggestions; -import com.google.cloud.tools.jib.plugins.common.MainClassInferenceException; -import com.google.cloud.tools.jib.plugins.common.PluginConfigurationProcessor; -import com.google.cloud.tools.jib.plugins.common.RawConfiguration; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Preconditions; -import com.google.common.io.InsecureRecursiveDeleteException; -import java.io.IOException; -import java.nio.file.Paths; -import java.util.List; -import javax.annotation.Nullable; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.plugins.annotations.Mojo; -import org.apache.maven.plugins.annotations.Parameter; -import org.apache.maven.plugins.annotations.ResolutionScope; - -/** Exports to a Docker context. */ -@Mojo( - name = DockerContextMojo.GOAL_NAME, - requiresDependencyResolution = ResolutionScope.RUNTIME_PLUS_SYSTEM) -public class DockerContextMojo extends JibPluginConfiguration { - - @VisibleForTesting static final String GOAL_NAME = "exportDockerContext"; - - @Nullable - @Parameter( - property = "jibTargetDir", - defaultValue = "${project.build.directory}/jib-docker-context", - required = true) - @VisibleForTesting - String targetDir; - - @Override - public void execute() throws MojoExecutionException { - Preconditions.checkNotNull(targetDir); - - if (isSkipped()) { - getLog().info("Skipping containerization because jib-maven-plugin: skip = true"); - return; - } - if ("pom".equals(getProject().getPackaging())) { - getLog().info("Skipping containerization because packaging is 'pom'..."); - return; - } - - try { - JibSystemProperties.checkHttpTimeoutProperty(); - AbsoluteUnixPath appRoot = MojoCommon.getAppRootChecked(this); - - MavenProjectProperties projectProperties = - MavenProjectProperties.getForProject( - getProject(), - getLog(), - MojoCommon.getExtraDirectoryPath(this), - MojoCommon.convertPermissionsList(getExtraDirectoryPermissions()), - appRoot); - DefaultEventDispatcher eventDispatcher = - new DefaultEventDispatcher(projectProperties.getEventHandlers()); - RawConfiguration rawConfiguration = new MavenRawConfiguration(this, eventDispatcher); - - List entrypoint = - PluginConfigurationProcessor.computeEntrypoint(rawConfiguration, projectProperties); - String baseImage = - PluginConfigurationProcessor.getBaseImage(rawConfiguration, projectProperties); - - // Validate port input, but don't save the output because we don't want the ranges expanded - // here. - ExposedPortsParser.parse(getExposedPorts()); - - new JavaDockerContextGenerator(projectProperties.getJavaLayerConfigurations()) - .setBaseImage(baseImage) - .setEntrypoint(entrypoint) - .setProgramArguments(getArgs()) - .setExposedPorts(getExposedPorts()) - .setEnvironment(getEnvironment()) - .setLabels(getLabels()) - .setUser(getUser()) - .generate(Paths.get(targetDir)); - - getLog().info("Created Docker context at " + targetDir); - - } catch (InsecureRecursiveDeleteException ex) { - throw new MojoExecutionException( - HelpfulSuggestions.forDockerContextInsecureRecursiveDelete( - "Export Docker context failed because cannot clear directory '" - + targetDir - + "' safely", - targetDir), - ex); - - } catch (IOException ex) { - throw new MojoExecutionException( - HelpfulSuggestions.suggest( - "Export Docker context failed", "check if `targetDir` is set correctly"), - ex); - - } catch (AppRootInvalidException ex) { - throw new MojoExecutionException( - " is not an absolute Unix-style path: " + ex.getInvalidAppRoot()); - - } catch (MainClassInferenceException ex) { - throw new MojoExecutionException(ex.getMessage(), ex); - } - } -} diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoIntegrationTest.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoIntegrationTest.java deleted file mode 100644 index 2a3849a1f4..0000000000 --- a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoIntegrationTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.maven; - -import com.google.cloud.tools.jib.Command; -import java.io.IOException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Arrays; -import javax.annotation.Nullable; -import org.apache.maven.it.VerificationException; -import org.apache.maven.it.Verifier; -import org.hamcrest.CoreMatchers; -import org.junit.After; -import org.junit.Assert; -import org.junit.ClassRule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.junit.MockitoJUnitRunner; - -/** Integration tests for {@link DockerContextMojo}. */ -@RunWith(MockitoJUnitRunner.class) -public class DockerContextMojoIntegrationTest { - - @ClassRule public static final TestPlugin testPlugin = new TestPlugin(); - - @ClassRule - public static final TestProject simpleTestProject = new TestProject(testPlugin, "simple"); - - @ClassRule - public static final TestProject skippedTestProject = new TestProject(testPlugin, "empty"); - - @ClassRule - public static final TestProject servlet25Project = new TestProject(testPlugin, "war_servlet25"); - - @Nullable private String detachedContainerName; - - @After - public void tearDown() throws IOException, InterruptedException { - if (detachedContainerName != null) { - new Command("docker", "stop", detachedContainerName).run(); - } - } - - @Test - public void testExecute() throws VerificationException, IOException, InterruptedException { - Verifier verifier = new Verifier(simpleTestProject.getProjectRoot().toString()); - verifier.setAutoclean(false); - verifier.executeGoal("compile"); - verifier.executeGoal("jib:" + DockerContextMojo.GOAL_NAME); - - Path dockerContextDirectory = - simpleTestProject.getProjectRoot().resolve("target").resolve("jib-docker-context"); - Assert.assertTrue(Files.exists(dockerContextDirectory)); - - String imageName = "jib/integration-test" + System.nanoTime(); - new Command("docker", "build", "-t", imageName, dockerContextDirectory.toString()).run(); - String dockerInspect = new Command("docker", "inspect", imageName).run(); - Assert.assertThat( - dockerInspect, - CoreMatchers.containsString( - " \"ExposedPorts\": {\n" - + " \"1000/tcp\": {},\n" - + " \"2000/udp\": {},\n" - + " \"2001/udp\": {},\n" - + " \"2002/udp\": {},\n" - + " \"2003/udp\": {}")); - Assert.assertThat( - dockerInspect, - CoreMatchers.containsString( - " \"Labels\": {\n" - + " \"key1\": \"value1\",\n" - + " \"key2\": \"value2\"\n" - + " }")); - - String output = new Command("docker", "run", "--rm", imageName).run(); - Assert.assertThat(output, CoreMatchers.startsWith("Hello, world. An argument.\n")); - Assert.assertThat(output, CoreMatchers.endsWith("foo\ncat\n")); - } - - @Test - public void testExecute_skipJibGoal() throws VerificationException, IOException { - SkippedGoalVerifier.verifyGoalIsSkipped(skippedTestProject, BuildDockerMojo.GOAL_NAME); - } - - @Test - public void testExecute_jettyServlet25() - throws VerificationException, IOException, InterruptedException { - String expectedDockerfile = - "FROM gcr.io/distroless/java/jetty\n" - + "\n" - + "COPY libs /\n" - + "COPY resources /\n" - + "COPY classes /"; - verifyWarBuildAndRun(expectedDockerfile, "pom.xml"); - } - - @Test - public void testExecute_tomcatServlet25() - throws VerificationException, IOException, InterruptedException { - String expectedDockerfile = - "FROM tomcat:8.5-jre8-alpine\n" - + "\n" - + "COPY libs /\n" - + "COPY resources /\n" - + "COPY classes /"; - verifyWarBuildAndRun(expectedDockerfile, "pom-tomcat.xml"); - } - - private void verifyWarBuildAndRun(String expectedDockerfile, String pomXml) - throws VerificationException, IOException, InterruptedException { - Verifier verifier = new Verifier(servlet25Project.getProjectRoot().toString()); - verifier.setAutoclean(false); - verifier.addCliOption("--file=" + pomXml); - verifier.executeGoals(Arrays.asList("clean", "package", "jib:exportDockerContext")); - - Path dockerContext = - servlet25Project.getProjectRoot().resolve("target").resolve("jib-docker-context"); - Assert.assertTrue(Files.exists(dockerContext)); - String dockerfile = String.join("\n", Files.readAllLines(dockerContext.resolve("Dockerfile"))); - Assert.assertEquals(expectedDockerfile, dockerfile); - - String imageName = "jib/integration-test" + System.nanoTime(); - new Command("docker", "build", "-t", imageName, dockerContext.toString()).run(); - detachedContainerName = - new Command("docker", "run", "--rm", "--detach", "-p8080:8080", imageName).run().trim(); - - HttpGetVerifier.verifyBody("Hello world", new URL("http://localhost:8080/hello")); - } -} diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoTest.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoTest.java deleted file mode 100644 index c7d078e6e1..0000000000 --- a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/DockerContextMojoTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright 2018 Google LLC. - * - * 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 com.google.cloud.tools.jib.maven; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import javax.annotation.Nullable; -import org.apache.maven.execution.MavenSession; -import org.apache.maven.model.Build; -import org.apache.maven.plugin.MojoExecutionException; -import org.apache.maven.project.MavenProject; -import org.apache.maven.settings.crypto.SettingsDecrypter; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.TemporaryFolder; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; - -/** Tests for {@link DockerContextMojo}. */ -@RunWith(MockitoJUnitRunner.class) -public class DockerContextMojoTest { - - @Rule public final TemporaryFolder projectRoot = new TemporaryFolder(); - - @Mock private MavenProject project; - @Mock private Build build; - - private DockerContextMojo mojo; - private String appRoot = "/app"; - private File outputFolder; - - @Before - public void setUp() throws IOException { - outputFolder = projectRoot.newFolder("target"); - Mockito.when(project.getBuild()).thenReturn(build); - Mockito.when(project.getBasedir()).thenReturn(projectRoot.getRoot()); - Mockito.when(build.getOutputDirectory()).thenReturn(outputFolder.toString()); - - mojo = new BaseDockerContextMojo(); - mojo.targetDir = outputFolder.toString(); - } - - @Test - public void testEntrypoint() throws MojoExecutionException, IOException { - mojo.execute(); - - Assert.assertEquals( - "ENTRYPOINT [\"java\",\"-cp\",\"/app/resources:/app/classes:/app/libs/*\",\"MainClass\"]", - getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testEntrypoint_nonDefaultAppRoot() throws MojoExecutionException, IOException { - appRoot = "/"; - mojo.execute(); - - Assert.assertEquals( - "ENTRYPOINT [\"java\",\"-cp\",\"/resources:/classes:/libs/*\",\"MainClass\"]", - getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testGenerateDockerContext_errorOnNonAbsoluteAppRoot() { - appRoot = "relative/path"; - try { - mojo.execute(); - Assert.fail(); - } catch (MojoExecutionException ex) { - Assert.assertEquals( - " is not an absolute Unix-style path: relative/path", - ex.getMessage()); - } - } - - @Test - public void testGenerateDockerContext_errorOnWindowsAppRoot() { - appRoot = "\\windows\\path"; - try { - mojo.execute(); - Assert.fail(); - } catch (MojoExecutionException ex) { - Assert.assertEquals( - " is not an absolute Unix-style path: \\windows\\path", - ex.getMessage()); - } - } - - @Test - public void testGenerateDockerContext_errorOnWindowsAppRootWithDriveLetter() { - appRoot = "C:\\windows\\path"; - try { - mojo.execute(); - Assert.fail(); - } catch (MojoExecutionException ex) { - Assert.assertEquals( - " is not an absolute Unix-style path: C:\\windows\\path", - ex.getMessage()); - } - } - - @Test - public void testGeneratedDockerContext_env() throws MojoExecutionException, IOException { - mojo.execute(); - Assert.assertEquals("ENV envKey=\"envVal\"", getDockerfileLine("ENV")); - } - - public void testBaseImage_nonWarPackaging() throws MojoExecutionException, IOException { - mojo.execute(); - - Assert.assertEquals("FROM gcr.io/distroless/java", getDockerfileLine("FROM")); - } - - @Test - public void testBaseImage_warPackaging() throws MojoExecutionException, IOException { - Mockito.doReturn("war").when(project).getPackaging(); - Mockito.doReturn("final-name").when(build).getFinalName(); - projectRoot.newFolder("final-name", "WEB-INF", "lib"); - projectRoot.newFolder("final-name", "WEB-INF", "classes"); - Mockito.doReturn(projectRoot.getRoot().toString()).when(build).getDirectory(); - mojo.execute(); - - Assert.assertEquals("FROM gcr.io/distroless/java/jetty", getDockerfileLine("FROM")); - } - - @Test - public void testBaseImage_nonDefault() throws MojoExecutionException, IOException { - Mockito.doReturn("war").when(project).getPackaging(); - Mockito.doReturn("final-name").when(build).getFinalName(); - mojo = - new BaseDockerContextMojo() { - @Override - String getBaseImage() { - return "tomcat:8.5-jre8-alpine"; - } - }; - mojo.targetDir = outputFolder.toString(); - - projectRoot.newFolder("final-name", "WEB-INF", "lib"); - projectRoot.newFolder("final-name", "WEB-INF", "classes"); - Mockito.doReturn(projectRoot.getRoot().toString()).when(build).getDirectory(); - mojo.execute(); - - Assert.assertEquals("FROM tomcat:8.5-jre8-alpine", getDockerfileLine("FROM")); - } - - @Test - public void testEntrypoint_defaultWarPackaging() throws MojoExecutionException, IOException { - Mockito.doReturn("war").when(project).getPackaging(); - Mockito.doReturn("final-name").when(build).getFinalName(); - projectRoot.newFolder("final-name", "WEB-INF", "lib"); - projectRoot.newFolder("final-name", "WEB-INF", "classes"); - Mockito.doReturn(projectRoot.getRoot().toString()).when(build).getDirectory(); - mojo.execute(); - - Assert.assertNull(getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testEntrypoint_warPackaging() throws MojoExecutionException, IOException { - Mockito.doReturn("war").when(project).getPackaging(); - Mockito.doReturn("final-name").when(build).getFinalName(); - projectRoot.newFolder("final-name", "WEB-INF", "lib"); - projectRoot.newFolder("final-name", "WEB-INF", "classes"); - Mockito.doReturn(projectRoot.getRoot().toString()).when(build).getDirectory(); - mojo = - new BaseDockerContextMojo() { - @Override - List getEntrypoint() { - return ImmutableList.of("catalina.sh", "run"); - } - }; - mojo.targetDir = outputFolder.toString(); - mojo.execute(); - Assert.assertEquals("ENTRYPOINT [\"catalina.sh\",\"run\"]", getDockerfileLine("ENTRYPOINT")); - Assert.assertNull(getDockerfileLine("CMD")); - } - - @Test - public void testUser() throws IOException, MojoExecutionException { - mojo = - new BaseDockerContextMojo() { - @Override - String getUser() { - return "tomcat"; - } - }; - mojo.targetDir = outputFolder.toString(); - mojo.execute(); - Assert.assertEquals("USER tomcat", getDockerfileLine("USER")); - } - - @Test - public void testUser_null() throws IOException, MojoExecutionException { - mojo = new BaseDockerContextMojo(); - mojo.targetDir = outputFolder.toString(); - mojo.execute(); - Assert.assertNull(getDockerfileLine("USER")); - } - - private class BaseDockerContextMojo extends DockerContextMojo { - - @Override - MavenProject getProject() { - return project; - } - - @Override - Optional getExtraDirectoryPath() { - return Optional.of(projectRoot.getRoot().toPath()); - } - - @Override - String getMainClass() { - return "MainClass"; - } - - @Override - String getAppRoot() { - return appRoot; - } - - @Override - Map getEnvironment() { - return ImmutableMap.of("envKey", "envVal"); - } - - @Override - MavenSession getSession() { - return Mockito.mock(MavenSession.class); - } - - @Override - SettingsDecrypter getSettingsDecrypter() { - return Mockito.mock(SettingsDecrypter.class); - } - } - - @Nullable - private String getDockerfileLine(String command) throws IOException { - Path dockerfile = projectRoot.getRoot().toPath().resolve("target/Dockerfile"); - List lines = Files.readAllLines(dockerfile); - return lines.stream().filter(line -> line.startsWith(command)).findFirst().orElse(null); - } -}