diff --git a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java index 0e49e8fa68..0320e4d851 100644 --- a/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java +++ b/jib-core/src/integration-test/java/com/google/cloud/tools/jib/builder/BuildStepsIntegrationTest.java @@ -54,7 +54,13 @@ public class BuildStepsIntegrationTest { @Before public void setUp() throws IOException, URISyntaxException { - sourceFilesConfiguration = new TestSourceFilesConfiguration(); + sourceFilesConfiguration = + TestSourceFilesConfiguration.builder() + .withClasses() + .withDependencies() + .withSnapshotDependencies() + .withResources() + .build(); } @Test diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/SourceFilesConfiguration.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/SourceFilesConfiguration.java index 15de722be6..695227c751 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/SourceFilesConfiguration.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/SourceFilesConfiguration.java @@ -35,6 +35,12 @@ public interface SourceFilesConfiguration { */ ImmutableList getDependenciesFiles(); + /** + * @return the source files for snapshot dependencies. These files should be in a deterministic + * order + */ + ImmutableList getSnapshotDependenciesFiles(); + /** * @return the source files for the resources layer. These files should be in a deterministic * order. @@ -48,7 +54,7 @@ public interface SourceFilesConfiguration { /** * @return the Unix-style path where the dependencies source files are placed in the container - * filesystem. Must end with slash. + * filesystem. Must end with slash. This includes both regular and snapshot dependencies. */ String getDependenciesPathOnImage(); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStep.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStep.java index bff71a426b..0536ea01f6 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStep.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStep.java @@ -86,6 +86,20 @@ static ImmutableList makeList( .build(), cache)); + // Adds a snapshot dependencies layer, if snapshot files present. + if (!sourceFilesConfiguration.getSnapshotDependenciesFiles().isEmpty()) { + buildLayerStepsBuilder.add( + new BuildAndCacheApplicationLayerStep( + "snapshot-dependencies", + listeningExecutorService, + buildConfiguration, + LayerConfiguration.builder() + .addEntry( + sourceFilesConfiguration.getSnapshotDependenciesFiles(), + sourceFilesConfiguration.getDependenciesPathOnImage()) + .build(), + cache)); + } // Adds the extra layer to be built, if configured. if (buildConfiguration.getExtraFilesLayerConfiguration() != null) { buildLayerStepsBuilder.add( diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java index 91bbafd809..83275229f2 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/docker/DockerContextGenerator.java @@ -136,14 +136,18 @@ public void generate(Path targetDirectory) throws IOException { // Creates the directories. Path dependenciesDir = targetDirectory.resolve("libs"); + Path snapshotDependenciesDir = targetDirectory.resolve("snapshot-libs"); Path resourcesDIr = targetDirectory.resolve("resources"); Path classesDir = targetDirectory.resolve("classes"); Files.createDirectory(dependenciesDir); + Files.createDirectories(snapshotDependenciesDir); Files.createDirectory(resourcesDIr); Files.createDirectory(classesDir); // Copies dependencies. FileOperations.copy(sourceFilesConfiguration.getDependenciesFiles(), dependenciesDir); + FileOperations.copy( + sourceFilesConfiguration.getSnapshotDependenciesFiles(), snapshotDependenciesDir); FileOperations.copy(sourceFilesConfiguration.getResourcesFiles(), resourcesDIr); FileOperations.copy(sourceFilesConfiguration.getClassesFiles(), classesDir); @@ -179,6 +183,8 @@ String makeDockerfile() throws JsonProcessingException { .append(Preconditions.checkNotNull(baseImage)) .append("\n\nCOPY libs ") .append(sourceFilesConfiguration.getDependenciesPathOnImage()) + .append("\nCOPY snapshot-libs ") + .append(sourceFilesConfiguration.getDependenciesPathOnImage()) .append("\nCOPY resources ") .append(sourceFilesConfiguration.getResourcesPathOnImage()) .append("\nCOPY classes ") diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/TestSourceFilesConfiguration.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/TestSourceFilesConfiguration.java index 49d27ce489..33396e3295 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/TestSourceFilesConfiguration.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/TestSourceFilesConfiguration.java @@ -28,16 +28,70 @@ /** Implementation of {@link SourceFilesConfiguration} that uses test resources. */ public class TestSourceFilesConfiguration implements SourceFilesConfiguration { + public static class Builder { + private ImmutableList dependenciesSourceFiles = ImmutableList.of(); + private ImmutableList snapshotDependenciesSourceFiles = ImmutableList.of(); + private ImmutableList resourcesSourceFiles = ImmutableList.of(); + private ImmutableList classesSourceFiles = ImmutableList.of(); + + public Builder withDependencies() throws IOException, URISyntaxException { + dependenciesSourceFiles = getFilesList("application/dependencies"); + return this; + } + + public Builder withSnapshotDependencies() throws IOException, URISyntaxException { + snapshotDependenciesSourceFiles = getFilesList("application/snapshot-dependencies"); + return this; + } + + public Builder withResources() throws IOException, URISyntaxException { + resourcesSourceFiles = getFilesList("application/resources"); + return this; + } + + public Builder withClasses() throws IOException, URISyntaxException { + classesSourceFiles = getFilesList("application/classes"); + return this; + } + + public TestSourceFilesConfiguration build() { + return new TestSourceFilesConfiguration( + dependenciesSourceFiles, + snapshotDependenciesSourceFiles, + resourcesSourceFiles, + classesSourceFiles); + } + + /** Lists the files in the {@code resourcePath} resources directory. */ + private ImmutableList getFilesList(String resourcePath) + throws URISyntaxException, IOException { + try (Stream fileStream = + Files.list(Paths.get(Resources.getResource(resourcePath).toURI()))) { + return fileStream.collect(ImmutableList.toImmutableList()); + } + } + } + + public static Builder builder() { + return new Builder(); + } + private static final String EXTRACTION_PATH = "/some/extraction/path/"; private final ImmutableList dependenciesSourceFiles; + private final ImmutableList snapshotDependenciesSourceFiles; private final ImmutableList resourcesSourceFiles; private final ImmutableList classesSourceFiles; - public TestSourceFilesConfiguration() throws URISyntaxException, IOException { - dependenciesSourceFiles = getFilesList("application/dependencies"); - resourcesSourceFiles = getFilesList("application/resources"); - classesSourceFiles = getFilesList("application/classes"); + private TestSourceFilesConfiguration( + ImmutableList dependenciesSourceFiles, + ImmutableList snapshotDependenciesSourceFiles, + ImmutableList resourcesSourceFiles, + ImmutableList classesSourceFiles) { + this.dependenciesSourceFiles = dependenciesSourceFiles; + this.snapshotDependenciesSourceFiles = snapshotDependenciesSourceFiles; + this.resourcesSourceFiles = resourcesSourceFiles; + this.classesSourceFiles = classesSourceFiles; } @Override @@ -45,6 +99,11 @@ public ImmutableList getDependenciesFiles() { return dependenciesSourceFiles; } + @Override + public ImmutableList getSnapshotDependenciesFiles() { + return snapshotDependenciesSourceFiles; + } + @Override public ImmutableList getResourcesFiles() { return resourcesSourceFiles; @@ -69,13 +128,4 @@ public String getResourcesPathOnImage() { public String getClassesPathOnImage() { return EXTRACTION_PATH + "classes/"; } - - /** Lists the files in the {@code resourcePath} resources directory. */ - private ImmutableList getFilesList(String resourcePath) - throws URISyntaxException, IOException { - try (Stream fileStream = - Files.list(Paths.get(Resources.getResource(resourcePath).toURI()))) { - return fileStream.collect(ImmutableList.toImmutableList()); - } - } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStepTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStepTest.java index 0c2049f855..eacaf0659b 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStepTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildAndCacheApplicationLayerStepTest.java @@ -18,6 +18,7 @@ import com.google.cloud.tools.jib.async.NonBlockingSteps; import com.google.cloud.tools.jib.builder.BuildConfiguration; +import com.google.cloud.tools.jib.builder.SourceFilesConfiguration; import com.google.cloud.tools.jib.builder.TestBuildLogger; import com.google.cloud.tools.jib.builder.TestSourceFilesConfiguration; import com.google.cloud.tools.jib.cache.Cache; @@ -37,6 +38,7 @@ import java.nio.file.Paths; import java.util.concurrent.ExecutionException; import org.junit.Assert; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; @@ -49,30 +51,35 @@ @RunWith(MockitoJUnitRunner.class) public class BuildAndCacheApplicationLayerStepTest { + private static final String EXTRA_FILES_LAYER_EXTRACTION_PATH = "/extra"; + @Rule public TemporaryFolder temporaryFolder = new TemporaryFolder(); @Mock private BuildConfiguration mockBuildConfiguration; + private Path temporaryCacheDirectory; - @Test - public void testRun() - throws LayerPropertyNotFoundException, IOException, CacheMetadataCorruptedException, - URISyntaxException, ExecutionException { + @Before + public void setUp() throws IOException, URISyntaxException { Mockito.when(mockBuildConfiguration.getBuildLogger()).thenReturn(new TestBuildLogger()); - TestSourceFilesConfiguration testSourceFilesConfiguration = new TestSourceFilesConfiguration(); - Path temporaryCacheDirectory = temporaryFolder.newFolder().toPath(); + temporaryCacheDirectory = temporaryFolder.newFolder().toPath(); + } - // Adds an extra file layer. + private ImmutableList configureExtraFilesLayer() throws URISyntaxException { ImmutableList extraFilesLayerSourceFiles = ImmutableList.of( Paths.get(Resources.getResource("fileA").toURI()), Paths.get(Resources.getResource("fileB").toURI())); - String extraFilesLayerExtractionPath = "/extra"; Mockito.when(mockBuildConfiguration.getExtraFilesLayerConfiguration()) .thenReturn( LayerConfiguration.builder() - .addEntry(extraFilesLayerSourceFiles, extraFilesLayerExtractionPath) + .addEntry(extraFilesLayerSourceFiles, EXTRA_FILES_LAYER_EXTRACTION_PATH) .build()); + return extraFilesLayerSourceFiles; + } + private ImageLayers configureAvailableLayers( + SourceFilesConfiguration testSourceFilesConfiguration) + throws CacheMetadataCorruptedException, IOException, ExecutionException { ImageLayers.Builder applicationLayersBuilder = ImageLayers.builder(); ImageLayers applicationLayers; @@ -91,8 +98,30 @@ public void testRun() applicationLayers = applicationLayersBuilder.build(); cache.addCachedLayersWithMetadataToMetadata(applicationLayers.getLayers()); - Assert.assertEquals(4, applicationLayers.size()); } + return applicationLayers; + } + + @Test + public void testRun() + throws LayerPropertyNotFoundException, IOException, CacheMetadataCorruptedException, + URISyntaxException, ExecutionException { + + TestSourceFilesConfiguration testSourceFilesConfiguration = + TestSourceFilesConfiguration.builder() + .withDependencies() + .withSnapshotDependencies() + .withClasses() + .withResources() + .build(); + + // Adds an extra file layer. + ImmutableList extraFilesLayerSourceFiles = configureExtraFilesLayer(); + + // Populate the cache + ImageLayers applicationLayers = + configureAvailableLayers(testSourceFilesConfiguration); + Assert.assertEquals(5, applicationLayers.size()); // Re-initialize cache with the updated metadata. Cache cache = Cache.init(temporaryCacheDirectory); @@ -102,6 +131,11 @@ public void testRun() new LayerEntry( testSourceFilesConfiguration.getDependenciesFiles(), testSourceFilesConfiguration.getDependenciesPathOnImage())); + ImmutableList snapshotDependenciesLayerEntry = + ImmutableList.of( + new LayerEntry( + testSourceFilesConfiguration.getSnapshotDependenciesFiles(), + testSourceFilesConfiguration.getDependenciesPathOnImage())); ImmutableList resourcesLayerEntry = ImmutableList.of( new LayerEntry( @@ -113,7 +147,8 @@ public void testRun() testSourceFilesConfiguration.getClassesFiles(), testSourceFilesConfiguration.getClassesPathOnImage())); ImmutableList extraFilesLayerEntry = - ImmutableList.of(new LayerEntry(extraFilesLayerSourceFiles, extraFilesLayerExtractionPath)); + ImmutableList.of( + new LayerEntry(extraFilesLayerSourceFiles, EXTRA_FILES_LAYER_EXTRACTION_PATH)); // Verifies that the cached layers are up-to-date. CacheReader cacheReader = new CacheReader(cache); @@ -128,6 +163,11 @@ public void testRun() cacheReader.getUpToDateLayerByLayerEntries(classesLayerEntry).getBlobDescriptor()); Assert.assertEquals( applicationLayers.get(3).getBlobDescriptor(), + cacheReader + .getUpToDateLayerByLayerEntries(snapshotDependenciesLayerEntry) + .getBlobDescriptor()); + Assert.assertEquals( + applicationLayers.get(4).getBlobDescriptor(), cacheReader.getUpToDateLayerByLayerEntries(extraFilesLayerEntry).getBlobDescriptor()); // Verifies that the cache reader gets the same layers as the newest application layers. @@ -139,6 +179,66 @@ public void testRun() Assert.assertEquals( applicationLayers.get(2).getContentFile(), cacheReader.getLayerFile(classesLayerEntry)); Assert.assertEquals( - applicationLayers.get(3).getContentFile(), cacheReader.getLayerFile(extraFilesLayerEntry)); + applicationLayers.get(3).getContentFile(), + cacheReader.getLayerFile(snapshotDependenciesLayerEntry)); + Assert.assertEquals( + applicationLayers.get(4).getContentFile(), cacheReader.getLayerFile(extraFilesLayerEntry)); + } + + @Test + public void testRun_emptyLayersIgnored() + throws IOException, URISyntaxException, CacheMetadataCorruptedException, ExecutionException { + + TestSourceFilesConfiguration testSourceFilesConfiguration = + TestSourceFilesConfiguration.builder() + .withDependencies() + .withClasses() + .withResources() + .build(); + + // Populate the cache + ImageLayers applicationLayers = + configureAvailableLayers(testSourceFilesConfiguration); + Assert.assertEquals(3, applicationLayers.size()); + + ImmutableList dependenciesLayerEntry = + ImmutableList.of( + new LayerEntry( + testSourceFilesConfiguration.getDependenciesFiles(), + testSourceFilesConfiguration.getDependenciesPathOnImage())); + ImmutableList resourcesLayerEntry = + ImmutableList.of( + new LayerEntry( + testSourceFilesConfiguration.getResourcesFiles(), + testSourceFilesConfiguration.getResourcesPathOnImage())); + ImmutableList classesLayerEntry = + ImmutableList.of( + new LayerEntry( + testSourceFilesConfiguration.getClassesFiles(), + testSourceFilesConfiguration.getClassesPathOnImage())); + + // Re-initialize cache with the updated metadata. + Cache cache = Cache.init(temporaryCacheDirectory); + + // Verifies that the cached layers are up-to-date. + CacheReader cacheReader = new CacheReader(cache); + Assert.assertEquals( + applicationLayers.get(0).getBlobDescriptor(), + cacheReader.getUpToDateLayerByLayerEntries(dependenciesLayerEntry).getBlobDescriptor()); + Assert.assertEquals( + applicationLayers.get(1).getBlobDescriptor(), + cacheReader.getUpToDateLayerByLayerEntries(resourcesLayerEntry).getBlobDescriptor()); + Assert.assertEquals( + applicationLayers.get(2).getBlobDescriptor(), + cacheReader.getUpToDateLayerByLayerEntries(classesLayerEntry).getBlobDescriptor()); + + // Verifies that the cache reader gets the same layers as the newest application layers. + Assert.assertEquals( + applicationLayers.get(0).getContentFile(), + cacheReader.getLayerFile(dependenciesLayerEntry)); + Assert.assertEquals( + applicationLayers.get(1).getContentFile(), cacheReader.getLayerFile(resourcesLayerEntry)); + Assert.assertEquals( + applicationLayers.get(2).getContentFile(), cacheReader.getLayerFile(classesLayerEntry)); } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java index 89ac1936eb..8dc223fba9 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/docker/DockerContextGeneratorTest.java @@ -79,16 +79,22 @@ public void setUpMocks() { @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()); ImmutableList expectedDependenciesFiles = new DirectoryWalker(testDependencies).filterRoot().walk(); + ImmutableList expectedSnapshotDependenciesFiles = + new DirectoryWalker(testSnapshotDependencies).filterRoot().walk(); ImmutableList expectedResourcesFiles = new DirectoryWalker(testResources).filterRoot().walk(); ImmutableList expectedClassesFiles = new DirectoryWalker(testClasses).filterRoot().walk(); Mockito.when(mockSourceFilesConfiguration.getDependenciesFiles()) .thenReturn(expectedDependenciesFiles); + Mockito.when(mockSourceFilesConfiguration.getSnapshotDependenciesFiles()) + .thenReturn(expectedSnapshotDependenciesFiles); Mockito.when(mockSourceFilesConfiguration.getResourcesFiles()) .thenReturn(expectedResourcesFiles); Mockito.when(mockSourceFilesConfiguration.getClassesFiles()).thenReturn(expectedClassesFiles); @@ -107,6 +113,7 @@ public void testGenerate() throws IOException, URISyntaxException { Assert.assertTrue(Files.exists(targetDirectory.resolve("Dockerfile"))); assertSameFiles(targetDirectory.resolve("libs"), testDependencies); + assertSameFiles(targetDirectory.resolve("snapshot-libs"), testSnapshotDependencies); assertSameFiles(targetDirectory.resolve("resources"), testResources); assertSameFiles(targetDirectory.resolve("classes"), testClasses); } diff --git a/jib-core/src/test/resources/application/snapshot-dependencies/dependency-1.0.0-SNAPSHOT.jar b/jib-core/src/test/resources/application/snapshot-dependencies/dependency-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000..dd68926802 Binary files /dev/null and b/jib-core/src/test/resources/application/snapshot-dependencies/dependency-1.0.0-SNAPSHOT.jar differ diff --git a/jib-core/src/test/resources/sampleDockerfile b/jib-core/src/test/resources/sampleDockerfile index 73d372b6d0..474ea0c4e2 100644 --- a/jib-core/src/test/resources/sampleDockerfile +++ b/jib-core/src/test/resources/sampleDockerfile @@ -1,6 +1,7 @@ FROM somebaseimage COPY libs /app/libs/ +COPY snapshot-libs /app/libs/ COPY resources /app/resources/ COPY classes /app/classes/ diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index c3426cb817..16093e1766 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [unreleased] ### Added +- Snapshot dependencies are added as their own layer ([#584](https://github.com/GoogleContainerTools/jib/pull/584)) ### Changed diff --git a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfiguration.java b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfiguration.java index 1f22997656..56397b79b9 100644 --- a/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfiguration.java +++ b/jib-gradle-plugin/src/main/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfiguration.java @@ -43,6 +43,7 @@ static GradleSourceFilesConfiguration getForProject( } private final ImmutableList dependenciesFiles; + private final ImmutableList snapshotDependenciesFiles; private final ImmutableList resourcesFiles; private final ImmutableList classesFiles; @@ -55,6 +56,7 @@ private GradleSourceFilesConfiguration(Project project, GradleBuildLogger gradle SourceSet mainSourceSet = javaPluginConvention.getSourceSets().getByName(MAIN_SOURCE_SET_NAME); List dependenciesFiles = new ArrayList<>(); + List snapshotDependenciesFiles = new ArrayList<>(); List resourcesFiles = new ArrayList<>(); List classesFiles = new ArrayList<>(); @@ -92,11 +94,16 @@ private GradleSourceFilesConfiguration(Project project, GradleBuildLogger gradle if (resourcesOutputDirectory.equals(dependencyFile.toPath())) { continue; } - dependenciesFiles.add(dependencyFile.toPath()); + if (dependencyFile.getName().contains("SNAPSHOT")) { + snapshotDependenciesFiles.add(dependencyFile.toPath()); + } else { + dependenciesFiles.add(dependencyFile.toPath()); + } } // Sorts all files by path for consistent ordering. this.dependenciesFiles = ImmutableList.sortedCopyOf(dependenciesFiles); + this.snapshotDependenciesFiles = ImmutableList.sortedCopyOf(snapshotDependenciesFiles); this.resourcesFiles = ImmutableList.sortedCopyOf(resourcesFiles); this.classesFiles = ImmutableList.sortedCopyOf(classesFiles); } @@ -106,6 +113,11 @@ public ImmutableList getDependenciesFiles() { return dependenciesFiles; } + @Override + public ImmutableList getSnapshotDependenciesFiles() { + return snapshotDependenciesFiles; + } + @Override public ImmutableList getResourcesFiles() { return resourcesFiles; diff --git a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfigurationTest.java b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfigurationTest.java index 54376a14c5..cd70617596 100644 --- a/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfigurationTest.java +++ b/jib-gradle-plugin/src/test/java/com/google/cloud/tools/jib/gradle/GradleSourceFilesConfigurationTest.java @@ -93,6 +93,11 @@ public void setUp() throws URISyntaxException, IOException { allFiles.add( Paths.get(Resources.getResource("application/dependencies/dependency-1.0.0.jar").toURI()) .toFile()); + allFiles.add( + Paths.get( + Resources.getResource("application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar") + .toURI()) + .toFile()); FileCollection runtimeFileCollection = new TestFileCollection(allFiles); Mockito.when(mockProject.getConvention()).thenReturn(mockConvention); @@ -117,6 +122,11 @@ public void test_correctFiles() throws URISyntaxException { Resources.getResource("application/dependencies/dependency-1.0.0.jar").toURI()), Paths.get(Resources.getResource("application/dependencies/libraryA.jar").toURI()), Paths.get(Resources.getResource("application/dependencies/libraryB.jar").toURI())); + ImmutableList expectedSnapshotDependenciesFiles = + ImmutableList.of( + Paths.get( + Resources.getResource("application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar") + .toURI())); ImmutableList expectedResourcesFiles = ImmutableList.of( Paths.get(Resources.getResource("application/resources").toURI()).resolve("resourceA"), @@ -130,6 +140,9 @@ public void test_correctFiles() throws URISyntaxException { Assert.assertEquals( expectedDependenciesFiles, testGradleSourceFilesConfiguration.getDependenciesFiles()); + Assert.assertEquals( + expectedSnapshotDependenciesFiles, + testGradleSourceFilesConfiguration.getSnapshotDependenciesFiles()); Assert.assertEquals( expectedResourcesFiles, testGradleSourceFilesConfiguration.getResourcesFiles()); Assert.assertEquals(expectedClassesFiles, testGradleSourceFilesConfiguration.getClassesFiles()); diff --git a/jib-gradle-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar b/jib-gradle-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000..dd68926802 Binary files /dev/null and b/jib-gradle-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar differ diff --git a/jib-maven-plugin/CHANGELOG.md b/jib-maven-plugin/CHANGELOG.md index fa707cb743..fbff4fe022 100644 --- a/jib-maven-plugin/CHANGELOG.md +++ b/jib-maven-plugin/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. ## [unreleased] ### Added +- Snapshot dependencies are added as their own layer ([#584](https://github.com/GoogleContainerTools/jib/pull/584)) ### Changed diff --git a/jib-maven-plugin/pom.xml b/jib-maven-plugin/pom.xml index 5c4d3214ff..ee93d11df0 100644 --- a/jib-maven-plugin/pom.xml +++ b/jib-maven-plugin/pom.xml @@ -123,6 +123,20 @@ 2.12.0 test + + + org.apache.maven.plugin-testing + maven-plugin-testing-harness + 3.3.0 + test + + + org.apache.maven + maven-compat + 3.5.4 + test + + diff --git a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfiguration.java b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfiguration.java index 506b19da04..a3d919eaf5 100644 --- a/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfiguration.java +++ b/jib-maven-plugin/src/main/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfiguration.java @@ -44,6 +44,7 @@ static MavenSourceFilesConfiguration getForProject(MavenProject project) throws } private final ImmutableList dependenciesFiles; + private final ImmutableList snapshotDependenciesFiles; private final ImmutableList resourcesFiles; private final ImmutableList classesFiles; @@ -53,12 +54,17 @@ private MavenSourceFilesConfiguration(MavenProject project) throws IOException { Path classesOutputDirectory = Paths.get(project.getBuild().getOutputDirectory()); List dependenciesFiles = new ArrayList<>(); + List snapshotDependenciesFiles = new ArrayList<>(); List resourcesFiles = new ArrayList<>(); List classesFiles = new ArrayList<>(); // Gets all the dependencies. for (Artifact artifact : project.getArtifacts()) { - dependenciesFiles.add(artifact.getFile().toPath()); + if (artifact.isSnapshot()) { + snapshotDependenciesFiles.add(artifact.getFile().toPath()); + } else { + dependenciesFiles.add(artifact.getFile().toPath()); + } } // Gets the classes files in the 'classes' output directory. It finds the files that are classes @@ -88,6 +94,7 @@ private MavenSourceFilesConfiguration(MavenProject project) throws IOException { // Sort all files by path for consistent ordering. this.dependenciesFiles = ImmutableList.sortedCopyOf(dependenciesFiles); + this.snapshotDependenciesFiles = ImmutableList.sortedCopyOf(snapshotDependenciesFiles); this.resourcesFiles = ImmutableList.sortedCopyOf(resourcesFiles); this.classesFiles = ImmutableList.sortedCopyOf(classesFiles); } @@ -97,6 +104,11 @@ public ImmutableList getDependenciesFiles() { return dependenciesFiles; } + @Override + public ImmutableList getSnapshotDependenciesFiles() { + return snapshotDependenciesFiles; + } + @Override public ImmutableList getResourcesFiles() { return resourcesFiles; diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfigurationTest.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfigurationTest.java index b91fb61401..f43e2c8cf3 100644 --- a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfigurationTest.java +++ b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/MavenSourceFilesConfigurationTest.java @@ -17,19 +17,20 @@ package com.google.cloud.tools.jib.maven; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import com.google.common.io.Resources; import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; -import java.util.HashSet; import java.util.Set; import org.apache.maven.artifact.Artifact; import org.apache.maven.model.Build; import org.apache.maven.project.MavenProject; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.junit.Assert; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -40,25 +41,30 @@ @RunWith(MockitoJUnitRunner.class) public class MavenSourceFilesConfigurationTest { + @Rule public TestRepository testRepository = new TestRepository(); + @Mock private MavenProject mockMavenProject; @Mock private Build mockBuild; private MavenSourceFilesConfiguration testMavenSourceFilesConfiguration; @Before - public void setUp() throws IOException, URISyntaxException { + public void setUp() throws IOException, URISyntaxException, ComponentLookupException { Path sourcePath = Paths.get(Resources.getResource("application/source").toURI()); Path outputPath = Paths.get(Resources.getResource("application/output").toURI()); Mockito.when(mockMavenProject.getBuild()).thenReturn(mockBuild); Mockito.when(mockBuild.getSourceDirectory()).thenReturn(sourcePath.toString()); Mockito.when(mockBuild.getOutputDirectory()).thenReturn(outputPath.toString()); + Set artifacts = - new HashSet<>( - Arrays.asList( - makeArtifact(Paths.get("application", "dependencies", "libraryB.jar")), - makeArtifact(Paths.get("application", "dependencies", "libraryA.jar")), - makeArtifact(Paths.get("application", "dependencies", "dependency-1.0.0.jar")))); + ImmutableSet.of( + makeArtifact(Paths.get("application", "dependencies", "libraryB.jar")), + makeArtifact(Paths.get("application", "dependencies", "libraryA.jar")), + // maven reads and populates "Artifacts" with it's own processing, so read some from + // a repository + testRepository.findArtifact("com.test", "dependency", "1.0.0"), + testRepository.findArtifact("com.test", "dependencyX", "1.0.0-SNAPSHOT")); Mockito.when(mockMavenProject.getArtifacts()).thenReturn(artifacts); testMavenSourceFilesConfiguration = @@ -68,10 +74,15 @@ public void setUp() throws IOException, URISyntaxException { @Test public void test_correctFiles() throws URISyntaxException { ImmutableList expectedDependenciesFiles = + // on windows, these files may be in a different order, so sort + ImmutableList.sortedCopyOf( + ImmutableList.of( + testRepository.artifactPathOnDisk("com.test", "dependency", "1.0.0"), + Paths.get("application", "dependencies", "libraryA.jar"), + Paths.get("application", "dependencies", "libraryB.jar"))); + ImmutableList expectedSnapshotDependenciesFiles = ImmutableList.of( - Paths.get("application", "dependencies", "dependency-1.0.0.jar"), - Paths.get("application", "dependencies", "libraryA.jar"), - Paths.get("application", "dependencies", "libraryB.jar")); + testRepository.artifactPathOnDisk("com.test", "dependencyX", "1.0.0-SNAPSHOT")); ImmutableList expectedResourcesFiles = ImmutableList.of( Paths.get(Resources.getResource("application/output/directory").toURI()), @@ -86,6 +97,9 @@ public void test_correctFiles() throws URISyntaxException { Assert.assertEquals( expectedDependenciesFiles, testMavenSourceFilesConfiguration.getDependenciesFiles()); + Assert.assertEquals( + expectedSnapshotDependenciesFiles, + testMavenSourceFilesConfiguration.getSnapshotDependenciesFiles()); Assert.assertEquals( expectedResourcesFiles, testMavenSourceFilesConfiguration.getResourcesFiles()); Assert.assertEquals(expectedClassesFiles, testMavenSourceFilesConfiguration.getClassesFiles()); diff --git a/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/TestRepository.java b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/TestRepository.java new file mode 100644 index 0000000000..701fa470ed --- /dev/null +++ b/jib-maven-plugin/src/test/java/com/google/cloud/tools/jib/maven/TestRepository.java @@ -0,0 +1,69 @@ +package com.google.cloud.tools.jib.maven; + +import com.google.common.io.Resources; +import java.net.MalformedURLException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import org.apache.maven.artifact.Artifact; +import org.apache.maven.artifact.DefaultArtifact; +import org.apache.maven.artifact.handler.ArtifactHandler; +import org.apache.maven.artifact.handler.manager.ArtifactHandlerManager; +import org.apache.maven.artifact.repository.ArtifactRepository; +import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; +import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout; +import org.apache.maven.artifact.resolver.ArtifactResolutionRequest; +import org.apache.maven.artifact.resolver.ArtifactResolutionResult; +import org.apache.maven.artifact.resolver.ArtifactResolver; +import org.apache.maven.plugin.testing.MojoRule; +import org.codehaus.plexus.component.repository.exception.ComponentLookupException; +import org.junit.Assert; +import org.junit.rules.ExternalResource; + +/** A test helper to resolve artifacts from a local repository in test/resources */ +public class TestRepository extends ExternalResource { + + private static final String TEST_M2 = "testM2"; + + private MojoRule testHarness; + private ArtifactRepositoryFactory artifactRepositoryFactory; + private ArtifactHandlerManager artifactHandlerManager; + private ArtifactRepository testLocalRepo; + private ArtifactResolver artifactResolver; + private ArtifactHandler jarHandler; + + @Override + protected void before() + throws ComponentLookupException, URISyntaxException, MalformedURLException { + testHarness = new MojoRule(); + artifactRepositoryFactory = testHarness.lookup(ArtifactRepositoryFactory.class); + artifactHandlerManager = testHarness.lookup(ArtifactHandlerManager.class); + artifactResolver = testHarness.lookup(ArtifactResolver.class); + jarHandler = artifactHandlerManager.getArtifactHandler("jar"); + + testLocalRepo = + artifactRepositoryFactory.createArtifactRepository( + "test", + Resources.getResource(TEST_M2).toURI().toURL().toString(), + new DefaultRepositoryLayout(), + null, + null); + } + + public Artifact findArtifact(String group, String artifact, String version) { + ArtifactResolutionRequest artifactResolutionRequest = new ArtifactResolutionRequest(); + artifactResolutionRequest.setLocalRepository(testLocalRepo); + Artifact artifactToFind = + new DefaultArtifact(group, artifact, version, null, "jar", null, jarHandler); + + artifactResolutionRequest.setArtifact(artifactToFind); + + ArtifactResolutionResult ars = artifactResolver.resolve(artifactResolutionRequest); + + Assert.assertEquals(1, ars.getArtifacts().size()); + return ars.getArtifacts().iterator().next(); + } + + public Path artifactPathOnDisk(String group, String artifact, String version) { + return findArtifact(group, artifact, version).getFile().toPath(); + } +} diff --git a/jib-maven-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar b/jib-maven-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000..dd68926802 Binary files /dev/null and b/jib-maven-plugin/src/test/resources/application/dependencies/dependencyX-1.0.0-SNAPSHOT.jar differ diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/_remote.repositories b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/_remote.repositories new file mode 100644 index 0000000000..d4aa0ba7cb --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/_remote.repositories @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Wed Jul 11 18:33:40 EDT 2018 +dependency-1.0.0.pom>= +dependency-1.0.0.jar>= diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.jar b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.jar new file mode 100644 index 0000000000..333ceb39b2 Binary files /dev/null and b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.jar differ diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.pom b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.pom new file mode 100644 index 0000000000..242f57433c --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/1.0.0/dependency-1.0.0.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + com.test + dependency + 1.0.0 + POM was created from install:install-file + diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/maven-metadata-local.xml b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/maven-metadata-local.xml new file mode 100644 index 0000000000..d10105b967 --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependency/maven-metadata-local.xml @@ -0,0 +1,12 @@ + + + com.test + dependency + + 1.0.0 + + 1.0.0 + + 20180711223340 + + diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/_remote.repositories b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/_remote.repositories new file mode 100644 index 0000000000..b12c035277 --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/_remote.repositories @@ -0,0 +1,4 @@ +#NOTE: This is an Aether internal implementation file, its format can be changed without prior notice. +#Wed Jul 11 18:35:24 EDT 2018 +dependencyX-1.0.0-SNAPSHOT.pom>= +dependencyX-1.0.0-SNAPSHOT.jar>= diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.jar b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.jar new file mode 100644 index 0000000000..333ceb39b2 Binary files /dev/null and b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.jar differ diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.pom b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.pom new file mode 100644 index 0000000000..fcf75bd78e --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/dependencyX-1.0.0-SNAPSHOT.pom @@ -0,0 +1,9 @@ + + + 4.0.0 + com.test + dependencyX + 1.0.0-SNAPSHOT + POM was created from install:install-file + diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/maven-metadata-local.xml b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/maven-metadata-local.xml new file mode 100644 index 0000000000..87f1ad7dcf --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/1.0.0-SNAPSHOT/maven-metadata-local.xml @@ -0,0 +1,24 @@ + + + com.test + dependencyX + 1.0.0-SNAPSHOT + + + true + + 20180711223524 + + + jar + 1.0.0-SNAPSHOT + 20180711223524 + + + pom + 1.0.0-SNAPSHOT + 20180711223524 + + + + diff --git a/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/maven-metadata-local.xml b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/maven-metadata-local.xml new file mode 100644 index 0000000000..8f606ea131 --- /dev/null +++ b/jib-maven-plugin/src/test/resources/testM2/com/test/dependencyX/maven-metadata-local.xml @@ -0,0 +1,11 @@ + + + com.test + dependencyX + + + 1.0.0-SNAPSHOT + + 20180711223524 + +