Spring boot layer jar and build pack - spring-boot

I just started using spring boot 2.3 with layer jar and build pack feature.
Docker image is always built when
mvn clean install/package
code is committed and requested PR in git
However, this will slow down build process, how can I control the phase in which the image is being built and how can I control if image should be built at all?
Following is configuration that added to pom file
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
<image>
<name>${image.name}</name>
<env>
<BP_JVM_VERSION>${BP_JVM_VERSION}</BP_JVM_VERSION>
</env>
</image>
</configuration>
<executions>
<execution>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

The build-image goal is attached to the package phase by default. It is run each time the package goal is run because of the executions configuration you have in your pom.xml:
<executions>
<execution>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>
If you remove this <executions> block, build-image will not be run automatically, but can be run manually with mvn spring-boot:build-image.
Alternatively, you can attach the goal to a different phase like install by specifying the phase in the <execution> block like this:
<executions>
<execution>
<phase>install</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>

You can use a spring-boot.build-image.skip property
Add it to the propertied with true value
<properties>
<spring-boot.build-image.skip>true</spring-boot.build-image.skip>
</properties>
so the build-image goal will be skipped by default. Whenever you want to build the image pass false to the cmd
mvn clean install -Dspring-boot.build-image.skip=false
Update:
If you want to change the phase from install to package, you need to configure the plugin as following:
<executions>
<execution>
<id>default</id>
<phase>none</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
<execution>
<id>build-image-during-package</id>
<phase>package</phase>
<goals>
<goal>build-image</goal>
</goals>
</execution>
</executions>

Related

Maven plugin in not getting executed

I have a custom maven plugin but when i use that in my project pom , it does not get triggered !
Here is how i using same:
<plugin>
<groupId>com.autodeploy.maven</groupId>
<artifactId>my-docs-plugin</artifactId>
<version>1.0.2-0</version>
<inherited>false</inherited>
<executions>
<execution>
<id>myid</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
<configuration>
<outputDirectory>target/doc</outputDirectory>
<custom-Folders>
<param>${basedir}/files/</param>
</custom-Folders>
</configuration>
</execution>
</executions>
</plugin>
I am triggering build cycle like mvn install:install or even mvn install ! None of these invoke my maven plugin !

Why does exec-maven-plugin run all phases twice?

When I run a build with maven using the exec-maven-plugin, it runs everything twice for some reason. Is there a way to fix this so it only runs once? I've tried setting my phase in the pom.xml to compile and package and either way, it runs twice. My pom looks like
<build>
<plugins>
<plugin>
<artifactId>exec-maven-plugin</artifactId>
<groupId>org.codehaus.mojo</groupId>
<version>1.0</version>
<executions>
<execution>
<id>foo</id>
<phase>compile</phase>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>bash</executable>
<commandlineArgs>myscript.sh</commandlineArgs>
</configuration>
</plugin>
</plugins>
</build>
It turned out that adding the phase tag caused the command to get executed twice. Leaving that out, it is now getting run once as expected. I guess it doesn't matter what phase I give it now, it'll always run the goal, which works for me.
If you need to run this early in the build, excluding the phase isn't an option.
You can do something like this instead in the plugin config:
<executions>
<execution>
<id>default</id>
<phase>none</phase> <!-- disable the default execution in validate phase -->
</execution>
<execution>
<id>exec-do-something</id>
<goals>
<goal>java</goal>
</goals>
<phase>generate-sources</phase><!-- now it will run once but in an earlier phase -->
</execution>
</executions>
I saw this happening due to the inclusion of:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
This seems to be that the maven-source-plugin causes a re-execution of the generate-sources phase. See https://maven.apache.org/plugins/maven-source-plugin/jar-mojo.html
Invokes the execution of the lifecycle phase generate-sources prior to executing itself.
If I removed this plugin, the exec goal only executed once.

Tagging created image with dockerfile-maven-plugin

I am using dockerfile-maven-plugin with the following configuration:
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>1.3.6</version>
<executions>
<execution>
<id>build-image</id>
<goals>
<goal>build</goal>
</goals>
<configuration>
<tag>latest</tag>
<repository>root/${project.artifactId}</repository>
<buildArgs>
<APP_NAME>${project.artifactId}</APP_NAME>
</buildArgs>
</configuration>
</execution>
<execution>
<id>push-image</id>
<goals>
<goal>push</goal>
</goals>
<configuration>
<repository>${docker.registry.url}/root/${project.artifactId}</repository>
</configuration>
</execution>
</executions>
</plugin>
Project deployment fails due to:
[INFO] The push refers to a repository [my-repository:9090/root/image-name]
[ERROR] An image does not exist locally with the tag: my-repository:9090/root/image-name
[WARNING] An attempt failed, will retry 1 more times
org.apache.maven.plugin.MojoExecutionException: Could not push image
.
.
.
Prefixing the repository under the build goal (in similar way to push goal) solves the issue. But then the locally created image prefixed with the repository tag.
Didn't find any documentation reference on how to perform the tag before push task.
In other words, I want that my local docker images will contain 2 images after plugin execution:
REPOSITORY TAG IMAGE ID CREATED SIZE
root/image-name latest 7ac1144c607e 21 minutes ago 175MB
my-repository:9090/root/image-name latest 7ac1144c607e 21 minutes ago 175MB
My docker version is: 17.06.0-ce
We didn't want to build all over again even if existing docker layers would be used. In the first execution we build and push and in the second execution we just tag and push.
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>${dockerfile-maven-plugin.version}</version>
<executions>
<execution>
<id>default</id>
<goals>
<goal>build</goal>
<goal>push</goal>
</goals>
<configuration>
<tag>${build.number}</tag>
</configuration>
</execution>
<execution>
<id>default-2</id>
<goals>
<goal>tag</goal>
<goal>push</goal>
</goals>
<configuration>
<tag>latest</tag>
</configuration>
</execution>
</executions>
<configuration>
<repository>${docker-remote.registry}/path/${project.version.lowercase}</repository>
<buildArgs>
<EAR_FILE>${project.build.finalName}.ear</EAR_FILE>
</buildArgs>
<useMavenSettingsForAuth>true</useMavenSettingsForAuth>
</configuration>
</plugin>
</plugins>
</build>
Adding additional execution step to my configuration solved the issue:
<execution>
<id>tag-image</id>
<phase>deploy</phase>
<goals>
<goal>tag</goal>
</goals>
<configuration>
<repository>${docker.registry.url}/root/${project.artifactId}</repository>
</configuration>
</execution>
You can also tag your image manually after a successful build with
mvn dockerfile:tag -Dproject.plugin.dockerfile.tag=my-repository:9090/root/image-name

maven-replacer-plugin to replace tokens in build and not source

I am trying to use the maven-replacer-plugin to replace tokens in my web.xml when it is built in the WAR file but not in the source, which would remove the tokens for subsequent builds and show the file as changed relative to the version control repository.
Currently, I am only able to change the file in the source, which does not meet my requirement:
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${project.basedir}/src/main/webapp/WEB-INF/web.xml</file>
<replacements>
<replacement>
<token>##sec.level##</token>
<value>local</value>
</replacement>
</replacements>
</configuration>
</plugin>
Question: How can I run the replacer to only change the file in the WAR package while leaving the source unchanged for subsequent builds?
You can use the exploded goal of the maven-war-plugin to get to a temporary folder (like whatever created under target actually) the exploded version of what would later on be part of the final war file, then execute the replacer plugin on this file (a safe copy, not in conflict with other plugins consuming the file).
This approach is actually also documented by the official replacer plugin doc
That is, having a similar configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<useCache>true</useCache>
</configuration>
<executions>
<execution>
<id>prepare-war</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${project.build.directory}/${project.build.finalName}/WEB-INF/web.xml</file>
<token>##sec.level##</token>
<value>local</value>
</configuration>
</plugin>
Note: the replacer documentation also suggests to use the useCache option which should prevent the plugin to override what the exploded goal previously created. However, the option doesn't really suit this purpose.
Similarly, the following approach would instead work according to my tests:
Use the exploded goal of the maven-war-plugin to create a temporary copy of the future war file in a <war_name>-tmp directory under target: that's not an issue, whatever is under target is supposed to be discarded via a clean command anyway
Configure the replacer plugin to replace that copy of the web.xml file
Configure the default war goal using its webXml option to point to that web.xml file for its final war file
The following would apply the approach described above:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<!-- explode the future war content for pre-package processing -->
<id>prepare-war</id>
<phase>prepare-package</phase>
<goals>
<goal>exploded</goal>
</goals>
<configuration>
<webappDirectory>${project.build.directory}/${project.build.finalName}-tmp</webappDirectory>
</configuration>
</execution>
<execution>
<!-- use the same execution id to further configure the default binding and execution -->
<id>default-war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
<!-- during the package phase, use the processed web.xml file -->
<webXml>${project.build.directory}/${project.build.finalName}-tmp/WEB-INF/web.xml</webXml>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.2</version>
<executions>
<execution>
<!-- apply pre-package processing on web resources -->
<id>process-web-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<file>${project.build.directory}/${project.build.finalName}-tmp/WEB-INF/web.xml</file>
<token>##test##</token>
<value>local</value>
</configuration>
</plugin>

Maven tell plugin to not run during phase

Is there any phase I can use to prevent Maven from running a plugin goal or any other way I can tell Maven to skip a plugin goal?
Basically, I want to just run it manually.
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<phase >pre-integration-test</phase>
<goals>
<goal>wget</goal>
</goals>
</execution>
</executions>
<configuration>
<outputDirectory>${project.build.directory}/output</outputDirectory>
<url>http://some.url</url>
<outputFileName>filename</outputFileName>
</configuration>
</plugin>
When I use pre-integration-test it runs during mvn install. However, I just want to run it manually.
Phase none worked for my scenario to keep test-jars from being created for specific modules in my multi-module maven project. Like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>test-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>

Resources