Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Run Maven plugin extensions #2397

Merged
merged 3 commits into from
Apr 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright 2020 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.maven.extension.MavenData;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.project.MavenProject;

/** Maven-specific data and properties to supply to plugin extensions. */
class MavenExtensionData implements MavenData {

private final MavenProject project;
private final MavenSession session;

MavenExtensionData(MavenProject project, MavenSession session) {
this.project = project;
this.session = session;
}

@Override
public MavenProject getMavenProject() {
return project;
}

@Override
public MavenSession getMavenSession() {
return session;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2020 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.api.LogEvent;
import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger;
import java.util.function.Consumer;

/** Logger for Maven plugin extensions. */
class MavenExtensionLogger implements ExtensionLogger {

private final Consumer<LogEvent> logger;

MavenExtensionLogger(Consumer<LogEvent> logger) {
this.logger = logger;
}

@Override
public void log(ExtensionLogger.LogLevel logLevel, String message) {
switch (logLevel) {
case ERROR:
logger.accept(LogEvent.error(message));
break;
case WARN:
logger.accept(LogEvent.warn(message));
break;
case LIFECYCLE:
logger.accept(LogEvent.lifecycle(message));
break;
case INFO:
logger.accept(LogEvent.info(message));
break;
case DEBUG:
logger.accept(LogEvent.debug(message));
break;
default:
throw new RuntimeException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,19 @@
package com.google.cloud.tools.jib.maven;

import com.google.cloud.tools.jib.api.Containerizer;
import com.google.cloud.tools.jib.api.ImageReference;
import com.google.cloud.tools.jib.api.InvalidImageReferenceException;
import com.google.cloud.tools.jib.api.JavaContainerBuilder;
import com.google.cloud.tools.jib.api.JavaContainerBuilder.LayerType;
import com.google.cloud.tools.jib.api.JibContainerBuilder;
import com.google.cloud.tools.jib.api.LogEvent;
import com.google.cloud.tools.jib.api.buildplan.ContainerBuildPlan;
import com.google.cloud.tools.jib.event.events.ProgressEvent;
import com.google.cloud.tools.jib.event.events.TimerEvent;
import com.google.cloud.tools.jib.event.progress.ProgressEventHandler;
import com.google.cloud.tools.jib.filesystem.DirectoryWalker;
import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider;
import com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension;
import com.google.cloud.tools.jib.plugins.common.ContainerizingMode;
import com.google.cloud.tools.jib.plugins.common.JavaContainerBuilderHelper;
import com.google.cloud.tools.jib.plugins.common.ProjectProperties;
Expand All @@ -39,16 +43,19 @@
import com.google.cloud.tools.jib.plugins.extension.JibPluginExtensionException;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Verify;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.ServiceLoader;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -526,6 +533,37 @@ boolean jarRepackagedBySpringBoot() {
@Override
public JibContainerBuilder runPluginExtensions(JibContainerBuilder jibContainerBuilder)
throws JibPluginExtensionException {
return jibContainerBuilder;
return runPluginExtensions(
ServiceLoader.load(JibMavenPluginExtension.class).iterator(), jibContainerBuilder);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need to create some sort of ordering mechanism so like some file manipulation extension can run after a framework extension has populated all the file?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. In a follow-up PR, I'll add a new extension configuration option, as I proposed in the internal doc. I think I will be able to enforce ordering with it.

}

@VisibleForTesting
JibContainerBuilder runPluginExtensions(
Iterator<JibMavenPluginExtension> services, JibContainerBuilder jibContainerBuilder)
throws JibPluginExtensionException {
if (!services.hasNext()) {
log(LogEvent.debug("No Jib plugin extensions discovered"));
return jibContainerBuilder;
}

JibMavenPluginExtension extension = null;
ContainerBuildPlan buildPlan = jibContainerBuilder.toContainerBuildPlan();
MavenExtensionData mavenData = new MavenExtensionData(project, session);
MavenExtensionLogger logger = new MavenExtensionLogger(this::log);
try {
while (services.hasNext()) {
extension = services.next();
log(LogEvent.lifecycle("Running extension: " + extension.getClass().getName()));
buildPlan = extension.extendContainerBuildPlan(buildPlan, mavenData, logger);
ImageReference.parse(buildPlan.getBaseImage()); // to validate image reference
}
return jibContainerBuilder.applyContainerBuildPlan(buildPlan);

} catch (InvalidImageReferenceException ex) {
throw new JibPluginExtensionException(
Verify.verifyNotNull(extension).getClass(),
"invalid base image reference: " + buildPlan.getBaseImage(),
ex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.cloud.tools.jib.api.InvalidImageReferenceException;
import com.google.cloud.tools.jib.api.JavaContainerBuilder;
import com.google.cloud.tools.jib.api.JavaContainerBuilder.LayerType;
import com.google.cloud.tools.jib.api.Jib;
import com.google.cloud.tools.jib.api.JibContainerBuilder;
import com.google.cloud.tools.jib.api.JibContainerBuilderTestHelper;
import com.google.cloud.tools.jib.api.RegistryImage;
Expand All @@ -30,12 +31,16 @@
import com.google.cloud.tools.jib.configuration.BuildContext;
import com.google.cloud.tools.jib.filesystem.DirectoryWalker;
import com.google.cloud.tools.jib.filesystem.TempDirectoryProvider;
import com.google.cloud.tools.jib.maven.extension.JibMavenPluginExtension;
import com.google.cloud.tools.jib.plugins.common.ContainerizingMode;
import com.google.cloud.tools.jib.plugins.extension.ExtensionLogger.LogLevel;
import com.google.cloud.tools.jib.plugins.extension.JibPluginExtensionException;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.ByteStreams;
import com.google.common.io.Resources;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
Expand Down Expand Up @@ -66,6 +71,7 @@
import org.codehaus.plexus.archiver.zip.ZipEntry;
import org.codehaus.plexus.archiver.zip.ZipOutputStream;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
Expand Down Expand Up @@ -1002,6 +1008,79 @@ public void testGetWarArtifact_executionIdNotMatched() {
Paths.get("/foo/bar/helloworld-1.war"), mavenProjectProperties.getWarArtifact());
}

@Test
public void testRunPluginExtensions_noExtensionsFound()
throws JibPluginExtensionException, InvalidImageReferenceException {
JibContainerBuilder originalBuilder = Jib.from(RegistryImage.named("from/nothing"));
JibContainerBuilder extendedBuilder =
mavenProjectProperties.runPluginExtensions(Collections.emptyIterator(), originalBuilder);
Assert.assertSame(extendedBuilder, originalBuilder);

mavenProjectProperties.waitForLoggingThread();
Mockito.verify(mockLog).debug("No Jib plugin extensions discovered");
}

@Test
public void testRunPluginExtensions()
throws JibPluginExtensionException, InvalidImageReferenceException {
JibMavenPluginExtension extension =
(buildPlan, mavenData, logger) -> {
logger.log(LogLevel.ERROR, "awesome error from my extension");
return buildPlan.toBuilder().setUser("user from extension").build();
};

JibContainerBuilder extendedBuilder =
mavenProjectProperties.runPluginExtensions(
Arrays.asList(extension).iterator(), Jib.from(RegistryImage.named("from/nothing")));
Assert.assertEquals("user from extension", extendedBuilder.toContainerBuildPlan().getUser());

mavenProjectProperties.waitForLoggingThread();
Mockito.verify(mockLog).error("awesome error from my extension");
Mockito.verify(mockLog)
.info(
Mockito.startsWith(
"Running extension: com.google.cloud.tools.jib.maven.MavenProjectProperties"));
}

@Test
public void testRunPluginExtensions_exceptionFromExtension()
throws InvalidImageReferenceException {
FileNotFoundException fakeException = new FileNotFoundException();
JibMavenPluginExtension extension =
(buildPlan, mavenData, logger) -> {
throw new JibPluginExtensionException(
JibMavenPluginExtension.class, "exception from extension", fakeException);
};

JibContainerBuilder originalBuilder = Jib.from(RegistryImage.named("scratch"));
try {
mavenProjectProperties.runPluginExtensions(
Arrays.asList(extension).iterator(), originalBuilder);
Assert.fail();
} catch (JibPluginExtensionException ex) {
Assert.assertEquals("exception from extension", ex.getMessage());
Assert.assertSame(fakeException, ex.getCause());
}
}

@Test
public void testRunPluginExtensions_invalidBaseImageFromExtension()
throws InvalidImageReferenceException {
JibMavenPluginExtension extension =
(buildPlan, mavenData, logger) -> buildPlan.toBuilder().setBaseImage(" in*val+id").build();

JibContainerBuilder originalBuilder = Jib.from(RegistryImage.named("from/nothing"));
try {
mavenProjectProperties.runPluginExtensions(
Arrays.asList(extension).iterator(), originalBuilder);
Assert.fail();
} catch (JibPluginExtensionException ex) {
Assert.assertEquals("invalid base image reference: in*val+id", ex.getMessage());
Assert.assertThat(
ex.getCause(), CoreMatchers.instanceOf(InvalidImageReferenceException.class));
}
}

private BuildContext setUpBuildContext(String appRoot, ContainerizingMode containerizingMode)
throws InvalidImageReferenceException, IOException, CacheDirectoryCreationException {
JavaContainerBuilder javaContainerBuilder =
Expand Down