Replace the Maven Plugin's site with Asciidoctor documentation

Closes gh-19080

Co-authored-by: Stephane Nicoll <snicoll@pivotal.io>
pull/19094/head
Andy Wilkinson 5 years ago
parent b62fea5c32
commit 3e2454f8c4

@ -1250,8 +1250,8 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${revision}</version>
<classifier>site</classifier>
<type>jar</type>
<classifier>docs</classifier>
<type>zip</type>
<outputDirectory>
${project.build.directory}/contents/maven-plugin
</outputDirectory>

@ -30,8 +30,8 @@
<maven-resolver.version>1.1.1</maven-resolver.version>
<spock.version>1.3-groovy-2.5</spock.version>
<spring-asciidoctor-extensions.version>0.3.0.RELEASE</spring-asciidoctor-extensions.version>
<spring-doc-resources.version>0.1.3.RELEASE</spring-doc-resources.version>
<spring-doc-resources.url>https://repo.spring.io/release/io/spring/docresources/spring-doc-resources/${spring-doc-resources.version}/spring-doc-resources-${spring-doc-resources.version}.zip</spring-doc-resources.url>
<spring-doc-resources.version>0.1.4.BUILD-20191119.185717-2</spring-doc-resources.version>
<spring-doc-resources.url>https://repo.spring.io/snapshot/io/spring/docresources/spring-doc-resources/0.1.4.BUILD-SNAPSHOT/spring-doc-resources-${spring-doc-resources.version}.zip</spring-doc-resources.url>
<testcontainers.version>1.12.2</testcontainers.version>
<testng.version>6.14.3</testng.version>
</properties>

@ -14,6 +14,7 @@
<properties>
<main.basedir>${basedir}/../../..</main.basedir>
<maven.version>3.3.9</maven.version>
<refdocs.build.directory>${project.build.directory}/refdocs/</refdocs.build.directory>
</properties>
<scm>
<url>${git.url}</url>
@ -204,18 +205,6 @@
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<executions>
<execution>
<id>generate-site</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-invoker-plugin</artifactId>
@ -249,6 +238,29 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>ant-contrib</groupId>
<artifactId>ant-contrib</artifactId>
<version>1.0b3</version>
<exclusions>
<exclusion>
<groupId>ant</groupId>
<artifactId>ant</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant-nodeps</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.tigris.antelope</groupId>
<artifactId>antelopetasks</artifactId>
<version>3.2.10</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>cleanup-local-integration-repo</id>
@ -267,37 +279,221 @@
</target>
</configuration>
</execution>
<execution>
<id>set-up-maven-properties</id>
<phase>prepare-package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<taskdef
resource="net/sf/antcontrib/antcontrib.properties" />
<taskdef name="stringutil"
classname="ise.antelope.tasks.StringUtilTask" />
<var name="version-type" value="${project.version}" />
<propertyregex property="version-type"
override="true" input="${version-type}" regexp=".*\.(.*)"
replace="\1" />
<propertyregex property="version-type"
override="true" input="${version-type}" regexp="(M)\d+"
replace="MILESTONE" />
<propertyregex property="version-type"
override="true" input="${version-type}" regexp="(RC)\d+"
replace="MILESTONE" />
<propertyregex property="version-type"
override="true" input="${version-type}" regexp="BUILD-(.*)"
replace="SNAPSHOT" />
<var name="github-tag" value="v${project.version}" />
<propertyregex property="github-tag"
override="true" input="${github-tag}" regexp=".*SNAPSHOT"
replace="master" />
</target>
</configuration>
</execution>
<execution>
<id>package-docs-zip</id>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<zip
destfile="${project.build.directory}/${project.artifactId}-${project.version}-docs.zip">
<zipfileset
dir="${project.build.directory}/generated-docs/reference/html"
prefix="html" />
<mappedresources>
<fileset
dir="${project.build.directory}/generated-docs/reference/pdf"
includes="index.pdf" />
<globmapper from="index.pdf"
to="pdf/spring-boot-maven-plugin.pdf" />
</mappedresources>
</zip>
</target>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-plugin-plugin</artifactId>
<groupId>com.googlecode.maven-download-plugin</groupId>
<artifactId>download-maven-plugin</artifactId>
<executions>
<execution>
<id>unpack-doc-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>wget</goal>
</goals>
<configuration>
<url>${spring-doc-resources.url}</url>
<unpack>true</unpack>
<outputDirectory>${refdocs.build.directory}</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.9</version>
<reportSets>
<reportSet>
<reports>
<report>index</report>
<report>cim</report>
<report>issue-tracking</report>
<report>license</report>
<report>scm</report>
</reports>
</reportSet>
</reportSets>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>execute</goal>
</goals>
<phase>prepare-package</phase>
</execution>
</executions>
<configuration>
<scripts>
<script>file:///${project.basedir}/src/main/groovy/generateGoalsDocumentation.groovy</script>
</scripts>
</configuration>
<dependencies>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-ant</artifactId>
<version>${groovy.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-xml</artifactId>
<version>${groovy.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<executions>
<execution>
<id>generate-html-documentation</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>html5</backend>
<outputDirectory>${project.build.directory}/generated-docs/reference/html</outputDirectory>
<sourceHighlighter>highlight.js</sourceHighlighter>
<doctype>book</doctype>
<attributes>
<highlightjsdir>js/highlight</highlightjsdir>
<highlightjs-theme>github</highlightjs-theme>
<linkcss>true</linkcss>
<imagesdir>./images</imagesdir>
<icons>font</icons>
<stylesdir>css/</stylesdir>
<stylesheet>spring.css</stylesheet>
<attribute-missing>warn</attribute-missing>
</attributes>
<logHandler>
<outputToConsole>true</outputToConsole>
<failIf>
<severity>DEBUG</severity>
</failIf>
</logHandler>
</configuration>
</execution>
<execution>
<id>generate-pdf-documentation</id>
<phase>prepare-package</phase>
<goals>
<goal>process-asciidoc</goal>
</goals>
<configuration>
<backend>pdf</backend>
<outputDirectory>${project.build.directory}/generated-docs/reference/pdf</outputDirectory>
</configuration>
</execution>
</executions>
<configuration>
<linkOnly>true</linkOnly>
<sourceDirectory>${refdocs.build.directory}</sourceDirectory>
<sourceDocumentName>index.adoc</sourceDocumentName>
<attributes>
<version>${project.version}</version>
<build-helper-maven-plugin-version>${build-helper-maven-plugin.version}</build-helper-maven-plugin-version>
<maven-failsafe-plugin-version>${maven-failsafe-plugin.version}</maven-failsafe-plugin-version>
<maven-jar-plugin-version>${maven-jar-plugin.version}</maven-jar-plugin-version>
<generated-resources-root>${project.basedir}/target/generated-resources</generated-resources-root>
</attributes>
</configuration>
<dependencies>
<dependency>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctorj-pdf</artifactId>
<version>1.5.0-alpha.18</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-asciidoc-resources</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${refdocs.build.directory}</outputDirectory>
<resources>
<resource>
<directory>src/main/asciidoc</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>attach-zip</id>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.build.directory}/${project.artifactId}-${project.version}-docs.zip</file>
<type>zip</type>
<classifier>docs</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</reporting>
</build>
</profile>
</profiles>
</project>

@ -0,0 +1,41 @@
[[build-info]]
== Integrating with Actuator
Spring Boot Actuator displays build-related information if a `META-INF/build-info.properties` file is present.
The `build-info` goal generates such file with the coordinates of the project and the build time.
It also allows you to add an arbitrary number of additional properties, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<goals>
<goal>build-info</goal>
</goals>
<configuration>
<additionalProperties>
<encoding.source>UTF-8</encoding.source>
<encoding.reporting>UTF-8</encoding.reporting>
<java.source>${maven.compiler.source}</java.source>
<java.target>${maven.compiler.target}</java.target>
</additionalProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
This configuration will generate a `build-info.properties` at the expected location with four additional keys.
Note that `maven.compiler.source` and `maven.compiler.target` are expected to be regular properties available in the project.
They will be interpolated as you would expect.
include::{generated-resources-root}/goals/build-info.adoc[leveloffset=+1]

@ -0,0 +1,7 @@
[[getting-started]]
== Getting started
The Spring Boot Plugin has the following goals:
include::{generated-resources-root}/goals/overview.adoc[]

@ -0,0 +1,5 @@
[[help]]
== Help information
The `help` goal is a standard goal that displays information on the capabilities of the plugin.
include::{generated-resources-root}/goals/help.adoc[leveloffset=+1]

@ -0,0 +1,23 @@
= Spring Boot Maven Plugin Documentation
Stephane Nicoll, Andy Wilkinson
:doctype: book
:toc: left
:toclevels: 4
:source-highlighter: prettify
:numbered:
:icons: font
:hide-uri-scheme:
:docinfo: shared,private
[[introduction]]
== Introduction
The Spring Boot Maven Plugin provides Spring Boot support in https://maven.org[Apache Maven].
It allows you to package executable jar or war archives, run Spring Boot applications, generate build information and start your Spring Boot application prior to running integration tests.
include::getting-started.adoc[]
include::packaging.adoc[]
include::running.adoc[]
include::integration-tests.adoc[]
include::build-info.adoc[]
include::help.adoc[]

@ -0,0 +1,179 @@
[[integration-tests]]
== Running Integration tests
While you may start your Spring Boot application very easily from your test (or test suite) itself, it may be desirable to handle that in the build itself.
To make sure that the lifecycle of your Spring Boot application is properly managed around your integration tests, you can use the `start` and `stop` goals, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
Such setup can now use the https://maven.apache.org/surefire/maven-failsafe-plugin[failsafe-plugi to run your integration tests as you would expect.
You could also configure a more advanced setup to skip the integration tests when a specific property has been set, see <<integration-tests-example-skip,the dedicated example>>.
include::{generated-resources-root}/goals/start.adoc[leveloffset=+1]
include::{generated-resources-root}/goals/stop.adoc[leveloffset=+1]
[[integration-tests-example]]
=== Examples
[[integration-tests-example-random-port]]
==== Random Port for Integration Tests
One nice feature of the Spring Boot test integration is that it can allocate a free port for the web application.
When the `start` goal of the plugin is used, the Spring Boot application is started separately, making it difficult to pass the actual port to the integration test itself.
The example below showcases how you could achieve the same feature using the https://www.mojohaus.org/build-helper-maven-plugin[Build Helper Maven Plugin]:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>{build-helper-maven-plugin-version}</version>
<executions>
<execution>
<id>reserve-tomcat-port</id>
<goals>
<goal>reserve-network-port</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<portNames>
<portName>tomcat.http.port</portName>
</portNames>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<arguments>
<argument>--server.port=${tomcat.http.port}</argument>
</arguments>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>{maven-failsafe-plugin-version}</version>
<configuration>
<systemPropertyVariables>
<test.server.port>${tomcat.http.port}</test.server.port>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
You can now retrieve the `test.server.port` system property in any of your integration test to create a proper `URL` to the server.
[[integration-tests-example-skip]]
==== Skip Integration Tests
The `skip` property allows to skip the execution of the Spring Boot maven plugin altogether.
This example shows how you can skip integration tests with a command-line property and still make sure that the `repackage` goal runs:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<properties>
<skip.it>false</skip.it>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>start</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<goals>
<goal>stop</goal>
</goals>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>{maven-failsafe-plugin-version}</version>
<configuration>
<skip>${skip.it}</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
By default, the integration tests will run but this setup allows you to easily disable them on the command-line as follows:
[indent=0]
----
$ mvn verify -Dskip.it=true
----

@ -0,0 +1,395 @@
[[repackage]]
== Packaging executable archives
The plugin can create executable archives (jar files and war files) that contain all of an application's dependencies and can then be run with `java -jar`.
Packaging an executable archive is performed by the `repackage` goal, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
TIP: If you are using `spring-boot-starter-parent`, such execution is already pre-configured with a `repackage` execution id so that only the plugin definition should be added.
The example above repackages a jar or war that is built during the package phase of the Maven lifecycle, including any `provided` dependencies that are defined in the project.
If some of these dependencies need to be excluded, you can use one of the exclude options, see the <<repackage-example-exclude-dependency,dependency exclusion>> for more details.
NOTE: The `outputFileNameMapping` feature of the `maven-war-plugin` is currently not supported.
Devtools is automatically excluded by default (you can control that using the `excludeDevtools` property).
In order to make that work with `war` packaging, the `spring-boot-devtools` dependency must be set as `optional` or with the `provided` scope.
The original (i.e. non executable) artifact is renamed to `.original` by default but it is also possible to keep the original artifact using a custom classifier.
The plugin rewrites your manifest, and in particular it manages the "Main-Class" and "Start-Class" entries, so if the defaults don't work you have to configure those there (not in the jar plugin).
The "Main-Class" in the manifest is actually controlled by the "layout" property of the Spring Boot plugin, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<mainClass>${start.class}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----
The `layout` property defaults to a guess based on the archive type (`jar` or `war`). The following layouts are available:
* `JAR`: regular executable JAR layout.
* `WAR`: executable WAR layout. `provided` dependencies are placed in `WEB-INF/lib-provided` to avoid any clash when the `war` is deployed in a servlet container.
* `ZIP` (alias to `DIR`): similar to the `JAR` layout using `PropertiesLauncher`.
* `NONE`: Bundle all dependencies and project resources. Does not bundle a bootstrap loader.
include::{generated-resources-root}/goals/repackage.adoc[leveloffset=+1]
[[repackage-examples]]
=== Examples
[[repackage-example-custom-classifier]]
==== Custom Classifier
By default, the `repackage` goal replaces the original artifact with the repackaged one.
That is a sane behavior for modules that represent an application but if your module is used as a dependency of another module, you need to provide a classifier for the repackaged one.
The reason for that is that application classes are packaged in `BOOT-INF/classes` so that the dependent module cannot load a repackaged jar's classes.
If that is the case or if you prefer to keep the original artifact and attach the repackaged one with a different classifier, configure the plugin as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
If you are using `spring-boot-starter-parent`, the `repackage` goal is executed automatically in an execution with id `repackage`.
In that setup, only the configuration should be specified, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
This configuration will generate two artifacts: the original one and the repackaged counter part produced by the repackage goal.
Both will be installed/deployed transparently.
You can also use the same configuration if you want to repackage a secondary artifact the same way the main artifact is replaced.
The following configuration installs/deploys a single `task` classified artifact with the repackaged application:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>{maven-jar-plugin-version}</version>
<executions>
<execution>
<goals>
<goal>jar</goal>
</goals>
<phase>package</phase>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
As both the `maven-jar-plugin` and the `spring-boot-maven-plugin` runs at the same phase, it is important that the jar plugin is defined first (so that it runs before the repackage goal).
Again, if you are using `spring-boot-starter-parent`, this can be simplified as follows:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-jar</id>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>repackage</id>
<configuration>
<classifier>task</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
[[repackage-example-custom-name]]
==== Custom Name
If you need the repackaged jar to have a different local name than the one defined by the `artifactId` attribute of the project, simply use the standard `finalName`, as shown in the following example:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<finalName>my-app</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
This configuration will generate the repackaged artifact in `target/my-app.jar`.
[[repackage-example-local-artifact]]
==== Local Repackaged Artifact
By default, the `repackage` goal replaces the original artifact with the executable one.
If you need to only deploy the original jar and yet be able to run your app with the regular file name, configure the plugin as follows:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<attach>false</attach>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
----
This configuration generates two artifacts: the original one and the executable counter part produced by the `repackage` goal.
Only the original one will be installed/deployed.
[[repackage-example-custom-layout]]
==== Custom Layout
Spring Boot repackages the jar file for this project using a custom layout factory defined in the additional jar file, provided as a dependency to the build plugin:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<layoutFactory implementation="com.example.CustomLayoutFactory">
<customProperty>value</customProperty>
</layoutFactory>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>custom-layout</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
</project>
----
The layout factory is provided as an implementation of `LayoutFactory` (from `spring-boot-loader-tools`) explicitly specified in the pom.
If there is only one custom `LayoutFactory` on the plugin classpath and it is listed in `META-INF/spring.factories` then it is unnecessary to explicitly set it in the plugin configuration.
Layout factories are always ignored if an explicit <<goals-repackage-optional-parameters-layout,layout>> is set.
[[repackage-example-exclude-dependency]]
==== Dependency Exclusion
By default, both the `repackage` and the `run` goals will include any `provided` dependencies that are defined in the project.
A Spring Boot project should consider `provided` dependencies as "container" dependencies that are required to run the application.
Some of these dependencies may not be required at all and should be excluded from the executable jar.
For consistency, they should not be present either when running the application.
There are two ways one can exclude a dependency from being packaged/used at runtime:
* Exclude a specific artifact identified by `groupId` and `artifactId`, optionally with a `classifier` if needed.
* Exclude any artifact belonging to a given `groupId`.
The following example excludes `com.foo:bar`, and only that artifact:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<excludes>
<exclude>
<groupId>com.foo</groupId>
<artifactId>bar</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
This example excludes any artifact belonging to the `com.foo` group:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<excludeGroupIds>com.foo</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
</project>
----

@ -0,0 +1,241 @@
[[run]]
== Running your application with Maven
The plugin includes a run goal which can be used to launch your application from the command line, as shown in the following example:
[indent=0]
----
$ mvn spring-boot:run
----
By default the application is executed in a forked process and setting properties on the command-line will not affect the application.
If you need to specify some JVM arguments (i.e. for debugging purposes), you can use the `jvmArguments` parameter, see <<run-example-debug,Debug the application>> for more details.
There is also explicit support for <<run-example-system-properties,system properties>> and <<run-example-environment-variable,environment variables>>.
As enabling a profile is quite common, there is dedicated `profiles` property that offers a shortcut for `-Dspring-boot.run.jvmArguments="-Dspring.profiles.active=dev"`, see <<run-example-active-profiles,Specify active profiles>>.
Although this is not recommended, it is possible to execute the application directly from the Maven JVM by disabling the `fork` property.
Doing so means that the `jvmArguments`, `systemPropertyVariables`, `environmentVariables` and `agents` options are ignored.
Spring Boot `devtools` is a module to improve the development-time experience when working on Spring Boot applications.
To enable it, just add the following dependency to your project:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>{version}</version>
<optional>true</optional>
</dependency>
</dependencies>
----
When `devtools` is running, it detects change when you recompile your application and automatically refreshes it.
This works for not only resources but code as well.
It also provides a LiveReload server so that it can automatically trigger a browser refresh whenever things change.
Devtools can also be configured to only refresh the browser whenever a static resource has changed (and ignore any change in the code).
Just include the following property in your project:
[source,properties,indent=0]
----
spring.devtools.remote.restart.enabled=false
----
Prior to `devtools`, the plugin supported hot refreshing of resources by default which has now be disabled in favour of the solution described above.
You can restore it at any time by configuring your project:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<addResources>true</addResources>
</configuration>
</plugin>
</plugins>
</build>
----
When `addResources` is enabled, any `src/main/resources` folder will be added to the application classpath when you run the application and any duplicate found in `target/classes` will be removed.
This allows hot refreshing of resources which can be very useful when developing web applications.
For example, you can work on HTML, CSS or JavaScript files and see your changes immediately without recompiling your application.
It is also a helpful way of allowing your front end developers to work without needing to download and install a Java IDE.
NOTE: A side effect of using this feature is that filtering of resources at build time will not work.
In order to be consistent with the `repackage` goal, the `run` goal builds the classpath in such a way that any dependency that is excluded in the plugin's configuration gets excluded from the classpath as well.
For more details, see <<run-example-exclude-dependency,the dedicated example>>.
Sometimes it is useful to include test dependencies when running the application.
For example, if you want to run your application in a test mode that uses stub classes.
If you wish to do this, you can set the `useTestClasspath` parameter to true.
Note that this is only applied when you run an application: the `repackage` goal will not add test dependencies to the resulting JAR/WAR.
include::{generated-resources-root}/goals/run.adoc[leveloffset=+1]
[[run-examples]]
=== Examples
[[run-example-debug]]
==== Debug the Application
By default, the `run` goal runs your application in a forked process.
If you need to debug it, you should add the necessary JVM arguments to enable remote debugging.
The following configuration suspend the process until a debugger has joined on port 5005:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<jvmArguments>
-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005
</jvmArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
These arguments can be specified on the command line as well, make sure to wrap that properly, that is:
[indent=0]
----
$ mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"
----
[[run-example-system-properties]]
==== Using System Properties
System properties can be specified using the `systemPropertyVariables` attribute.
The following example sets `property1` to `test` and `property2` to 42:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<properties>
<my.value>42</my.value>
</properties>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<systemPropertyVariables>
<property1>test</property1>
<property2>${my.value}</property2>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
If the value is empty or not defined (i.e. `<my-property/`>), the system property is set with an empty String as the value.
Maven trims values specified in the pom so it is not possible to specify a System property which needs to start or end with a space via this mechanism: consider using `jvmArguments` instead.
Any String typed Maven variable can be passed as system properties.
Any attempt to pass any other Maven variable type (e.g. a `List` or a `URL` variable) will cause the variable expression to be passed literally (unevaluated).
The `jvmArguments` parameter takes precedence over system properties defined with the mechanism above.
In the following example, the value for `property1` is `overridden`:
[indent=0]
----
$ mvn spring-boot:run -Dspring-boot.run.jvmArguments="-Dproperty1=overridden"
----
[[run-example-environment-variables]]
==== Using Environment Variables
Environment variables can be specified using the `environmentVariables` attribute.
The following example sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<environmentVariables>
<ENV1>5000</ENV1>
<ENV2>Some Text</ENV2>
<ENV3/>
<ENV4></ENV4>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
If the value is empty or not defined (i.e. `<MY_ENV/`>), the env variable is set with an empty String as the value.
Maven trims values specified in the pom so it is not possible to specify an env variable which needs to start or end with a space.
Any String typed Maven variable can be passed as system properties.
Any attempt to pass any other Maven variable type (e.g. a `List` or a `URL` variable) will cause the variable expression to be passed literally (unevaluated).
Environment variables defined this way take precedence over existing values.
[[run-example-active-profiles]]
==== Specify Active Profiles
The active profiles to use for a particular application can be specified using the `profiles` argument.
The following configuration enables the `foo` and `bar` profiles:
[source,xml,indent=0,subs="verbatim,attributes"]
----
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>{version}</version>
<configuration>
<profiles>
<profile>foo</profile>
<profile>bar</profile>
</profiles>
</configuration>
</plugin>
</plugins>
</build>
</project>
----
The profiles to enable can be specified on the command line as well, make sure to separate them with a comma, as shown in the following example:
[indent=0]
----
$ mvn spring-boot:run -Dspring-boot.run.profiles=foo,bar
----

@ -0,0 +1,129 @@
import groovy.util.XmlSlurper
private String format(String input) {
input.replace("<code>", "`")
.replace("</code>", "`")
.replace("&lt;", "<")
.replace("&gt;", ">")
.replace("<br>", " ")
.replace("\n", " ")
.replace("&quot;", '"')
.replaceAll('\\{@code (.*?)\\}', '`$1`')
.replaceAll('\\{@link (.*?)\\}', '`$1`')
.replaceAll('\\{@literal (.*?)\\}', '`$1`')
.replaceAll('<a href=."(.*?)".>(.*?)</a>', '\$1[\$2]')
}
private writeParametersTable(PrintWriter writer, def goal, def parameters, def configuration) {
writer.println '[cols="3,2,3"]'
writer.println '|==='
writer.println '| Name | Type | Default'
writer.println()
parameters.each { parameter ->
def name = parameter.name.text()
writer.println("| <<goals-$goal-parameters-details-$name,$name>>")
def type = parameter.type.text()
if (type.lastIndexOf('.') >= 0) {
type = type.substring(type.lastIndexOf('.') + 1)
}
writer.println("| `$type`")
def defaultValue = "${configuration[name].@'default-value'}"
if (defaultValue) {
writer.println("| `$defaultValue`")
}
else {
writer.println("|")
}
writer.println()
}
writer.println '|==='
}
private writeParameterDetails(PrintWriter writer, def parameters, def configuration, def sectionId) {
parameters.each { parameter ->
def name = parameter.name.text()
writer.println "[[$sectionId-$name]]"
writer.println "==== `$name`"
writer.println(format(parameter.description.text()))
writer.println()
writer.println '[cols="10h,90"]'
writer.println '|==='
writer.println()
writer.println '| Name'
writer.println "| `$name`"
writer.println '| Type'
def type = parameter.type.text()
if (type.lastIndexOf('.') >= 0) {
type = type.substring(type.lastIndexOf('.') + 1)
}
writer.println("| `$type`")
def defaultValue = "${configuration[name].@'default-value'}"
if (defaultValue) {
writer.println '| Default value'
writer.println("| `$defaultValue`")
}
def userProperty = "${configuration[name].text().replace('${', '`').replace('}', '`')}"
writer.println '| User property'
userProperty ? writer.println("| ${userProperty}") : writer.println("|")
writer.println '| Since'
def since = parameter.since.text()
since ? writer.println("| `${since}`") : writer.println("|")
writer.println '| Required'
writer.println "| ${parameter.required.text()}"
writer.println()
writer.println '|==='
}
}
def plugin = new XmlSlurper().parse("${project.build.outputDirectory}/META-INF/maven/plugin.xml" as File)
String goalPrefix = plugin.goalPrefix.text()
File goalsDir = new File(project.build.directory, "generated-resources/goals/")
goalsDir.mkdirs()
new File(goalsDir, "overview.adoc").withPrintWriter { writer ->
writer.println '[cols="1,3"]'
writer.println '|==='
writer.println '| Goal | Description'
writer.println()
plugin.mojos.mojo.each { mojo ->
def goal = mojo.goal.text()
writer.println "| <<goals-$goal,${goalPrefix}:${mojo.goal.text()}>>"
writer.println "| ${format(mojo.description.text())}"
writer.println()
}
writer.println '|==='
}
plugin.mojos.mojo.each { mojo ->
String goal = mojo.goal.text()
new File(goalsDir, "${goal}.adoc").withPrintWriter { writer ->
def sectionId = "goals-$goal"
writer.println()
writer.println("[[$sectionId]]")
writer.println("== `$goalPrefix:$goal`")
writer.println("`${plugin.groupId.text()}:${plugin.artifactId.text()}:${plugin.version.text()}:${mojo.goal.text()}`")
writer.println()
writer.println(format(mojo.description.text()))
writer.println()
def parameters = mojo.parameters.parameter.findAll { it.editable.text() == 'true' }
def requiredParameters = parameters.findAll { it.required.text() == 'true' }
if (requiredParameters.size()) {
writer.println("[[$sectionId-parameters-required]]")
writer.println("=== Required parameters")
writeParametersTable(writer, goal, requiredParameters, mojo.configuration)
writer.println()
}
def optionalParameters = parameters.findAll { it.required.text() == 'false' }
if (optionalParameters.size()) {
writer.println("[[$sectionId-parameters-optional]]")
writer.println("=== Optional parameters")
writeParametersTable(writer, goal, optionalParameters, mojo.configuration)
writer.println()
}
def detailsSectionId = "$sectionId-parameters-details"
writer.println("[[$detailsSectionId]]")
writer.println("=== Parameter details")
writeParameterDetails(writer, parameters, mojo.configuration, detailsSectionId)
writer.println()
}
}

@ -112,7 +112,7 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
* attached as a supplemental artifact with that classifier. Attaching the artifact
* allows to deploy it alongside to the original one, see <a href=
* "https://maven.apache.org/plugins/maven-deploy-plugin/examples/deploying-with-classifiers.html"
* > the maven documentation for more details</a>.
* >the Maven documentation for more details</a>.
* @since 1.0.0
*/
@Parameter

Loading…
Cancel
Save