diff --git a/spring-boot-dependencies/pom.xml b/spring-boot-dependencies/pom.xml index 7409ed41901..3821310b094 100644 --- a/spring-boot-dependencies/pom.xml +++ b/spring-boot-dependencies/pom.xml @@ -78,7 +78,6 @@ 2.3.25-incubating 2.4.4 3.0.0 - 3.4 2.4.10 2.8.0 1.4.194 diff --git a/spring-boot-docs/pom.xml b/spring-boot-docs/pom.xml index 7c96c172e99..33788d4b041 100644 --- a/spring-boot-docs/pom.xml +++ b/spring-boot-docs/pom.xml @@ -853,6 +853,15 @@ META-INF/** + + org.springframework.boot + spring-boot-gradle-plugin + ${project.version} + docs + zip + ${project.build.directory}/contents/gradle-plugin + META-INF/** + diff --git a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc index 1f914771ba6..d0de570135d 100644 --- a/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc +++ b/spring-boot-docs/src/main/asciidoc/build-tool-plugins.adoc @@ -164,516 +164,11 @@ Advanced configuration options and examples are available in the [[build-tool-plugins-gradle-plugin]] == Spring Boot Gradle plugin -The Spring Boot Gradle Plugin provides Spring Boot support in Gradle, allowing you to -package executable jar or war archives, run Spring Boot applications and use the -dependency management provided by `spring-boot-dependencies`. - - - -[[build-tool-plugins-including-the-gradle-plugin]] -=== Including the plugin -ifeval::["{spring-boot-repo}" == "release"] -To use the Spring Boot Gradle Plugin configure it using the `plugins` block: -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - plugins { - id 'org.springframework.boot' version '{spring-boot-version}' - } ----- -endif::[] -ifeval::["{spring-boot-repo}" != "release"] -To use the Spring Boot Gradle Plugin simply include a `buildscript` dependency and apply -the `spring-boot` plugin: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - buildscript { - repositories { - maven { url 'http://repo.spring.io/snapshot' } - maven { url 'http://repo.spring.io/milestone' } - } - dependencies { - classpath 'org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}'' - } - } - apply plugin: 'org.springframework.boot' ----- -endif::[] - - - -[[build-tool-plugins-gradle-dependency-management]] -=== Gradle dependency management -The `spring-boot` plugin automatically applies the -{dependency-management-plugin}/[Dependency Management Plugin] and configures it to import -the `spring-boot-starter-parent` bom. This provides a similar dependency management -experience to the one that is enjoyed by Maven users. For example, it allows you to omit -version numbers when declaring dependencies that are managed in the bom. To make use of -this functionality, simply declare dependencies in the usual way, but leave the version -number empty: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - compile("org.thymeleaf:thymeleaf-spring5") - compile("nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect") - } ----- - -NOTE: The version of the `spring-boot` gradle plugin that you declare determines the -version of the `spring-boot-starter-parent` bom that is imported (this ensures that builds -are always repeatable). You should always set the version of the `spring-boot` gradle -plugin to the actual Spring Boot version that you wish to use. Details of the versions -that are provided can be found in the <>. - -To learn more about the capabilities of the Dependency Management Plugin, please refer to -its {dependency-management-plugin-documentation}[documentation]. - - - -[[build-tool-plugins-gradle-packaging]] -=== Packaging executable jar and war files -Once the `spring-boot` plugin has been applied to your project it will automatically -attempt to rewrite archives to make them executable using the -<>. You -should configure your project to build a jar or war (as appropriate) in the usual way. - -The main class that you want to launch can either be specified using a configuration -option, or by adding a `Main-Class` attribute to the manifest. If you don't specify a -main class the plugin will search for a class with a -`public static void main(String[] args)` method. - -TIP: Check <> for a full list of -configuration options. - -To build and run a project artifact, you can type the following: - -[indent=0] ----- - $ gradle build - $ java -jar build/libs/mymodule-0.0.1-SNAPSHOT.jar ----- - -To build a war file that is both executable and deployable into an external container, -you need to mark the embedded container dependencies as belonging to the war plugin's -`providedRuntime` configuration, e.g.: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - ... - apply plugin: 'war' - - war { - baseName = 'myapp' - version = '0.5.0' - } - - repositories { - jcenter() - maven { url "http://repo.spring.io/libs-snapshot" } - } - - dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") - ... - } ----- - -TIP: See the "`<>`" section for more details on -how to create a deployable war file. - - - -[[build-tool-plugins-gradle-running-applications]] -=== Running a project in-place -To run a project in place without building a jar first you can use the "`bootRun`" task: - -[indent=0] ----- - $ gradle bootRun ----- - -If <> has been added to your project -it will automatically monitor your application for changes. Alternatively, you can also -run the application so that your static classpath resources (i.e. in `src/main/resources` -by default) are reloadable in the live application, which can be helpful at development -time. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - bootRun { - addResources = true - } ----- - -Making static classpath resources reloadable means that `bootRun` does not use the output -of the `processResources` task, i.e., when invoked using `bootRun`, your application will -use the resources in their unprocessed form. - - - -[[build-tool-plugins-gradle-global-configuration]] -=== Spring Boot plugin configuration -The gradle plugin automatically extends your build script DSL with a `springBoot` element -for global configuration of the Boot plugin. Set the appropriate properties as you would -with any other Gradle extension (see below for a list of configuration options): - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - springBoot { - backupSource = false - } ----- - - - -[[build-tool-plugins-gradle-repackage-configuration]] -=== Repackage configuration -The plugin adds a `bootRepackage` task which you can also configure directly, e.g.: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - bootRepackage { - mainClass = 'demo.Application' - } ----- - -The following configuration options are available: - -[cols="2,4"] -|=== -|Name |Description - -|`enabled` -|Boolean flag to switch the repackager off (sometimes useful if you -want the other Boot features but not this one) - -|`mainClass` -|The main class that should be run. If not specified, and you have applied the application - plugin, the `mainClassName` project property will be used. If the application plugin has - not been applied or no `mainClassName` has been specified, the archive will be searched - for a suitable class. "Suitable" means a unique class with a well-formed `main()` method - (if more than one is found the build will fail). If you have applied the application - plugin, the main class can also be specified via its "run" task (`main` property) and/or - its "startScripts" task (`mainClassName` property) as an alternative to using the - "springBoot" configuration. - -|`classifier` -|A file name segment (before the extension) to add to the archive, so that the original is - preserved in its original location. Defaults to `null` in which case the archive is - repackaged in place. The default is convenient for many purposes, but if you want to use - the original jar as a dependency in another project you must use a classifier to define - the executable archive. - -|`withJarTask` -|The name or value of the `Jar` task (defaults to all tasks of type `Jar`) which is used - to locate the archive to repackage. - -|`customConfiguration` -|The name of the custom configuration which is used to populate the nested lib directory - (without specifying this you get all compile and runtime dependencies). - -|`executable` -|Boolean flag to indicate if jar files are fully executable on Unix like operating - systems. Defaults to `false`. - -|`embeddedLaunchScript` -|The embedded launch script to prepend to the front of the jar if it is fully executable. - If not specified the 'Spring Boot' default script will be used. - -|`embeddedLaunchScriptProperties` -|Additional properties that to be expanded in the launch script. The default script - supports a `mode` property which can contain the values `auto`, `service` or `run`. - -|`excludeDevtools` -|Boolean flag to indicate if the devtools jar should be excluded from the repackaged -archives. Defaults to `true`. -|=== - - - -[[build-tool-plugins-gradle-repackage-custom-configuration]] -=== Repackage with custom Gradle configuration -Sometimes it may be more appropriate to not package default dependencies resolved from -`compile`, `runtime` and `provided` scopes. If the created executable jar file -is intended to be run as it is, you need to have all dependencies nested inside it; -however, if the plan is to explode a jar file and run the main class manually, you may already -have some of the libraries available via `CLASSPATH`. This is a situation where -you can repackage your jar with a different set of dependencies. - -Using a custom -configuration will automatically disable dependency resolving from -`compile`, `runtime` and `provided` scopes. Custom configuration can be either -defined globally (inside the `springBoot` section) or per task. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - task clientJar(type: Jar) { - appendix = 'client' - from sourceSets.main.output - exclude('**/*Something*') - } - - task clientBoot(type: BootRepackage, dependsOn: clientJar) { - withJarTask = clientJar - customConfiguration = "mycustomconfiguration" - } ----- - -In above example, we created a new `clientJar` Jar task to package a customized -file set from your compiled sources. Then we created a new `clientBoot` -BootRepackage task and instructed it to work with only `clientJar` task and -`mycustomconfiguration`. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - configurations { - mycustomconfiguration.exclude group: 'log4j' - } - - dependencies { - mycustomconfiguration configurations.runtime - } ----- - -The configuration that we are referring to in `BootRepackage` is a normal -{gradle-dsl}/org.gradle.api.artifacts.Configuration.html[Gradle -configuration]. In the above example we created a new configuration named -`mycustomconfiguration` instructing it to derive from a `runtime` and exclude the `log4j` -group. If the `clientBoot` task is executed, the repackaged boot jar will have all -dependencies from `runtime` but no `log4j` jars. - - - -[[build-tool-plugins-gradle-configuration-options]] -==== Configuration options -The following configuration options are available: - -[cols="2,4"] -|=== -|Name |Description - -|`mainClass` -|The main class that should be run by the executable archive. - -|`providedConfiguration` -|The name of the provided configuration (defaults to `providedRuntime`). - -|`backupSource` -|If the original source archive should be backed-up before being repackaged (defaults - to `true`). - -|`customConfiguration` -|The name of the custom configuration. - -|`layout` -|The type of archive, corresponding to how the dependencies are laid out inside - (defaults to a guess based on the archive type). See - <>. - -|`layoutFactory` -|A layout factory that can be used if a custom layout is required. Alternative layouts -can be provided by 3rd parties. Layout factories are only used when `layout` is not -specified. - -|`requiresUnpack` -|A list of dependencies (in the form "`groupId:artifactId`" that must be unpacked from - fat jars in order to run. Items are still packaged into the fat jar, but they will be - automatically unpacked when it runs. -|=== - - - -[[build-tool-plugins-gradle-configuration-layouts]] -==== Available layouts - -The `layout` attribute configures the format of the archive and whether the bootstrap -loader should be included or not. The following layouts are available: - -[cols="2,4,1"] -|=== -|Name |Description |Executable - -|`JAR` -|Regular executable - <>. -|Yes - -|`WAR` -|Executable - <>. - `provided` dependencies are placed in `WEB-INF/lib-provided` to avoid any clash when - the `war` is deployed in a servlet container. -|Yes - -|`ZIP` (alias to `DIR`) -|Similar to `JAR` layout, using - <>. -| Yes - -|`MODULE` -|Bundle dependencies (excluding those with `provided` scope) and project resources. -|No - -|`NONE` -|Bundle all dependencies and project resources. -|No -|=== - - - -[[build-tool-plugins-gradle-configuration-custom-repackager]] -==== Using a custom layout -If you have custom requirements for how to arrange the dependencies and loader classes -inside the repackaged jar, you can use a custom layout. Any library which defines one -or more `LayoutFactory` implementations can be added to the build script dependencies -and then the layout factory becomes available in the `springBoot` configuration. -For example: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}") - classpath("com.example:custom-layout:1.0.0") - } -} - -springBoot { - layoutFactory = new com.example.CustomLayoutFactory() -} ----- - -NOTE: If there is only one custom `LayoutFactory` on the build classpath and it is -listed in `META-INF/spring.factories` then it is unnecessary to explicitly set it in the -`springBoot` configuration. Layout factories are only used when no explicit `layout` is -specified. - - - -[[build-tool-plugins-understanding-the-gradle-plugin]] -=== Understanding how the Gradle plugin works -When `spring-boot` is applied to your Gradle project a default task named `bootRepackage` -is created automatically. The `bootRepackage` task depends on Gradle `assemble` task, and -when executed, it tries to find all jar artifacts whose qualifier is empty (i.e. tests and -sources jars are automatically skipped). - -Due to the fact that `bootRepackage` finds 'all' created jar artifacts, the order of -Gradle task execution is important. Most projects only create a single jar file, so -usually this is not an issue; however, if you are planning to create a more complex -project setup, with custom `Jar` and `BootRepackage` tasks, there are few tweaks to -consider. - -If you are 'just' creating custom jar files from your project you can simply disable -default `jar` and `bootRepackage` tasks: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - jar.enabled = false - bootRepackage.enabled = false ----- - -Another option is to instruct the default `bootRepackage` task to only work with a -default `jar` task. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - bootRepackage.withJarTask = jar ----- - -If you have a default project setup where the main jar file is created and repackaged, -'and' you still want to create additional custom jars, you can combine your custom -repackage tasks together and use `dependsOn` so that the `bootJars` task will run after -the default `bootRepackage` task is executed: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - task bootJars - bootJars.dependsOn = [clientBoot1,clientBoot2,clientBoot3] - build.dependsOn(bootJars) ----- - -All the above tweaks are usually used to avoid situations where an already created boot -jar is repackaged again. Repackaging an existing boot jar will not break anything, but -you may find that it includes unnecessary dependencies. - - - -[[build-tool-plugins-gradle-publishing-artifacts-to-a-maven-repository]] -=== Publishing artifacts to a Maven repository using Gradle -If you are <> and you want to publish artifacts to a Maven repository -you will need to configure the Maven publication with details of Spring Boot's -dependency management. This can be achieved by configuring it to publish poms that -inherit from `spring-boot-starter-parent` or that import dependency management from -`spring-boot-dependencies`. The exact details of this configuration depend on how you're -using Gradle and how you're trying to publish the artifacts. - - - -[[build-tool-plugins-gradle-publishing-artifacts-to-a-maven-repository-inherit]] -==== Configuring Gradle to produce a pom that inherits dependency management -The following is an example of configuring Gradle to generate a pom that inherits -from `spring-boot-starter-parent`. Please refer to the -{gradle-user-guide}/userguide.html[Gradle User Guide] for further information. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - uploadArchives { - repositories { - mavenDeployer { - pom { - project { - parent { - groupId "org.springframework.boot" - artifactId "spring-boot-starter-parent" - version "{spring-boot-version}" - } - } - } - } - } - } ----- - - - -[[build-tool-plugins-gradle-publishing-artifacts-to-a-maven-repository-import]] -==== Configuring Gradle to produce a pom that imports dependency management -The following is an example of configuring Gradle to generate a pom that imports -the dependency management provided by `spring-boot-dependencies`. Please refer to the -http://www.gradle.org/docs/current/userguide/userguide.html[Gradle User Guide] for -further information. - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - uploadArchives { - repositories { - mavenDeployer { - pom { - project { - dependencyManagement { - dependencies { - dependency { - groupId "org.springframework.boot" - artifactId "spring-boot-dependencies" - version "{spring-boot-version}" - type "pom" - scope "import" - } - } - } - } - } - } - } - } ----- +The {spring-boot-gradle-plugin}[Spring Boot Gradle Plugin] provides Spring Boot support +in Gradle, allowing you to package executable jar or war archives, run Spring Boot +applications and use the dependency management provided by `spring-boot-dependencies`. +It requires Gradle 3.4 or later. Please refer to the {spring-boot-gradle-plugin}[plugin's +documentation] to learn more. diff --git a/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-docs/src/main/asciidoc/howto.adoc index e4fea6f5903..368919a2138 100644 --- a/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -827,12 +827,12 @@ Example in Gradle: [source,groovy,indent=0,subs="verbatim,quotes,attributes"] ---- configurations { - compile.exclude module: "spring-boot-starter-tomcat" + compile.exclude module: 'spring-boot-starter-tomcat' } dependencies { - compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}") - compile("org.springframework.boot:spring-boot-starter-jetty:{spring-boot-version}") + compile 'org.springframework.boot:spring-boot-starter-web' + compile 'org.springframework.boot:spring-boot-starter-jetty' // ... } ---- @@ -881,12 +881,12 @@ Example in Gradle: [source,groovy,indent=0,subs="verbatim,quotes,attributes"] ---- configurations { - compile.exclude module: "spring-boot-starter-tomcat" + compile.exclude module: 'spring-boot-starter-tomcat' } dependencies { - compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}") - compile("org.springframework.boot:spring-boot-starter-undertow:{spring-boot-version}") + compile 'org.springframework.boot:spring-boot-starter-web' + compile 'org.springframework.boot:spring-boot-starter-undertow' // ... } ---- @@ -2355,9 +2355,11 @@ To configure IntelliJ IDEA correctly you can use the `idea` Gradle plugin: [source,groovy,indent=0,subs="verbatim,attributes"] ---- buildscript { - repositories { jcenter() } + repositories { + jcenter() + } dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}" + classpath 'org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}' classpath 'org.springframework:springloaded:1.2.6.RELEASE' } } @@ -2424,7 +2426,7 @@ And to do the same with Gradle: [source,groovy,indent=0,subs="verbatim,attributes"] ---- - springBoot { + springBoot { buildInfo() } ---- @@ -2502,16 +2504,7 @@ the artifact yourself instead of overriding the property. WARNING: Each Spring Boot release is designed and tested against a specific set of third-party dependencies. Overriding versions may cause compatibility issues. -To override dependency versions in Gradle, you can specify a version as shown below: - -[source,groovy,indent=0] ----- - ext['slf4j.version'] = '1.7.5' ----- -For additional information, please refer to the -https://github.com/spring-gradle-plugins/dependency-management-plugin[Gradle Dependency -Management Plugin documentation]. [[howto-create-an-executable-jar-with-maven]] === Create an executable JAR with Maven @@ -2593,15 +2586,6 @@ To configure a classifier of `exec` in Maven, the following configuration can be ---- -And when using Gradle, the following configuration can be used: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - bootRepackage { - classifier = 'exec' - } ----- - [[howto-extract-specific-libraries-when-an-executable-jar-runs]] @@ -2637,15 +2621,6 @@ you would add the following configuration: ---- -And to do that same with Gradle: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - springBoot { - requiresUnpack = ['org.jruby:jruby-complete'] - } ----- - [[howto-create-a-nonexecutable-jar]] @@ -2689,29 +2664,6 @@ jar must be the main artifact and you can add a classified jar for the library: ---- -In Gradle you can create a new JAR archive with standard task DSL features, and then have -the `bootRepackage` task depend on that one using its `withJarTask` property: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - jar { - baseName = 'spring-boot-sample-profile' - version = '0.0.0' - excludes = ['**/application.yml'] - } - - task('execJar', type:Jar, dependsOn: 'jar') { - baseName = 'spring-boot-sample-profile' - version = '0.0.0' - classifier = 'exec' - from sourceSets.main.output - } - - bootRepackage { - withJarTask = tasks['execJar'] - } ----- - [[howto-remote-debug-maven-run]] @@ -2723,34 +2675,6 @@ Check {spring-boot-maven-plugin-site}/examples/run-debug.html[this example] for -[[howto-remote-debug-gradle-run]] -=== Remote debug a Spring Boot application started with Gradle -To attach a remote debugger to a Spring Boot application started with Gradle you can use -the `jvmArgs` property of `bootRun` task or `--debug-jvm` command line option. - -`build.gradle`: - -[source,groovy,indent=0,subs="verbatim,attributes"] ----- - bootRun { - jvmArgs "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" - } ----- - - -Command line: - -[indent=0] ----- - $ gradle bootRun --debug-jvm ----- - - -Check {gradle-userguide}/application_plugin.html[Gradle Application Plugin] for more -details. - - - [[howto-build-an-executable-archive-with-ant]] === Build an executable archive from Ant without using spring-boot-antlib To build with Ant you need to grab dependencies, compile and then create a jar or war @@ -2894,10 +2818,9 @@ And if you're using Gradle: } ---- -NOTE: If you are using a version of Gradle that supports compile only dependencies (2.12 -or later), you should continue to use `providedRuntime`. Among other limitations, -`compileOnly` dependencies are not on the test classpath so any web-based integration -tests will fail. +NOTE: `providedRuntime` is prefered to Gradle's `compileOnly` configuration as, among other +limitations, `compileOnly` dependencies are not on the test classpath so any web-based +integration tests will fail. If you're using the <>, marking the embedded servlet container dependency as provided will produce an executable war diff --git a/spring-boot-docs/src/main/asciidoc/index.adoc b/spring-boot-docs/src/main/asciidoc/index.adoc index de0438ccfb3..d79d7e60b59 100644 --- a/spring-boot-docs/src/main/asciidoc/index.adoc +++ b/spring-boot-docs/src/main/asciidoc/index.adoc @@ -34,7 +34,8 @@ Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson; :dc-spring-boot-test-autoconfigure: {dc-root}/org/springframework/boot/test/autoconfigure :dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin :dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md -:spring-boot-maven-plugin-site: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin +:spring-boot-maven-plugin-site: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/maven-plugin/ +:spring-boot-gradle-plugin: http://docs.spring.io/spring-boot/docs/{spring-boot-docs-version}/gradle-plugin/ :spring-reference: http://docs.spring.io/spring/docs/{spring-docs-version}/spring-framework-reference/htmlsingle :spring-security-reference: http://docs.spring.io/spring-security/site/docs/{spring-security-docs-version}/reference/htmlsingle :spring-security-oauth2-reference: http://projects.spring.io/spring-security-oauth/docs/oauth2.html @@ -50,8 +51,7 @@ Phillip Webb; Dave Syer; Josh Long; Stéphane Nicoll; Rob Winch; Andy Wilkinson; :propdeps-plugin: https://github.com/spring-projects/gradle-plugins/tree/master/propdeps-plugin :ant-manual: http://ant.apache.org/manual :code-examples: ../java/org/springframework/boot -:gradle-user-guide: https://docs.gradle.org/2.14.1/userguide -:gradle-dsl: https://docs.gradle.org/2.14.1/dsl +:gradle-user-guide: https://docs.gradle.org/3.4.1/userguide // ====================================================================================== include::documentation-overview.adoc[] diff --git a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc index 8b8ea14149a..7ac1ddb5578 100644 --- a/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc +++ b/spring-boot-docs/src/main/asciidoc/using-spring-boot.adoc @@ -41,8 +41,8 @@ feel that's necessary. The curated list contains all the spring modules that you can use with Spring Boot as well as a refined list of third party libraries. The list is available as a standard <> -and additional dedicated support for <> and -<> are available as well. +that can be used with both <> and +{spring-boot-gradle-plugin}[Gradle]. WARNING: Each release of Spring Boot is associated with a base version of the Spring Framework so we **highly** recommend you to not specify its version on your own. @@ -194,70 +194,8 @@ the parent. [[using-boot-gradle]] === Gradle -Gradle users can directly import '`starters`' in their `dependencies` section. Unlike -Maven, there is no "`super parent`" to import to share some configuration. - -[source,groovy,indent=0,subs="attributes"] ----- - repositories { -ifeval::["{spring-boot-repo}" != "release"] - maven { url "http://repo.spring.io/snapshot" } - maven { url "http://repo.spring.io/milestone" } -endif::[] -ifeval::["{spring-boot-repo}" == "release"] - jcenter() -endif::[] - } - - dependencies { - compile("org.springframework.boot:spring-boot-starter-web:{spring-boot-version}") - } ----- - -The <> is also available and provides tasks to create executable -jars and run projects from source. It also provides -<> that, among -other capabilities, allows you to omit the version number for any dependencies that are -managed by Spring Boot: - -[source,groovy,indent=0,subs="attributes"] ----- -ifeval::["{spring-boot-repo}" == "release"] - plugins { - id 'org.springframework.boot' version '{spring-boot-version}' - id 'java' - } -endif::[] -ifeval::["{spring-boot-repo}" != "release"] - buildscript { - repositories { - jcenter() - maven { url 'http://repo.spring.io/snapshot' } - maven { url 'http://repo.spring.io/milestone' } - } - dependencies { - classpath 'org.springframework.boot:spring-boot-gradle-plugin:{spring-boot-version}' - } - } - - apply plugin: 'java' - apply plugin: 'org.springframework.boot' -endif::[] - - repositories { - jcenter() -ifeval::["{spring-boot-repo}" != "release"] - maven { url 'http://repo.spring.io/snapshot' } - maven { url 'http://repo.spring.io/milestone' } -endif::[] - } - - dependencies { - compile("org.springframework.boot:spring-boot-starter-web") - testCompile("org.springframework.boot:spring-boot-starter-test") - } ----- +To learn about using Spring Boot with Gradle, please refer to the +{spring-boot-gradle-plugin}[documentation for Spring Boot's Gradle plugin]. @@ -704,8 +642,8 @@ You might also want to use the useful operating system environment variable: [[using-boot-running-with-the-gradle-plugin]] === Using the Gradle plugin The Spring Boot Gradle plugin also includes a `bootRun` task which can be used to run -your application in an exploded form. The `bootRun` task is added whenever you import -the `spring-boot-gradle-plugin`: +your application in an exploded form. The `bootRun` task is added whenever you apply the +the `org.springframework.boot` and `java` plugins: [indent=0,subs="attributes"] ---- diff --git a/spring-boot-integration-tests/pom.xml b/spring-boot-integration-tests/pom.xml index 6b62d0d12f6..dc500531375 100644 --- a/spring-boot-integration-tests/pom.xml +++ b/spring-boot-integration-tests/pom.xml @@ -23,7 +23,6 @@ spring-boot-devtools-tests spring-boot-integration-tests-embedded-servlet-container - spring-boot-gradle-tests spring-boot-launch-script-tests spring-boot-security-tests diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/pom.xml b/spring-boot-integration-tests/spring-boot-gradle-tests/pom.xml deleted file mode 100644 index 7f465d6f398..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/pom.xml +++ /dev/null @@ -1,87 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-integration-tests - 2.0.0.BUILD-SNAPSHOT - - spring-boot-gradle-tests - jar - Spring Boot Gradle Integration Tests - Spring Boot Gradle Integration Tests - http://projects.spring.io/spring-boot/ - - Pivotal Software, Inc. - http://www.spring.io - - - ${basedir}/../.. - - - - org.gradle - gradle-tooling-api - ${gradle.version} - test - - - org.springframework.boot - spring-boot - test - - - org.apache.maven - maven-model-builder - 3.2.1 - test - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - copy-effective-pom - generate-test-resources - - copy - - - - - org.springframework.boot - spring-boot-dependencies - ${project.version} - effective-pom - true - ${project.build.directory} - dependencies-pom.xml - - - - - - - - - - - gradle - http://repo.gradle.org/gradle/libs-releases-local - - true - - - false - - - - diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/BootRunResourceTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/BootRunResourceTests.java deleted file mode 100644 index 68c701f4aff..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/BootRunResourceTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.IOException; - -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Rule; -import org.junit.Test; - -import org.springframework.boot.test.rule.OutputCapture; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for bootRun's resource handling - * - * @author Andy Wilkinson - */ -public class BootRunResourceTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @Rule - public OutputCapture output = new OutputCapture(); - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("boot-run-resources"); - } - - @Test - public void resourcesDirectlyFromSource() { - project.newBuild().forTasks("clean", "bootRun") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PaddResources=true") - .setStandardOutput(System.out).run(); - - assertThat(this.output.toString()).contains("src/main/resources/test.txt"); - } - - @Test - public void resourcesFromBuildOutput() { - project.newBuild().forTasks("clean", "bootRun") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PaddResources=false") - .setStandardOutput(System.out).run(); - assertThat(this.output.toString()).contains("build/resources/main/test.txt"); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ClassifierTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ClassifierTests.java deleted file mode 100644 index 37a52642b59..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ClassifierTests.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.util.jar.JarFile; - -import org.gradle.tooling.ProjectConnection; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for using the Gradle plugin's support for installing artifacts - * - * @author Dave Syer - */ -public class ClassifierTests { - - private ProjectConnection project; - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - @Test - public void classifierInBootTask() throws Exception { - this.project = new ProjectCreator().createProject("classifier"); - this.project.newBuild().forTasks("build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); - checkFilesExist("classifier"); - } - - @Test - public void classifierInBootExtension() throws Exception { - this.project = new ProjectCreator().createProject("classifier-extension"); - this.project.newBuild().forTasks("build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace", "--info") - .run(); - } - - private void checkFilesExist(String name) throws Exception { - JarFile jar = new JarFile("target/" + name + "/build/libs/" + name + ".jar"); - assertThat(jar.getManifest()).isNotNull(); - jar.close(); - jar = new JarFile("target/" + name + "/build/libs/" + name + "-exec.jar"); - assertThat(jar.getManifest()).isNotNull(); - jar.close(); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FlatdirTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FlatdirTests.java deleted file mode 100644 index 15da226fb50..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FlatdirTests.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; - -import org.gradle.tooling.ProjectConnection; -import org.junit.Before; -import org.junit.Test; - -import org.springframework.util.FileCopyUtils; -import org.springframework.util.FileSystemUtils; - -/** - * Tests for using the Gradle plugin's support for flat directory repos - * - * @author Dave Syer - */ -public class FlatdirTests { - - private ProjectConnection project; - - private File libs = new File("target/flatdir/lib"); - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - @Before - public void init() { - if (this.libs.exists()) { - FileSystemUtils.deleteRecursively(this.libs); - } - } - - @Test - public void flatdir() throws Exception { - this.project = new ProjectCreator().createProject("flatdir"); - if (!this.libs.exists()) { - this.libs.mkdirs(); - } - FileCopyUtils.copy(new File("src/test/resources/foo.jar"), - new File(this.libs, "foo-1.0.0.jar")); - this.project.newBuild().forTasks("build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FullyExecutableJarTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FullyExecutableJarTests.java deleted file mode 100644 index c90f1fc40dd..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/FullyExecutableJarTests.java +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Pattern; - -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for creating a fully executable jar with Gradle. - * - * @author Andy Wilkinson - */ -public class FullyExecutableJarTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("executable-jar"); - } - - @Test - public void jarIsNotExecutableByDefault() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION).run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isFalse(); - } - - @Test - public void madeExecutableViaExtension() throws IOException { - project.newBuild().forTasks("clean", "build").withArguments( - "-PbootVersion=" + BOOT_VERSION, "-PextensionExecutable=true").run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - } - - @Test - public void madeExecutableViaTask() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PtaskExecutable=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - } - - @Test - public void taskTakesPrecedenceForMakingJarExecutable() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, - "-PextensionExecutable=false", "-PtaskExecutable=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - } - - @Test - public void scriptPropertiesFromTask() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PtaskProperties=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - assertThat(containsLine("# Provides:.*__task__", executableJar)).isTrue(); - } - - @Test - public void scriptPropertiesFromExtension() throws IOException { - project.newBuild().forTasks("clean", "build").withArguments( - "-PbootVersion=" + BOOT_VERSION, "-PextensionProperties=true").run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - assertThat(containsLine("# Provides:.*__extension__", executableJar)).isTrue(); - } - - @Test - public void taskTakesPrecedenceForScriptProperties() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, - "-PextensionProperties=true", "-PtaskProperties=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(isFullyExecutable(executableJar)).isTrue(); - assertThat(containsLine("# Provides:.*__task__", executableJar)).isTrue(); - } - - @Test - public void customScriptFromTask() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PtaskScript=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(containsLine("Custom task script", executableJar)).isTrue(); - } - - @Test - public void customScriptFromExtension() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PextensionScript=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(containsLine("Custom extension script", executableJar)).isTrue(); - } - - @Test - public void taskTakesPrecedenceForCustomScript() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PextensionScript=true", - "-PtaskScript=true") - .run(); - File buildLibs = new File("target/executable-jar/build/libs"); - File executableJar = new File(buildLibs, "executable-jar.jar"); - assertThat(containsLine("Custom task script", executableJar)).isTrue(); - } - - private boolean isFullyExecutable(File file) throws IOException { - return containsLine("#!/bin/bash", file); - } - - private boolean containsLine(String toMatch, File file) throws IOException { - Pattern pattern = Pattern.compile(toMatch); - for (String line : readLines(file)) { - if (pattern.matcher(line).matches()) { - return true; - } - } - return false; - } - - private List readLines(File file) throws IOException { - BufferedReader reader = new BufferedReader(new FileReader(file)); - List lines = new ArrayList<>(); - try { - String line = reader.readLine(); - while (line != null && lines.size() < 50) { - lines.add(line); - line = reader.readLine(); - } - } - finally { - reader.close(); - } - return lines; - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java deleted file mode 100644 index 344edb79221..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/InstallTests.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import org.gradle.tooling.ProjectConnection; -import org.junit.Test; - -/** - * Tests for using the Gradle plugin's support for installing artifacts - * - * @author Dave Syer - */ -public class InstallTests { - - private ProjectConnection project; - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - @Test - public void cleanInstall() throws Exception { - this.project = new ProjectCreator().createProject("installer"); - this.project.newBuild().forTasks("install") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); - } - - @Test - public void cleanInstallDist() throws Exception { - this.project = new ProjectCreator().createProject("install-app"); - this.project.newBuild().forTasks("installDist") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java deleted file mode 100644 index 2921466c1b5..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MainClassTests.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.IOException; - -import org.gradle.tooling.BuildException; -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for configuring a project's main class. - * - * @author Dave Syer - * @author Andy Wilkinson - */ -public class MainClassTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("main-class"); - } - - @Test - public void mainFromBootRun() { - project.newBuild().forTasks("build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-PbootRunMain=true") - .run(); - } - - @Test - public void nonJavaExecRunTaskIsIgnored() { - try { - project.newBuild().forTasks("build").withArguments( - "-PbootVersion=" + BOOT_VERSION, "-PnonJavaExecRun=true").run(); - } - catch (BuildException ex) { - Throwable rootCause = getRootCause(ex); - assertThat(rootCause.getMessage()).isEqualTo("Unable to find main class"); - } - } - - private Throwable getRootCause(Throwable ex) { - Throwable candidate = ex; - while (candidate.getCause() != null) { - candidate = candidate.getCause(); - } - return candidate; - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java deleted file mode 100644 index f4d0832f509..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MixedVersionRepackagingTests.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; -import java.io.IOException; -import java.util.jar.JarFile; - -import org.assertj.core.api.Condition; -import org.assertj.core.description.TextDescription; -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.not; - -/** - * Integration tests for Gradle repackaging with two different versions of the same - * dependency. - * - * @author Andy Wilkinson - */ -public class MixedVersionRepackagingTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("mixed-version-repackaging"); - } - - @Test - public void singleVersionIsIncludedInJar() throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true", - "-PexcludeDevtools=false") - .run(); - File buildLibs = new File("target/mixed-version-repackaging/build/libs"); - File repackageFile = new File(buildLibs, "mixed-version-repackaging.jar"); - assertThat(repackageFile.exists()).isTrue(); - assertThat(new JarFile(repackageFile)) - .has(entryNamed("BOOT-INF/lib/guava-18.0.jar")); - assertThat(new JarFile(repackageFile)) - .has(not(entryNamed("BOOT-INF/lib/guava-16.0.jar"))); - } - - private Condition entryNamed(String name) { - return new JarFileEntryCondition(name); - } - - private final class JarFileEntryCondition extends Condition { - - private final String entryName; - - private JarFileEntryCondition(String entryName) { - super(new TextDescription("entry named '%s'", entryName)); - this.entryName = entryName; - } - - @Override - public boolean matches(JarFile jarFile) { - return jarFile.getEntry(this.entryName) != null; - } - - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java deleted file mode 100644 index b8296184e34..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/MultiProjectRepackagingTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; -import java.util.jar.JarFile; - -import org.gradle.tooling.ProjectConnection; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for Gradle repackaging with a multi-project build. - * - * @author Andy Wilkinson - */ -public class MultiProjectRepackagingTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - @Test - public void repackageWithTransitiveFileDependency() throws Exception { - ProjectConnection project = new ProjectCreator() - .createProject("multi-project-transitive-file-dependency"); - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION).run(); - File buildLibs = new File( - "target/multi-project-transitive-file-dependency/main/build/libs"); - JarFile jarFile = new JarFile(new File(buildLibs, "main.jar")); - assertThat(jarFile.getEntry("BOOT-INF/lib/commons-logging-1.1.3.jar")) - .isNotNull(); - assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); - jarFile.close(); - } - - @Test - public void repackageWithCommonFileDependency() throws Exception { - ProjectConnection project = new ProjectCreator() - .createProject("multi-project-common-file-dependency"); - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION).run(); - File buildLibs = new File( - "target/multi-project-common-file-dependency/build/libs"); - JarFile jarFile = new JarFile( - new File(buildLibs, "multi-project-common-file-dependency.jar")); - assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); - jarFile.close(); - } - - @Test - public void repackageWithRuntimeProjectDependency() throws Exception { - ProjectConnection project = new ProjectCreator() - .createProject("multi-project-runtime-project-dependency"); - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION).run(); - File buildLibs = new File( - "target/multi-project-runtime-project-dependency/projectA/build/libs"); - JarFile jarFile = new JarFile(new File(buildLibs, "projectA.jar")); - assertThat(jarFile.getEntry("BOOT-INF/lib/projectB.jar")).isNotNull(); - jarFile.close(); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java deleted file mode 100644 index 8e08921d372..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/ProjectCreator.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; -import java.io.IOException; - -import org.gradle.tooling.GradleConnector; -import org.gradle.tooling.ProjectConnection; -import org.gradle.tooling.internal.consumer.DefaultGradleConnector; - -import org.springframework.util.FileCopyUtils; -import org.springframework.util.FileSystemUtils; - -/** - * @author Andy Wilkinson - */ -public class ProjectCreator { - - private String gradleVersion; - - public ProjectCreator() { - this("3.4"); - } - - public ProjectCreator(String gradleVersion) { - this.gradleVersion = gradleVersion; - } - - public ProjectConnection createProject(String name) throws IOException { - File projectDirectory = new File("target/" + name); - projectDirectory.mkdirs(); - - File gradleScript = new File(projectDirectory, "build.gradle"); - - if (new File("src/test/resources", name).isDirectory()) { - FileSystemUtils.copyRecursively(new File("src/test/resources", name), - projectDirectory); - } - else { - FileCopyUtils.copy(new File("src/test/resources/" + name + ".gradle"), - gradleScript); - } - - GradleConnector gradleConnector = GradleConnector.newConnector(); - gradleConnector.useGradleVersion(this.gradleVersion); - - ((DefaultGradleConnector) gradleConnector).embedded(true); - return gradleConnector.forProjectDirectory(projectDirectory).connect(); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java deleted file mode 100644 index fd4b7e1e548..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/RepackagingTests.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; -import java.io.IOException; -import java.util.jar.JarFile; - -import org.gradle.tooling.BuildLauncher; -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Test; - -import org.springframework.util.FileCopyUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Integration tests for gradle repackaging. - * - * @author Andy Wilkinson - */ -public class RepackagingTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("repackage"); - } - - @Test - public void repackagingEnabled() throws IOException { - createBuildForTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); - File buildLibs = new File("target/repackage/build/libs"); - File repackageFile = new File(buildLibs, "repackage.jar"); - assertThat(repackageFile.exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - } - - @Test - public void repackagingDisabled() { - createBuildForTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "repackage.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isFalse(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - } - - @Test - public void repackagingDisabledWithCustomRepackagedJar() { - createBuildForTasks("clean", "build", "customRepackagedJar") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "repackage.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isFalse(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(new File(buildLibs, "custom.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "custom.jar.original").exists()).isTrue(); - } - - @Test - public void repackagingDisabledWithCustomRepackagedJarUsingStringJarTaskReference() { - project.newBuild() - .forTasks("clean", "build", "customRepackagedJarWithStringReference") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "repackage.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isFalse(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(new File(buildLibs, "custom.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "custom.jar.original").exists()).isTrue(); - } - - @Test - public void repackagingEnabledWithCustomRepackagedJar() { - createBuildForTasks("clean", "build", "customRepackagedJar") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "repackage.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(new File(buildLibs, "custom.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "custom.jar.original").exists()).isTrue(); - } - - @Test - public void repackagingEnableWithCustomRepackagedJarUsingStringJarTaskReference() { - project.newBuild() - .forTasks("clean", "build", "customRepackagedJarWithStringReference") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "repackage.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(new File(buildLibs, "custom.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "custom.jar.original").exists()).isTrue(); - } - - @Test - public void repackageWithFileDependency() throws Exception { - FileCopyUtils.copy(new File("src/test/resources/foo.jar"), - new File("target/repackage/foo.jar")); - createBuildForTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); - File buildLibs = new File("target/repackage/build/libs"); - JarFile jarFile = new JarFile(new File(buildLibs, "repackage.jar")); - assertThat(jarFile.getEntry("BOOT-INF/lib/foo.jar")).isNotNull(); - jarFile.close(); - } - - @Test - public void devtoolsIsExcludedByDefault() throws IOException { - createBuildForTasks("clean", "bootRepackage") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run(); - File buildLibs = new File("target/repackage/build/libs"); - File repackageFile = new File(buildLibs, "repackage.jar"); - assertThat(repackageFile.exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(isDevToolsJarIncluded(repackageFile)).isFalse(); - } - - @Test - public void devtoolsCanBeIncludedUsingTheExtension() throws IOException { - createBuildForTasks("clean", "bootRepackage") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true", - "-PexcludeDevtoolsOnExtension=false") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - File repackageFile = new File(buildLibs, "repackage.jar"); - assertThat(repackageFile.exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(isDevToolsJarIncluded(repackageFile)).isTrue(); - } - - @Test - public void devtoolsCanBeIncludedUsingBootRepackage() throws IOException { - createBuildForTasks("clean", "bootRepackage") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true", - "-PexcludeDevtoolsOnBootRepackage=false") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - File repackageFile = new File(buildLibs, "repackage.jar"); - assertThat(repackageFile.exists()).isTrue(); - assertThat(new File(buildLibs, "repackage.jar.original").exists()).isTrue(); - assertThat(new File(buildLibs, "repackage-sources.jar.original").exists()) - .isFalse(); - assertThat(isDevToolsJarIncluded(repackageFile)).isTrue(); - } - - @Test - public void customRepackagingTaskWithOwnMainClassNameAnNoGlobalMainClassName() { - createBuildForTasks("clean", "customRepackagedJarWithOwnMainClass") - .withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true", - "-PnoMainClass=true") - .run(); - File buildLibs = new File("target/repackage/build/libs"); - assertThat(new File(buildLibs, "custom.jar").exists()).isTrue(); - assertThat(new File(buildLibs, "custom.jar.original").exists()).isTrue(); - } - - private BuildLauncher createBuildForTasks(String... taskNames) { - return project.newBuild().setStandardError(System.err) - .setStandardOutput(System.out).forTasks(taskNames); - } - - private boolean isDevToolsJarIncluded(File repackageFile) throws IOException { - JarFile jarFile = new JarFile(repackageFile); - try { - String name = "BOOT-INF/lib/spring-boot-devtools-" + BOOT_VERSION + ".jar"; - return jarFile.getEntry(name) != null; - } - finally { - jarFile.close(); - } - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/SpringLoadedTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/SpringLoadedTests.java deleted file mode 100644 index da131ea2bec..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/SpringLoadedTests.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import org.gradle.tooling.ProjectConnection; -import org.junit.Test; - -import static org.junit.Assert.fail; - -/** - * Integration tests for the Gradle plugin's Spring Loaded support - * - * @author Andy Wilkinson - */ -public class SpringLoadedTests { - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static final String SPRING_LOADED_VERSION = Versions.getSpringLoadedVersion(); - - @Test - public void defaultJvmArgsArePreservedWhenLoadedAgentIsConfigured() - throws IOException { - ProjectConnection project = new ProjectCreator() - .createProject("spring-loaded-jvm-args"); - project.newBuild().forTasks("bootRun") - .withArguments("-PbootVersion=" + BOOT_VERSION, - "-PspringLoadedVersion=" + SPRING_LOADED_VERSION, "--stacktrace") - .run(); - - List output = getOutput(); - assertOutputContains("-DSOME_ARG=someValue", output); - assertOutputContains("-Xverify:none", output); - assertOutputMatches("-javaagent:.*springloaded-" + SPRING_LOADED_VERSION + ".jar", - output); - } - - private List getOutput() throws IOException { - BufferedReader reader = new BufferedReader(new FileReader( - new File("target/spring-loaded-jvm-args/build/output.txt"))); - try { - List lines = new ArrayList<>(); - - String line; - - while ((line = reader.readLine()) != null) { - lines.add(line); - } - return lines; - } - finally { - reader.close(); - } - } - - private void assertOutputContains(String requiredOutput, List actualOutput) { - for (String line : actualOutput) { - if (line.equals(requiredOutput)) { - return; - } - } - fail("Required output '" + requiredOutput + "' not found in " + actualOutput); - } - - private void assertOutputMatches(String requiredPattern, List actualOutput) { - for (String line : actualOutput) { - if (line.matches(requiredPattern)) { - return; - } - } - fail("Required pattern '" + requiredPattern + "' not matched in " + actualOutput); - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/Versions.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/Versions.java deleted file mode 100644 index 63431bd9426..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/Versions.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.FileReader; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathFactory; - -import org.xml.sax.InputSource; - -/** - * @author Andy Wilkinson - */ -public final class Versions { - - private Versions() { - } - - public static String getBootVersion() { - return evaluateExpression( - "/*[local-name()='project']/*[local-name()='version']" + "/text()"); - } - - public static String getSpringLoadedVersion() { - return evaluateExpression( - "/*[local-name()='project']/*[local-name()='properties']" - + "/*[local-name()='spring-loaded.version']/text()"); - } - - public static String getSpringVersion() { - return evaluateExpression( - "/*[local-name()='project']/*[local-name()='properties']" - + "/*[local-name()='spring.version']/text()"); - } - - private static String evaluateExpression(String expression) { - try { - XPathFactory xPathFactory = XPathFactory.newInstance(); - XPath xpath = xPathFactory.newXPath(); - XPathExpression expr = xpath.compile(expression); - String version = expr.evaluate( - new InputSource(new FileReader("target/dependencies-pom.xml"))); - return version; - } - catch (Exception ex) { - throw new IllegalStateException("Failed to evaluate expression", ex); - } - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/WarPackagingTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/WarPackagingTests.java deleted file mode 100644 index 3c5b41c429b..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/WarPackagingTests.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import org.gradle.tooling.ProjectConnection; -import org.junit.BeforeClass; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for war packaging with Gradle to ensure that only the Servlet container and its - * dependencies are packaged in WEB-INF/lib-provided - * - * @author Andy Wilkinson - */ -public class WarPackagingTests { - - private static final String WEB_INF_LIB_PROVIDED_PREFIX = "WEB-INF/lib-provided/"; - - private static final String WEB_INF_LIB_PREFIX = "WEB-INF/lib/"; - - private static final Set TOMCAT_EXPECTED_IN_WEB_INF_LIB_PROVIDED = new HashSet<>( - Arrays.asList("spring-boot-starter-tomcat-", "tomcat-embed-core-", - "tomcat-embed-el-", "tomcat-embed-websocket-")); - - private static final Set JETTY_EXPECTED_IN_WEB_INF_LIB_PROVIDED = new HashSet<>( - Arrays.asList("spring-boot-starter-jetty-", "jetty-continuation", - "jetty-util-", "javax.servlet-", "jetty-client", "jetty-io-", - "jetty-http-", "jetty-server-", "jetty-security-", "jetty-servlet-", - "jetty-servlets", "jetty-webapp-", "websocket-api", - "javax.annotation-api", "jetty-plus", "javax-websocket-server-impl-", - "apache-el", "asm-", "javax.websocket-api-", "asm-tree-", - "asm-commons-", "websocket-common-", "jetty-annotations-", - "javax-websocket-client-impl-", "websocket-client-", - "websocket-server-", "jetty-xml-", "websocket-servlet-")); - - private static final String BOOT_VERSION = Versions.getBootVersion(); - - private static ProjectConnection project; - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("war-packaging"); - } - - @Test - public void onlyTomcatIsPackagedInWebInfLibProvided() throws IOException { - checkWebInfEntriesForWebServer("tomcat", - TOMCAT_EXPECTED_IN_WEB_INF_LIB_PROVIDED); - } - - @Test - public void onlyJettyIsPackagedInWebInfLibProvided() throws IOException { - checkWebInfEntriesForWebServer("jetty", - JETTY_EXPECTED_IN_WEB_INF_LIB_PROVIDED); - } - - private void checkWebInfEntriesForWebServer(String webServer, - Set expectedLibProvidedEntries) throws IOException { - project.newBuild().forTasks("clean", "build") - .withArguments("-PbootVersion=" + BOOT_VERSION, - "-PservletContainer=" + webServer) - .run(); - - JarFile war = new JarFile("target/war-packaging/build/libs/war-packaging.war"); - - checkWebInfLibProvidedEntries(war, expectedLibProvidedEntries); - - checkWebInfLibEntries(war, expectedLibProvidedEntries); - - try { - war.close(); - } - catch (IOException ex) { - // Ignore - } - } - - private void checkWebInfLibProvidedEntries(JarFile war, Set expectedEntries) - throws IOException { - Set entries = getWebInfLibProvidedEntries(war); - assertThat(entries).hasSameSizeAs(expectedEntries); - List unexpectedLibProvidedEntries = new ArrayList<>(); - for (String entry : entries) { - if (!isExpectedInWebInfLibProvided(entry, expectedEntries)) { - unexpectedLibProvidedEntries.add(entry); - } - } - assertThat(unexpectedLibProvidedEntries.isEmpty()); - } - - private void checkWebInfLibEntries(JarFile war, Set entriesOnlyInLibProvided) - throws IOException { - Set entries = getWebInfLibEntries(war); - List unexpectedLibEntries = new ArrayList<>(); - for (String entry : entries) { - if (!isExpectedInWebInfLib(entry, entriesOnlyInLibProvided)) { - unexpectedLibEntries.add(entry); - } - } - assertThat(unexpectedLibEntries.isEmpty()); - } - - private Set getWebInfLibProvidedEntries(JarFile war) throws IOException { - Set webInfLibProvidedEntries = new HashSet<>(); - Enumeration entries = war.entries(); - while (entries.hasMoreElements()) { - String name = entries.nextElement().getName(); - if (isWebInfLibProvidedEntry(name)) { - webInfLibProvidedEntries.add(name); - } - } - return webInfLibProvidedEntries; - } - - private Set getWebInfLibEntries(JarFile war) throws IOException { - Set webInfLibEntries = new HashSet<>(); - Enumeration entries = war.entries(); - while (entries.hasMoreElements()) { - String name = entries.nextElement().getName(); - if (isWebInfLibEntry(name)) { - webInfLibEntries.add(name); - } - } - return webInfLibEntries; - } - - private boolean isWebInfLibProvidedEntry(String name) { - return name.startsWith(WEB_INF_LIB_PROVIDED_PREFIX) - && !name.equals(WEB_INF_LIB_PROVIDED_PREFIX); - } - - private boolean isWebInfLibEntry(String name) { - return name.startsWith(WEB_INF_LIB_PREFIX) && !name.equals(WEB_INF_LIB_PREFIX); - } - - private boolean isExpectedInWebInfLibProvided(String name, - Set expectedEntries) { - for (String expected : expectedEntries) { - if (name.startsWith(WEB_INF_LIB_PROVIDED_PREFIX + expected)) { - return true; - } - } - return false; - } - - private boolean isExpectedInWebInfLib(String name, Set unexpectedEntries) { - for (String unexpected : unexpectedEntries) { - if (name.startsWith(WEB_INF_LIB_PREFIX + unexpected)) { - return false; - } - } - return true; - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/starter/StarterDependenciesIntegrationTests.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/starter/StarterDependenciesIntegrationTests.java deleted file mode 100644 index f8d2fc7922a..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/starter/StarterDependenciesIntegrationTests.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.starter; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.gradle.tooling.BuildException; -import org.gradle.tooling.ProjectConnection; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; -import org.junit.runners.Parameterized.Parameters; - -import org.springframework.boot.gradle.ProjectCreator; -import org.springframework.boot.gradle.Versions; - -/** - * Tests for the various starter projects to check that they don't pull in unwanted - * transitive dependencies when used with Gradle - * - * @author Andy Wilkinson - */ -@RunWith(Parameterized.class) -public class StarterDependenciesIntegrationTests { - - private static final String STARTER_NAME_PREFIX = "spring-boot-starter"; - - private static final List EXCLUDED_STARTERS = Arrays - .asList("spring-boot-starter-parent"); - - private static ProjectConnection project; - - private static String bootVersion; - - private static String springVersion; - - private final String[] buildArguments; - - @Parameters - public static List getStarters() { - List starters = new ArrayList<>(); - for (File file : new File("../../spring-boot-starters").listFiles()) { - if (file.isDirectory() && new File(file, "pom.xml").exists()) { - String name = file.getName(); - if (name.startsWith(STARTER_NAME_PREFIX) - && !EXCLUDED_STARTERS.contains(file.getName())) { - starters.add(new String[] { file.getName() }); - } - } - } - return starters; - } - - @BeforeClass - public static void createProject() throws IOException { - project = new ProjectCreator().createProject("starter-dependencies"); - } - - @BeforeClass - public static void determineVersions() throws Exception { - springVersion = Versions.getSpringVersion(); - bootVersion = Versions.getBootVersion(); - } - - @AfterClass - public static void closeProject() { - project.close(); - } - - public StarterDependenciesIntegrationTests(String starter) { - this.buildArguments = new String[] { "-Pstarter=" + starter, - "-PbootVersion=" + bootVersion, "-PspringVersion=" + springVersion }; - } - - @Test - public void commonsLoggingIsNotATransitiveDependency() throws IOException { - runBuildForTask("checkCommonsLogging"); - } - - @Test - public void oldSpringModulesAreNotTransitiveDependencies() throws IOException { - runBuildForTask("checkSpring"); - } - - private void runBuildForTask(String task) { - try { - project.newBuild().forTasks(task).withArguments(this.buildArguments).run(); - } - catch (BuildException ex) { - throw new RuntimeException(ex); - } - } - -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/build.gradle deleted file mode 100644 index c8a854743cc..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/build.gradle +++ /dev/null @@ -1,19 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -repositories { - mavenLocal() -} - -bootRun { - addResources = Boolean.valueOf(project.addResources) -} \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/src/main/resources/test.txt b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/src/main/resources/test.txt deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier-extension.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier-extension.gradle deleted file mode 100644 index 302cb56e617..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier-extension.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'org.springframework.boot' - -jar { - baseName = 'classifier-extension' -} - -springBoot { - classifier = 'exec' - mainClass = 'demo.Application' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "org.springframework:spring-core" -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier.gradle deleted file mode 100644 index abf9c95bfaa..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/classifier.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'org.springframework.boot' - -jar { - baseName = 'classifier' -} - -bootRepackage { - classifier = 'exec' - mainClass = 'demo.Application' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "org.springframework:spring-core" -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/build.gradle deleted file mode 100644 index 25986b5968b..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/build.gradle +++ /dev/null @@ -1,53 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'org.springframework.boot' -apply plugin: 'java' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-freemarker' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.springframework.boot:spring-boot-devtools' - compile files("foo.jar") -} - -springBoot { - mainClass = 'foo.bar.Baz' -} - -if (project.properties['taskExecutable']) { - bootRepackage.executable = Boolean.valueOf(project.taskExecutable) -} - -if (project.properties['extensionExecutable']) { - springBoot.executable = Boolean.valueOf(project.extensionExecutable) -} - -if (project.properties['taskProperties']) { - bootRepackage.executable = true - bootRepackage.embeddedLaunchScriptProperties = ['initInfoProvides': '__task__'] -} - -if (project.properties['extensionProperties']) { - bootRepackage.executable = true - springBoot.embeddedLaunchScriptProperties = ['initInfoProvides': '__extension__'] -} - -if (project.properties['taskScript']) { - bootRepackage.embeddedLaunchScript = file('task.script') -} - -if (project.properties['extensionScript']) { - springBoot.embeddedLaunchScript = file('extension.script') -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/extension.script b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/extension.script deleted file mode 100644 index 9c5657221ef..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/extension.script +++ /dev/null @@ -1 +0,0 @@ -Custom extension script diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/task.script b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/task.script deleted file mode 100644 index 17a55b540d5..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/executable-jar/task.script +++ /dev/null @@ -1 +0,0 @@ -Custom task script diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle deleted file mode 100644 index 1617ae2a874..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/flatdir.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'org.springframework.boot' - -group = 'flatdir' -version = '0.0.0' - -bootRun { - main = 'Foo' -} - -jar { - baseName = 'flatdir' -} - -repositories { - mavenLocal() - flatDir( dirs:'lib' ) -} - -dependencies { - compile ':foo:1.0.0' -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/foo.jar b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/foo.jar deleted file mode 100644 index 6b017f90e88..00000000000 Binary files a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/foo.jar and /dev/null differ diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle deleted file mode 100644 index 89744abfe34..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/install-app.gradle +++ /dev/null @@ -1,33 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'org.springframework.boot' -apply plugin: 'application' - -group = 'installer' -version = '0.0.0' - -bootRun { - main = 'org.springframework.boot.SpringApplication' -} - -jar { - baseName = 'install-app' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "org.springframework.boot:spring-boot-starter" -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/installer.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/installer.gradle deleted file mode 100644 index db0f6c0fbd8..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/installer.gradle +++ /dev/null @@ -1,40 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'org.springframework.boot' - -group = 'installer' -version = '0.0.0' - -install { - repositories.mavenInstaller { - pom.project { - parent { - groupId 'org.springframework.boot' - artifactId 'spring-boot-starter-parent' - version "${project.bootVersion}" - } - } - } -} - -jar { - baseName = 'installer' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "org.springframework.boot:spring-boot-starter" -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-class.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-class.gradle deleted file mode 100644 index 7688b62d8a3..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/main-class.gradle +++ /dev/null @@ -1,39 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'maven' -apply plugin: 'org.springframework.boot' - -group = 'installer' -version = '0.0.0' - -if (project.hasProperty('bootRunMain')) { - bootRun { - main = 'org.springframework.boot.SpringApplication' - } -} - -if (project.hasProperty('nonJavaExecRun')) { - task run { } -} - - -jar { - baseName = 'installer' -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile "org.springframework.boot:spring-boot-starter" -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle deleted file mode 100644 index 9b2ef45dfa3..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/mixed-version-repackaging.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'org.springframework.boot' -apply plugin: 'java' - -dependencies { - compile 'com.google.guava:guava:16.0' - runtime 'com.google.guava:guava:18.0' -} - -dependencyManagement { - overriddenByDependencies = false -} - -springBoot { - mainClass = 'foo.bar.Baz' -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/build.gradle deleted file mode 100644 index 9285bfc05b4..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/build.gradle +++ /dev/null @@ -1,32 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -subprojects { - apply plugin: 'java' - - dependencies { - compile rootProject.files {'lib/foo.jar'} - } -} - -apply plugin: 'org.springframework.boot' - -repositories { - mavenLocal() -} - -springBoot { - mainClass = 'foo.bar.Baz' -} - -dependencies { - compile project(':one') - compile project(':two') -} - diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/lib/foo.jar b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/lib/foo.jar deleted file mode 100644 index 6b017f90e88..00000000000 Binary files a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/lib/foo.jar and /dev/null differ diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/settings.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/settings.gradle deleted file mode 100644 index 9ae3a92d296..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-common-file-dependency/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ - -include 'one' -include 'two' \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/build.gradle deleted file mode 100644 index e33e5c4baff..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/build.gradle +++ /dev/null @@ -1,25 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -project(':projectA') { - apply plugin: 'org.springframework.boot' - repositories { - mavenLocal() - } - dependencies { - runtime project(':projectB') - } - bootRepackage { - mainClass 'com.foo.Bar' - } -} - -project(':projectB') { - apply plugin: 'java' -} \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/settings.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/settings.gradle deleted file mode 100644 index ee6b6cd92c0..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-runtime-project-dependency/settings.gradle +++ /dev/null @@ -1 +0,0 @@ -include 'projectA', 'projectB' \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/build.gradle deleted file mode 100644 index 7b1e7ab95bb..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -project('main') { - apply plugin: 'org.springframework.boot' - apply plugin: 'java' - - repositories { - mavenLocal() - mavenCentral() - } - - dependencies { - compile project(':common') - } - - springBoot { - mainClass = 'foo.bar.Baz' - } -} - -project('common') { - apply plugin: 'java' - - repositories { - mavenLocal() - mavenCentral() - } - - dependencies { - compile "commons-logging:commons-logging:1.1.3" - compile files { "lib/foo.jar" } - } -} \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/common/lib/foo.jar b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/common/lib/foo.jar deleted file mode 100644 index 6b017f90e88..00000000000 Binary files a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/common/lib/foo.jar and /dev/null differ diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/settings.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/settings.gradle deleted file mode 100644 index 567c0652675..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/multi-project-transitive-file-dependency/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ - -include 'main' -include 'common' \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/nojar.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/nojar.gradle deleted file mode 100644 index b2e18726485..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/nojar.gradle +++ /dev/null @@ -1,30 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -apply plugin: 'org.springframework.boot' - -group = 'nojar' -version = '0.0.0' - -jar { - enabled = false -} - -bootRepackage { - enabled = false -} - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile 'org.springframework.boot:spring-boot-starter' -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/repackage.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/repackage.gradle deleted file mode 100644 index 5851ba39b53..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/repackage.gradle +++ /dev/null @@ -1,66 +0,0 @@ -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'org.springframework.boot' -apply plugin: 'java' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-freemarker' - compile 'org.springframework.boot:spring-boot-starter-web' - compile 'org.springframework.boot:spring-boot-devtools' - compile files("foo.jar") -} - -springBoot { - if (!project.hasProperty("noMainClass")) { - mainClass = 'foo.bar.Baz' - } - if (project.hasProperty("excludeDevtoolsOnExtension")) { - excludeDevtools = Boolean.valueOf(project.excludeDevtoolsOnExtension) - } -} - -bootRepackage { - enabled = Boolean.valueOf(project.repackage) - if (project.hasProperty("excludeDevtoolsOnBootRepackage")) { - excludeDevtools = Boolean.valueOf(project.excludeDevtoolsOnBootRepackage) - } -} - -task customJar(type: Jar) { - archiveName = 'custom.jar' - from sourceSets.main.output -} - -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = 'sources' - from sourceSets.main.allSource -} - -artifacts { - archives sourcesJar -} - -task customRepackagedJar(type: BootRepackage, dependsOn: customJar) { - withJarTask = customJar -} - -task customRepackagedJarWithStringReference(type: BootRepackage, dependsOn: customJar) { - withJarTask = 'customJar' -} - -task customRepackagedJarWithOwnMainClass(type: BootRepackage, dependsOn: customJar) { - withJarTask = customJar - mainClass = 'foo.bar.Baz' -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/build.gradle deleted file mode 100644 index 18551e99f09..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/build.gradle +++ /dev/null @@ -1,31 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - classpath("org.springframework:springloaded:${project.springLoadedVersion}") - } -} - -apply plugin: 'application' -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile("org.springframework.boot:spring-boot-starter") -} - -applicationDefaultJvmArgs = [ - "-DSOME_ARG=someValue" -] - -jar { - baseName = 'spring-loaded-jvm-args' -} \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/src/main/java/test/Application.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/src/main/java/test/Application.java deleted file mode 100644 index a648170a304..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-jvm-args/src/main/java/test/Application.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 test; - -import java.io.File; -import java.io.FileWriter; -import java.io.PrintWriter; -import java.lang.management.ManagementFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.Assert; - -public class Application { - - public static void main(String[] args) throws Exception { - PrintWriter writer = new PrintWriter(new FileWriter(new File("build/output.txt"))); - for (String argument: ManagementFactory.getRuntimeMXBean().getInputArguments()) { - writer.println(argument); - } - writer.close(); - } -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/build.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/build.gradle deleted file mode 100644 index 83ca8f70a27..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/build.gradle +++ /dev/null @@ -1,26 +0,0 @@ -buildscript { - repositories { - mavenLocal() - mavenCentral() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - classpath("org.springframework:springloaded:${project.springLoadedVersion}") - } -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -repositories { - mavenLocal() - mavenCentral() -} - -dependencies { - compile("org.springframework.boot:spring-boot-starter") -} - -jar { - baseName = 'spring-loaded-old-gradle' -} \ No newline at end of file diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/src/main/java/test/Application.java b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/src/main/java/test/Application.java deleted file mode 100644 index a648170a304..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/spring-loaded-old-gradle/src/main/java/test/Application.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 test; - -import java.io.File; -import java.io.FileWriter; -import java.io.PrintWriter; -import java.lang.management.ManagementFactory; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.util.Assert; - -public class Application { - - public static void main(String[] args) throws Exception { - PrintWriter writer = new PrintWriter(new FileWriter(new File("build/output.txt"))); - for (String argument: ManagementFactory.getRuntimeMXBean().getInputArguments()) { - writer.println(argument); - } - writer.close(); - } -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/starter-dependencies.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/starter-dependencies.gradle deleted file mode 100644 index f00c9d2de82..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/starter-dependencies.gradle +++ /dev/null @@ -1,60 +0,0 @@ -import org.gradle.api.artifacts.result.UnresolvedDependencyResult; - -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath("org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}") - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -configurations { - springBootStarter -} - -dependencies { - springBootStarter "org.springframework.boot:${project.starter}:${project.bootVersion}" -} - -apply plugin: 'org.springframework.boot' - -task checkCommonsLogging { - doFirst { - def commonsLogging = resolvedDependencies - .find { it.selected.id.group == 'commons-logging' } - if (commonsLogging) { - throw new GradleException("${project.starter} pulls in commons-logging") - } - } -} - -task checkSpring { - doFirst { - def wrongSpring = resolvedDependencies - .findAll{it.selected.id.group == 'org.springframework'} - .findAll{it.selected.id.version != project.springVersion} - .collect {it.selected.id} - if (wrongSpring) { - throw new GradleException("${project.starter} pulled in ${wrongSpring as Set}") - } - } -} - -def getResolvedDependencies() { - def allDependencies = configurations.springBootStarter.incoming - .resolutionResult.allDependencies - .split { it instanceof UnresolvedDependencyResult } - - def unresolved = allDependencies.first() - def resolved = allDependencies.last() - if (unresolved) { - throw new GradleException("Resolution of ${project.starter} failed: ${unresolved}") - } - resolved -} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/war-packaging.gradle b/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/war-packaging.gradle deleted file mode 100644 index af52898c6e1..00000000000 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/war-packaging.gradle +++ /dev/null @@ -1,27 +0,0 @@ -import org.gradle.api.artifacts.result.UnresolvedDependencyResult; - -buildscript { - repositories { - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'org.springframework.boot' -apply plugin: 'war' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter-freemarker' - providedRuntime "org.springframework.boot:spring-boot-starter-$servletContainer" -} - -springBoot { - mainClass = 'foo.bar.Baz' -} \ No newline at end of file diff --git a/spring-boot-parent/pom.xml b/spring-boot-parent/pom.xml index 4c223f882bd..6b5998382c2 100644 --- a/spring-boot-parent/pom.xml +++ b/spring-boot-parent/pom.xml @@ -199,46 +199,6 @@ aether-util ${aether.version} - - org.gradle - gradle-base-services - ${gradle.version} - - - org.gradle - gradle-base-services-groovy - ${gradle.version} - - - org.gradle - gradle-core - ${gradle.version} - - - org.gradle - gradle-language-java - ${gradle.version} - - - org.gradle - gradle-language-jvm - ${gradle.version} - - - org.gradle - gradle-platform-jvm - ${gradle.version} - - - org.gradle - gradle-plugins - ${gradle.version} - - - org.gradle - gradle-process-services - ${gradle.version} - org.jetbrains.kotlin kotlin-runtime diff --git a/spring-boot-samples/spring-boot-sample-actuator/build.gradle b/spring-boot-samples/spring-boot-sample-actuator/build.gradle index 3a3930054c6..0d4912053b0 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/build.gradle +++ b/spring-boot-samples/spring-boot-sample-actuator/build.gradle @@ -19,10 +19,7 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' - -jar { - baseName = 'spring-boot-sample-actuator' -} +apply plugin: 'io.spring.dependency-management' group = 'org.springframework.boot' version = springBootVersion @@ -37,10 +34,6 @@ repositories { } dependencies { - configurations { - insecure.exclude module: 'spring-boot-starter-security' - } - compile("org.springframework.boot:spring-boot-starter-actuator") compile("org.springframework.boot:spring-boot-starter-jdbc") compile("org.springframework.boot:spring-boot-starter-security") @@ -50,18 +43,6 @@ dependencies { compileOnly('org.springframework.boot:spring-boot-configuration-processor') testCompile("org.springframework.boot:spring-boot-starter-test") - - insecure configurations.runtime -} - -// Slightly odd requirement (package a jar file as an insecure app, excluding Spring Security) -// just to demonstrate the "customConfiguration" feature of the Boot gradle plugin. -springBoot { - customConfiguration = "insecure" -} - -task wrapper(type: Wrapper) { - gradleVersion = '1.6' } springBoot { diff --git a/spring-boot-samples/spring-boot-sample-custom-layout/pom.xml b/spring-boot-samples/spring-boot-sample-custom-layout/pom.xml index b118522f106..b545cd9ea7f 100644 --- a/spring-boot-samples/spring-boot-sample-custom-layout/pom.xml +++ b/spring-boot-samples/spring-boot-sample-custom-layout/pom.xml @@ -25,18 +25,6 @@ org.springframework.boot spring-boot-loader-tools - - - org.springframework.boot - spring-boot-starter-test - test - - - org.gradle - gradle-tooling-api - ${gradle.version} - test - @@ -96,16 +84,4 @@ - - - gradle - http://repo.gradle.org/gradle/libs-releases-local - - true - - - false - - - diff --git a/spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/build.gradle b/spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/build.gradle deleted file mode 100644 index 4bad1c3da16..00000000000 --- a/spring-boot-samples/spring-boot-sample-custom-layout/src/it/custom/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -buildscript { - repositories { - flatDir { - dirs '../..' - } - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - classpath "org.springframework.boot:spring-boot-sample-custom-layout:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -springBoot { - layoutFactory = new sample.layout.SampleLayoutFactory('custom') -} - -dependencies { - compile 'org.springframework.boot:spring-boot-starter' -} diff --git a/spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/build.gradle b/spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/build.gradle deleted file mode 100644 index 7c10b209ff0..00000000000 --- a/spring-boot-samples/spring-boot-sample-custom-layout/src/it/default/build.gradle +++ /dev/null @@ -1,24 +0,0 @@ -buildscript { - repositories { - flatDir { - dirs '../..' - } - mavenLocal() - } - dependencies { - classpath "org.springframework.boot:spring-boot-gradle-plugin:${project.bootVersion}" - classpath "org.springframework.boot:spring-boot-sample-custom-layout:${project.bootVersion}" - } -} - -repositories { - mavenLocal() - mavenCentral() -} - -apply plugin: 'java' -apply plugin: 'org.springframework.boot' - -dependencies { - compile 'org.springframework.boot:spring-boot-starter' -} diff --git a/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/GradleIT.java b/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/GradleIT.java deleted file mode 100644 index b488064a21e..00000000000 --- a/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/GradleIT.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 sample.layout; - -import java.io.File; -import java.io.FileReader; - -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathExpression; -import javax.xml.xpath.XPathFactory; - -import org.gradle.tooling.GradleConnector; -import org.gradle.tooling.ProjectConnection; -import org.gradle.tooling.internal.consumer.DefaultGradleConnector; -import org.junit.Test; -import org.xml.sax.InputSource; - -import org.springframework.util.FileCopyUtils; - -public class GradleIT { - - @Test - public void sampleDefault() throws Exception { - test("default", "sample"); - } - - @Test - public void sampleCustom() throws Exception { - test("custom", "custom"); - } - - private void test(String name, String expected) throws Exception { - File projectDirectory = new File("target/gradleit/" + name); - File javaDirectory = new File( - "target/gradleit/" + name + "/src/main/java/org/test/"); - projectDirectory.mkdirs(); - javaDirectory.mkdirs(); - File script = new File(projectDirectory, "build.gradle"); - FileCopyUtils.copy(new File("src/it/" + name + "/build.gradle"), script); - FileCopyUtils.copy( - new File("src/it/" + name - + "/src/main/java/org/test/SampleApplication.java"), - new File(javaDirectory, "SampleApplication.java")); - GradleConnector gradleConnector = GradleConnector.newConnector(); - gradleConnector.useGradleVersion("2.9"); - ((DefaultGradleConnector) gradleConnector).embedded(true); - ProjectConnection project = gradleConnector.forProjectDirectory(projectDirectory) - .connect(); - project.newBuild().forTasks("clean", "build").setStandardOutput(System.out) - .setStandardError(System.err) - .withArguments("-PbootVersion=" + getBootVersion()).run(); - Verify.verify( - new File("target/gradleit/" + name + "/build/libs/" + name + ".jar"), - expected); - } - - public static String getBootVersion() { - return evaluateExpression( - "/*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']" - + "/text()"); - } - - private static String evaluateExpression(String expression) { - try { - XPathFactory xPathFactory = XPathFactory.newInstance(); - XPath xpath = xPathFactory.newXPath(); - XPathExpression expr = xpath.compile(expression); - String version = expr.evaluate(new InputSource(new FileReader("pom.xml"))); - return version; - } - catch (Exception ex) { - throw new IllegalStateException("Failed to evaluate expression", ex); - } - } - -} diff --git a/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/Verify.java b/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/Verify.java deleted file mode 100644 index 496eea67288..00000000000 --- a/spring-boot-samples/spring-boot-sample-custom-layout/src/test/java/sample/layout/Verify.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 sample.layout; - -import java.io.File; -import java.util.Enumeration; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -public final class Verify { - - private Verify() { - } - - public static void verify(File file, String entry) throws Exception { - ZipFile zipFile = new ZipFile(file); - try { - Enumeration entries = zipFile.entries(); - while (entries.hasMoreElements()) { - if (entries.nextElement().getName().equals(entry)) { - return; - } - } - throw new AssertionError("No entry " + entry); - } - finally { - zipFile.close(); - } - } - -} diff --git a/spring-boot-samples/spring-boot-sample-logback/build.gradle b/spring-boot-samples/spring-boot-sample-logback/build.gradle index 19ca3a9c7b3..5033fc98186 100644 --- a/spring-boot-samples/spring-boot-sample-logback/build.gradle +++ b/spring-boot-samples/spring-boot-sample-logback/build.gradle @@ -19,15 +19,10 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' -jar { - baseName = 'spring-boot-sample-simple' - version = '0.0.0' -} - -bootRun { - systemProperties = System.properties -} +version = springBootVersion +group = 'org.springframework.boot' repositories { // NOTE: You should declare only repositories that you need here @@ -41,8 +36,4 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter") testCompile("org.springframework.boot:spring-boot-starter-test") -} - -task wrapper(type: Wrapper) { - gradleVersion = '1.6' -} +} \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-profile/build.gradle b/spring-boot-samples/spring-boot-sample-profile/build.gradle index 59e1f0d23a9..5033fc98186 100644 --- a/spring-boot-samples/spring-boot-sample-profile/build.gradle +++ b/spring-boot-samples/spring-boot-sample-profile/build.gradle @@ -19,23 +19,10 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' -jar { - baseName = 'spring-boot-sample-profile' - version = '0.0.0' - excludes = ['**/application.yml'] -} - -task('execJar', type:Jar, dependsOn: 'jar') { - baseName = 'spring-boot-sample-profile' - version = '0.0.0' - classifier = 'exec' - from sourceSets.main.output -} - -bootRepackage { - withJarTask = tasks['execJar'] -} +version = springBootVersion +group = 'org.springframework.boot' repositories { // NOTE: You should declare only repositories that you need here @@ -49,8 +36,4 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter") testCompile("org.springframework.boot:spring-boot-starter-test") -} - -task wrapper(type: Wrapper) { - gradleVersion = '1.6' -} +} \ No newline at end of file diff --git a/spring-boot-samples/spring-boot-sample-profile/pom.xml b/spring-boot-samples/spring-boot-sample-profile/pom.xml index 24df492afc7..358102090df 100644 --- a/spring-boot-samples/spring-boot-sample-profile/pom.xml +++ b/spring-boot-samples/spring-boot-sample-profile/pom.xml @@ -37,23 +37,6 @@ org.springframework.boot spring-boot-maven-plugin - - maven-jar-plugin - - - lib - - jar - - - lib - - application.yml - - - - - diff --git a/spring-boot-samples/spring-boot-sample-simple/build.gradle b/spring-boot-samples/spring-boot-sample-simple/build.gradle index 19ca3a9c7b3..36820a55ecb 100644 --- a/spring-boot-samples/spring-boot-sample-simple/build.gradle +++ b/spring-boot-samples/spring-boot-sample-simple/build.gradle @@ -19,15 +19,10 @@ apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' -jar { - baseName = 'spring-boot-sample-simple' - version = '0.0.0' -} - -bootRun { - systemProperties = System.properties -} +version = springBootVersion +group = 'org.springframework.boot' repositories { // NOTE: You should declare only repositories that you need here @@ -40,9 +35,6 @@ repositories { dependencies { compile("org.springframework.boot:spring-boot-starter") + compile("org.hibernate:hibernate-validator") testCompile("org.springframework.boot:spring-boot-starter-test") } - -task wrapper(type: Wrapper) { - gradleVersion = '1.6' -} diff --git a/spring-boot-samples/spring-boot-sample-web-static/build.gradle b/spring-boot-samples/spring-boot-sample-web-static/build.gradle index fed57e1af9e..1f777a1f6d5 100644 --- a/spring-boot-samples/spring-boot-sample-web-static/build.gradle +++ b/spring-boot-samples/spring-boot-sample-web-static/build.gradle @@ -15,17 +15,12 @@ buildscript { } } - -apply plugin: 'java' -apply plugin: 'eclipse-wtp' -apply plugin: 'idea' apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' apply plugin: 'war' -war { - baseName = 'spring-boot-sample-web-static' - version = '0.0.0' -} +version = springBootVersion +group = 'org.springframework.boot' repositories { // NOTE: You should declare only repositories that you need here @@ -36,10 +31,6 @@ repositories { maven { url "http://repo.spring.io/snapshot" } } -configurations { - providedRuntime -} - dependencies { compile("org.springframework.boot:spring-boot-starter-web") compile("org.webjars:bootstrap:3.0.3") @@ -47,5 +38,3 @@ dependencies { providedRuntime("org.springframework.boot:spring-boot-starter-tomcat") testCompile("org.springframework.boot:spring-boot-starter-test") } - -task wrapper(type: Wrapper) { gradleVersion = '1.6' } diff --git a/spring-boot-samples/spring-boot-sample-web-ui/build.gradle b/spring-boot-samples/spring-boot-sample-web-ui/build.gradle index e57c30fbf13..67602012a14 100644 --- a/spring-boot-samples/spring-boot-sample-web-ui/build.gradle +++ b/spring-boot-samples/spring-boot-sample-web-ui/build.gradle @@ -17,20 +17,11 @@ buildscript { } } - apply plugin: 'java' -apply plugin: 'eclipse' -apply plugin: 'idea' apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' -springBoot { - classifier = 'exec' -} - -jar { - baseName = 'spring-boot-sample-web-ui' - version = '0.0.0' -} +version = springBootVersion repositories { // NOTE: You should declare only repositories that you need here @@ -46,5 +37,3 @@ dependencies { compile("org.hibernate:hibernate-validator") testCompile("org.springframework.boot:spring-boot-starter-test") } - -task wrapper(type: Wrapper) { gradleVersion = '1.6' } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/build.gradle b/spring-boot-tools/spring-boot-gradle-plugin/build.gradle new file mode 100644 index 00000000000..cc3fcc49751 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/build.gradle @@ -0,0 +1,83 @@ +plugins { + id 'java' + id 'eclipse' + id 'org.sonarqube' version '2.2.1' +} + +repositories { + mavenLocal() +} + +def addDependency(configurationName, dependency) { + def coordinates = [ + 'group': dependency.groupId.text(), + 'name': dependency.artifactId.text(), + 'version': dependency.version.text() + ] + dependencies { + add configurationName, coordinates + } +} + +def effectivePomFile = file('target/effective-pom.xml') +if (effectivePomFile.file) { + def pom = new XmlSlurper().parseText(file('target/effective-pom.xml').text) + pom.dependencies.dependency.each { dependency -> + def scope = dependency.scope.text() + if (scope == 'compile') { + addDependency scope, dependency + } + else if (scope == 'test') { + addDependency 'testCompile', dependency + } + } +} + +dependencies { + compile localGroovy() + compile gradleApi() + testCompile gradleTestKit() + testCompile 'org.apache.commons:commons-compress:1.13' +} + +jar { + manifest { + attributes 'Implementation-Version': (version ? version : 'unknown') + } +} + +eclipseJdt { + inputFile = rootProject.file('../../eclipse/org.eclipse.jdt.core.prefs') + doLast { + project.file('.settings/org.eclipse.jdt.ui.prefs').withWriter { writer -> + writer << file('../../eclipse/org.eclipse.jdt.ui.prefs').text + } + } +} + +javadoc { + options { + author() + stylesheetFile = file('src/main/javadoc/spring-javadoc.css') + links = [ + 'http://docs.oracle.com/javase/8/docs/api/', + 'https://docs.gradle.org/current/javadoc/' + ] + } + title = "${project.description} $version API" +} + +task sourcesJar(type: Jar) { + classifier = 'sources' + from sourceSets.main.allSource +} + +task javadocJar(type: Jar) { + classifier = "javadoc" + from javadoc +} + +artifacts { + archives sourcesJar + archives javadocJar +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/gradle.properties b/spring-boot-tools/spring-boot-gradle-plugin/gradle.properties new file mode 100644 index 00000000000..6b1823d86a6 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/gradle.properties @@ -0,0 +1 @@ +org.gradle.daemon=false diff --git a/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.jar b/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000000..52b668fd0f3 Binary files /dev/null and b/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.jar differ diff --git a/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties b/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..d5a35ad90a7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Mar 16 20:08:41 GMT 2017 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-3.4-bin.zip diff --git a/spring-boot-tools/spring-boot-gradle-plugin/gradlew b/spring-boot-tools/spring-boot-gradle-plugin/gradlew new file mode 100755 index 00000000000..4453ccea33d --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/spring-boot-tools/spring-boot-gradle-plugin/gradlew.bat b/spring-boot-tools/spring-boot-gradle-plugin/gradlew.bat new file mode 100644 index 00000000000..f9553162f12 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/spring-boot-tools/spring-boot-gradle-plugin/pom.xml b/spring-boot-tools/spring-boot-gradle-plugin/pom.xml index b9134a3c447..a9e432ece70 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/pom.xml +++ b/spring-boot-tools/spring-boot-gradle-plugin/pom.xml @@ -7,6 +7,7 @@ 2.0.0.BUILD-SNAPSHOT spring-boot-gradle-plugin + pom Spring Boot Gradle Plugin Spring Boot Gradle Plugin http://projects.spring.io/spring-boot/ @@ -16,9 +17,9 @@ ${basedir}/../.. + ./gradlew - org.springframework.boot spring-boot-loader-tools @@ -27,58 +28,223 @@ io.spring.gradle dependency-management-plugin - - - org.codehaus.groovy - groovy - provided - - - org.gradle - gradle-base-services - provided - - - org.gradle - gradle-core - provided - - - org.gradle - gradle-language-java - provided - - - org.gradle - gradle-language-jvm - provided - - - org.gradle - gradle-platform-jvm - provided - - - org.gradle - gradle-plugins - provided - - - org.gradle - gradle-process-services - provided - - - - gradle - http://repo.gradle.org/gradle/libs-releases-local - - true - - - false - - - + + + + maven-help-plugin + + + prepare-package + + effective-pom + + + ${project.build.directory}/effective-pom.xml + + + + + + org.codehaus.mojo + exec-maven-plugin + + + gradle + prepare-package + + ${gradle.executable} + + clean + build + -Pversion=${project.version} + -Pdescription=${project.description} + + + + exec + + + + + + org.codehaus.mojo + build-helper-maven-plugin + 1.12 + + + attach-artifacts + package + + attach-artifact + + + + + build/libs/${project.artifactId}-${project.version}.jar + jar + + + build/libs/${project.artifactId}-${project.version}-javadoc.jar + jar + javadoc + + + build/libs/${project.artifactId}-${project.version}-sources.jar + jar + sources + + + + + + + + + + + windows + + + windows + + + + gradlew.bat + + + + full + + + + org.apache.maven.plugins + maven-antrun-plugin + + + ant-contrib + ant-contrib + 1.0b3 + + + ant + ant + + + + + org.apache.ant + ant-nodeps + 1.8.1 + + + org.tigris.antelope + antelopetasks + 3.2.10 + + + + + set-up-maven-properties + prepare-package + + run + + + true + + + + + + + + + + + + + + + package-docs-zip + package + + run + + + + + + + + + + + + + + org.asciidoctor + asciidoctor-maven-plugin + 1.5.3 + + + generate-html-documentation + prepare-package + + process-asciidoc + + + html + + + + generate-pdf-documentation + prepare-package + + process-asciidoc + + + pdf + + + + + + ${version-type} + ${project.version} + + + + + org.asciidoctor + asciidoctorj-pdf + 1.5.0-alpha.11 + + + + + org.codehaus.mojo + build-helper-maven-plugin + + + attach-zip + + attach-artifact + + + + + ${project.build.directory}/${project.artifactId}-${project.version}-docs.zip + zip + docs + + + + + + + + + + diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/getting-started.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/getting-started.adoc new file mode 100644 index 00000000000..0ec83436f45 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/getting-started.adoc @@ -0,0 +1,43 @@ +[[getting-started]] +== Getting started + +To get started with the plugin it needs to be applied to your project. + +ifeval::["{version-type}" == "RELEASE"] +The plugin is https://plugins.gradle.org/plugin/org.springframework.boot[published to +Gradle's plugin portal] and can be applied using the `plugins` block: +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +include::../gradle/getting-started/apply-plugin-release.gradle[] +---- +endif::[] +ifeval::["{version-type}" == "MILESTONE"] +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +include::../gradle/getting-started/apply-plugin-milestone.gradle[] +---- +endif::[] +ifeval::["{version-type}" == "SNAPSHOT"] +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +include::../gradle/getting-started/apply-plugin-snapshot.gradle[] +---- +endif::[] + +Applied in isolation the plugin makes few changes to a project. Instead, the plugin +detects when certain other plugins are applied and reacts accordingly. For example, when +the `java` plugin is applied a task for building an executable jar is automatically +configured. + +A typical Spring Boot project will apply the {groovy-plugin}[`groovy`], +{java-plugin}java_plugin.html[`java`], or {kotlin-plugin}[`org.jetbrains.kotlin.jvm`] +plugin and the {dependency-management-plugin}[`io.spring.dependency-management`] plugin as +a minimum. For example: + +[source,groovy,indent=0,subs="verbatim,attributes"] +---- +include::../gradle/getting-started/typical-plugins.gradle[tags=apply] +---- + +To learn more about how the Spring Boot plugin behaves when other plugins are applied +please see the section on <>. \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc new file mode 100644 index 00000000000..17645f4e9f8 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/index.adoc @@ -0,0 +1,48 @@ += Spring Boot Gradle Plugin Reference Guide +Andy Wilkinson +:doctype: book +:toc: left +:toclevels: 4 +:source-highlighter: prettify +:numbered: +:icons: font +:hide-uri-scheme: +:dependency-management-plugin: https://github.com/spring-gradle-plugins/dependency-management-plugin +:dependency-management-plugin-documentation: {dependency-management-plugin}/blob/master/README.md +:gradle-userguide: http://www.gradle.org/docs/current/userguide +:gradle-dsl: https://docs.gradle.org/current/dsl +:application-plugin: {gradle-userguide}/application_plugin.html +:groovy-plugin: {gradle-userguide}/groovy_plugin.html +:java-plugin: {gradle-userguide}/java_plugin.html +:war-plugin: {gradle-userguide}/war_plugin.html +:maven-plugin: {gradle-userguide}/maven_plugin.html +:maven-publish-plugin: {gradle-userguide}/maven_publish_plugin.html +:software-component: {gradle-userguide}/software_model_extend.html +:kotlin-plugin: https://kotlinlang.org/docs/reference/using-gradle.html +:spring-boot-docs: https://docs.spring.io/spring-boot/{version} +:api-documentation: {spring-boot-docs}/gradle-plugin/api +:spring-boot-reference: {spring-boot-docs}/reference/htmlsingle +:build-info-javadoc: {api-documentation}/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.html +:boot-jar-javadoc: {api-documentation}/org/springframework/boot/gradle/tasks/bundling/BootJar.html +:boot-war-javadoc: {api-documentation}/org/springframework/boot/gradle/tasks/bundling/BootWar.html +:boot-run-javadoc: {api-documentation}/org/springframework/boot/gradle/tasks/run/BootRun.html +:github-code: https://github.com/spring-projects/spring-boot/tree/{github-tag} + + + +[[introduction]] +== Introduction + +The Spring Boot Gradle Plugin provides Spring Boot support in https://gradle.org[Gradle], +allowing you to package executable jar or war archives, run Spring Boot applications, and +use the dependency management provided by `spring-boot-dependencies`. Spring Boot's +Gradle plugin requires Gradle 3.4 or later. + +In addition to this user guide, {api-documentation}[API documentation] is also available. + +include::getting-started.adoc[] +include::managing-dependencies.adoc[] +include::packaging.adoc[] +include::running.adoc[] +include::integrating-with-actuator.adoc[] +include::reacting.adoc[] \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/integrating-with-actuator.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/integrating-with-actuator.adoc new file mode 100644 index 00000000000..0460273bbc9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/integrating-with-actuator.adoc @@ -0,0 +1,55 @@ +[[integrating-with-actuator]] +== Integrating with Actuator + + +[[integrating-with-actuator-build-info]] +=== Generating build information + +Spring Boot Actuator's `info` endpoint automatically publishes information about your +build in the presence of a `META-INF/build-info.properties` file. A +{build-info-javadoc}[`BuildInfo`] task is provided to generate this file. The easiest way +to use the task is via the plugin's DSL: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/integrating-with-actuator/build-info-basic.gradle[tags=build-info] +---- + +This will configure a {build-info-javadoc}[`BuildInfo`] task named `bootBuildInfo` and, if +it exists, make the Java plugin's `classes` task depend upon it. The task's desination +directory will be `META-INF` in the output directory of the main source set's resources +(typically `build/resources/main`). + +By default, the generated build information is derived from the project: + +|=== +| Property | Default value + +| `build.artifact` +| The base name of the `bootJar` or `bootWar` task, or `unspecified` if no such task + exists + +| `build.group` +| The group of the project + +| `build.name` +| The name of the project + +| `build.version` +| The version of the project + +|=== + +The properties can be customized using the DSL: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/integrating-with-actuator/build-info-custom-values.gradle[tags=custom-values] +---- + +Additional properties can also be added to the build information: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/integrating-with-actuator/build-info-additional.gradle[tags=additional] +---- diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/managing-dependencies.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/managing-dependencies.adoc new file mode 100644 index 00000000000..31981561b38 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/managing-dependencies.adoc @@ -0,0 +1,46 @@ +[[managing-dependencies]] +== Managing dependencies + +When you apply the {dependency-management-plugin}[`io.spring.dependency-management`] +plugin, Spring Boot's plugin will +automatically <> from the version of Spring Boot that you are using. +This provides a similar dependency management experience to the one that's enjoyed by +Maven users. For example, it allows you to omit version numbers when declaring +dependencies that are managed in the bom. To make use of this functionality, simply +declare dependencies in the usual way but omit the version number: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/managing-dependencies/dependencies.gradle[tags=dependencies] +---- + + + +[[managing-dependencies-customizing]] +=== Customizing managed versions + +The `spring-boot-dependencies` bom that is automatically imported when the dependency +management plugin is applied uses properties to control the versions of the dependencies +that it manages. Please refer to the {github-code}/spring-boot-dependencies/pom.xml[bom] +for a complete list of these properties. + +To customize a managed version you set its corresponding property. For example, to +customize the version of SLF4J which is controlled by the `slf4j.version` property: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/managing-dependencies/custom-version.gradle[tags=custom-version] +---- + +WARNING: Each Spring Boot release is designed and tested against a specific set of +third-party dependencies. Overriding versions may cause compatibility issues and should +be done with care. + + + +[[managing-dependencies-learning-more]] +=== Learning more + +To learn more about the capabilities of the dependency management plugin, please refer to +its {dependency-management-plugin-documentation}[documentation]. \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/packaging.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/packaging.adoc new file mode 100644 index 00000000000..686f20a4eae --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/packaging.adoc @@ -0,0 +1,167 @@ +[[packaging-executable]] +== 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-executable-jars]] +=== Packaging executable jars + +Executable jars can be built using the `bootJar` task. The task is automatically created +when the `java` plugin is applied and is an instance of {boot-jar-javadoc}[`BootJar`]. + + + +[[packaging-executable-wars]] +=== Packaging executable wars + +Executable wars can be built using the `bootWar` task. The task is automatically created +when the `war` plugin is applied and is an instance of {boot-war-javadoc}[`BootWar`]. + + + +[[packaging-executable-wars-deployable]] +==== Packaging executable and deployable wars + +A war file can be packaged such that it can be executed using `java -jar` and deployed +to an external container. To do so, the embedded servlet container dependencies should +be added to the `providedRuntime` configuration, for example: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/war-container-dependency.gradle[tags=dependencies] +---- + +This ensures that they are package in the war file's `WEB-INF/lib-provided` directory +from where they will not conflict with the external container's own classes. + +NOTE: `providedRuntime` is prefered to Gradle's `compileOnly` configuration as, among +other limitations, `compileOnly` dependencies are not on the test classpath so any +web-based integration tests will fail. + + + +[[packaging-executable-configuring]] +=== Configuring executable archive packaging + +The {boot-jar-javadoc}[`BootJar`] and {boot-war-javadoc}[`BootWar`] tasks are subclasses +of Gradle's `Jar` and `War` tasks respectively. As a result, all of the standard +configuration options that are available when packaging a jar or war are also available +when packaging an executable jar or war. A number of configuration options that are +specific to executable jars and wars are also provided. + + +[[packaging-executable-configuring-main-class]] +==== Configuring the main class + +By default, the executable archive's main class will be configured automatically by +looking for a class with a `public static void main(String[])` method in directories on +the task's classpath. + +The main class can also be configured explicity using the task's `mainClass` property: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-main-class.gradle[tags=main-class] +---- + +Alternatively, if the {application-plugin}[`application` plugin] has been applied +its `mainClassName` project property can be used: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/application-plugin-main-class.gradle[tags=main-class] +---- + +Lastly, the `Start-Class` attribute can be configured on the task's manifest: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-manifest-main-class.gradle[tags=main-class] +---- + + + +[[packaging-executable-configuring-excluding-devtools]] +==== Excluding Devtools + +By default, Spring Boot's Devtools module, +`org.springframework.boot:spring-boot-devtools`, will be excluded from an executable jar +or war. If you want to include Devtools in your archive set the `excludeDevtools` +property to `true`: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-war-include-devtools.gradle[tags=include-devtools] +---- + + + +[[packaging-executable-configuring-unpacking]] +==== Configuring libraries that require unpacking + +Most libraries can be used directly when nested in an executable archive, however certain +libraries can have problems. For example, JRuby includes its own nested jar support which +assumes that `jruby-complete.jar` is always directly available on the file system. + +To deal with any problematic libraries, an executable archive can be configured to unpack +specific nested jars to a temporary folder when the executable archive is run. Libraries +can be identified as requiring unpacking using Ant-style patterns that match against +the absolute path of the source jar file: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-requires-unpack.gradle[tags=requires-unpack] +---- + +For more control a closure can also be used. The closure is passed a `FileTreeElement` +and should return a `boolean` indicating whether or not unpacking is required. + + + +[[packaging-executable-configuring-launch-script]] +==== Making an archive fully executable + +Spring Boot provides support for fully executable archives. An archive is made fully +executable by prepending a shell script that knows how to launch the application. On +Unix-like platforms, this launch script allows the archive to be run directly like any +other executable or to be installed as a service. + +To use this feature, the inclusion of the launch script must be enabled: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-include-launch-script.gradle[tags=include-launch-script] +---- + +This will add Spring Boot's default launch script to the archive. The default launch +script includes several properties with sensible default values. The values can be +customized using the `properties` property: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-launch-script-properties.gradle[tags=launch-script-properties] +---- + +If the default launch script does not meet your needs, the `script` property can be used +to provide a custom launch script: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-jar-custom-launch-script.gradle[tags=custom-launch-script] +---- + + + +[[packaging-executable-configuring-properties-launcher]] +==== Using the `PropertiesLauncher` + +To use the `PropertiesLauncher` to launch an executable jar or war, configure the task's +manifest to set the `Main-Class` attribute: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/packaging/boot-war-properties-launcher.gradle[tags=properties-launcher] +---- \ No newline at end of file diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/publishing.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/publishing.adoc new file mode 100644 index 00000000000..69be4ed6cef --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/publishing.adoc @@ -0,0 +1,43 @@ +[[publishing-your-application]] +== Publishing your application + + + +[[publishing-your-application-maven]] +=== Publishing with the `maven` plugin + +When the {maven-plugin}[`maven` plugin] is applied, an `Upload` task for the +`bootArchives` configuration named `uploadBootArchives` is automatically created. By +default, the `bootArchives` configuration contains the archive produced by the `bootJar` +or `bootWar` task. The `uploadBootArchives` task can be configured to publish the archive +to a Maven repository: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/publishing/maven.gradle[tags=upload] +---- + +[[publishing-your-application-maven-publish]] +=== Publishing with the `maven-publish` plugin + +When the {java-plugin}[`java` plugin] is applied Spring Boot automatically creates a +{software-component}[software component] named `bootJava`. Similarly, when the `war` +plugin is applied, a software component named `bootWeb` is created. `bootJava` contains +the archive produced by the `bootJar` task and `bootWeb` contains the archive provided by +the `bootWar` task. The components can be used with the +{maven-publish-plugin}[`maven-publish` plugin] to publish the archive, for example: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/publishing/maven-publish.gradle[tags=publishing] +---- + + + +[[publishing-your-application-distrubution]] +=== Distributing with the `application` plugin + +When the {application-plugin}[`application` plugin] is applied a distribution named +`boot` is created. This distribution contains the archive produced by the `bootJar` or +`bootWar` task and scripts to launch it on Unix-like platforms and Windows. Zip and tar +distributions can be built by the `bootDistZip` and `bootDistTar` tasks respectively. diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/reacting.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/reacting.adoc new file mode 100644 index 00000000000..4c5fa9a8c1f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/reacting.adoc @@ -0,0 +1,78 @@ +[[reacting-to-other-plugins]] +== Reacting to other plugins + +When another plugin is applied the Spring Boot plugin reacts by making various changes +to the project's configuration. This section describes those changes. + +[[reacting-to-other-plugins-java]] +=== Reacting to the Java plugin + +When Gradle's {java-plugin}[`java` plugin] is applied to a project, the Spring Boot +plugin: + +1. Creates a {boot-jar-javadoc}[`BootJar`] task named `bootJar` that will create an + executable, fat jar for the project. The jar will contain everything on the runtime + classpath of the main source set; classes are packaged in `BOOT-INF/classes` and jars + are packaged in `BOOT-INF/lib` +2. Creates a {software-component}[software component] named `bootJava` that contains the + archive produced by the `bootJar` task. +3. Creates a {boot-run-javadoc}[`BootRun`] task named `bootRun` that can be used to run + your application. +4. Creates a configuration named `bootArchives` that contains the artifact produced by + the `bootJar` task. +5. Configures any `JavaCompile` tasks with no configured encoding to use `UTF-8`. + + + +[[reacting-to-other-plugins-war]] +=== Reacting to the war plugin + +When Gradle's {war-plugin}[`war` plugin] is applied to a project, the Spring Boot plugin: + +1. Creates a {boot-war-javadoc}[`BootWar`] task named `bootWar` that will create an + executable, fat war for the project. In addition to the standard packaging, everything + in the `providedRuntime` configuration will be packaged in `WEB-INF/lib-provided`. +2. Creates a {software-component}[software component] named `bootWeb` that contains the + archive produced by the `bootWar` task. +3. Configures the `bootArchives` configuration to contain the artifact produced by the + `bootWar` task. + + + +[[reacting-to-other-plugins-dependency-management]] +=== Reacting to the dependency management plugin + +When the {dependency-management-plugin}[`io.spring.dependency-management` plugin] is +applied to a project, the Spring Boot plugin will automatically import the +`spring-boot-dependencies` bom. + + + +[[reacting-to-other-plugins-application]] +=== Reacting to the application plugin + +When Gradle's {application-plugin}[`application` plugin] is applied to a project, the +Spring Boot plugin: + +1. Creates a `CreateStartScripts` task named `bootStartScripts` that will creates scripts + that launch the artifact in the `bootArchives` configuration using `java -jar`. +2. Creates a new distribution named `boot` and configures it to contain the artifact in + the `bootArchives` configuration in its `lib` directory and the start scripts in its + `bin` directory. +3. Configures the `bootRun` task to use the `mainClassName` property as a convention for + its `main` property. +4. Configures the `bootRun` task to use the `applicationDefaultJvmArgs` property as a + convention for its `jvmArgs` property. +5. Configures the `bootJar` task to use the `mainClassName` property as a convention for + the `Start-Class` entry in its manifest. +6. Configures the `bootWar` task to use the `mainClassName` property as a convention for + the `Start-Class` entry in its manifest. + + + +[[reacting-to-other-plugins-maven]] +=== Reacting to the Maven plugin + +When Gradle's {maven-plugin}[`maven` plugin] is applied to a project, the Spring Boot +plugin will configure the `uploadBootArchives` `Upload` task to ensure that no +dependencies are declared in the pom that it generates. diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/running.adoc b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/running.adoc new file mode 100644 index 00000000000..5a8f0cb1ece --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/asciidoc/running.adoc @@ -0,0 +1,49 @@ +[[running-your-application]] +== Running your application with Gradle + +To run your application without first building an archive use the `bootRun` task: + +[source,bash,indent=0,subs="verbatim"] +---- + $ ./gradlew bootRun +---- + +The `bootRun` task is an instance of +{boot-run-javadoc}[`BootRun`] which is a `JavaExec` subclass. As such, all of the +{gradle-dsl}/org.gradle.api.tasks.JavaExec.html[usual configuration options] for executing +a Java process in Gradle are available to you. The task is automatically configured to use +the runtime classpath of the main source set. + +By default, the main class will be configured automatically by looking for a class with a +`public static void main(String[])` method in directories on the task's classpath. + +The main class can also be configured explicity using the task's `main` property: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/running/boot-run-main.gradle[tags=main] +---- + +Alternatively, if the {application-plugin}[`application` plugin] has been applied +its `mainClassName` project property can be used: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/running/application-plugin-main-class-name.gradle[tags=main-class] +---- + + + +[[running-your-application-reloading-resources]] +=== Reloading resources +If devtools has been added to your project it will automatically monitor your +application for changes. Alternatively, you can configure `bootRun` such that your +application's static resources are loaded from their source location: + +[source,groovy,indent=0,subs="verbatim"] +---- +include::../gradle/running/boot-run-source-resources.gradle[tags=source-resources] +---- + +This makes them reloadable in the live application which can be helpful at development +time. diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-milestone.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-milestone.gradle new file mode 100644 index 00000000000..0302ec6f4de --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-milestone.gradle @@ -0,0 +1,11 @@ +buildscript { + repositories { + maven { url 'https://repo.spring.io/libs-milestone' } + } + + dependencies { + classpath 'org.springframework.boot:spring-boot-gradle-plugin:{version}' + } +} + +apply plugin: 'org.springframework.boot' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-release.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-release.gradle new file mode 100644 index 00000000000..cf13509ffdd --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-release.gradle @@ -0,0 +1,3 @@ +plugins { + id 'org.springframework.boot' version '{version}' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-snapshot.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-snapshot.gradle new file mode 100644 index 00000000000..c775fa09252 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/apply-plugin-snapshot.gradle @@ -0,0 +1,11 @@ +buildscript { + repositories { + maven { url 'https://repo.spring.io/libs-snapshot' } + } + + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/typical-plugins.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/typical-plugins.gradle new file mode 100644 index 00000000000..6549d2bd3e4 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/getting-started/typical-plugins.gradle @@ -0,0 +1,17 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +// tag::apply[] +apply plugin: 'java' +apply plugin: 'io.spring.dependency-management' +// end::apply[] + +task verify { + doLast { + plugins.getPlugin(org.gradle.api.plugins.JavaPlugin.class) + plugins.getPlugin(io.spring.gradle.dependencymanagement.DependencyManagementPlugin.class) + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-additional.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-additional.gradle new file mode 100644 index 00000000000..a70995ea380 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-additional.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::additional[] +springBoot { + buildInfo { + properties { + additional = [ + 'a': 'alpha', + 'b': 'bravo' + ] + } + } +} +// end::additional[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-basic.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-basic.gradle new file mode 100644 index 00000000000..43329cdd618 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-basic.gradle @@ -0,0 +1,14 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::build-info[] +springBoot { + buildInfo() +} +// end::build-info[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-custom-values.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-custom-values.gradle new file mode 100644 index 00000000000..c8e8b0b4168 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/integrating-with-actuator/build-info-custom-values.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::custom-values[] +springBoot { + buildInfo { + properties { + artifact = 'example-app' + version = '1.2.3' + group = 'com.example' + name = 'Example application' + } + } +} +// end::custom-values[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/custom-version.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/custom-version.gradle new file mode 100644 index 00000000000..54009ee8c20 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/custom-version.gradle @@ -0,0 +1,32 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +dependencyManagement { + resolutionStrategy { + eachDependency { + if (it.requested.group == 'org.springframework.boot') { + it.useVersion project.bootVersion + } + } + } +} + +// tag::custom-version[] +ext['slf4j.version'] = '1.7.20' +// end::custom-version[] + +repositories { + mavenLocal() +} + +task slf4jVersion { + doLast { + println dependencyManagement.managedVersions['org.slf4j:slf4j-api'] + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/dependencies.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/dependencies.gradle new file mode 100644 index 00000000000..ecbf6ffedc1 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/managing-dependencies/dependencies.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +plugins { + id 'java' +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +// tag::dependencies[] +dependencies { + compile 'org.springframework.boot:spring-boot-starter-web' + compile 'org.springframework.boot:spring-boot-starter-data-jpa' +} +// end::dependencies[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/application-plugin-main-class.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/application-plugin-main-class.gradle new file mode 100644 index 00000000000..b91321d8fde --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/application-plugin-main-class.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' +apply plugin: 'application' + +// tag::main-class[] +mainClassName = 'com.example.ExampleApplication' +// end::main-class[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-custom-launch-script.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-custom-launch-script.gradle new file mode 100644 index 00000000000..c813b9a134f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-custom-launch-script.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +bootJar { + mainClass 'com.example.ExampleApplication' +} + +// tag::custom-launch-script[] +bootJar { + launchScript { + included = true + script = file('src/custom.script') + } +} +// end::custom-launch-script[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-include-launch-script.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-include-launch-script.gradle new file mode 100644 index 00000000000..6df82aeb198 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-include-launch-script.gradle @@ -0,0 +1,20 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +bootJar { + mainClass 'com.example.ExampleApplication' +} + +// tag::include-launch-script[] +bootJar { + launchScript { + included = true + } +} +// end::include-launch-script[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-launch-script-properties.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-launch-script-properties.gradle new file mode 100644 index 00000000000..1de01e52b5b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-launch-script-properties.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +bootJar { + mainClass 'com.example.ExampleApplication' +} + +// tag::launch-script-properties[] +bootJar { + launchScript { + included = true + properties 'logFilename': 'example-app.log' + } +} +// end::launch-script-properties[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-main-class.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-main-class.gradle new file mode 100644 index 00000000000..b3ce53b9ec7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-main-class.gradle @@ -0,0 +1,14 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::main-class[] +bootJar { + mainClass = 'com.example.ExampleApplication' +} +// end::main-class[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-manifest-main-class.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-manifest-main-class.gradle new file mode 100644 index 00000000000..557242e3f1e --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-manifest-main-class.gradle @@ -0,0 +1,16 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::main-class[] +bootJar { + manifest { + attributes 'Start-Class': 'com.example.ExampleApplication' + } +} +// end::main-class[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-requires-unpack.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-requires-unpack.gradle new file mode 100644 index 00000000000..e21da8d831e --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-jar-requires-unpack.gradle @@ -0,0 +1,26 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +repositories { + mavenCentral() +} + +dependencies { + runtime 'org.jruby:jruby-complete:1.7.25' +} + +bootJar { + mainClass 'com.example.ExampleApplication' +} + +// tag::requires-unpack[] +bootJar { + requiresUnpack '**/jruby-complete-*.jar' +} +// end::requires-unpack[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-include-devtools.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-include-devtools.gradle new file mode 100644 index 00000000000..a739250d3bc --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-include-devtools.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'war' + +bootWar { + mainClass 'com.example.ExampleApplication' + classpath file('spring-boot-devtools-1.2.3.RELEASE.jar') +} + +// tag::include-devtools[] +bootWar { + excludeDevtools = false +} +// end::include-devtools[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-properties-launcher.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-properties-launcher.gradle new file mode 100644 index 00000000000..a2d915d9051 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/boot-war-properties-launcher.gradle @@ -0,0 +1,20 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'war' + +bootWar { + mainClass 'com.example.ExampleApplication' +} + +// tag::properties-launcher[] +bootWar { + manifest { + attributes 'Main-Class': 'org.springframework.boot.loader.PropertiesLauncher' + } +} +// end::properties-launcher[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/war-container-dependency.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/war-container-dependency.gradle new file mode 100644 index 00000000000..9f8c91b64e6 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/packaging/war-container-dependency.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +plugins { + id 'war' +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'io.spring.dependency-management' + +// tag::dependencies[] +dependencies { + compile 'org.springframework.boot:spring-boot-starter-web' + providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat' +} +// end::dependencies[] diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven-publish.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven-publish.gradle new file mode 100644 index 00000000000..61ded0c3578 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven-publish.gradle @@ -0,0 +1,31 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' +apply plugin: 'maven-publish' + +// tag::publishing[] +publishing { + publications { + bootJava(MavenPublication) { + from components.bootJava + } + } + repositories { + maven { + url 'https://repo.example.com' + } + } +} +// end::publishing[] + +task publishingConfiguration { + doLast { + println publishing.publications.bootJava + println publishing.repositories.maven.url + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven.gradle new file mode 100644 index 00000000000..8adefa06431 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/publishing/maven.gradle @@ -0,0 +1,25 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' +apply plugin: 'maven' + +// tag::upload[] +uploadBootArchives { + repositories { + mavenDeployer { + repository url: 'https://repo.example.com' + } + } +} +// end::upload[] + +task deployerRepository { + doLast { + println uploadBootArchives.repositories.mavenDeployer.repository.url + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/application-plugin-main-class-name.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/application-plugin-main-class-name.gradle new file mode 100644 index 00000000000..6e05ceaa3df --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/application-plugin-main-class-name.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' +apply plugin: 'application' + +// tag::main-class[] +mainClassName = 'com.example.ExampleApplication' +// end::main-class[] + +task configuredMainClass { + doLast { + println bootRun.main + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-main.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-main.gradle new file mode 100644 index 00000000000..82907a4c4e0 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-main.gradle @@ -0,0 +1,20 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::main[] +bootRun { + main = 'com.example.ExampleApplication' +} +// end::main[] + +task configuredMainClass { + doLast { + println bootRun.main + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-source-resources.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-source-resources.gradle new file mode 100644 index 00000000000..19b016b5263 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/gradle/running/boot-run-source-resources.gradle @@ -0,0 +1,20 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +// tag::source-resources[] +bootRun { + sourceResources sourceSets.main +} +// end::source-resources[] + +task configuredClasspath { + doLast { + println bootRun.classpath.files + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java deleted file mode 100644 index d3fde163f9e..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/SpringBootPluginExtension.java +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle; - -import java.io.File; -import java.util.Map; -import java.util.Set; - -import groovy.lang.Closure; -import org.gradle.api.Project; -import org.gradle.api.plugins.JavaPlugin; - -import org.springframework.boot.gradle.buildinfo.BuildInfo; -import org.springframework.boot.loader.tools.Layout; -import org.springframework.boot.loader.tools.LayoutFactory; -import org.springframework.boot.loader.tools.Layouts; - -/** - * Gradle DSL Extension for 'Spring Boot'. Most of the time Spring Boot can guess the - * settings in this extension, but occasionally you might need to explicitly set one or - * two of them. E.g. - * - *
- *     apply plugin: 'org.springframework.boot'
- *     springBoot {
- *         mainClass = 'org.demo.Application'
- *         layout = 'ZIP'
- *     }
- * 
- * - * @author Phillip Webb - * @author Dave Syer - * @author Stephane Nicoll - * @author Andy Wilkinson - */ -public class SpringBootPluginExtension { - - private final Project project; - - /** - * The main class that should be run. Instead of setting this explicitly you can use - * the 'mainClassName' of the project or the 'main' of the 'run' task. If not - * specified the value from the MANIFEST will be used, or if no manifest entry is the - * archive will be searched for a suitable class. - */ - String mainClass; - - /** - * The classifier (file name part before the extension). Instead of setting this - * explicitly you can use the 'classifier' property of the 'bootRepackage' task. If - * not specified the archive will be replaced instead of renamed. - */ - String classifier; - - /** - * The name of the ivy configuration name to treat as 'provided' (when packaging those - * dependencies in a separate path). If not specified 'providedRuntime' will be used. - */ - String providedConfiguration; - - /** - * The name of the custom configuration to use. - */ - String customConfiguration; - - /** - * If the original source archive should be backed-up before being repackaged. - */ - boolean backupSource = true; - - /** - * The layout of the archive if it can't be derived from the file extension. Valid - * values are JAR, WAR, ZIP, DIR (for exploded zip file). ZIP and DIR are actually - * synonymous, and should be used if there is no MANIFEST.MF available, or if you want - * the MANIFEST.MF 'Main-Class' to be PropertiesLauncher. Gradle will coerce literal - * String values to the correct type. - */ - LayoutType layout; - - /** - * The layout factory that will be used when no explicit layout is specified. - * Alternative layouts can be provided by 3rd parties. - */ - LayoutFactory layoutFactory; - - /** - * Libraries that must be unpacked from fat jars in order to run. Use Strings in the - * form {@literal groupId:artifactId}. - */ - Set requiresUnpack; - - /** - * Whether Spring Boot Devtools should be excluded from the fat jar. - */ - boolean excludeDevtools = true; - - /** - * Location of an agent jar to attach to the VM when running the application with - * runJar task. - */ - File agent; - - /** - * Flag to indicate that the agent requires -noverify (and the plugin will refuse to - * start if it is not set). - */ - Boolean noverify; - - /** - * If exclude rules should be applied to dependencies based on the - * spring-dependencies-bom. - */ - boolean applyExcludeRules = true; - - /** - * If a fully executable jar (for *nix machines) should be generated by prepending a - * launch script to the jar. - */ - boolean executable = false; - - /** - * The embedded launch script to prepend to the front of the jar if it is fully - * executable. If not specified the 'Spring Boot' default script will be used. - */ - File embeddedLaunchScript; - - /** - * Properties that should be expanded in the embedded launch script. - */ - Map embeddedLaunchScriptProperties; - - public SpringBootPluginExtension(Project project) { - this.project = project; - } - - /** - * Convenience method for use in a custom task. - * @return the Layout to use or null if not explicitly set - */ - public Layout convertLayout() { - return (this.layout == null ? null : this.layout.layout); - } - - public String getMainClass() { - return this.mainClass; - } - - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - public String getClassifier() { - return this.classifier; - } - - public void setClassifier(String classifier) { - this.classifier = classifier; - } - - public String getProvidedConfiguration() { - return this.providedConfiguration; - } - - public void setProvidedConfiguration(String providedConfiguration) { - this.providedConfiguration = providedConfiguration; - } - - public String getCustomConfiguration() { - return this.customConfiguration; - } - - public void setCustomConfiguration(String customConfiguration) { - this.customConfiguration = customConfiguration; - } - - public boolean isBackupSource() { - return this.backupSource; - } - - public void setBackupSource(boolean backupSource) { - this.backupSource = backupSource; - } - - public LayoutType getLayout() { - return this.layout; - } - - public void setLayout(LayoutType layout) { - this.layout = layout; - } - - public LayoutFactory getLayoutFactory() { - return this.layoutFactory; - } - - public void setLayoutFactory(LayoutFactory layoutFactory) { - this.layoutFactory = layoutFactory; - } - - public Set getRequiresUnpack() { - return this.requiresUnpack; - } - - public void setRequiresUnpack(Set requiresUnpack) { - this.requiresUnpack = requiresUnpack; - } - - public boolean isExcludeDevtools() { - return this.excludeDevtools; - } - - public void setExcludeDevtools(boolean excludeDevtools) { - this.excludeDevtools = excludeDevtools; - } - - public File getAgent() { - return this.agent; - } - - public void setAgent(File agent) { - this.agent = agent; - } - - public Boolean getNoverify() { - return this.noverify; - } - - public void setNoverify(Boolean noverify) { - this.noverify = noverify; - } - - public boolean isApplyExcludeRules() { - return this.applyExcludeRules; - } - - public void setApplyExcludeRules(boolean applyExcludeRules) { - this.applyExcludeRules = applyExcludeRules; - } - - public boolean isExecutable() { - return this.executable; - } - - public void setExecutable(boolean executable) { - this.executable = executable; - } - - public File getEmbeddedLaunchScript() { - return this.embeddedLaunchScript; - } - - public void setEmbeddedLaunchScript(File embeddedLaunchScript) { - this.embeddedLaunchScript = embeddedLaunchScript; - } - - public Map getEmbeddedLaunchScriptProperties() { - return this.embeddedLaunchScriptProperties; - } - - public void setEmbeddedLaunchScriptProperties( - Map embeddedLaunchScriptProperties) { - this.embeddedLaunchScriptProperties = embeddedLaunchScriptProperties; - } - - public void buildInfo() { - this.buildInfo(null); - } - - public void buildInfo(Closure taskConfigurer) { - BuildInfo bootBuildInfo = this.project.getTasks().create("bootBuildInfo", - BuildInfo.class); - this.project.getTasks().getByName(JavaPlugin.CLASSES_TASK_NAME) - .dependsOn(bootBuildInfo); - if (taskConfigurer != null) { - taskConfigurer.setDelegate(bootBuildInfo); - taskConfigurer.call(); - } - } - - /** - * Layout Types. - */ - enum LayoutType { - - JAR(new Layouts.Jar()), - - WAR(new Layouts.War()), - - ZIP(new Layouts.Expanded()), - - DIR(new Layouts.Expanded()), - - NONE(new Layouts.None()); - - Layout layout; - - LayoutType(Layout layout) { - this.layout = layout; - } - - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java deleted file mode 100644 index 77b5447df67..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentTasksEnhancer.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 org.springframework.boot.gradle.agent; - -import java.io.File; -import java.net.URISyntaxException; -import java.security.CodeSource; - -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.tasks.JavaExec; - -import org.springframework.boot.gradle.SpringBootPluginExtension; - -/** - * Add a java agent to the "run" task if configured. You can add an agent in 3 ways (4 if - * you want to use native gradle features as well): - * - *
    - *
  1. Use "-Prun.agent=[path-to-jar]" on the gradle command line
  2. - *
  3. Add an "agent" property (jar file) to the "springBoot" extension in build.gradle - *
  4. - *
  5. As a special case springloaded is detected as a build script dependency
  6. - *
- * - * @author Dave Syer - * @author Phillip Webb - */ -public class AgentTasksEnhancer implements Action { - - private static final String SPRING_LOADED_AGENT_CLASS_NAME = "org.springsource.loaded.agent.SpringLoadedAgent"; - - private File agent; - - private Boolean noverify; - - @Override - public void execute(Project project) { - setup(project); - if (this.agent != null) { - for (Task task : project.getTasks()) { - addAgent(project, task); - } - } - } - - private void setup(Project project) { - project.getLogger().info("Configuring agent"); - SpringBootPluginExtension extension = project.getExtensions() - .getByType(SpringBootPluginExtension.class); - this.noverify = extension.getNoverify(); - this.agent = getAgent(project, extension); - if (this.agent == null) { - this.agent = getSpringLoadedAgent(); - if (this.noverify == null) { - this.noverify = true; - } - } - project.getLogger().debug("Agent: " + this.agent); - } - - private File getAgent(Project project, SpringBootPluginExtension extension) { - if (project.hasProperty("run.agent")) { - return project.file(project.property("run.agent")); - } - return extension.getAgent(); - } - - private File getSpringLoadedAgent() { - try { - Class loaded = Class.forName(SPRING_LOADED_AGENT_CLASS_NAME); - if (loaded != null) { - CodeSource source = loaded.getProtectionDomain().getCodeSource(); - if (source != null) { - try { - return new File(source.getLocation().toURI()); - } - catch (URISyntaxException ex) { - return new File(source.getLocation().getPath()); - } - } - } - } - catch (ClassNotFoundException ex) { - // ignore; - } - return null; - } - - private void addAgent(Project project, Task task) { - if (task instanceof JavaExec) { - addAgent(project, (JavaExec) task); - } - } - - private void addAgent(Project project, JavaExec exec) { - project.getLogger().debug("Attaching to: " + exec); - if (this.agent != null) { - project.getLogger().info("Attaching agent: " + this.agent); - exec.jvmArgs("-javaagent:" + this.agent.getAbsolutePath()); - if (this.noverify != null && this.noverify) { - exec.jvmArgs("-noverify"); - } - Iterable defaultJvmArgs = exec.getConventionMapping() - .getConventionValue(null, "jvmArgs", false); - if (defaultJvmArgs != null) { - exec.jvmArgs(defaultJvmArgs); - } - } - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/buildinfo/BuildInfo.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/buildinfo/BuildInfo.java deleted file mode 100644 index b7d30287f07..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/buildinfo/BuildInfo.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle.buildinfo; - -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.gradle.api.DefaultTask; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.TaskExecutionException; -import org.gradle.api.tasks.bundling.Jar; - -import org.springframework.boot.loader.tools.BuildPropertiesWriter; -import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails; - -/** - * {@link DefaultTask} for generating a {@code build-info.properties} file from a - * {@code Project}. - *

- * By default, the {@code build-info.properties} file is generated in - * project.buildDir/resources/main/META-INF. - *

- * - * @author Andy Wilkinson - */ -public class BuildInfo extends DefaultTask { - - @OutputFile - private File outputFile = getProject().file(new File(getProject().getBuildDir(), - "resources/main/META-INF/build-info.properties")); - - @Input - private String projectGroup = getProject().getGroup().toString(); - - @Input - private String projectArtifact = ((Jar) getProject().getTasks() - .getByName(JavaPlugin.JAR_TASK_NAME)).getBaseName(); - - @Input - private String projectVersion = getProject().getVersion().toString(); - - @Input - private String projectName = getProject().getName(); - - @Input - private Map additionalProperties = new HashMap<>(); - - @TaskAction - public void generateBuildProperties() { - try { - new BuildPropertiesWriter(this.outputFile) - .writeBuildProperties(new ProjectDetails(this.projectGroup, - this.projectArtifact, this.projectVersion, this.projectName, - coerceToStringValues(this.additionalProperties))); - } - catch (IOException ex) { - throw new TaskExecutionException(this, ex); - } - } - - public String getProjectGroup() { - return this.projectGroup; - } - - public void setProjectGroup(String projectGroup) { - this.projectGroup = projectGroup; - } - - public String getProjectArtifact() { - return this.projectArtifact; - } - - public void setProjectArtifact(String projectArtifact) { - this.projectArtifact = projectArtifact; - } - - public String getProjectVersion() { - return this.projectVersion; - } - - public void setProjectVersion(String projectVersion) { - this.projectVersion = projectVersion; - } - - public String getProjectName() { - return this.projectName; - } - - public void setProjectName(String projectName) { - this.projectName = projectName; - } - - public File getOutputFile() { - return this.outputFile; - } - - public void setOutputFile(File outputFile) { - this.outputFile = outputFile; - } - - public Map getAdditionalProperties() { - return this.additionalProperties; - } - - public void setAdditionalProperties(Map additionalProperties) { - this.additionalProperties = additionalProperties; - } - - private Map coerceToStringValues(Map input) { - Map output = new HashMap<>(); - for (Entry entry : input.entrySet()) { - output.put(entry.getKey(), entry.getValue().toString()); - } - return output; - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/SpringBootExtension.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/SpringBootExtension.java new file mode 100644 index 00000000000..04896a63853 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/SpringBootExtension.java @@ -0,0 +1,117 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.dsl; + +import java.io.File; +import java.util.concurrent.Callable; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.bundling.Jar; + +import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo; +import org.springframework.boot.gradle.tasks.buildinfo.BuildInfoProperties; + +/** + * Entry point to Spring Boot's Gradle DSL. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class SpringBootExtension { + + private final Project project; + + /** + * Creates a new {@code SpringBootPluginExtension} that is associated with the given + * {@code project}. + * + * @param project the project + */ + public SpringBootExtension(Project project) { + this.project = project; + } + + /** + * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the + * Java plugin's {@code classes} task to depend upon it. + *

+ * By default, the task's destination dir will be a directory named {@code META-INF} + * beneath the main source set's resources output directory, and the task's project + * artifact will be the base name of the {@code bootWar} or {@code bootJar} task. + */ + public void buildInfo() { + this.buildInfo(null); + } + + /** + * Creates a new {@link BuildInfo} task named {@code bootBuildInfo} and configures the + * Java plugin's {@code classes} task to depend upon it. The task is passed to the + * given {@code configurer} for further configuration. + *

+ * By default, the task's destination dir will be a directory named {@code META-INF} + * beneath the main source set's resources output directory, and the task's project + * artifact will be the base name of the {@code bootWar} or {@code bootJar} task. + * + * @param configurer the task configurer + */ + public void buildInfo(Action configurer) { + BuildInfo bootBuildInfo = this.project.getTasks().create("bootBuildInfo", + BuildInfo.class); + this.project.getPlugins().withType(JavaPlugin.class, plugin -> { + this.project.getTasks().getByName(JavaPlugin.CLASSES_TASK_NAME) + .dependsOn(bootBuildInfo); + this.project.afterEvaluate(evaluated -> { + BuildInfoProperties properties = bootBuildInfo.getProperties(); + if (properties.getArtifact() == null) { + properties.setArtifact(determineArtifactBaseName()); + } + }); + bootBuildInfo.getConventionMapping() + .map("destinationDir", + (Callable) () -> new File( + determineMainSourceSetResourcesOutputDir(), + "META-INF")); + }); + if (configurer != null) { + configurer.execute(bootBuildInfo); + } + } + + private File determineMainSourceSetResourcesOutputDir() { + return this.project.getConvention().getPlugin(JavaPluginConvention.class) + .getSourceSets().getByName(SourceSet.MAIN_SOURCE_SET_NAME).getOutput() + .getResourcesDir(); + } + + private String determineArtifactBaseName() { + Jar artifactTask = findArtifactTask(); + return artifactTask == null ? null : artifactTask.getBaseName(); + } + + private Jar findArtifactTask() { + Jar artifactTask = (Jar) this.project.getTasks().findByName("bootWar"); + if (artifactTask != null) { + return artifactTask; + } + return (Jar) this.project.getTasks().findByName("bootJar"); + } + +} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/src/main/java/BootRunResourcesApplication.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/package-info.java similarity index 66% rename from spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/src/main/java/BootRunResourcesApplication.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/package-info.java index 1a640c586ba..8dd9565304f 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/resources/boot-run-resources/src/main/java/BootRunResourcesApplication.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dsl/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,7 @@ * limitations under the License. */ -public class BootRunResourcesApplication { - - public static void main(String[] args) { - ClassLoader classLoader = BootRunResourcesApplication.class.getClassLoader(); - System.out.println(classLoader.getResource("test.txt")); - } - -} +/** + * Spring Boot Gradle DSL. + */ +package org.springframework.boot.gradle.dsl; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java new file mode 100644 index 00000000000..cf66561c3b7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/ApplicationPluginAction.java @@ -0,0 +1,108 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StringWriter; +import java.util.concurrent.Callable; + +import org.gradle.api.GradleException; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.distribution.Distribution; +import org.gradle.api.distribution.DistributionContainer; +import org.gradle.api.file.CopySpec; +import org.gradle.api.file.FileCollection; +import org.gradle.api.plugins.ApplicationPlugin; +import org.gradle.api.plugins.ApplicationPluginConvention; +import org.gradle.jvm.application.scripts.TemplateBasedScriptGenerator; + +import org.springframework.boot.gradle.tasks.application.CreateBootStartScripts; + +/** + * Action that is executed in response to the {@link ApplicationPlugin} being applied. + * + * @author Andy Wilkinson + */ +final class ApplicationPluginAction implements PluginApplicationAction { + + @Override + public void execute(Project project) { + ApplicationPluginConvention applicationConvention = project.getConvention() + .getPlugin(ApplicationPluginConvention.class); + DistributionContainer distributions = project.getExtensions() + .getByType(DistributionContainer.class); + Distribution distribution = distributions.create("boot"); + CreateBootStartScripts bootStartScripts = project.getTasks() + .create("bootStartScripts", CreateBootStartScripts.class); + ((TemplateBasedScriptGenerator) bootStartScripts.getUnixStartScriptGenerator()) + .setTemplate(project.getResources().getText() + .fromString(loadResource("/unixStartScript.txt"))); + ((TemplateBasedScriptGenerator) bootStartScripts.getWindowsStartScriptGenerator()) + .setTemplate(project.getResources().getText() + .fromString(loadResource("/windowsStartScript.txt"))); + project.getConfigurations().all(configuration -> { + if ("bootArchives".equals(configuration.getName())) { + distribution.getContents() + .with(project.copySpec().into("lib") + .from((Callable) () -> configuration + .getArtifacts().getFiles())); + bootStartScripts.setClasspath(configuration.getArtifacts().getFiles()); + } + }); + bootStartScripts.getConventionMapping().map("outputDir", + () -> new File(project.getBuildDir(), "bootScripts")); + bootStartScripts.getConventionMapping().map("applicationName", + () -> applicationConvention.getApplicationName()); + CopySpec binCopySpec = project.copySpec().into("bin").from(bootStartScripts); + binCopySpec.setFileMode(0x755); + distribution.getContents().with(binCopySpec); + } + + @Override + public Class> getPluginClass() { + return ApplicationPlugin.class; + } + + private String loadResource(String name) { + InputStreamReader reader = new InputStreamReader( + getClass().getResourceAsStream(name)); + char[] buffer = new char[4096]; + int read = 0; + StringWriter writer = new StringWriter(); + try { + while ((read = reader.read(buffer)) > 0) { + writer.write(buffer, 0, read); + } + return writer.toString(); + } + catch (IOException ex) { + throw new GradleException("Failed to read '" + name + "'", ex); + } + finally { + try { + reader.close(); + } + catch (IOException ex) { + // Continue + } + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dependencymanagement/DependencyManagementPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginAction.java similarity index 53% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dependencymanagement/DependencyManagementPluginFeatures.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginAction.java index 763bad251ad..acd7e5ed7a8 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/dependencymanagement/DependencyManagementPluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,44 +14,37 @@ * limitations under the License. */ -package org.springframework.boot.gradle.dependencymanagement; +package org.springframework.boot.gradle.plugin; import io.spring.gradle.dependencymanagement.DependencyManagementPlugin; import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension; -import io.spring.gradle.dependencymanagement.dsl.ImportsHandler; import org.gradle.api.Action; +import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.springframework.boot.gradle.PluginFeatures; - /** - * {@link PluginFeatures} to configure dependency management. + * {@link Action} that is performed in response to the {@link DependencyManagementPlugin} + * being applied. * * @author Andy Wilkinson - * @author Phillip Webb - * @since 1.3.0 */ -public class DependencyManagementPluginFeatures implements PluginFeatures { +final class DependencyManagementPluginAction implements PluginApplicationAction { - private static final String SPRING_BOOT_VERSION = DependencyManagementPluginFeatures.class + private static final String SPRING_BOOT_VERSION = DependencyManagementPluginAction.class .getPackage().getImplementationVersion(); - private static final String SPRING_BOOT_BOM = "org.springframework.boot:spring-boot-starter-parent:" + private static final String SPRING_BOOT_BOM = "org.springframework.boot:spring-boot-dependencies:" + SPRING_BOOT_VERSION; @Override - public void apply(Project project) { - project.getPlugins().apply(DependencyManagementPlugin.class); - DependencyManagementExtension dependencyManagement = project.getExtensions() - .findByType(DependencyManagementExtension.class); - dependencyManagement.imports(new Action() { - - @Override - public void execute(ImportsHandler importsHandler) { - importsHandler.mavenBom(SPRING_BOOT_BOM); - } - - }); + public void execute(Project project) { + project.getExtensions().findByType(DependencyManagementExtension.class) + .imports(importsHandler -> importsHandler.mavenBom(SPRING_BOOT_BOM)); + } + + @Override + public Class> getPluginClass() { + return DependencyManagementPlugin.class; } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java new file mode 100644 index 00000000000..16e1a3e98ee --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.util.Collections; +import java.util.concurrent.Callable; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; +import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact; +import org.gradle.api.plugins.JavaPlugin; +import org.gradle.api.plugins.JavaPluginConvention; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.compile.JavaCompile; + +import org.springframework.boot.gradle.tasks.bundling.BootJar; +import org.springframework.boot.gradle.tasks.run.BootRun; + +/** + * {@link Action} that is executed in response to the {@link JavaPlugin} being applied. + * + * @author Andy Wilkinson + */ +final class JavaPluginAction implements PluginApplicationAction { + + private final SinglePublishedArtifact singlePublishedArtifact; + + JavaPluginAction(SinglePublishedArtifact singlePublishedArtifact) { + this.singlePublishedArtifact = singlePublishedArtifact; + } + + @Override + public Class> getPluginClass() { + return JavaPlugin.class; + } + + @Override + public void execute(Project project) { + BootJar bootJar = configureBootJarTask(project); + configureArtifactPublication(project, bootJar); + configureBootRunTask(project); + configureUtf8Encoding(project); + } + + private BootJar configureBootJarTask(Project project) { + BootJar bootJar = project.getTasks().create(SpringBootPlugin.BOOT_JAR_TASK_NAME, + BootJar.class); + bootJar.classpath((Callable) () -> { + JavaPluginConvention convention = project.getConvention() + .getPlugin(JavaPluginConvention.class); + SourceSet mainSourceSet = convention.getSourceSets() + .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + return mainSourceSet.getRuntimeClasspath(); + }); + bootJar.conventionMapping("mainClass", + new MainClassConvention(project, bootJar::getClasspath)); + return bootJar; + } + + private void configureArtifactPublication(Project project, BootJar bootJar) { + ArchivePublishArtifact artifact = new ArchivePublishArtifact(bootJar); + this.singlePublishedArtifact.addCandidate(artifact); + project.getComponents().add(new SpringBootSoftwareComponent(artifact, + SpringBootPlugin.BOOT_JAVA_SOFTWARE_COMPONENT_NAME)); + } + + private void configureBootRunTask(Project project) { + JavaPluginConvention javaConvention = project.getConvention() + .getPlugin(JavaPluginConvention.class); + BootRun run = project.getTasks().create("bootRun", BootRun.class); + run.setDescription("Run the project with support for " + + "auto-detecting main class and reloading static resources"); + run.setGroup("application"); + run.classpath(javaConvention.getSourceSets() + .findByName(SourceSet.MAIN_SOURCE_SET_NAME).getRuntimeClasspath()); + run.getConventionMapping().map("jvmArgs", () -> { + if (project.hasProperty("applicationDefaultJvmArgs")) { + return project.property("applicationDefaultJvmArgs"); + } + return Collections.emptyList(); + }); + run.conventionMapping("main", + new MainClassConvention(project, run::getClasspath)); + } + + private void configureUtf8Encoding(Project project) { + project.afterEvaluate( + evaluated -> evaluated.getTasks().withType(JavaCompile.class, compile -> { + if (compile.getOptions().getEncoding() == null) { + compile.getOptions().setEncoding("UTF-8"); + } + })); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java new file mode 100644 index 00000000000..766ff3c7e5f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MainClassConvention.java @@ -0,0 +1,72 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.io.File; +import java.io.IOException; +import java.util.Objects; +import java.util.concurrent.Callable; +import java.util.function.Supplier; + +import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; + +import org.springframework.boot.loader.tools.MainClassFinder; + +/** + * A {@link Callable} that provide a convention for the project's main class name. + * + * @author Andy Wilkinson + */ +final class MainClassConvention implements Callable { + + private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication"; + + private final Project project; + + private final Supplier classpathSupplier; + + MainClassConvention(Project project, Supplier classpathSupplier) { + this.project = project; + this.classpathSupplier = classpathSupplier; + } + + @Override + public Object call() throws Exception { + if (this.project.hasProperty("mainClassName")) { + return this.project.property("mainClassName"); + } + return resolveMainClass(); + } + + private String resolveMainClass() { + return this.classpathSupplier.get().filter(File::isDirectory).getFiles().stream() + .map(this::findMainClass).filter(Objects::nonNull).findFirst() + .orElse(null); + } + + private String findMainClass(File file) { + try { + return MainClassFinder.findSingleMainClass(file, + SPRING_BOOT_APPLICATION_CLASS_NAME); + } + catch (IOException ex) { + return null; + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MavenPluginAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MavenPluginAction.java new file mode 100644 index 00000000000..644ce661ef9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/MavenPluginAction.java @@ -0,0 +1,58 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.maven.MavenResolver; +import org.gradle.api.plugins.MavenPlugin; +import org.gradle.api.tasks.Upload; + +/** + * {@link Action} that is executed in response to the {@link MavenPlugin} being applied. + * + * @author Andy Wilkinson + */ +final class MavenPluginAction implements PluginApplicationAction { + + private final String uploadTaskName; + + MavenPluginAction(String uploadTaskName) { + this.uploadTaskName = uploadTaskName; + } + + @Override + public Class> getPluginClass() { + return MavenPlugin.class; + } + + @Override + public void execute(Project project) { + project.getTasks().withType(Upload.class, upload -> { + if (this.uploadTaskName.equals(upload.getName())) { + project.afterEvaluate(evaluated -> clearConfigurationMappings(upload)); + } + }); + } + + private void clearConfigurationMappings(Upload upload) { + upload.getRepositories().withType(MavenResolver.class, + resolver -> resolver.getPom().getScopeMappings().getMappings().clear()); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/PluginApplicationAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/PluginApplicationAction.java new file mode 100644 index 00000000000..a02de18610b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/PluginApplicationAction.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; + +/** + * An {@link Action} to be executed on a {@link Project} in response to a particular type + * of {@link Plugin} being applied. + * + * @author Andy Wilkinson + */ +interface PluginApplicationAction extends Action { + + /** + * The class of the {@code Plugin} that, when applied, will trigger the execution of + * this action. + * + * @return the plugin class + */ + Class> getPluginClass(); + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SinglePublishedArtifact.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SinglePublishedArtifact.java new file mode 100644 index 00000000000..5b081358e9c --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SinglePublishedArtifact.java @@ -0,0 +1,46 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.gradle.api.artifacts.PublishArtifact; +import org.gradle.api.artifacts.PublishArtifactSet; + +/** + * A wrapper for a {@PublishArtifactSet} that ensures that only a single artifact is + * published, with a war file taking precedence over a jar file. + * + * @author Andy Wilkinson + */ +final class SinglePublishedArtifact { + + private final PublishArtifactSet artifacts; + + private PublishArtifact currentArtifact; + + SinglePublishedArtifact(PublishArtifactSet artifacts) { + this.artifacts = artifacts; + } + + void addCandidate(PublishArtifact candidate) { + if (this.currentArtifact == null || "war".equals(candidate.getExtension())) { + this.artifacts.remove(this.currentArtifact); + this.artifacts.add(candidate); + this.currentArtifact = candidate; + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java index 604ca6fe244..8d6bf837f29 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,20 @@ package org.springframework.boot.gradle.plugin; -import org.gradle.api.Action; +import java.util.Arrays; +import java.util.List; + import org.gradle.api.Plugin; import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.compile.JavaCompile; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.component.SoftwareComponent; -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.gradle.agent.AgentPluginFeatures; -import org.springframework.boot.gradle.dependencymanagement.DependencyManagementPluginFeatures; -import org.springframework.boot.gradle.repackage.RepackagePluginFeatures; -import org.springframework.boot.gradle.run.RunPluginFeatures; +import org.springframework.boot.gradle.dsl.SpringBootExtension; +import org.springframework.boot.gradle.tasks.bundling.BootJar; +import org.springframework.boot.gradle.tasks.bundling.BootWar; /** - * Gradle 'Spring Boot' {@link Plugin}. + * Gradle plugin for Spring Boot. * * @author Phillip Webb * @author Dave Syer @@ -38,34 +37,65 @@ import org.springframework.boot.gradle.run.RunPluginFeatures; */ public class SpringBootPlugin implements Plugin { - @Override - public void apply(Project project) { - project.getExtensions().create("springBoot", SpringBootPluginExtension.class, - project); - project.getPlugins().apply(JavaPlugin.class); - new AgentPluginFeatures().apply(project); - new RepackagePluginFeatures().apply(project); - new RunPluginFeatures().apply(project); - new DependencyManagementPluginFeatures().apply(project); - project.getTasks().withType(JavaCompile.class).all(new SetUtf8EncodingAction()); - } + /** + * The name of the {@link Configuration} that contains Spring Boot archives. + * + * @since 2.0.0 + */ + public static final String BOOT_ARCHIVES_CONFIURATION_NAME = "bootArchives"; - private static class SetUtf8EncodingAction implements Action { + /** + * The name of the {@link SoftwareComponent} for a Spring Boot Java application. + * + * @since 2.0.0 + */ + public static final String BOOT_JAVA_SOFTWARE_COMPONENT_NAME = "bootJava"; - @Override - public void execute(final JavaCompile compile) { - compile.doFirst(new Action() { + /** + * The name of the {@link SoftwareComponent} for a Spring Boot Web application. + * + * @since 2.0.0 + */ + public static final String BOOT_WEB_SOFTWARE_COMPONENT_NAME = "bootWeb"; - @Override - public void execute(Task t) { - if (compile.getOptions().getEncoding() == null) { - compile.getOptions().setEncoding("UTF-8"); - } - } + /** + * The name of the default {@link BootJar} task. + * + * @since 2.0.0 + */ + public static final String BOOT_JAR_TASK_NAME = "bootJar"; - }); - } + /** + * The name of the default {@link BootWar} task. + * + * @since 2.0.0 + */ + public static final String BOOT_WAR_TASK_NAME = "bootWar"; + @Override + public void apply(Project project) { + project.getExtensions().create("springBoot", SpringBootExtension.class, project); + Configuration bootArchives = project.getConfigurations() + .create(BOOT_ARCHIVES_CONFIURATION_NAME); + SinglePublishedArtifact singlePublishedArtifact = new SinglePublishedArtifact( + bootArchives.getArtifacts()); + List actions = Arrays.asList( + new JavaPluginAction(singlePublishedArtifact), + new WarPluginAction(singlePublishedArtifact), + new MavenPluginAction(bootArchives.getUploadTaskName()), + new DependencyManagementPluginAction(), new ApplicationPluginAction()); + for (PluginApplicationAction action : actions) { + project.getPlugins().withType(action.getPluginClass(), + plugin -> action.execute(project)); + } + UnresolvedDependenciesAnalyzer unresolvedDependenciesAnalyzer = new UnresolvedDependenciesAnalyzer(); + project.getConfigurations().all(configuration -> configuration.getIncoming() + .afterResolve(resolvableDependencies -> unresolvedDependenciesAnalyzer + .analyze(configuration.getResolvedConfiguration() + .getLenientConfiguration() + .getUnresolvedModuleDependencies()))); + project.getGradle().buildFinished( + buildResult -> unresolvedDependenciesAnalyzer.buildFinished(project)); } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootSoftwareComponent.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootSoftwareComponent.java new file mode 100644 index 00000000000..83f6b5dfc16 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/SpringBootSoftwareComponent.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.util.Collections; +import java.util.Set; + +import org.gradle.api.artifacts.ModuleDependency; +import org.gradle.api.artifacts.PublishArtifact; +import org.gradle.api.attributes.Usage; +import org.gradle.api.internal.attributes.Usages; +import org.gradle.api.internal.component.SoftwareComponentInternal; +import org.gradle.api.internal.component.UsageContext; + +/** + * {@link org.gradle.api.component.SoftwareComponent} for a Spring Boot fat jar or war. + * + * @author Andy Wilkinson + */ +final class SpringBootSoftwareComponent implements SoftwareComponentInternal { + + private final PublishArtifact artifact; + + private final String name; + + SpringBootSoftwareComponent(PublishArtifact artifact, String name) { + this.artifact = artifact; + this.name = name; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Set getUsages() { + return Collections.singleton(new BootUsageContext(this.artifact)); + } + + private static final class BootUsageContext implements UsageContext { + + private static final Usage USAGE = Usages.usage("master"); + + private final PublishArtifact artifact; + + private BootUsageContext(PublishArtifact artifact) { + this.artifact = artifact; + } + + @Override + public Usage getUsage() { + return USAGE; + } + + @Override + public Set getArtifacts() { + return Collections.singleton(this.artifact); + } + + @Override + public Set getDependencies() { + return Collections.emptySet(); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/UnresolvedDependenciesAnalyzer.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/UnresolvedDependenciesAnalyzer.java new file mode 100644 index 00000000000..b56ab5cea0a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/UnresolvedDependenciesAnalyzer.java @@ -0,0 +1,69 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import io.spring.gradle.dependencymanagement.DependencyManagementPlugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.ModuleVersionSelector; +import org.gradle.api.artifacts.UnresolvedDependency; +import org.slf4j.LoggerFactory; + +/** + * An analyzer for {@link UnresolvedDependency unresolvable dependencies} that logs a + * warning suggesting that the {@code io.spring.dependency-management} plugin is applied + * when one or more versionless dependencies fails to resolve. + * + * @author Andy Wilkinson + */ +class UnresolvedDependenciesAnalyzer { + + private static final org.slf4j.Logger logger = LoggerFactory + .getLogger(SpringBootPlugin.class); + + private Set dependenciesWithNoVersion = new HashSet<>(); + + void analyze(Set unresolvedDependencies) { + this.dependenciesWithNoVersion = unresolvedDependencies.stream() + .map(unresolvedDependency -> unresolvedDependency.getSelector()) + .filter(this::hasNoVersion).collect(Collectors.toSet()); + } + + void buildFinished(Project project) { + if (!this.dependenciesWithNoVersion.isEmpty() + && !project.getPlugins().hasPlugin(DependencyManagementPlugin.class)) { + StringBuilder message = new StringBuilder(); + message.append("\nDuring the build, one or more dependencies that were " + + "declared without a version failed to resolve:\n"); + this.dependenciesWithNoVersion.stream() + .forEach(dependency -> message.append(" " + dependency + "\n")); + message.append("\nDid you forget to apply the " + + "io.spring.dependency-management plugin to the " + project.getName() + + " project?\n"); + logger.warn(message.toString()); + } + } + + private boolean hasNoVersion(ModuleVersionSelector selector) { + String version = selector.getVersion(); + return version == null || version.trim().length() == 0; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java new file mode 100644 index 00000000000..f5dec40f069 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/WarPluginAction.java @@ -0,0 +1,64 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.gradle.api.Action; +import org.gradle.api.Plugin; +import org.gradle.api.Project; +import org.gradle.api.artifacts.Configuration; +import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact; +import org.gradle.api.plugins.WarPlugin; + +import org.springframework.boot.gradle.tasks.bundling.BootWar; + +/** + * {@link Action} that is executed in response to the {@link WarPlugin} being applied. + * + * @author Andy Wilkinson + */ +class WarPluginAction implements PluginApplicationAction { + + private final SinglePublishedArtifact singlePublishedArtifact; + + WarPluginAction(SinglePublishedArtifact singlePublishedArtifact) { + this.singlePublishedArtifact = singlePublishedArtifact; + } + + @Override + public Class> getPluginClass() { + return WarPlugin.class; + } + + @Override + public void execute(Project project) { + BootWar bootWar = project.getTasks().create(SpringBootPlugin.BOOT_WAR_TASK_NAME, + BootWar.class); + bootWar.providedClasspath(providedRuntimeConfiguration(project)); + ArchivePublishArtifact artifact = new ArchivePublishArtifact(bootWar); + this.singlePublishedArtifact.addCandidate(artifact); + project.getComponents().add(new SpringBootSoftwareComponent(artifact, + SpringBootPlugin.BOOT_WEB_SOFTWARE_COMPONENT_NAME)); + bootWar.conventionMapping("mainClass", + new MainClassConvention(project, bootWar::getClasspath)); + } + + private Configuration providedRuntimeConfiguration(Project project) { + return project.getConfigurations() + .getByName(WarPlugin.PROVIDED_RUNTIME_CONFIGURATION_NAME); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/package-info.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/package-info.java new file mode 100644 index 00000000000..28ebf0d2893 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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. + */ + +/** + * Central classes for the Spring Boot Gradle plugin. + */ +package org.springframework.boot.gradle.plugin; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java deleted file mode 100644 index 1ebd3a6c331..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/ProjectLibraries.java +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle.repackage; - -import java.io.File; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.gradle.api.Project; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.artifacts.FileCollectionDependency; -import org.gradle.api.artifacts.ModuleVersionIdentifier; -import org.gradle.api.artifacts.ProjectDependency; -import org.gradle.api.artifacts.ResolvedArtifact; - -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.loader.tools.Libraries; -import org.springframework.boot.loader.tools.Library; -import org.springframework.boot.loader.tools.LibraryCallback; -import org.springframework.boot.loader.tools.LibraryScope; - -/** - * Expose Gradle {@link Configuration}s as {@link Libraries}. - * - * @author Phillip Webb - * @author Andy Wilkinson - */ -class ProjectLibraries implements Libraries { - - private final Project project; - - private final SpringBootPluginExtension extension; - - private final boolean excludeDevtools; - - private final TargetConfigurationResolver targetConfigurationResolver; - - private String providedConfigurationName = "providedRuntime"; - - private String customConfigurationName = null; - - /** - * Create a new {@link ProjectLibraries} instance of the specified {@link Project}. - * @param project the gradle project - * @param extension the extension - * @param excludeDevTools whether Spring Boot Devtools should be excluded - */ - ProjectLibraries(Project project, SpringBootPluginExtension extension, - boolean excludeDevTools) { - this.project = project; - this.extension = extension; - this.excludeDevtools = excludeDevTools; - this.targetConfigurationResolver = createTargetConfigurationResolver(); - } - - private static TargetConfigurationResolver createTargetConfigurationResolver() { - try { - return new Gradle3TargetConfigurationResolver( - ProjectDependency.class.getMethod("getTargetConfiguration")); - } - catch (Exception ex) { - return new Gradle2TargetConfigurationResolver(); - } - } - - /** - * Set the name of the provided configuration. Defaults to 'providedRuntime'. - * @param providedConfigurationName the providedConfigurationName to set - */ - public void setProvidedConfigurationName(String providedConfigurationName) { - this.providedConfigurationName = providedConfigurationName; - } - - public void setCustomConfigurationName(String customConfigurationName) { - this.customConfigurationName = customConfigurationName; - } - - @Override - public void doWithLibraries(LibraryCallback callback) throws IOException { - Set custom = getLibraries(this.customConfigurationName, - LibraryScope.CUSTOM); - if (custom != null) { - libraries(custom, callback); - } - else { - Set runtime = getLibraries("runtime", LibraryScope.RUNTIME); - Set provided = getLibraries(this.providedConfigurationName, - LibraryScope.PROVIDED); - if (provided != null) { - runtime = minus(runtime, provided); - } - libraries(runtime, callback); - libraries(provided, callback); - } - } - - private Set getLibraries(String configurationName, - LibraryScope scope) { - Configuration configuration = (configurationName == null ? null - : this.project.getConfigurations().findByName(configurationName)); - if (configuration == null) { - return null; - } - Set libraries = new LinkedHashSet<>(); - for (ResolvedArtifact artifact : configuration.getResolvedConfiguration() - .getResolvedArtifacts()) { - libraries.add(new ResolvedArtifactLibrary(artifact, scope)); - } - libraries.addAll(getLibrariesForFileDependencies(configuration, scope)); - return libraries; - } - - private Set getLibrariesForFileDependencies( - Configuration configuration, LibraryScope scope) { - Set libraries = new LinkedHashSet<>(); - for (Dependency dependency : configuration.getIncoming().getDependencies()) { - if (dependency instanceof FileCollectionDependency) { - FileCollectionDependency fileDependency = (FileCollectionDependency) dependency; - for (File file : fileDependency.resolve()) { - libraries.add( - new GradleLibrary(fileDependency.getGroup(), file, scope)); - } - } - else if (dependency instanceof ProjectDependency) { - ProjectDependency projectDependency = (ProjectDependency) dependency; - libraries - .addAll(getLibrariesForFileDependencies( - this.targetConfigurationResolver - .resolveTargetConfiguration(projectDependency), - scope)); - } - } - return libraries; - } - - private Set minus(Set source, - Set toRemove) { - if (source == null || toRemove == null) { - return source; - } - Set filesToRemove = new HashSet<>(); - for (GradleLibrary library : toRemove) { - filesToRemove.add(library.getFile()); - } - Set result = new LinkedHashSet<>(); - for (GradleLibrary library : source) { - if (!filesToRemove.contains(library.getFile())) { - result.add(library); - } - } - return result; - } - - private void libraries(Set libraries, LibraryCallback callback) - throws IOException { - if (libraries != null) { - Set duplicates = getDuplicates(libraries); - for (GradleLibrary library : libraries) { - if (!isExcluded(library)) { - library.setIncludeGroupName(duplicates.contains(library.getName())); - callback.library(library); - } - } - } - } - - private boolean isExcluded(GradleLibrary library) { - if (this.excludeDevtools && isDevToolsJar(library)) { - return true; - } - return false; - } - - private boolean isDevToolsJar(GradleLibrary library) { - return "org.springframework.boot".equals(library.getGroup()) - && library.getName().startsWith("spring-boot-devtools"); - } - - private Set getDuplicates(Set libraries) { - Set duplicates = new HashSet<>(); - Set seen = new HashSet<>(); - for (GradleLibrary library : libraries) { - if (library.getFile() != null && !seen.add(library.getFile().getName())) { - duplicates.add(library.getFile().getName()); - } - } - return duplicates; - } - - private class GradleLibrary extends Library { - - private final String group; - - private boolean includeGroupName; - - GradleLibrary(String group, File file, LibraryScope scope) { - super(file, scope); - this.group = group; - } - - public void setIncludeGroupName(boolean includeGroupName) { - this.includeGroupName = includeGroupName; - } - - public String getGroup() { - return this.group; - } - - @Override - public String getName() { - String name = super.getName(); - if (this.includeGroupName && this.group != null) { - name = this.group + "-" + name; - } - return name; - } - - @Override - public int hashCode() { - return getFile().hashCode(); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof GradleLibrary) { - return getFile().equals(((GradleLibrary) obj).getFile()); - } - return false; - } - - @Override - public String toString() { - return getFile().getAbsolutePath(); - } - - } - - /** - * Adapts a {@link ResolvedArtifact} to a {@link Library}. - */ - private class ResolvedArtifactLibrary extends GradleLibrary { - - private final ResolvedArtifact artifact; - - ResolvedArtifactLibrary(ResolvedArtifact artifact, LibraryScope scope) { - super(artifact.getModuleVersion().getId().getGroup(), artifact.getFile(), - scope); - this.artifact = artifact; - } - - @Override - public boolean isUnpackRequired() { - if (ProjectLibraries.this.extension.getRequiresUnpack() != null) { - ModuleVersionIdentifier id = this.artifact.getModuleVersion().getId(); - return ProjectLibraries.this.extension.getRequiresUnpack() - .contains(id.getGroup() + ":" + id.getName()); - } - return false; - } - - } - - /** - * Strategy used to resolve configurations regardless of the underlying Gradle - * version. - */ - private interface TargetConfigurationResolver { - - Configuration resolveTargetConfiguration(ProjectDependency projectDependency); - - } - - /** - * {@link TargetConfigurationResolver} for Gradle 2.x. - */ - private static final class Gradle2TargetConfigurationResolver - implements TargetConfigurationResolver { - - @Override - public Configuration resolveTargetConfiguration( - ProjectDependency projectDependency) { - return projectDependency.getProjectConfiguration(); - } - - } - - /** - * {@link TargetConfigurationResolver} for Gradle 3.x. - */ - private static final class Gradle3TargetConfigurationResolver - implements TargetConfigurationResolver { - - private final Method getTargetConfiguration; - - private Gradle3TargetConfigurationResolver(Method getTargetConfiguration) { - this.getTargetConfiguration = getTargetConfiguration; - } - - @Override - public Configuration resolveTargetConfiguration( - ProjectDependency projectDependency) { - try { - String configurationName = (String) this.getTargetConfiguration - .invoke(projectDependency); - return projectDependency.getDependencyProject().getConfigurations() - .getByName(configurationName == null - ? Dependency.DEFAULT_CONFIGURATION : configurationName); - } - catch (Exception ex) { - throw new RuntimeException("Failed to get target configuration", ex); - } - } - - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java deleted file mode 100644 index b979ed4c7d8..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackagePluginFeatures.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 org.springframework.boot.gradle.repackage; - -import java.io.File; -import java.io.IOException; - -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.artifacts.Configuration; -import org.gradle.api.artifacts.Dependency; -import org.gradle.api.logging.Logger; -import org.gradle.api.plugins.BasePlugin; -import org.gradle.api.plugins.JavaPlugin; -import org.gradle.api.tasks.TaskDependency; -import org.gradle.api.tasks.bundling.Jar; - -import org.springframework.boot.gradle.PluginFeatures; -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.gradle.run.FindMainClassTask; -import org.springframework.boot.loader.tools.Library; -import org.springframework.boot.loader.tools.LibraryCallback; -import org.springframework.util.StringUtils; - -/** - * {@link PluginFeatures} to add repackage support. - * - * @author Phillip Webb - * @author Dave Syer - * @author Andy Wilkinson - */ -public class RepackagePluginFeatures implements PluginFeatures { - - /** - * The name of the repackage task. - */ - public static final String REPACKAGE_TASK_NAME = "bootRepackage"; - - @Override - public void apply(Project project) { - addRepackageTask(project); - registerRepackageTaskProperty(project); - } - - private void addRepackageTask(Project project) { - RepackageTask task = project.getTasks().create(REPACKAGE_TASK_NAME, - RepackageTask.class); - task.setDescription("Repackage existing JAR and WAR " - + "archives so that they can be executed from the command " - + "line using 'java -jar'"); - task.setGroup(BasePlugin.BUILD_GROUP); - Configuration runtimeConfiguration = project.getConfigurations() - .getByName(JavaPlugin.RUNTIME_CONFIGURATION_NAME); - TaskDependency runtimeProjectDependencyJarTasks = runtimeConfiguration - .getTaskDependencyFromProjectDependency(true, JavaPlugin.JAR_TASK_NAME); - task.dependsOn( - project.getConfigurations().getByName(Dependency.ARCHIVES_CONFIGURATION) - .getAllArtifacts().getBuildDependencies(), - runtimeProjectDependencyJarTasks); - registerOutput(project, task); - ensureTaskRunsOnAssembly(project, task); - ensureMainClassHasBeenFound(project, task); - } - - private void registerOutput(Project project, final RepackageTask task) { - project.afterEvaluate(new Action() { - @Override - public void execute(Project project) { - project.getTasks().withType(Jar.class, - new RegisterInputsOutputsAction(task)); - Object withJar = task.getWithJarTask(); - if (withJar != null) { - task.dependsOn(withJar); - } - } - }); - } - - private void ensureTaskRunsOnAssembly(Project project, Task task) { - project.getTasks().getByName(BasePlugin.ASSEMBLE_TASK_NAME).dependsOn(task); - } - - private void ensureMainClassHasBeenFound(Project project, Task task) { - task.dependsOn(project.getTasks().withType(FindMainClassTask.class)); - } - - /** - * Register BootRepackage so that we can use task {@code foo(type: BootRepackage)}. - * @param project the source project - */ - private void registerRepackageTaskProperty(Project project) { - project.getExtensions().getExtraProperties().set("BootRepackage", - RepackageTask.class); - } - - /** - * Register task input/outputs when classifiers are used. - */ - private static class RegisterInputsOutputsAction implements Action { - - private final RepackageTask task; - - private final Project project; - - RegisterInputsOutputsAction(RepackageTask task) { - this.task = task; - this.project = task.getProject(); - } - - @Override - public void execute(Jar jarTask) { - if ("".equals(jarTask.getClassifier())) { - String classifier = this.task.getClassifier(); - if (classifier == null) { - SpringBootPluginExtension extension = this.project.getExtensions() - .getByType(SpringBootPluginExtension.class); - classifier = extension.getClassifier(); - this.task.setClassifier(classifier); - } - if (classifier != null) { - setupInputOutputs(jarTask, classifier); - } - } - } - - private void setupInputOutputs(Jar jarTask, String classifier) { - Logger logger = this.project.getLogger(); - logger.debug("Using classifier: " + classifier + " for task " - + this.task.getName()); - File inputFile = jarTask.getArchivePath(); - String outputName = inputFile.getName(); - outputName = StringUtils.stripFilenameExtension(outputName) + "-" + classifier - + "." + StringUtils.getFilenameExtension(outputName); - File outputFile = new File(inputFile.getParentFile(), outputName); - this.task.getInputs().file(jarTask); - addLibraryDependencies(this.task); - this.task.getOutputs().file(outputFile); - this.task.setOutputFile(outputFile); - } - - private void addLibraryDependencies(final RepackageTask task) { - try { - task.getLibraries().doWithLibraries(new LibraryCallback() { - @Override - public void library(Library library) throws IOException { - task.getInputs().file(library.getFile()); - } - }); - } - catch (IOException ex) { - throw new IllegalStateException(ex); - } - } - - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java deleted file mode 100644 index 155adebca2e..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/repackage/RepackageTask.java +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle.repackage; - -import java.io.File; -import java.io.IOException; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import org.gradle.api.Action; -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.ExtraPropertiesExtension; -import org.gradle.api.tasks.TaskAction; -import org.gradle.api.tasks.bundling.Jar; - -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.loader.tools.DefaultLaunchScript; -import org.springframework.boot.loader.tools.LaunchScript; -import org.springframework.boot.loader.tools.Layout; -import org.springframework.boot.loader.tools.Repackager; -import org.springframework.boot.loader.tools.Repackager.MainClassTimeoutWarningListener; -import org.springframework.util.FileCopyUtils; - -/** - * Repackage task. - * - * @author Phillip Webb - * @author Janne Valkealahti - * @author Andy Wilkinson - */ -public class RepackageTask extends DefaultTask { - - private String customConfiguration; - - private Object withJarTask; - - private String mainClass; - - private String classifier; - - private File outputFile; - - private Boolean excludeDevtools; - - private Boolean executable; - - private File embeddedLaunchScript; - - private Map embeddedLaunchScriptProperties; - - public void setCustomConfiguration(String customConfiguration) { - this.customConfiguration = customConfiguration; - } - - public Object getWithJarTask() { - return this.withJarTask; - } - - public void setWithJarTask(Object withJarTask) { - this.withJarTask = withJarTask; - } - - public void setMainClass(String mainClass) { - this.mainClass = mainClass; - } - - public String getMainClass() { - return this.mainClass; - } - - public String getClassifier() { - return this.classifier; - } - - public void setClassifier(String classifier) { - this.classifier = classifier; - } - - void setOutputFile(File file) { - this.outputFile = file; - } - - public Boolean getExcludeDevtools() { - return this.excludeDevtools; - } - - public void setExcludeDevtools(Boolean excludeDevtools) { - this.excludeDevtools = excludeDevtools; - } - - public Boolean getExecutable() { - return this.executable; - } - - public void setExecutable(Boolean executable) { - this.executable = executable; - } - - public File getEmbeddedLaunchScript() { - return this.embeddedLaunchScript; - } - - public void setEmbeddedLaunchScript(File embeddedLaunchScript) { - this.embeddedLaunchScript = embeddedLaunchScript; - } - - public Map getEmbeddedLaunchScriptProperties() { - return this.embeddedLaunchScriptProperties; - } - - public void setEmbeddedLaunchScriptProperties( - Map embeddedLaunchScriptProperties) { - this.embeddedLaunchScriptProperties = embeddedLaunchScriptProperties; - } - - @TaskAction - public void repackage() { - Project project = getProject(); - SpringBootPluginExtension extension = project.getExtensions() - .getByType(SpringBootPluginExtension.class); - ProjectLibraries libraries = getLibraries(); - project.getTasks().withType(Jar.class, new RepackageAction(extension, libraries)); - } - - public ProjectLibraries getLibraries() { - Project project = getProject(); - SpringBootPluginExtension extension = project.getExtensions() - .getByType(SpringBootPluginExtension.class); - ProjectLibraries libraries = new ProjectLibraries(project, extension, - this.excludeDevtools == null ? extension.isExcludeDevtools() - : this.excludeDevtools); - if (extension.getProvidedConfiguration() != null) { - libraries.setProvidedConfigurationName(extension.getProvidedConfiguration()); - } - if (this.customConfiguration != null) { - libraries.setCustomConfigurationName(this.customConfiguration); - } - else if (extension.getCustomConfiguration() != null) { - libraries.setCustomConfigurationName(extension.getCustomConfiguration()); - } - return libraries; - } - - /** - * Action to repackage JARs. - */ - private class RepackageAction implements Action { - - private final SpringBootPluginExtension extension; - - private final ProjectLibraries libraries; - - RepackageAction(SpringBootPluginExtension extension, ProjectLibraries libraries) { - this.extension = extension; - this.libraries = libraries; - } - - @Override - public void execute(Jar jarTask) { - if (!RepackageTask.this.isEnabled()) { - getLogger().info("Repackage disabled"); - return; - } - Object withJarTask = RepackageTask.this.withJarTask; - if (!isTaskMatch(jarTask, withJarTask)) { - getLogger().info( - "Jar task not repackaged (didn't match withJarTask): " + jarTask); - return; - } - File file = jarTask.getArchivePath(); - if (file.exists()) { - repackage(file); - } - } - - private boolean isTaskMatch(Jar task, Object withJarTask) { - if (withJarTask == null) { - if ("".equals(task.getClassifier())) { - Set tasksWithCustomRepackaging = new HashSet<>(); - for (RepackageTask repackageTask : RepackageTask.this.getProject() - .getTasks().withType(RepackageTask.class)) { - if (repackageTask.getWithJarTask() != null) { - tasksWithCustomRepackaging - .add(repackageTask.getWithJarTask()); - } - } - return !tasksWithCustomRepackaging.contains(task); - } - return false; - } - return task.equals(withJarTask) || task.getName().equals(withJarTask); - } - - private void repackage(File file) { - File outputFile = RepackageTask.this.outputFile; - if (outputFile != null && !file.equals(outputFile)) { - copy(file, outputFile); - file = outputFile; - } - Repackager repackager = new Repackager(file, - this.extension.getLayoutFactory()); - repackager.addMainClassTimeoutWarningListener( - new LoggingMainClassTimeoutWarningListener()); - setMainClass(repackager); - Layout layout = this.extension.convertLayout(); - if (layout != null) { - repackager.setLayout(layout); - } - repackager.setBackupSource(this.extension.isBackupSource()); - try { - LaunchScript launchScript = getLaunchScript(); - repackager.repackage(file, this.libraries, launchScript); - } - catch (IOException ex) { - throw new IllegalStateException(ex.getMessage(), ex); - } - } - - private void copy(File source, File dest) { - try { - FileCopyUtils.copy(source, dest); - } - catch (IOException ex) { - throw new IllegalStateException(ex.getMessage(), ex); - } - } - - private void setMainClass(Repackager repackager) { - String mainClassName = getMainClassNameProperty(); - if (RepackageTask.this.mainClass != null) { - mainClassName = RepackageTask.this.mainClass; - } - else if (this.extension.getMainClass() != null) { - mainClassName = this.extension.getMainClass(); - } - else { - Task runTask = getProject().getTasks().findByName("run"); - if (runTask != null && runTask.hasProperty("main")) { - mainClassName = (String) getProject().getTasks().getByName("run") - .property("main"); - } - } - if (mainClassName != null) { - getLogger().info("Setting mainClass: " + mainClassName); - repackager.setMainClass(mainClassName); - } - else { - getLogger().info("No mainClass configured"); - } - } - - private String getMainClassNameProperty() { - if (getProject().hasProperty("mainClassName")) { - return (String) getProject().property("mainClassName"); - } - ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) getProject() - .getExtensions().getByName("ext"); - if (extraProperties.has("mainClassName")) { - return (String) extraProperties.get("mainClassName"); - } - return null; - } - - private LaunchScript getLaunchScript() throws IOException { - if (isExecutable() || getEmbeddedLaunchScript() != null) { - return new DefaultLaunchScript(getEmbeddedLaunchScript(), - getEmbeddedLaunchScriptProperties()); - } - return null; - } - - private boolean isExecutable() { - return RepackageTask.this.executable != null ? RepackageTask.this.executable - : this.extension.isExecutable(); - } - - private File getEmbeddedLaunchScript() { - return RepackageTask.this.embeddedLaunchScript != null - ? RepackageTask.this.embeddedLaunchScript - : this.extension.getEmbeddedLaunchScript(); - } - - private Map getEmbeddedLaunchScriptProperties() { - return RepackageTask.this.embeddedLaunchScriptProperties != null - ? RepackageTask.this.embeddedLaunchScriptProperties - : this.extension.getEmbeddedLaunchScriptProperties(); - } - - } - - /** - * {@link Repackager} that also logs when searching takes too long. - */ - private class LoggingMainClassTimeoutWarningListener - implements MainClassTimeoutWarningListener { - - @Override - public void handleTimeoutWarning(long duration, String mainMethod) { - getLogger().warn("Searching for the main-class is taking " - + "some time, consider using setting " + "'springBoot.mainClass'"); - } - - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java deleted file mode 100644 index 7f51972f9f1..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/BootRunTask.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2012-2017 the original author or authors. - * - * 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 org.springframework.boot.gradle.run; - -import java.io.File; -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -import org.gradle.api.internal.file.collections.SimpleFileCollection; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSet; - -import org.springframework.boot.loader.tools.FileUtils; - -/** - * Extension of the standard 'run' task with additional Spring Boot features. - * - * @author Dave Syer - * @author Phillip Webb - */ -public class BootRunTask extends JavaExec { - - /** - * Whether or not resources (typically in {@code src/main/resources} are added - * directly to the classpath. When enabled, this allows live in-place editing of - * resources. Duplicate resources are removed from the resource output directory to - * prevent them from appearing twice if {@code ClassLoader.getResources()} is called. - */ - private boolean addResources = false; - - public boolean getAddResources() { - return this.addResources; - } - - public void setAddResources(boolean addResources) { - this.addResources = addResources; - } - - @Override - public void exec() { - if (System.console() != null) { - // Record that the console is available here for AnsiOutput to detect later - this.getEnvironment().put("spring.output.ansi.console-available", true); - } - addResourcesIfNecessary(); - super.exec(); - } - - private void addResourcesIfNecessary() { - if (this.addResources) { - SourceSet mainSourceSet = SourceSets.findMainSourceSet(getProject()); - final File outputDir = (mainSourceSet == null ? null - : mainSourceSet.getOutput().getResourcesDir()); - final Set resources = new LinkedHashSet<>(); - if (mainSourceSet != null) { - resources.addAll(mainSourceSet.getResources().getSrcDirs()); - } - List classPath = new ArrayList<>(getClasspath().getFiles()); - classPath.addAll(0, resources); - getLogger().info("Adding classpath: " + resources); - setClasspath(new SimpleFileCollection(classPath)); - if (outputDir != null) { - for (File directory : resources) { - FileUtils.removeDuplicatesFromOutputDirectory(outputDir, directory); - } - } - } - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java deleted file mode 100644 index c3d2470a92b..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/FindMainClassTask.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle.run; - -import java.io.IOException; - -import org.gradle.api.DefaultTask; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.ApplicationPluginConvention; -import org.gradle.api.plugins.ExtraPropertiesExtension; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.JavaExec; -import org.gradle.api.tasks.SourceSetOutput; -import org.gradle.api.tasks.TaskAction; - -import org.springframework.boot.gradle.SpringBootPluginExtension; -import org.springframework.boot.loader.tools.MainClassFinder; - -/** - * Task to find and set the 'mainClassName' convention when it's missing by searching the - * main source code. - * - * @author Dave Syer - * @author Phillip Webb - * @author Andy Wilkinson - */ -public class FindMainClassTask extends DefaultTask { - - private static final String SPRING_BOOT_APPLICATION_CLASS_NAME = "org.springframework.boot.autoconfigure.SpringBootApplication"; - - @Input - private SourceSetOutput mainClassSourceSetOutput; - - public void setMainClassSourceSetOutput(SourceSetOutput sourceSetOutput) { - this.mainClassSourceSetOutput = sourceSetOutput; - this.dependsOn(this.mainClassSourceSetOutput.getBuildDependencies()); - } - - @TaskAction - public void setMainClassNameProperty() { - Project project = getProject(); - if (!project.hasProperty("mainClassName") - || project.property("mainClassName") == null) { - String mainClass = findMainClass(); - if (project.hasProperty("mainClassName")) { - project.setProperty("mainClassName", mainClass); - } - else { - ExtraPropertiesExtension extraProperties = (ExtraPropertiesExtension) project - .getExtensions().getByName("ext"); - extraProperties.set("mainClassName", mainClass); - } - } - } - - private String findMainClass() { - Project project = getProject(); - - String mainClass = null; - - // Try the SpringBoot extension setting - SpringBootPluginExtension bootExtension = project.getExtensions() - .getByType(SpringBootPluginExtension.class); - if (bootExtension.getMainClass() != null) { - mainClass = bootExtension.getMainClass(); - } - - ApplicationPluginConvention application = (ApplicationPluginConvention) project - .getConvention().getPlugins().get("application"); - - if (mainClass == null && application != null) { - // Try the Application extension setting - mainClass = application.getMainClassName(); - } - - JavaExec runTask = findRunTask(project); - if (mainClass == null && runTask != null) { - mainClass = runTask.getMain(); - } - - if (mainClass == null) { - Task bootRunTask = project.getTasks().findByName("bootRun"); - if (bootRunTask != null) { - mainClass = (String) bootRunTask.property("main"); - } - } - - if (mainClass == null) { - // Search - if (this.mainClassSourceSetOutput != null) { - project.getLogger().debug("Looking for main in: " - + this.mainClassSourceSetOutput.getClassesDir()); - try { - mainClass = MainClassFinder.findSingleMainClass( - this.mainClassSourceSetOutput.getClassesDir(), - SPRING_BOOT_APPLICATION_CLASS_NAME); - project.getLogger().info("Computed main class: " + mainClass); - } - catch (IOException ex) { - throw new IllegalStateException("Cannot find main class", ex); - } - } - } - - project.getLogger().info("Found main: " + mainClass); - - if (bootExtension.getMainClass() == null) { - bootExtension.setMainClass(mainClass); - } - if (application != null && application.getMainClassName() == null) { - application.setMainClassName(mainClass); - } - if (runTask != null && !runTask.hasProperty("main")) { - runTask.setMain(mainClass); - } - - return mainClass; - } - - private JavaExec findRunTask(Project project) { - Task runTask = project.getTasks().findByName("run"); - if (runTask instanceof JavaExec) { - return (JavaExec) runTask; - } - return null; - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java deleted file mode 100644 index ad56178980a..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/RunPluginFeatures.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2012-2016 the original author or authors. - * - * 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 org.springframework.boot.gradle.run; - -import java.util.Collections; -import java.util.concurrent.Callable; - -import org.gradle.api.Action; -import org.gradle.api.Project; -import org.gradle.api.Task; -import org.gradle.api.plugins.ExtraPropertiesExtension; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.SourceSet; -import org.gradle.api.tasks.application.CreateStartScripts; - -import org.springframework.boot.gradle.PluginFeatures; - -/** - * {@link PluginFeatures} to add run support. - * - * @author Phillip Webb - */ -public class RunPluginFeatures implements PluginFeatures { - - private static final String FIND_MAIN_CLASS_TASK_NAME = "findMainClass"; - - private static final String RUN_APP_TASK_NAME = "bootRun"; - - @Override - public void apply(Project project) { - mainClassNameFinder(project); - addBootRunTask(project); - } - - private void mainClassNameFinder(Project project) { - FindMainClassTask findMainClassTask = project.getTasks() - .create(FIND_MAIN_CLASS_TASK_NAME, FindMainClassTask.class); - SourceSet mainSourceSet = SourceSets.findMainSourceSet(project); - if (mainSourceSet != null) { - findMainClassTask.setMainClassSourceSetOutput(mainSourceSet.getOutput()); - } - project.getTasks().all(new Action() { - @Override - public void execute(Task task) { - if (task instanceof BootRunTask || task instanceof CreateStartScripts) { - task.dependsOn(FIND_MAIN_CLASS_TASK_NAME); - } - } - }); - } - - private void addBootRunTask(final Project project) { - final JavaPluginConvention javaConvention = project.getConvention() - .getPlugin(JavaPluginConvention.class); - - BootRunTask run = project.getTasks().create(RUN_APP_TASK_NAME, BootRunTask.class); - run.setDescription("Run the project with support for " - + "auto-detecting main class and reloading static resources"); - run.setGroup("application"); - run.setClasspath( - javaConvention.getSourceSets().findByName("main").getRuntimeClasspath()); - run.getConventionMapping().map("main", new Callable() { - @Override - public Object call() throws Exception { - if (project.hasProperty("mainClassName") - && project.property("mainClassName") != null) { - return project.property("mainClassName"); - } - ExtraPropertiesExtension extraPropertiesExtension = (ExtraPropertiesExtension) project - .getExtensions().getByName("ext"); - if (extraPropertiesExtension.has("mainClassName") - && extraPropertiesExtension.get("mainClassName") != null) { - return extraPropertiesExtension.get("mainClassName"); - } - return null; - } - }); - run.getConventionMapping().map("jvmArgs", new Callable() { - @Override - public Object call() throws Exception { - if (project.hasProperty("applicationDefaultJvmArgs")) { - return project.property("applicationDefaultJvmArgs"); - } - return Collections.emptyList(); - } - }); - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java deleted file mode 100644 index c722cc4f279..00000000000 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/run/SourceSets.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * 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 org.springframework.boot.gradle.run; - -import java.util.Collections; - -import org.gradle.api.Project; -import org.gradle.api.plugins.JavaPluginConvention; -import org.gradle.api.tasks.SourceSet; - -/** - * Utilities for working with {@link SourceSet}s. - * - * @author Dave Syer - * @author Phillip Webb - */ -final class SourceSets { - - private SourceSets() { - } - - public static SourceSet findMainSourceSet(Project project) { - for (SourceSet sourceSet : getJavaSourceSets(project)) { - if (SourceSet.MAIN_SOURCE_SET_NAME.equals(sourceSet.getName())) { - return sourceSet; - } - } - return null; - } - - private static Iterable getJavaSourceSets(Project project) { - JavaPluginConvention plugin = project.getConvention() - .getPlugin(JavaPluginConvention.class); - if (plugin == null) { - return Collections.emptyList(); - } - return plugin.getSourceSets(); - } - -} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/CreateBootStartScripts.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/CreateBootStartScripts.java new file mode 100644 index 00000000000..334cdcf8bfb --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/CreateBootStartScripts.java @@ -0,0 +1,36 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.application; + +import org.gradle.api.tasks.Optional; +import org.gradle.jvm.application.tasks.CreateStartScripts; + +/** + * Customization of {@link CreateStartScripts} that makes the {@link #getMainClassName() + * main class name} optional. + * + * @author Andy Wilkinson + */ +public class CreateBootStartScripts extends CreateStartScripts { + + @Override + @Optional + public String getMainClassName() { + return super.getMainClassName(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/package-info.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/package-info.java new file mode 100644 index 00000000000..3fdaffb3030 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/application/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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. + */ + +/** + * Classes related to Gradle's application features. + */ +package org.springframework.boot.gradle.tasks.application; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.java new file mode 100644 index 00000000000..273f7600e70 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfo.java @@ -0,0 +1,120 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.buildinfo; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.internal.ConventionTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.TaskExecutionException; + +import org.springframework.boot.loader.tools.BuildPropertiesWriter; +import org.springframework.boot.loader.tools.BuildPropertiesWriter.ProjectDetails; + +/** + * {@link Task} for generating a {@code build-info.properties} file from a + * {@code Project}. + * + * @author Andy Wilkinson + */ +public class BuildInfo extends ConventionTask { + + private final BuildInfoProperties properties = new BuildInfoProperties(getProject()); + + private File destinationDir; + + /** + * Generates the {@code build-info.properties} file in the configured + * {@link #setDestinationDir(File) destination}. + */ + @TaskAction + public void generateBuildProperties() { + try { + new BuildPropertiesWriter( + new File(getDestinationDir(), "build-info.properties")) + .writeBuildProperties(new ProjectDetails( + this.properties.getGroup(), + this.properties.getArtifact() == null ? "unspecified" + : this.properties.getArtifact(), + this.properties.getVersion(), + this.properties.getName(), coerceToStringValues( + this.properties.getAdditional()))); + } + catch (IOException ex) { + throw new TaskExecutionException(this, ex); + } + } + + /** + * Returns the directory to which the {@code build-info.properties} file will be + * written. Defaults to the {@link Project#getBuildDir() Project's build directory}. + * + * @return the destination directory + */ + @OutputDirectory + public File getDestinationDir() { + return this.destinationDir != null ? this.destinationDir + : getProject().getBuildDir(); + } + + /** + * Sets the directory to which the {@code build-info.properties} file will be written. + * + * @param destinationDir the destination directory + */ + public void setDestinationDir(File destinationDir) { + this.destinationDir = destinationDir; + } + + /** + * Returns the {@link BuildInfoProperties properties} that will be included in the + * {@code build-info.properties} file. + * + * @return the properties + */ + @Input + public BuildInfoProperties getProperties() { + return this.properties; + } + + /** + * Executes the given {@code action} on the {@link #getProperties()} properties. + * + * @param action the action + */ + public void properties(Action action) { + action.execute(this.properties); + } + + private Map coerceToStringValues(Map input) { + Map output = new HashMap<>(); + for (Entry entry : input.entrySet()) { + output.put(entry.getKey(), entry.getValue().toString()); + } + return output; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoProperties.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoProperties.java new file mode 100644 index 00000000000..6cbc243ef05 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoProperties.java @@ -0,0 +1,212 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.buildinfo; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.gradle.api.Project; + +/** + * The properties that are written into the {@code build-info.properties} file. + * + * @author Andy Wilkinson + */ +public class BuildInfoProperties implements Serializable { + + private final transient Project project; + + private String group; + + private String artifact; + + private String version; + + private String name; + + private Map additionalProperties = new HashMap<>(); + + BuildInfoProperties(Project project) { + this.project = project; + } + + /** + * Returns the value used for the {@code build.group} property. Defaults to the + * {@link Project#getGroup() Project's group}. + * + * @return the group + */ + public String getGroup() { + return this.group != null ? this.group : this.project.getGroup().toString(); + } + + /** + * Sets the value used for the {@code build.group} property. + * + * @param group the group name + */ + public void setGroup(String group) { + this.group = group; + } + + /** + * Returns the value used for the {@code build.artifact} property. + * + * @return the artifact + */ + public String getArtifact() { + return this.artifact; + } + + /** + * Sets the value used for the {@code build.artifact} property. + * + * @param artifact the artifact + */ + public void setArtifact(String artifact) { + this.artifact = artifact; + } + + /** + * Returns the value used for the {@code build.version} property. Defaults to the + * {@link Project#getVersion() Project's version}. + * + * @return the version + */ + public String getVersion() { + return this.version != null ? this.version : this.project.getVersion().toString(); + } + + /** + * Sets the value used for the {@code build.version} property. + * + * @param version the version + */ + public void setVersion(String version) { + this.version = version; + } + + /** + * Returns the value used for the {@code build.name} property. Defaults to the + * {@link Project#getDisplayName() Project's display name}. + * + * @return the name + */ + public String getName() { + return this.name != null ? this.name : this.project.getName(); + } + + /** + * Sets the value used for the {@code build.name} property. + * + * @param name the name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the additional properties that will be included. When written, the name of + * each additional property is prefixed with {@code build.}. + * + * @return the additional properties + */ + public Map getAdditional() { + return this.additionalProperties; + } + + /** + * Sets the additional properties that will be included. When written, the name of + * each additional property is prefixed with {@code build.}. + * + * @param additionalProperties the additional properties + */ + public void setAdditional(Map additionalProperties) { + this.additionalProperties = additionalProperties; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((this.additionalProperties == null) ? 0 + : this.additionalProperties.hashCode()); + result = prime * result + + ((this.artifact == null) ? 0 : this.artifact.hashCode()); + result = prime * result + ((this.group == null) ? 0 : this.group.hashCode()); + result = prime * result + ((this.name == null) ? 0 : this.name.hashCode()); + result = prime * result + ((this.version == null) ? 0 : this.version.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + BuildInfoProperties other = (BuildInfoProperties) obj; + if (this.additionalProperties == null) { + if (other.additionalProperties != null) { + return false; + } + } + else if (!this.additionalProperties.equals(other.additionalProperties)) { + return false; + } + if (this.artifact == null) { + if (other.artifact != null) { + return false; + } + } + else if (!this.artifact.equals(other.artifact)) { + return false; + } + if (this.group == null) { + if (other.group != null) { + return false; + } + } + else if (!this.group.equals(other.group)) { + return false; + } + if (this.name == null) { + if (other.name != null) { + return false; + } + } + else if (!this.name.equals(other.name)) { + return false; + } + if (this.version == null) { + if (other.version != null) { + return false; + } + } + else if (!this.version.equals(other.version)) { + return false; + } + return true; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/package-info.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/package-info.java new file mode 100644 index 00000000000..e107051c6b8 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/buildinfo/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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. + */ + +/** + * Support for producing build info for consumption by Spring Boot's actuator. + */ +package org.springframework.boot.gradle.tasks.buildinfo; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java new file mode 100644 index 00000000000..88996acd780 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchive.java @@ -0,0 +1,121 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.Task; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; + +/** + * A Spring Boot "fat" archive task. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public interface BootArchive extends Task { + + /** + * Returns the main class of the application. + * + * @return the main class + */ + @Input + @Optional + String getMainClass(); + + /** + * Sets the main class of the application. + * + * @param mainClass the main class of the application + */ + void setMainClass(String mainClass); + + /** + * Adds Ant-style patterns that identify files that must be unpacked from the archive + * when it is launched. + * + * @param patterns the patterns + */ + void requiresUnpack(String... patterns); + + /** + * Adds a spec that identifies files that must be unpacked from the archive when it is + * launched. + * + * @param spec the spec + */ + void requiresUnpack(Spec spec); + + /** + * Returns the {@link LaunchScriptConfiguration} that will control the script, if any, + * that is prepended to the archive. + * + * @return the launch script configuration + */ + @Input + LaunchScriptConfiguration getLaunchScript(); + + /** + * Applies the given {@code action} to the {@link LaunchScriptConfiguration} of this + * archive. + * + * @param action the action to apply + */ + void launchScript(Action action); + + /** + * Returns the classpath that will be included in the archive. + * + * @return the classpath + */ + @Optional + @Classpath + FileCollection getClasspath(); + + /** + * Adds files to the classpath to include in the archive. The given {@code classpath} + * are evaluated as per {@link Project#files(Object...)}. + * + * @param classpath the additions to the classpath + */ + void classpath(Object... classpath); + + /** + * Returns {@code true} if the Devtools jar should be excluded, otherwise + * {@code false}. + * + * @return {@code true} if the Devtools jar should be excluded, or {@code false} if + * not + */ + @Input + boolean isExcludeDevtools(); + + /** + * Sets whether or not the Devtools jar should be excluded. + * + * @param excludeDevtools {@code true} if the Devtools jar should be excluded, or + * {@code false} if not + */ + void setExcludeDevtools(boolean excludeDevtools); + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java new file mode 100644 index 00000000000..003808cd36f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java @@ -0,0 +1,151 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Function; + +import org.gradle.api.file.FileCopyDetails; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.file.RelativePath; +import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.internal.file.copy.CopyActionProcessingStream; +import org.gradle.api.internal.file.copy.FileCopyDetailsInternal; +import org.gradle.api.java.archives.Attributes; +import org.gradle.api.specs.Spec; +import org.gradle.api.specs.Specs; +import org.gradle.api.tasks.WorkResult; +import org.gradle.api.tasks.bundling.Jar; +import org.gradle.api.tasks.util.PatternSet; + +/** + * Support class for implementations of {@link BootArchive}. + * + * @author Andy Wilkinson + */ +class BootArchiveSupport { + + private static final Set DEFAULT_LAUNCHER_CLASSES; + + static { + Set defaultLauncherClasses = new HashSet(); + defaultLauncherClasses.add("org.springframework.boot.loader.JarLauncher"); + defaultLauncherClasses.add("org.springframework.boot.loader.PropertiesLauncher"); + defaultLauncherClasses.add("org.springframework.boot.loader.WarLauncher"); + DEFAULT_LAUNCHER_CLASSES = Collections.unmodifiableSet(defaultLauncherClasses); + } + + private final PatternSet requiresUnpack = new PatternSet(); + + private final Function compressionResolver; + + private final PatternSet exclusions = new PatternSet(); + + private final String loaderMainClass; + + private LaunchScriptConfiguration launchScript = new LaunchScriptConfiguration(); + + private boolean excludeDevtools = true; + + BootArchiveSupport(String loaderMainClass, + Function compressionResolver) { + this.loaderMainClass = loaderMainClass; + this.compressionResolver = compressionResolver; + this.requiresUnpack.include(Specs.satisfyNone()); + configureExclusions(); + } + + void configureManifest(Jar jar, String mainClass) { + Attributes attributes = jar.getManifest().getAttributes(); + attributes.putIfAbsent("Main-Class", this.loaderMainClass); + attributes.putIfAbsent("Start-Class", mainClass); + } + + CopyAction createCopyAction(Jar jar) { + CopyAction copyAction = new BootZipCopyAction(jar.getArchivePath(), + jar.isPreserveFileTimestamps(), isUsingDefaultLoader(jar), + this.requiresUnpack.getAsSpec(), this.exclusions.getAsExcludeSpec(), + this.launchScript, this.compressionResolver); + if (!jar.isReproducibleFileOrder()) { + return copyAction; + } + return new ReproducibleOrderingCopyAction(copyAction); + } + + private boolean isUsingDefaultLoader(Jar jar) { + return DEFAULT_LAUNCHER_CLASSES + .contains(jar.getManifest().getAttributes().get("Main-Class")); + } + + LaunchScriptConfiguration getLaunchScript() { + return this.launchScript; + } + + void setLaunchScript(LaunchScriptConfiguration launchScript) { + this.launchScript = launchScript; + } + + void requiresUnpack(String... patterns) { + this.requiresUnpack.include(patterns); + } + + void requiresUnpack(Spec spec) { + this.requiresUnpack.include(spec); + } + + boolean isExcludeDevtools() { + return this.excludeDevtools; + } + + void setExcludeDevtools(boolean excludeDevtools) { + this.excludeDevtools = excludeDevtools; + configureExclusions(); + } + + private void configureExclusions() { + Set excludes = new HashSet(); + if (this.excludeDevtools) { + excludes.add("**/spring-boot-devtools-*.jar"); + } + this.exclusions.setExcludes(excludes); + } + + private static final class ReproducibleOrderingCopyAction implements CopyAction { + + private final CopyAction delegate; + + private ReproducibleOrderingCopyAction(CopyAction delegate) { + this.delegate = delegate; + } + + @Override + public WorkResult execute(CopyActionProcessingStream stream) { + return this.delegate.execute(action -> { + Map detailsByPath = new TreeMap<>(); + stream.process( + details -> detailsByPath.put(details.getRelativePath(), details)); + detailsByPath.values().stream().forEach(action::processFile); + }); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java new file mode 100644 index 00000000000..74befe9eb67 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootJar.java @@ -0,0 +1,145 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.util.Collections; +import java.util.concurrent.Callable; + +import org.gradle.api.Action; +import org.gradle.api.file.CopySpec; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileCopyDetails; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.bundling.Jar; + +/** + * A custom {@link Jar} task that produces a Spring Boot executable jar. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class BootJar extends Jar implements BootArchive { + + private BootArchiveSupport support = new BootArchiveSupport( + "org.springframework.boot.loader.JarLauncher", this::resolveZipCompression); + + private FileCollection classpath; + + private String mainClass; + + /** + * Creates a new {@code BootJar} task. + */ + public BootJar() { + CopySpec bootInf = getRootSpec().addChildBeforeSpec(getMainSpec()) + .into("BOOT-INF"); + bootInf.into("lib", classpathFiles(File::isFile)); + bootInf.into("classes", classpathFiles(File::isDirectory)); + } + + private Action classpathFiles(Spec filter) { + return copySpec -> copySpec + .from((Callable>) () -> this.classpath == null + ? Collections.emptyList() : this.classpath.filter(filter)); + + } + + @Override + public void copy() { + this.support.configureManifest(this, getMainClass()); + super.copy(); + } + + @Override + protected CopyAction createCopyAction() { + return this.support.createCopyAction(this); + } + + @Override + public String getMainClass() { + return this.mainClass; + } + + @Override + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + @Override + public void requiresUnpack(String... patterns) { + this.support.requiresUnpack(patterns); + } + + @Override + public void requiresUnpack(Spec spec) { + this.support.requiresUnpack(spec); + } + + @Override + public LaunchScriptConfiguration getLaunchScript() { + return this.support.getLaunchScript(); + } + + @Override + public void launchScript(Action action) { + action.execute(getLaunchScript()); + } + + @Override + public FileCollection getClasspath() { + return this.classpath; + } + + @Override + public void classpath(Object... classpath) { + FileCollection existingClasspath = this.classpath; + this.classpath = getProject().files( + existingClasspath == null ? Collections.emptyList() : existingClasspath, + classpath); + } + + @Override + public boolean isExcludeDevtools() { + return this.support.isExcludeDevtools(); + } + + @Override + public void setExcludeDevtools(boolean excludeDevtools) { + this.support.setExcludeDevtools(excludeDevtools); + } + + /** + * Returns the {@link ZipCompression} that should be used when adding the file + * represented by the given {@code details} to the jar. + *

+ * By default, any file in {@code BOOT-INF/lib/} is stored and all other files are + * deflated. + * + * @param details the details + * @return the compression to use + */ + protected ZipCompression resolveZipCompression(FileCopyDetails details) { + if (details.getRelativePath().getPathString().startsWith("BOOT-INF/lib/")) { + return ZipCompression.STORED; + } + return ZipCompression.DEFLATED; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java new file mode 100644 index 00000000000..3b704135db3 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootWar.java @@ -0,0 +1,153 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.util.Collections; +import java.util.concurrent.Callable; + +import org.gradle.api.Action; +import org.gradle.api.Project; +import org.gradle.api.file.FileCollection; +import org.gradle.api.file.FileCopyDetails; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.bundling.War; + +/** + * A custom {@link War} task that produces a Spring Boot executable war. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class BootWar extends War implements BootArchive { + + private final BootArchiveSupport support = new BootArchiveSupport( + "org.springframework.boot.loader.WarLauncher", this::resolveZipCompression); + + private String mainClass; + + private FileCollection providedClasspath; + + /** + * Creates a new {@code BootWar} task. + */ + public BootWar() { + getWebInf().into("lib-provided", + copySpec -> copySpec + .from((Callable>) () -> this.providedClasspath == null + ? Collections.emptyList() : this.providedClasspath)); + } + + @Override + public void copy() { + this.support.configureManifest(this, getMainClass()); + super.copy(); + } + + @Override + protected CopyAction createCopyAction() { + return this.support.createCopyAction(this); + } + + @Override + public String getMainClass() { + return this.mainClass; + } + + @Override + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + @Override + public void requiresUnpack(String... patterns) { + this.support.requiresUnpack(patterns); + } + + @Override + public void requiresUnpack(Spec spec) { + this.support.requiresUnpack(spec); + } + + @Override + public LaunchScriptConfiguration getLaunchScript() { + return this.support.getLaunchScript(); + } + + @Override + public void launchScript(Action action) { + action.execute(getLaunchScript()); + } + + /** + * Returns the provided classpath, the contents of which will be included in the + * {@code WEB-INF/lib-provided} directory of the war. + * + * @return the provided classpath + */ + @Optional + public FileCollection getProvidedClasspath() { + return this.providedClasspath; + } + + /** + * Adds files to the provided classpath to include in the {@code WEB-INF/lib-provided} + * directory of the war. The given {@code classpath} are evaluated as per + * {@link Project#files(Object...)}. + * + * @param classpath the additions to the classpath + */ + public void providedClasspath(Object... classpath) { + FileCollection existingClasspath = this.providedClasspath; + this.providedClasspath = getProject().files( + existingClasspath == null ? Collections.emptyList() : existingClasspath, + classpath); + } + + @Override + public boolean isExcludeDevtools() { + return this.support.isExcludeDevtools(); + } + + @Override + public void setExcludeDevtools(boolean excludeDevtools) { + this.support.setExcludeDevtools(excludeDevtools); + } + + /** + * Returns the {@link ZipCompression} that should be used when adding the file + * represented by the given {@code details} to the jar. + *

+ * By default, any file in {@code WEB-INF/lib/} or {@code WEB-INF/lib-provided/} is + * stored and all other files are deflated. + * + * @param details the details + * @return the compression to use + */ + protected ZipCompression resolveZipCompression(FileCopyDetails details) { + String relativePath = details.getRelativePath().getPathString(); + if (relativePath.startsWith("WEB-INF/lib/") + || relativePath.startsWith("WEB-INF/lib-provided/")) { + return ZipCompression.STORED; + } + return ZipCompression.DEFLATED; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java new file mode 100644 index 00000000000..6a8086f21b3 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java @@ -0,0 +1,276 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.function.Function; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCopyDetails; +import org.gradle.api.file.FileTreeElement; +import org.gradle.api.internal.file.CopyActionProcessingStreamAction; +import org.gradle.api.internal.file.copy.CopyAction; +import org.gradle.api.internal.file.copy.CopyActionProcessingStream; +import org.gradle.api.internal.file.copy.FileCopyDetailsInternal; +import org.gradle.api.specs.Spec; +import org.gradle.api.tasks.WorkResult; +import org.gradle.util.GUtil; + +import org.springframework.boot.loader.tools.DefaultLaunchScript; +import org.springframework.boot.loader.tools.FileUtils; + +/** + * A {@link CopyAction} for creating a Spring Boot zip archive (typically a jar or war). + * Stores jar files without compression as required by Spring Boot's loader. + * + * @author Andy Wilkinson + */ +class BootZipCopyAction implements CopyAction { + + private final File output; + + private final boolean preserveFileTimestamps; + + private final boolean includeDefaultLoader; + + private final Spec requiresUnpack; + + private final Spec exclusions; + + private final LaunchScriptConfiguration launchScript; + + private final Function compressionResolver; + + BootZipCopyAction(File output, boolean preserveFileTimestamps, + boolean includeDefaultLoader, Spec requiresUnpack, + Spec exclusions, LaunchScriptConfiguration launchScript, + Function compressionResolver) { + this.output = output; + this.preserveFileTimestamps = preserveFileTimestamps; + this.includeDefaultLoader = includeDefaultLoader; + this.requiresUnpack = requiresUnpack; + this.exclusions = exclusions; + this.launchScript = launchScript; + this.compressionResolver = compressionResolver; + } + + @Override + public WorkResult execute(CopyActionProcessingStream stream) { + ZipOutputStream zipStream; + try { + FileOutputStream fileStream = new FileOutputStream(this.output); + writeLaunchScriptIfNecessary(fileStream); + zipStream = new ZipOutputStream(fileStream); + writeLoaderClassesIfNecessary(zipStream); + } + catch (IOException ex) { + throw new GradleException("Failed to create " + this.output, ex); + } + try { + stream.process(new ZipStreamAction(zipStream, this.output, + this.preserveFileTimestamps, this.requiresUnpack, this.exclusions, + this.compressionResolver)); + } + finally { + try { + zipStream.close(); + } + catch (IOException ex) { + // Continue + } + } + return () -> true; + } + + private void writeLoaderClassesIfNecessary(ZipOutputStream out) { + if (this.includeDefaultLoader) { + writeLoaderClasses(out); + } + } + + private void writeLoaderClasses(ZipOutputStream out) { + ZipEntry entry; + try (ZipInputStream in = new ZipInputStream(getClass() + .getResourceAsStream("/META-INF/loader/spring-boot-loader.jar"))) { + while ((entry = in.getNextEntry()) != null) { + if (entry.getName().endsWith(".class")) { + writeClass(entry, in, out); + } + } + } + catch (IOException ex) { + throw new GradleException("Failed to write loader classes", ex); + } + } + + private void writeClass(ZipEntry entry, ZipInputStream in, ZipOutputStream out) + throws IOException { + byte[] buffer = new byte[4096]; + if (!this.preserveFileTimestamps) { + entry.setTime(GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES); + } + out.putNextEntry(entry); + int read; + while ((read = in.read(buffer)) > 0) { + out.write(buffer, 0, read); + } + out.closeEntry(); + } + + private void writeLaunchScriptIfNecessary(FileOutputStream fileStream) { + try { + if (this.launchScript.isIncluded()) { + fileStream.write(new DefaultLaunchScript(this.launchScript.getScript(), + this.launchScript.getProperties()).toByteArray()); + } + } + catch (IOException ex) { + throw new GradleException("Failed to write launch script to " + this.output, + ex); + } + } + + private static final class ZipStreamAction + implements CopyActionProcessingStreamAction { + + private final ZipOutputStream zipStream; + + private final File output; + + private final boolean preserveFileTimestamps; + + private final Spec requiresUnpack; + + private final Spec exclusions; + + private final Function compressionType; + + private ZipStreamAction(ZipOutputStream zipStream, File output, + boolean preserveFileTimestamps, Spec requiresUnpack, + Spec exclusions, + Function compressionType) { + this.zipStream = zipStream; + this.output = output; + this.preserveFileTimestamps = preserveFileTimestamps; + this.requiresUnpack = requiresUnpack; + this.exclusions = exclusions; + this.compressionType = compressionType; + } + + @Override + public void processFile(FileCopyDetailsInternal details) { + if (this.exclusions.isSatisfiedBy(details)) { + return; + } + try { + if (details.isDirectory()) { + createDirectory(details); + } + else { + createFile(details); + } + } + catch (IOException ex) { + throw new GradleException( + "Failed to add " + details + " to " + this.output, ex); + } + } + + private void createDirectory(FileCopyDetailsInternal details) throws IOException { + ZipEntry archiveEntry = new ZipEntry( + details.getRelativePath().getPathString() + '/'); + archiveEntry.setTime(getTime(details)); + this.zipStream.putNextEntry(archiveEntry); + this.zipStream.closeEntry(); + } + + private void createFile(FileCopyDetailsInternal details) throws IOException { + String relativePath = details.getRelativePath().getPathString(); + ZipEntry archiveEntry = new ZipEntry(relativePath); + archiveEntry.setTime(getTime(details)); + this.zipStream.putNextEntry(archiveEntry); + ZipCompression compression = this.compressionType.apply(details); + if (compression == ZipCompression.STORED) { + archiveEntry.setMethod(ZipEntry.STORED); + archiveEntry.setSize(details.getSize()); + archiveEntry.setCompressedSize(details.getSize()); + Crc32OutputStream crcStream = new Crc32OutputStream(this.zipStream); + details.copyTo(crcStream); + archiveEntry.setCrc(crcStream.getCrc()); + if (this.requiresUnpack.isSatisfiedBy(details)) { + archiveEntry.setComment( + "UNPACK:" + FileUtils.sha1Hash(details.getFile())); + } + } + else { + details.copyTo(this.zipStream); + } + this.zipStream.closeEntry(); + } + + private long getTime(FileCopyDetails details) { + return this.preserveFileTimestamps ? details.getLastModified() + : GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES; + } + + } + + /** + * A {@code FilterOutputStream} that provides a CRC-32 of the data that is written to + * it. + */ + private static final class Crc32OutputStream extends FilterOutputStream { + + private final CRC32 crc32 = new CRC32(); + + private Crc32OutputStream(OutputStream out) { + super(out); + } + + @Override + public void write(int b) throws IOException { + this.crc32.update(b); + this.out.write(b); + } + + @Override + public void write(byte[] b) throws IOException { + this.crc32.update(b); + this.out.write(b); + } + + @Override + public void write(byte[] b, int off, int len) throws IOException { + this.crc32.update(b, off, len); + this.out.write(b, off, len); + } + + private long getCrc() { + return this.crc32.getValue(); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java new file mode 100644 index 00000000000..40ee454fb5a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LaunchScriptConfiguration.java @@ -0,0 +1,151 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.boot.loader.tools.FileUtils; + +/** + * Encapsulates the configuration of the launch script for an executable jar or war. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class LaunchScriptConfiguration implements Serializable { + + private boolean included = false; + + private final Map properties = new HashMap(); + + private File script; + + /** + * Returns whether the launch script is included. Defaults to {@code false}. + * + * @return {@code true} is the script is included, otherwise {@code false}. + */ + public boolean isIncluded() { + return this.included; + } + + /** + * Sets whether the launch script is included. Defaults to {@code false}. + * + * @param included {@code true} is the script is included, otherwise {@code false}. + */ + public void setIncluded(boolean included) { + this.included = included; + } + + /** + * Returns the properties that are applied to the launch script when it's being + * including in the executable archive. + * + * @return the properties + */ + public Map getProperties() { + return this.properties; + } + + /** + * Sets the properties that are applied to the launch script when it's being including + * in the executable archive. + * + * @param properties the properties + */ + public void properties(Map properties) { + this.properties.putAll(properties); + } + + /** + * Returns the script {@link File} that will be included in the executable archive. + * When {@code null}, the default launch script will be used. + * + * @return the script file + */ + public File getScript() { + return this.script; + } + + /** + * Sets the script {@link File} that will be included in the executable archive. When + * {@code null}, the default launch script will be used. + * + * @param script the script file + */ + public void setScript(File script) { + this.script = script; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (this.included ? 1231 : 1237); + result = prime * result + + ((this.properties == null) ? 0 : this.properties.hashCode()); + result = prime * result + ((this.script == null) ? 0 : this.script.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + LaunchScriptConfiguration other = (LaunchScriptConfiguration) obj; + if (this.included != other.included) { + return false; + } + if (!this.properties.equals(other.properties)) { + return false; + } + if (this.script == null) { + if (other.script != null) { + return false; + } + } + else if (!this.script.equals(other.script)) { + return false; + } + else if (!equalContents(this.script, other.script)) { + return false; + } + return true; + } + + private boolean equalContents(File one, File two) { + try { + return FileUtils.sha1Hash(one).equals(FileUtils.sha1Hash(two)); + } + catch (IOException ex) { + return false; + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/PluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ZipCompression.java similarity index 61% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/PluginFeatures.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ZipCompression.java index b4445396f68..782cddedd4c 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/PluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/ZipCompression.java @@ -14,23 +14,26 @@ * limitations under the License. */ -package org.springframework.boot.gradle; +package org.springframework.boot.gradle.tasks.bundling; -import org.gradle.api.Project; +import java.util.zip.ZipEntry; /** - * A specific set of {@code org.gradle.api.Plugin} features applied via the - * {@code SpringBootPlugin}. + * An enumeration of supported compression options for an entry in a ZIP archive. * - * @author Phillip Webb + * @author Andy Wilkinson + * @since 2.0.0 */ -@FunctionalInterface -public interface PluginFeatures { +public enum ZipCompression { /** - * Apply the features to the specified project. - * @param project the project to apply features to + * The entry should be {@link ZipEntry#STORED} in the archive. */ - void apply(Project project); + STORED, + + /** + * The entry should be {@link ZipEntry#DEFLATED} in the archive. + */ + DEFLATED; } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/package-info.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/package-info.java new file mode 100644 index 00000000000..59747886129 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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. + */ + +/** + * Support for creating executable jars and wars. + */ +package org.springframework.boot.gradle.tasks.bundling; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/BootRun.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/BootRun.java new file mode 100644 index 00000000000..07a463ae7ff --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/BootRun.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.run; + +import org.gradle.api.file.SourceDirectorySet; +import org.gradle.api.tasks.JavaExec; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetOutput; + +/** + * Custom {@link JavaExec} task for running a Spring Boot application. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public class BootRun extends JavaExec { + + /** + * Adds the {@link SourceDirectorySet#getSrcDirs() source directories} of the given + * {@code sourceSet's} {@link SourceSet#getResources() resources} to the start of the + * classpath in place of the {@link SourceSet#getOutput output's} + * {@link SourceSetOutput#getResourcesDir() resources directory}. + * + * @param sourceSet the source set + */ + public void sourceResources(SourceSet sourceSet) { + setClasspath(getProject() + .files(sourceSet.getResources().getSrcDirs(), getClasspath()) + .filter(file -> !file.equals(sourceSet.getOutput().getResourcesDir()))); + } + + @Override + public void exec() { + if (System.console() != null) { + // Record that the console is available here for AnsiOutput to detect later + this.getEnvironment().put("spring.output.ansi.console-available", true); + } + super.exec(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/package-info.java b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/package-info.java new file mode 100644 index 00000000000..a88fec5e61a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/run/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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. + */ + +/** + * Support for running Spring Boot applications. + */ +package org.springframework.boot.gradle.tasks.run; diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/javadoc/spring-javadoc.css b/spring-boot-tools/spring-boot-gradle-plugin/src/main/javadoc/spring-javadoc.css new file mode 100644 index 00000000000..06ad42277c6 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/javadoc/spring-javadoc.css @@ -0,0 +1,599 @@ +/* Javadoc style sheet */ +/* +Overall document style +*/ + +@import url('resources/fonts/dejavu.css'); + +body { + background-color:#ffffff; + color:#353833; + font-family:'DejaVu Sans', Arial, Helvetica, sans-serif; + font-size:14px; + margin:0; +} +a:link, a:visited { + text-decoration:none; + color:#4A6782; +} +a:hover, a:focus { + text-decoration:none; + color:#bb7a2a; +} +a:active { + text-decoration:none; + color:#4A6782; +} +a[name] { + color:#353833; +} +a[name]:hover { + text-decoration:none; + color:#353833; +} +pre { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; +} +h1 { + font-size:20px; +} +h2 { + font-size:18px; +} +h3 { + font-size:16px; + font-style:italic; +} +h4 { + font-size:13px; +} +h5 { + font-size:12px; +} +h6 { + font-size:11px; +} +ul { + list-style-type:disc; +} +code, tt { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; + margin-top:8px; + line-height:1.4em; +} +dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + padding-top:4px; +} +table tr td dt code { + font-family:'DejaVu Sans Mono', monospace; + font-size:14px; + vertical-align:top; + padding-top:4px; +} +sup { + font-size:8px; +} +/* +Document title and Copyright styles +*/ +.clear { + clear:both; + height:0px; + overflow:hidden; +} +.aboutLanguage { + float:right; + padding:0px 21px; + font-size:11px; + z-index:200; + margin-top:-9px; +} +.legalCopy { + margin-left:.5em; +} +.bar a, .bar a:link, .bar a:visited, .bar a:active { + color:#FFFFFF; + text-decoration:none; +} +.bar a:hover, .bar a:focus { + color:#bb7a2a; +} +.tab { + background-color:#0066FF; + color:#ffffff; + padding:8px; + width:5em; + font-weight:bold; +} +/* +Navigation bar styles +*/ +.bar { + background-color:#4D7A97; + color:#FFFFFF; + padding:.8em .5em .4em .8em; + height:auto;/*height:1.8em;*/ + font-size:11px; + margin:0; +} +.topNav { + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.bottomNav { + margin-top:10px; + background-color:#4D7A97; + color:#FFFFFF; + float:left; + padding:0; + width:100%; + clear:right; + height:2.8em; + padding-top:10px; + overflow:hidden; + font-size:12px; +} +.subNav { + background-color:#dee3e9; + float:left; + width:100%; + overflow:hidden; + font-size:12px; +} +.subNav div { + clear:left; + float:left; + padding:0 0 5px 6px; + text-transform:uppercase; +} +ul.navList, ul.subNavList { + float:left; + margin:0 25px 0 0; + padding:0; +} +ul.navList li{ + list-style:none; + float:left; + padding: 5px 6px; + text-transform:uppercase; +} +ul.subNavList li{ + list-style:none; + float:left; +} +.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited { + color:#FFFFFF; + text-decoration:none; + text-transform:uppercase; +} +.topNav a:hover, .bottomNav a:hover { + text-decoration:none; + color:#bb7a2a; + text-transform:uppercase; +} +.navBarCell1Rev { + background-color:#F8981D; + color:#253441; + margin: auto 5px; +} +.skipNav { + position:absolute; + top:auto; + left:-9999px; + overflow:hidden; +} +/* +Page header and footer styles +*/ +.header, .footer { + clear:both; + margin:0 20px; + padding:5px 0 0 0; +} +.indexHeader { + margin:10px; + position:relative; +} +.indexHeader span{ + margin-right:15px; +} +.indexHeader h1 { + font-size:13px; +} +.title { + color:#2c4557; + margin:10px 0; +} +.subTitle { + margin:5px 0 0 0; +} +.header ul { + margin:0 0 15px 0; + padding:0; +} +.footer ul { + margin:20px 0 5px 0; +} +.header ul li, .footer ul li { + list-style:none; + font-size:13px; +} +/* +Heading styles +*/ +div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList ul.blockList li.blockList h3 { + background-color:#dee3e9; + border:1px solid #d0d9e0; + margin:0 0 6px -8px; + padding:7px 5px; +} +ul.blockList ul.blockList li.blockList h3 { + padding:0; + margin:15px 0; +} +ul.blockList li.blockList h2 { + padding:0px 0 20px 0; +} +/* +Page layout container styles +*/ +.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer { + clear:both; + padding:10px 20px; + position:relative; +} +.indexContainer { + margin:10px; + position:relative; + font-size:12px; +} +.indexContainer h2 { + font-size:13px; + padding:0 0 3px 0; +} +.indexContainer ul { + margin:0; + padding:0; +} +.indexContainer ul li { + list-style:none; + padding-top:2px; +} +.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt { + font-size:12px; + font-weight:bold; + margin:10px 0 0 0; + color:#4E4E4E; +} +.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd { + margin:5px 0 10px 0px; + font-size:14px; + font-family:'DejaVu Sans Mono',monospace; +} +.serializedFormContainer dl.nameValue dt { + margin-left:1px; + font-size:1.1em; + display:inline; + font-weight:bold; +} +.serializedFormContainer dl.nameValue dd { + margin:0 0 0 1px; + font-size:1.1em; + display:inline; +} +/* +List styles +*/ +ul.horizontal li { + display:inline; + font-size:0.9em; +} +ul.inheritance { + margin:0; + padding:0; +} +ul.inheritance li { + display:inline; + list-style:none; +} +ul.inheritance li ul.inheritance { + margin-left:15px; + padding-left:15px; + padding-top:1px; +} +ul.blockList, ul.blockListLast { + margin:10px 0 10px 0; + padding:0; +} +ul.blockList li.blockList, ul.blockListLast li.blockList { + list-style:none; + margin-bottom:15px; + line-height:1.4; +} +ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList { + padding:0px 20px 5px 10px; + border:1px solid #ededed; + background-color:#f8f8f8; +} +ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList { + padding:0 0 5px 8px; + background-color:#ffffff; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockList { + margin-left:0; + padding-left:0; + padding-bottom:15px; + border:none; +} +ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast { + list-style:none; + border-bottom:none; + padding-bottom:0; +} +table tr td dl, table tr td dl dt, table tr td dl dd { + margin-top:0; + margin-bottom:1px; +} +/* +Table styles +*/ +.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary { + width:100%; + border-left:1px solid #EEE; + border-right:1px solid #EEE; + border-bottom:1px solid #EEE; +} +.overviewSummary, .memberSummary { + padding:0px; +} +.overviewSummary caption, .memberSummary caption, .typeSummary caption, +.useSummary caption, .constantsSummary caption, .deprecatedSummary caption { + position:relative; + text-align:left; + background-repeat:no-repeat; + color:#253441; + font-weight:bold; + clear:none; + overflow:hidden; + padding:0px; + padding-top:10px; + padding-left:1px; + margin:0px; + white-space:pre; +} +.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link, +.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link, +.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover, +.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover, +.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active, +.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active, +.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited, +.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited { + color:#FFFFFF; +} +.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span, +.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + padding-bottom:7px; + display:inline-block; + float:left; + background-color:#F8981D; + border: none; + height:16px; +} +.memberSummary caption span.activeTableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#F8981D; + height:16px; +} +.memberSummary caption span.tableTab span { + white-space:nowrap; + padding-top:5px; + padding-left:12px; + padding-right:12px; + margin-right:3px; + display:inline-block; + float:left; + background-color:#4D7A97; + height:16px; +} +.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab { + padding-top:0px; + padding-left:0px; + padding-right:0px; + background-image:none; + float:none; + display:inline; +} +.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd, +.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd { + display:none; + width:5px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .activeTableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + float:left; + background-color:#F8981D; +} +.memberSummary .tableTab .tabEnd { + display:none; + width:5px; + margin-right:3px; + position:relative; + background-color:#4D7A97; + float:left; + +} +.overviewSummary td, .memberSummary td, .typeSummary td, +.useSummary td, .constantsSummary td, .deprecatedSummary td { + text-align:left; + padding:0px 0px 12px 10px; + width:100%; +} +th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th, +td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{ + vertical-align:top; + padding-right:0px; + padding-top:8px; + padding-bottom:3px; +} +th.colFirst, th.colLast, th.colOne, .constantsSummary th { + background:#dee3e9; + text-align:left; + padding:8px 3px 3px 7px; +} +td.colFirst, th.colFirst { + white-space:nowrap; + font-size:13px; +} +td.colLast, th.colLast { + font-size:13px; +} +td.colOne, th.colOne { + font-size:13px; +} +.overviewSummary td.colFirst, .overviewSummary th.colFirst, +.overviewSummary td.colOne, .overviewSummary th.colOne, +.memberSummary td.colFirst, .memberSummary th.colFirst, +.memberSummary td.colOne, .memberSummary th.colOne, +.typeSummary td.colFirst{ + width:25%; + vertical-align:top; +} +td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover { + font-weight:bold; +} +.tableSubHeadingColor { + background-color:#EEEEFF; +} +.altColor { + background-color:#FFFFFF; +} +.rowColor { + background-color:#EEEEEF; +} +/* +Content styles +*/ +.description pre { + margin-top:0; +} +.deprecatedContent { + margin:0; + padding:10px 0; +} +.docSummary { + padding:0; +} + +ul.blockList ul.blockList ul.blockList li.blockList h3 { + font-style:normal; +} + +div.block { + font-size:14px; + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; +} + +td.colLast div { + padding-top:0px; +} + + +td.colLast a { + padding-bottom:3px; +} +/* +Formatting effect styles +*/ +.sourceLineNo { + color:green; + padding:0 30px 0 0; +} +h1.hidden { + visibility:hidden; + overflow:hidden; + font-size:10px; +} +.block { + display:block; + margin:3px 10px 2px 0px; + color:#474747; +} +.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink, +.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel, +.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink { + font-weight:bold; +} +.deprecationComment, .emphasizedPhrase, .interfaceName { + font-style:italic; +} + +div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase, +div.block div.block span.interfaceName { + font-style:normal; +} + +div.contentContainer ul.blockList li.blockList h2{ + padding-bottom:0px; +} + + + +/* +Spring +*/ + +pre.code { + background-color: #F8F8F8; + border: 1px solid #CCCCCC; + border-radius: 3px 3px 3px 3px; + overflow: auto; + padding: 10px; + margin: 4px 20px 2px 0px; +} + +pre.code code, pre.code code * { + font-size: 1em; +} + +pre.code code, pre.code code * { + padding: 0 !important; + margin: 0 !important; +} + diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/unixStartScript.txt b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/unixStartScript.txt new file mode 100644 index 00000000000..7c3539c7c2a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/unixStartScript.txt @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## ${applicationName} start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: \$0 may be a link +PRG="\$0" +# Need this for relative symlinks. +while [ -h "\$PRG" ] ; do + ls=`ls -ld "\$PRG"` + link=`expr "\$ls" : '.*-> \\(.*\\)\$'` + if expr "\$link" : '/.*' > /dev/null; then + PRG="\$link" + else + PRG=`dirname "\$PRG"`"/\$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"\$PRG\"`/${appHomeRelativePath}" >/dev/null +APP_HOME="`pwd -P`" +cd "\$SAVED" >/dev/null + +APP_NAME="${applicationName}" +APP_BASE_NAME=`basename "\$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. +DEFAULT_JVM_OPTS=${defaultJvmOpts} + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "\$*" +} + +die ( ) { + echo + echo "\$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +JARPATH=$classpath + +# Determine the Java command to use to start the JVM. +if [ -n "\$JAVA_HOME" ] ; then + if [ -x "\$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="\$JAVA_HOME/jre/sh/java" + else + JAVACMD="\$JAVA_HOME/bin/java" + fi + if [ ! -x "\$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: \$JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "\$cygwin" = "false" -a "\$darwin" = "false" -a "\$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ \$? -eq 0 ] ; then + if [ "\$MAX_FD" = "maximum" -o "\$MAX_FD" = "max" ] ; then + MAX_FD="\$MAX_FD_LIMIT" + fi + ulimit -n \$MAX_FD + if [ \$? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: \$MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: \$MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if \$darwin; then + GRADLE_OPTS="\$GRADLE_OPTS \\"-Xdock:name=\$APP_NAME\\" \\"-Xdock:icon=\$APP_HOME/media/gradle.icns\\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if \$cygwin ; then + APP_HOME=`cygpath --path --mixed "\$APP_HOME"` + JARPATH=`cygpath --path --mixed "\$JARPATH"` + JAVACMD=`cygpath --unix "\$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in \$ROOTDIRSRAW ; do + ROOTDIRS="\$ROOTDIRS\$SEP\$dir" + SEP="|" + done + OURCYGPATTERN="(^(\$ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "\$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="\$OURCYGPATTERN|(\$GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "\$@" ; do + CHECK=`echo "\$arg"|egrep -c "\$OURCYGPATTERN" -` + CHECK2=`echo "\$arg"|egrep -c "^-"` ### Determine if an option + + if [ \$CHECK -ne 0 ] && [ \$CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args\$i`=`cygpath --path --ignore --mixed "\$arg"` + else + eval `echo args\$i`="\"\$arg\"" + fi + i=\$((i+1)) + done + case \$i in + (0) set -- ;; + (1) set -- "\$args0" ;; + (2) set -- "\$args0" "\$args1" ;; + (3) set -- "\$args0" "\$args1" "\$args2" ;; + (4) set -- "\$args0" "\$args1" "\$args2" "\$args3" ;; + (5) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" ;; + (6) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" ;; + (7) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" ;; + (8) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" ;; + (9) set -- "\$args0" "\$args1" "\$args2" "\$args3" "\$args4" "\$args5" "\$args6" "\$args7" "\$args8" ;; + esac +fi + +# Escape application args +save ( ) { + for i do printf %s\\\\n "\$i" | sed "s/'/'\\\\\\\\''/g;1s/^/'/;\\\$s/\\\$/' \\\\\\\\/" ; done + echo " " +} +APP_ARGS=\$(save "\$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- \$DEFAULT_JVM_OPTS \$JAVA_OPTS \$${optsEnvironmentVar} <% if ( appNameSystemProperty ) { %>"\"-D${appNameSystemProperty}=\$APP_BASE_NAME\"" <% } %>-jar "\"\$JARPATH\"" "\$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "\$(uname)" = "Darwin" ] && [ "\$HOME" = "\$PWD" ]; then + cd "\$(dirname "\$0")" +fi + +exec "\$JAVACMD" "\$@" diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/windowsStartScript.txt b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/windowsStartScript.txt new file mode 100644 index 00000000000..58f2a3d59cf --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/main/resources/windowsStartScript.txt @@ -0,0 +1,85 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem ${applicationName} startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=.\ + +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME%${appHomeRelativePath} + +@rem Add default JVM options here. You can also use JAVA_OPTS and ${optsEnvironmentVar} to pass JVM options to this script. +set DEFAULT_JVM_OPTS=${defaultJvmOpts} + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set JARPATH=$classpath + +@rem Execute ${applicationName} +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %${optsEnvironmentVar}% <% if ( appNameSystemProperty ) { %>"-D${appNameSystemProperty}=%APP_BASE_NAME%"<% } %> -jar "%JARPATH%" %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable ${exitEnvironmentVar} if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%${exitEnvironmentVar}%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java new file mode 100644 index 00000000000..95cc04e06fe --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/com/example/BootRunApplication.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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.example; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Very basic application used for testing {@code BootRun}. + * + * @author Andy Wilkinson + */ +public class BootRunApplication { + + protected BootRunApplication() { + + } + + public static void main(String[] args) { + int i = 1; + for (URL url : ((URLClassLoader) BootRunApplication.class.getClassLoader()) + .getURLs()) { + System.out.println(i++ + ". " + url); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/GettingStartedDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/GettingStartedDocumentationTests.java new file mode 100644 index 00000000000..4c05d9f646e --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/GettingStartedDocumentationTests.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +/** + * Tests for the getting started documentation. + * + * @author Andy Wilkinson + */ +public class GettingStartedDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void applyPluginSnapshotExampleEvaluatesSuccessfully() { + this.gradleBuild + .script("src/main/gradle/getting-started/apply-plugin-snapshot.gradle") + .build(); + } + + @Test + public void typicalPluginsAppliesExceptedPlugins() { + this.gradleBuild.script("src/main/gradle/getting-started/typical-plugins.gradle") + .build("verify"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/IntegratingWithActuatorDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/IntegratingWithActuatorDocumentationTests.java new file mode 100644 index 00000000000..8ba0219bc20 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/IntegratingWithActuatorDocumentationTests.java @@ -0,0 +1,90 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the generating build info documentation. + * + * @author Andy Wilkinson + */ +public class IntegratingWithActuatorDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void basicBuildInfo() throws IOException { + this.gradleBuild + .script("src/main/gradle/integrating-with-actuator/build-info-basic.gradle") + .build("bootBuildInfo"); + assertThat(new File(this.gradleBuild.getProjectDir(), + "build/resources/main/META-INF/build-info.properties")).isFile(); + } + + @Test + public void buildInfoCustomValues() throws IOException { + this.gradleBuild + .script("src/main/gradle/integrating-with-actuator/build-info-custom-values.gradle") + .build("bootBuildInfo"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/resources/main/META-INF/build-info.properties"); + assertThat(file).isFile(); + Properties properties = buildInfoProperties(file); + assertThat(properties).containsEntry("build.artifact", "example-app"); + assertThat(properties).containsEntry("build.version", "1.2.3"); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.name", "Example application"); + } + + @Test + public void buildInfoAdditional() throws IOException { + this.gradleBuild + .script("src/main/gradle/integrating-with-actuator/build-info-additional.gradle") + .build("bootBuildInfo"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/resources/main/META-INF/build-info.properties"); + assertThat(file).isFile(); + Properties properties = buildInfoProperties(file); + assertThat(properties).containsEntry("build.a", "alpha"); + assertThat(properties).containsEntry("build.b", "bravo"); + } + + private Properties buildInfoProperties(File file) { + assertThat(file).isFile(); + Properties properties = new Properties(); + try (FileReader reader = new FileReader(file)) { + properties.load(reader); + return properties; + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/ManagingDependenciesDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/ManagingDependenciesDocumentationTests.java new file mode 100644 index 00000000000..0d69c8a0b6f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/ManagingDependenciesDocumentationTests.java @@ -0,0 +1,50 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the managing dependencies documentation. + * + * @author Andy Wilkinson + */ +public class ManagingDependenciesDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void dependenciesExampleEvaluatesSuccessfully() { + this.gradleBuild + .script("src/main/gradle/managing-dependencies/dependencies.gradle") + .build(); + } + + @Test + public void customManagedVersions() { + assertThat(this.gradleBuild + .script("src/main/gradle/managing-dependencies/custom-version.gradle") + .build("slf4jVersion").getOutput()).contains("1.7.20"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java new file mode 100644 index 00000000000..03afebb19c7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PackagingDocumentationTests.java @@ -0,0 +1,176 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; +import org.springframework.util.FileCopyUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the packaging documentation. + * + * @author Andy Wilkinson + */ +public class PackagingDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void warContainerDependencyEvaluatesSuccessfully() { + this.gradleBuild + .script("src/main/gradle/packaging/war-container-dependency.gradle") + .build(); + } + + @Test + public void bootJarMainClass() throws IOException { + this.gradleBuild.script("src/main/gradle/packaging/boot-jar-main-class.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + assertThat(jar.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.ExampleApplication"); + } + } + + @Test + public void bootJarManifestMainClass() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/boot-jar-manifest-main-class.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + assertThat(jar.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.ExampleApplication"); + } + } + + @Test + public void applicationPluginMainClass() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/application-plugin-main-class.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + assertThat(jar.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.ExampleApplication"); + } + } + + @Test + public void bootWarIncludeDevtools() throws IOException { + new File(this.gradleBuild.getProjectDir(), + "spring-boot-devtools-1.2.3.RELEASE.jar").createNewFile(); + this.gradleBuild + .script("src/main/gradle/packaging/boot-war-include-devtools.gradle") + .build("bootWar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".war"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + assertThat(jar.getEntry("WEB-INF/lib/spring-boot-devtools-1.2.3.RELEASE.jar")) + .isNotNull(); + } + } + + @Test + public void bootJarRequiresUnpack() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/boot-jar-requires-unpack.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + JarEntry entry = jar.getJarEntry("BOOT-INF/lib/jruby-complete-1.7.25.jar"); + assertThat(entry).isNotNull(); + assertThat(entry.getComment()).startsWith("UNPACK:"); + } + } + + @Test + public void bootJarIncludeLaunchScript() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/boot-jar-include-launch-script.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + assertThat(FileCopyUtils.copyToString(new FileReader(file))) + .startsWith("#!/bin/bash"); + } + + @Test + public void bootJarLaunchScriptProperties() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/boot-jar-launch-script-properties.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + assertThat(FileCopyUtils.copyToString(new FileReader(file))) + .contains("example-app.log"); + } + + @Test + public void bootJarCustomLaunchScript() throws IOException { + File customScriptFile = new File(this.gradleBuild.getProjectDir(), + "src/custom.script"); + customScriptFile.getParentFile().mkdirs(); + FileCopyUtils.copy("custom", new FileWriter(customScriptFile)); + this.gradleBuild + .script("src/main/gradle/packaging/boot-jar-custom-launch-script.gradle") + .build("bootJar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".jar"); + assertThat(file).isFile(); + assertThat(FileCopyUtils.copyToString(new FileReader(file))).startsWith("custom"); + } + + @Test + public void bootWarPropertiesLauncher() throws IOException { + this.gradleBuild + .script("src/main/gradle/packaging/boot-war-properties-launcher.gradle") + .build("bootWar"); + File file = new File(this.gradleBuild.getProjectDir(), + "build/libs/" + this.gradleBuild.getProjectDir().getName() + ".war"); + assertThat(file).isFile(); + try (JarFile jar = new JarFile(file)) { + assertThat(jar.getManifest().getMainAttributes().getValue("Main-Class")) + .isEqualTo("org.springframework.boot.loader.PropertiesLauncher"); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PublishingDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PublishingDocumentationTests.java new file mode 100644 index 00000000000..b57a0ab60e7 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/PublishingDocumentationTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the publishing documentation. + * + * @author Andy Wilkinson + */ +public class PublishingDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void mavenUpload() throws IOException { + assertThat(this.gradleBuild.script("src/main/gradle/publishing/maven.gradle") + .build("deployerRepository").getOutput()) + .contains("https://repo.example.com"); + } + + @Test + public void mavenPublish() throws IOException { + assertThat( + this.gradleBuild.script("src/main/gradle/publishing/maven-publish.gradle") + .build("publishingConfiguration").getOutput()) + .contains("MavenPublication") + .contains("https://repo.example.com"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/RunningDocumentationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/RunningDocumentationTests.java new file mode 100644 index 00000000000..742ed2b9f1b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/docs/RunningDocumentationTests.java @@ -0,0 +1,60 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.docs; + +import java.io.IOException; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for the integrating with Actuator documentation. + * + * @author Andy Wilkinson + */ +public class RunningDocumentationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void bootRunMain() throws IOException { + assertThat(this.gradleBuild.script("src/main/gradle/running/boot-run-main.gradle") + .build("configuredMainClass").getOutput()) + .contains("com.example.ExampleApplication"); + } + + @Test + public void applicationPluginMainClassName() throws IOException { + assertThat(this.gradleBuild + .script("src/main/gradle/running/application-plugin-main-class-name.gradle") + .build("configuredMainClass").getOutput()) + .contains("com.example.ExampleApplication"); + } + + @Test + public void bootRunSourceResources() throws IOException { + assertThat(this.gradleBuild + .script("src/main/gradle/running/boot-run-source-resources.gradle") + .build("configuredClasspath").getOutput()).contains("src/main/resources"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests.java new file mode 100644 index 00000000000..fe27924da2c --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests.java @@ -0,0 +1,129 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.dsl; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.tasks.buildinfo.BuildInfo; +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link BuildInfo} created using the + * {@link org.springframework.boot.gradle.dsl.SpringBootExtension DSL}. + * + * @author Andy Wilkinson + */ +public class BuildInfoDslIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void basicJar() throws IOException { + assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Properties properties = buildInfoProperties(); + assertThat(properties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.artifact", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.version", "1.0"); + } + + @Test + public void jarWithCustomName() throws IOException { + assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Properties properties = buildInfoProperties(); + assertThat(properties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.artifact", "foo"); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.version", "1.0"); + } + + @Test + public void basicWar() throws IOException { + assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Properties properties = buildInfoProperties(); + assertThat(properties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.artifact", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.version", "1.0"); + } + + @Test + public void warWithCustomName() throws IOException { + assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Properties properties = buildInfoProperties(); + assertThat(properties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.artifact", "foo"); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.version", "1.0"); + } + + @Test + public void additionalProperties() throws IOException { + assertThat(this.gradleBuild.build("bootBuildInfo", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + Properties properties = buildInfoProperties(); + assertThat(properties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.artifact", + this.gradleBuild.getProjectDir().getName()); + assertThat(properties).containsEntry("build.group", "com.example"); + assertThat(properties).containsEntry("build.version", "1.0"); + assertThat(properties).containsEntry("build.a", "alpha"); + assertThat(properties).containsEntry("build.b", "bravo"); + } + + @Test + public void classesDependency() throws IOException { + assertThat(this.gradleBuild.build("classes", "--stacktrace") + .task(":bootBuildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + private Properties buildInfoProperties() { + File file = new File(this.gradleBuild.getProjectDir(), + "build/resources/main/META-INF/build-info.properties"); + assertThat(file).isFile(); + Properties properties = new Properties(); + try (FileReader reader = new FileReader(file)) { + properties.load(reader); + return properties; + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java new file mode 100644 index 00000000000..6a9dd6c1f79 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.java @@ -0,0 +1,156 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import org.apache.commons.compress.archivers.tar.TarArchiveEntry; +import org.apache.commons.compress.archivers.tar.TarArchiveInputStream; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link ApplicationPluginAction}. + * + * @author Andy Wilkinson + */ +public class ApplicationPluginActionIntegrationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void noBootDistributionWithoutApplicationPluginApplied() { + assertThat(this.gradleBuild.build("distributionExists", "-PdistributionName=boot") + .getOutput()).contains("boot exists = false"); + } + + @Test + public void applyingApplicationPluginCreatesBootDistribution() { + assertThat(this.gradleBuild.build("distributionExists", "-PdistributionName=boot", + "-PapplyApplicationPlugin").getOutput()).contains("boot exists = true"); + } + + @Test + public void noBootStartScriptsTaskWithoutApplicationPluginApplied() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=bootStartScripts") + .getOutput()).contains("bootStartScripts exists = false"); + } + + @Test + public void applyingApplictionPluginCreatesBootStartScriptsTask() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=bootStartScripts", + "-PapplyApplicationPlugin").getOutput()) + .contains("bootStartScripts exists = true"); + } + + @Test + public void zipDistributionForJarCanBeBuilt() throws IOException { + assertThat( + this.gradleBuild.build("bootDistZip").task(":bootDistZip").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + String name = this.gradleBuild.getProjectDir().getName(); + File distribution = new File(this.gradleBuild.getProjectDir(), + "build/distributions/" + name + "-boot.zip"); + assertThat(distribution).isFile(); + assertThat(zipEntryNames(distribution)).containsExactlyInAnyOrder(name + "-boot/", + name + "-boot/lib/", name + "-boot/lib/" + name + ".jar", + name + "-boot/bin/", name + "-boot/bin/" + name, + name + "-boot/bin/" + name + ".bat"); + } + + @Test + public void tarDistributionForJarCanBeBuilt() throws IOException { + assertThat( + this.gradleBuild.build("bootDistTar").task(":bootDistTar").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + String name = this.gradleBuild.getProjectDir().getName(); + File distribution = new File(this.gradleBuild.getProjectDir(), + "build/distributions/" + name + "-boot.tar"); + assertThat(distribution).isFile(); + assertThat(tarEntryNames(distribution)).containsExactlyInAnyOrder(name + "-boot/", + name + "-boot/lib/", name + "-boot/lib/" + name + ".jar", + name + "-boot/bin/", name + "-boot/bin/" + name, + name + "-boot/bin/" + name + ".bat"); + } + + @Test + public void zipDistributionForWarCanBeBuilt() throws IOException { + assertThat( + this.gradleBuild.build("bootDistZip").task(":bootDistZip").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + String name = this.gradleBuild.getProjectDir().getName(); + File distribution = new File(this.gradleBuild.getProjectDir(), + "build/distributions/" + name + "-boot.zip"); + assertThat(distribution).isFile(); + assertThat(zipEntryNames(distribution)).containsExactlyInAnyOrder(name + "-boot/", + name + "-boot/lib/", name + "-boot/lib/" + name + ".war", + name + "-boot/bin/", name + "-boot/bin/" + name, + name + "-boot/bin/" + name + ".bat"); + } + + @Test + public void tarDistributionForWarCanBeBuilt() throws IOException { + assertThat( + this.gradleBuild.build("bootDistTar").task(":bootDistTar").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + String name = this.gradleBuild.getProjectDir().getName(); + File distribution = new File(this.gradleBuild.getProjectDir(), + "build/distributions/" + name + "-boot.tar"); + assertThat(distribution).isFile(); + assertThat(tarEntryNames(distribution)).containsExactlyInAnyOrder(name + "-boot/", + name + "-boot/lib/", name + "-boot/lib/" + name + ".war", + name + "-boot/bin/", name + "-boot/bin/" + name, + name + "-boot/bin/" + name + ".bat"); + } + + private List zipEntryNames(File distribution) throws IOException { + List entryNames = new ArrayList<>(); + try (ZipFile zipFile = new ZipFile(distribution)) { + Enumeration entries = zipFile.entries(); + while (entries.hasMoreElements()) { + entryNames.add(entries.nextElement().getName()); + } + } + return entryNames; + } + + private List tarEntryNames(File distribution) throws IOException { + List entryNames = new ArrayList<>(); + try (TarArchiveInputStream input = new TarArchiveInputStream( + new FileInputStream(distribution))) { + TarArchiveEntry entry; + while ((entry = input.getNextTarEntry()) != null) { + entryNames.add(entry.getName()); + } + } + return entryNames; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.java new file mode 100644 index 00000000000..b22c0a718d9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.java @@ -0,0 +1,77 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import java.io.File; +import java.io.IOException; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; +import org.springframework.util.FileSystemUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for the configuration applied by + * {@link DependencyManagementPluginAction}. + * + * @author Andy Wilkinson + */ +public class DependencyManagementPluginActionIntegrationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void noDependencyManagementIsAppliedByDefault() { + assertThat(this.gradleBuild.build("doesNotHaveDependencyManagement") + .task(":doesNotHaveDependencyManagement").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void bomIsImportedWhenDependencyManagementPluginIsApplied() { + assertThat(this.gradleBuild + .build("hasDependencyManagement", "-PapplyDependencyManagementPlugin") + .task(":hasDependencyManagement").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void helpfulErrorWhenVersionlessDependencyFailsToResolve() throws IOException { + File examplePackage = new File(this.gradleBuild.getProjectDir(), + "src/main/java/com/example"); + examplePackage.mkdirs(); + FileSystemUtils.copyRecursively(new File("src/test/java/com/example"), + examplePackage); + BuildResult result = this.gradleBuild.buildAndFail("compileJava"); + assertThat(result.task(":compileJava").getOutcome()) + .isEqualTo(TaskOutcome.FAILED); + String output = result.getOutput(); + assertThat(output).contains("During the build, one or more dependencies that " + + "were declared without a version failed to resolve:"); + assertThat(output).contains("org.springframework.boot:spring-boot-starter-web:"); + assertThat(output).contains("Did you forget to apply the " + + "io.spring.dependency-management plugin to the " + + this.gradleBuild.getProjectDir().getName() + " project?"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java new file mode 100644 index 00000000000..5ae7a016e0b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link WarPluginAction}. + * + * @author Andy Wilkinson + */ +public class JavaPluginActionIntegrationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void noBootJarTaskWithoutJavaPluginApplied() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=bootJar").getOutput()) + .contains("bootJar exists = false"); + } + + @Test + public void applyingJavaPluginCreatesBootJarTask() { + assertThat(this.gradleBuild + .build("taskExists", "-PtaskName=bootJar", "-PapplyJavaPlugin") + .getOutput()).contains("bootJar exists = true"); + } + + @Test + public void noBootRunTaskWithoutJavaPluginApplied() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=bootRun").getOutput()) + .contains("bootRun exists = false"); + } + + @Test + public void applyingJavaPluginCreatesBootRunTask() { + assertThat(this.gradleBuild + .build("taskExists", "-PtaskName=bootRun", "-PapplyJavaPlugin") + .getOutput()).contains("bootRun exists = true"); + } + + @Test + public void noBootJavaSoftwareComponentWithoutJavaPluginApplied() { + assertThat(this.gradleBuild.build("componentExists", "-PcomponentName=bootJava") + .getOutput()).contains("bootJava exists = false"); + } + + @Test + public void applyingJavaPluginCreatesBootJavaSoftwareComponent() { + assertThat(this.gradleBuild + .build("componentExists", "-PcomponentName=bootJava", "-PapplyJavaPlugin") + .getOutput()).contains("bootJava exists = true"); + } + + @Test + public void javaCompileTasksUseUtf8Encoding() { + assertThat(this.gradleBuild.build("javaCompileEncoding", "-PapplyJavaPlugin") + .getOutput()).contains("compileJava = UTF-8") + .contains("compileTestJava = UTF-8"); + } + +} diff --git a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/NoJarTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.java similarity index 50% rename from spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/NoJarTests.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.java index d3051eda25a..efc756eb555 100644 --- a/spring-boot-integration-tests/spring-boot-gradle-tests/src/test/java/org/springframework/boot/gradle/NoJarTests.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2016 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,32 +14,29 @@ * limitations under the License. */ -package org.springframework.boot.gradle; +package org.springframework.boot.gradle.plugin; -import java.io.File; - -import org.gradle.tooling.ProjectConnection; +import org.junit.Rule; import org.junit.Test; +import org.springframework.boot.gradle.testkit.GradleBuild; + import static org.assertj.core.api.Assertions.assertThat; /** - * Tests for using the Gradle plugin's support for flat directory repos + * Integration tests for {@link MavenPluginAction}. * - * @author Dave Syer + * @author Andy Wilkinson */ -public class NoJarTests { - - private ProjectConnection project; +public class MavenPluginActionIntegrationTests { - private static final String BOOT_VERSION = Versions.getBootVersion(); + @Rule + public GradleBuild gradleBuild = new GradleBuild(); @Test - public void nojar() throws Exception { - this.project = new ProjectCreator().createProject("nojar"); - this.project.newBuild().forTasks("build") - .withArguments("-PbootVersion=" + BOOT_VERSION, "--stacktrace").run(); - assertThat(new File("target/nojar/build/libs")).doesNotExist(); + public void clearsConf2ScopeMappingsOfUploadBootArchivesTask() { + assertThat(this.gradleBuild.build("conf2ScopeMappings").getOutput()) + .contains("Conf2ScopeMappings = 0"); } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java new file mode 100644 index 00000000000..c9555ed1b1a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.java @@ -0,0 +1,62 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.plugin; + +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link JavaPluginAction}. + * + * @author Andy Wilkinson + */ +public class WarPluginActionIntegrationTests { + + @Rule + public GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void noBootWarTaskWithoutWarPluginApplied() { + assertThat(this.gradleBuild.build("taskExists", "-PtaskName=bootWar").getOutput()) + .contains("bootWar exists = false"); + } + + @Test + public void applyingWarPluginCreatesBootWarTask() { + assertThat(this.gradleBuild + .build("taskExists", "-PtaskName=bootWar", "-PapplyWarPlugin") + .getOutput()).contains("bootWar exists = true"); + } + + @Test + public void noBootWebSoftwareComponentWithoutJavaPluginApplied() { + assertThat(this.gradleBuild.build("componentExists", "-PcomponentName=bootWeb") + .getOutput()).contains("bootWeb exists = false"); + } + + @Test + public void applyingJavaPluginCreatesBootWebSoftwareComponent() { + assertThat(this.gradleBuild + .build("componentExists", "-PcomponentName=bootWeb", "-PapplyWarPlugin") + .getOutput()).contains("bootWeb exists = true"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.java new file mode 100644 index 00000000000..fac2498efa0 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.java @@ -0,0 +1,127 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.buildinfo; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for the {@link BuildInfo} task. + * + * @author Andy Wilkinson + */ +public class BuildInfoIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void defaultValues() { + assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + Properties buildInfoProperties = buildInfoProperties(); + assertThat(buildInfoProperties).containsKey("build.time"); + assertThat(buildInfoProperties).containsEntry("build.artifact", "unspecified"); + assertThat(buildInfoProperties).containsEntry("build.group", ""); + assertThat(buildInfoProperties).containsEntry("build.name", + this.gradleBuild.getProjectDir().getName()); + assertThat(buildInfoProperties).containsEntry("build.version", "unspecified"); + } + + @Test + public void basicExecution() { + assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + Properties buildInfoProperties = buildInfoProperties(); + assertThat(buildInfoProperties).containsKey("build.time"); + assertThat(buildInfoProperties).containsEntry("build.artifact", "foo"); + assertThat(buildInfoProperties).containsEntry("build.group", "foo"); + assertThat(buildInfoProperties).containsEntry("build.additional", "foo"); + assertThat(buildInfoProperties).containsEntry("build.name", "foo"); + assertThat(buildInfoProperties).containsEntry("build.version", "1.0"); + } + + @Test + public void upToDateWhenExecutedTwice() { + assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("buildInfo").task(":buildInfo").getOutcome()) + .isEqualTo(TaskOutcome.UP_TO_DATE); + } + + @Test + public void notUpToDateWhenDestinationDirChanges() { + notUpToDateWithChangeToProperty("buildInfoDestinationDir"); + } + + @Test + public void notUpToDateWhenProjectArtifactChanges() { + notUpToDateWithChangeToProperty("buildInfoArtifact"); + } + + @Test + public void notUpToDateWhenProjectGroupChanges() { + notUpToDateWithChangeToProperty("buildInfoGroup"); + } + + @Test + public void notUpToDateWhenProjectVersionChanges() { + notUpToDateWithChangeToProperty("buildInfoVersion"); + } + + @Test + public void notUpToDateWhenProjectNameChanges() { + notUpToDateWithChangeToProperty("buildInfoName"); + } + + @Test + public void notUpToDateWhenAdditionalPropertyChanges() { + notUpToDateWithChangeToProperty("buildInfoAdditional"); + } + + private void notUpToDateWithChangeToProperty(String name) { + assertThat(this.gradleBuild.build("buildInfo", "--stacktrace").task(":buildInfo") + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("buildInfo", "-P" + name + "=changed") + .task(":buildInfo").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + private Properties buildInfoProperties() { + File file = new File(this.gradleBuild.getProjectDir(), + "build/build-info.properties"); + assertThat(file).isFile(); + Properties properties = new Properties(); + try (FileReader reader = new FileReader(file)) { + properties.load(reader); + return properties; + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoTests.java new file mode 100644 index 00000000000..f459919e619 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoTests.java @@ -0,0 +1,136 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.buildinfo; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.Properties; + +import org.gradle.api.Project; +import org.gradle.testfixtures.ProjectBuilder; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BuildInfo}. + * + * @author Andy Wilkinson + */ +public class BuildInfoTests { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @Test + public void basicExecution() { + Properties properties = buildInfoProperties(createTask(createProject("test"))); + assertThat(properties).containsKey("build.time"); + assertThat(properties).containsEntry("build.artifact", "unspecified"); + assertThat(properties).containsEntry("build.group", ""); + assertThat(properties).containsEntry("build.name", "test"); + assertThat(properties).containsEntry("build.version", "unspecified"); + } + + @Test + public void customArtifactIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProperties().setArtifact("custom"); + assertThat(buildInfoProperties(task)).containsEntry("build.artifact", "custom"); + } + + @Test + public void projectGroupIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProject().setGroup("com.example"); + assertThat(buildInfoProperties(task)).containsEntry("build.group", "com.example"); + } + + @Test + public void customGroupIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProperties().setGroup("com.example"); + assertThat(buildInfoProperties(task)).containsEntry("build.group", "com.example"); + } + + @Test + public void customNameIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProperties().setName("Example"); + assertThat(buildInfoProperties(task)).containsEntry("build.name", "Example"); + } + + @Test + public void projectVersionIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProject().setVersion("1.2.3"); + assertThat(buildInfoProperties(task)).containsEntry("build.version", "1.2.3"); + } + + @Test + public void customVersionIsReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProperties().setVersion("2.3.4"); + assertThat(buildInfoProperties(task)).containsEntry("build.version", "2.3.4"); + } + + @Test + public void additionalPropertiesAreReflectedInProperties() { + BuildInfo task = createTask(createProject("test")); + task.getProperties().getAdditional().put("a", "alpha"); + task.getProperties().getAdditional().put("b", "bravo"); + assertThat(buildInfoProperties(task)).containsEntry("build.a", "alpha"); + assertThat(buildInfoProperties(task)).containsEntry("build.b", "bravo"); + } + + private Project createProject(String projectName) { + try { + File projectDir = this.temp.newFolder(projectName); + return ProjectBuilder.builder().withProjectDir(projectDir) + .withName(projectName).build(); + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + private BuildInfo createTask(Project project) { + return project.getTasks().create("testBuildInfo", BuildInfo.class); + } + + private Properties buildInfoProperties(BuildInfo task) { + task.generateBuildProperties(); + return buildInfoProperties( + new File(task.getDestinationDir(), "build-info.properties")); + } + + private Properties buildInfoProperties(File file) { + assertThat(file).isFile(); + Properties properties = new Properties(); + try (FileReader reader = new FileReader(file)) { + properties.load(reader); + return properties; + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java new file mode 100644 index 00000000000..72d835d9af1 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java @@ -0,0 +1,115 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.IOException; +import java.util.jar.JarFile; + +import org.gradle.testkit.runner.InvalidRunnerConfigurationException; +import org.gradle.testkit.runner.TaskOutcome; +import org.gradle.testkit.runner.UnexpectedBuildFailure; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for {@link BootJar}. + * + * @author Andy Wilkinson + */ +public abstract class AbstractBootArchiveIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + private final String taskName; + + protected AbstractBootArchiveIntegrationTests(String taskName) { + this.taskName = taskName; + } + + @Test + public void basicBuild() throws InvalidRunnerConfigurationException, + UnexpectedBuildFailure, IOException { + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void upToDateWhenBuiltTwice() throws InvalidRunnerConfigurationException, + UnexpectedBuildFailure, IOException { + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.UP_TO_DATE); + } + + @Test + public void upToDateWhenBuiltTwiceWithLaunchScriptIncluded() + throws InvalidRunnerConfigurationException, UnexpectedBuildFailure, + IOException { + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", this.taskName) + .task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", this.taskName) + .task(":" + this.taskName).getOutcome()) + .isEqualTo(TaskOutcome.UP_TO_DATE); + } + + @Test + public void notUpToDateWhenLaunchScriptWasNotIncludedAndThenIsIncluded() { + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", this.taskName) + .task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void notUpToDateWhenLaunchScriptWasIncludedAndThenIsNotIncluded() { + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", this.taskName) + .task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void notUpToDateWhenLaunchScriptPropertyChanges() { + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", + "-PlaunchScriptProperty=foo", this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(this.gradleBuild.build("-PincludeLaunchScript=true", + "-PlaunchScriptProperty=bar", this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + } + + @Test + public void applicationPluginMainClassNameIsUsed() throws IOException { + assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName) + .getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + try (JarFile jarFile = new JarFile( + new File(this.gradleBuild.getProjectDir(), "build/libs") + .listFiles()[0])) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.CustomMain"); + } + + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java new file mode 100644 index 00000000000..befdd65f619 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveTests.java @@ -0,0 +1,318 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.gradle.api.Project; +import org.gradle.api.tasks.bundling.AbstractArchiveTask; +import org.gradle.api.tasks.bundling.Jar; +import org.gradle.testfixtures.ProjectBuilder; +import org.gradle.util.GUtil; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import org.springframework.boot.loader.tools.DefaultLaunchScript; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Abstract base class for testing {@link BootArchive} implementations. + * + * @param the type of the concrete BootArchive implementation + * @author Andy Wilkinson + */ +public abstract class AbstractBootArchiveTests { + + @Rule + public final TemporaryFolder temp = new TemporaryFolder(); + + private final Class taskClass; + + private final String launcherClass; + + private final String libPath; + + private final String classesPath; + + private T task; + + protected AbstractBootArchiveTests(Class taskClass, String launcherClass, + String libPath, String classesPath) { + this.taskClass = taskClass; + this.launcherClass = launcherClass; + this.libPath = libPath; + this.classesPath = classesPath; + } + + @Before + public void createTask() { + try { + Project project = ProjectBuilder.builder() + .withProjectDir(this.temp.newFolder()).build(); + this.task = configure( + project.getTasks().create("testArchive", this.taskClass)); + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + @Test + public void basicArchiveCreation() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Main-Class")) + .isEqualTo(this.launcherClass); + assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.Main"); + } + } + + @Test + public void classpathJarsArePackagedBeneathLibPath() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar")); + this.task.execute(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry(this.libPath + "/one.jar")).isNotNull(); + assertThat(jarFile.getEntry(this.libPath + "/two.jar")).isNotNull(); + } + } + + @Test + public void classpathFoldersArePackagedBeneathClassesPath() throws IOException { + this.task.setMainClass("com.example.Main"); + File classpathFolder = this.temp.newFolder(); + File applicationClass = new File(classpathFolder, + "com/example/Application.class"); + applicationClass.getParentFile().mkdirs(); + applicationClass.createNewFile(); + this.task.classpath(classpathFolder); + this.task.execute(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat( + jarFile.getEntry(this.classesPath + "/com/example/Application.class")) + .isNotNull(); + } + } + + @Test + public void loaderIsWrittenToTheRootOfTheJar() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.execute(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry( + "org/springframework/boot/loader/LaunchedURLClassLoader.class")) + .isNotNull(); + } + } + + @Test + public void loaderIsWrittenToTheRootOfTheJarWhenUsingThePropertiesLauncher() + throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.execute(); + this.task.getManifest().getAttributes().put("Main-Class", + "org.springframework.boot.loader.PropertiesLauncher"); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry( + "org/springframework/boot/loader/LaunchedURLClassLoader.class")) + .isNotNull(); + } + } + + @Test + public void unpackCommentIsAddedToEntryIdentifiedByAPattern() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar")); + this.task.requiresUnpack("**/one.jar"); + this.task.execute(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry(this.libPath + "/one.jar").getComment()) + .startsWith("UNPACK:"); + assertThat(jarFile.getEntry(this.libPath + "/two.jar").getComment()).isNull(); + } + } + + @Test + public void unpackCommentIsAddedToEntryIdentifiedByASpec() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.classpath(this.temp.newFile("one.jar"), this.temp.newFile("two.jar")); + this.task.requiresUnpack((element) -> element.getName().endsWith("two.jar")); + this.task.execute(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry(this.libPath + "/two.jar").getComment()) + .startsWith("UNPACK:"); + assertThat(jarFile.getEntry(this.libPath + "/one.jar").getComment()).isNull(); + } + } + + @Test + public void launchScriptCanBePrepended() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.getLaunchScript().setIncluded(true); + this.task.execute(); + assertThat(Files.readAllBytes(this.task.getArchivePath().toPath())) + .startsWith(new DefaultLaunchScript(null, null).toByteArray()); + } + + @Test + public void customLaunchScriptCanBePrepended() throws IOException { + this.task.setMainClass("com.example.Main"); + LaunchScriptConfiguration launchScript = this.task.getLaunchScript(); + launchScript.setIncluded(true); + File customScript = this.temp.newFile("custom.script"); + Files.write(customScript.toPath(), Arrays.asList("custom script"), + StandardOpenOption.CREATE); + launchScript.setScript(customScript); + this.task.execute(); + assertThat(Files.readAllBytes(this.task.getArchivePath().toPath())) + .startsWith("custom script".getBytes()); + } + + @Test + public void launchScriptPropertiesAreReplaced() throws IOException { + this.task.setMainClass("com.example.Main"); + LaunchScriptConfiguration launchScript = this.task.getLaunchScript(); + launchScript.setIncluded(true); + launchScript.getProperties().put("initInfoProvides", "test property value"); + this.task.execute(); + assertThat(Files.readAllBytes(this.task.getArchivePath().toPath())) + .containsSequence("test property value".getBytes()); + } + + @Test + public void customMainClassInTheManifestIsHonored() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.getManifest().getAttributes().put("Main-Class", + "com.example.CustomLauncher"); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Main-Class")) + .isEqualTo("com.example.CustomLauncher"); + assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.Main"); + assertThat(jarFile.getEntry( + "org/springframework/boot/loader/LaunchedURLClassLoader.class")) + .isNull(); + } + } + + @Test + public void customStartClassInTheManifestIsHonored() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.getManifest().getAttributes().put("Start-Class", + "com.example.CustomMain"); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getManifest().getMainAttributes().getValue("Main-Class")) + .isEqualTo(this.launcherClass); + assertThat(jarFile.getManifest().getMainAttributes().getValue("Start-Class")) + .isEqualTo("com.example.CustomMain"); + } + } + + @Test + public void fileTimestampPreservationCanBeDisabled() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.setPreserveFileTimestamps(false); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + assertThat(entry.getTime()) + .isEqualTo(GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES); + } + } + } + + @Test + public void reproducibleOrderingCanBeEnabled() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.from(this.temp.newFile("bravo.txt"), this.temp.newFile("alpha.txt"), + this.temp.newFile("charlie.txt")); + this.task.setReproducibleFileOrder(true); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + List textFiles = new ArrayList<>(); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".txt")) { + textFiles.add(entry.getName()); + } + } + } + assertThat(textFiles).containsExactly("alpha.txt", "bravo.txt", "charlie.txt"); + } + + @Test + public void devtoolsJarIsExcludedByDefault() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.classpath(this.temp.newFile("spring-boot-devtools-0.1.2.jar")); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry(this.libPath + "/spring-boot-devtools-0.1.2.jar")) + .isNull(); + } + } + + @Test + public void devtoolsJarCanBeIncluded() throws IOException { + this.task.setMainClass("com.example.Main"); + this.task.classpath(this.temp.newFile("spring-boot-devtools-0.1.2.jar")); + this.task.setExcludeDevtools(false); + this.task.execute(); + assertThat(this.task.getArchivePath().exists()); + try (JarFile jarFile = new JarFile(this.task.getArchivePath())) { + assertThat(jarFile.getEntry(this.libPath + "/spring-boot-devtools-0.1.2.jar")) + .isNotNull(); + } + } + + private T configure(T task) throws IOException { + AbstractArchiveTask archiveTask = task; + archiveTask.setBaseName("test"); + archiveTask.setDestinationDir(this.temp.newFolder()); + return task; + } + + protected T getTask() { + return this.task; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentPluginFeatures.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java similarity index 57% rename from spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentPluginFeatures.java rename to spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java index 024d9d5faef..78182fac7d7 100644 --- a/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/agent/AgentPluginFeatures.java +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,22 +14,17 @@ * limitations under the License. */ -package org.springframework.boot.gradle.agent; - -import org.gradle.api.Project; - -import org.springframework.boot.gradle.PluginFeatures; +package org.springframework.boot.gradle.tasks.bundling; /** - * {@link PluginFeatures} to add Java Agent support. + * Integration tests for {@link BootJar}. * - * @author Phillip Webb + * @author Andy Wilkinson */ -public class AgentPluginFeatures implements PluginFeatures { +public class BootJarIntegrationTests extends AbstractBootArchiveIntegrationTests { - @Override - public void apply(Project project) { - project.afterEvaluate(new AgentTasksEnhancer()); + public BootJarIntegrationTests() { + super("bootJar"); } } diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java new file mode 100644 index 00000000000..1dda05c1c11 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootJarTests.java @@ -0,0 +1,31 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +/** + * Tests for {@link BootJar}. + * + * @author Andy Wilkinson + */ +public class BootJarTests extends AbstractBootArchiveTests { + + public BootJarTests() { + super(BootJar.class, "org.springframework.boot.loader.JarLauncher", + "BOOT-INF/lib", "BOOT-INF/classes"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.java new file mode 100644 index 00000000000..437be974676 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.java @@ -0,0 +1,30 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +/** + * Integration tests for {@link BootJar}. + * + * @author Andy Wilkinson + */ +public class BootWarIntegrationTests extends AbstractBootArchiveIntegrationTests { + + public BootWarIntegrationTests() { + super("bootWar"); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarTests.java new file mode 100644 index 00000000000..316ad520748 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/BootWarTests.java @@ -0,0 +1,79 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.IOException; +import java.util.jar.JarFile; + +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link BootWar}. + * + * @author Andy Wilkinson + */ +public class BootWarTests extends AbstractBootArchiveTests { + + public BootWarTests() { + super(BootWar.class, "org.springframework.boot.loader.WarLauncher", "WEB-INF/lib", + "WEB-INF/classes"); + } + + @Test + public void providedClasspathJarsArePackagedInWebInfLibProvided() throws IOException { + getTask().setMainClass("com.example.Main"); + getTask().providedClasspath(this.temp.newFile("one.jar"), + this.temp.newFile("two.jar")); + getTask().execute(); + try (JarFile jarFile = new JarFile(getTask().getArchivePath())) { + assertThat(jarFile.getEntry("WEB-INF/lib-provided/one.jar")).isNotNull(); + assertThat(jarFile.getEntry("WEB-INF/lib-provided/two.jar")).isNotNull(); + } + } + + @Test + public void devtoolsJarIsExcludedByDefaultWhenItsOnTheProvidedClasspath() + throws IOException { + getTask().setMainClass("com.example.Main"); + getTask().providedClasspath(this.temp.newFile("spring-boot-devtools-0.1.2.jar")); + getTask().execute(); + assertThat(getTask().getArchivePath().exists()); + try (JarFile jarFile = new JarFile(getTask().getArchivePath())) { + assertThat(jarFile + .getEntry("WEB-INF/lib-provided/spring-boot-devtools-0.1.2.jar")) + .isNull(); + } + } + + @Test + public void devtoolsJarCanBeIncludedWhenItsOnTheProvidedClasspath() + throws IOException { + getTask().setMainClass("com.example.Main"); + getTask().providedClasspath(this.temp.newFile("spring-boot-devtools-0.1.2.jar")); + getTask().setExcludeDevtools(false); + getTask().execute(); + assertThat(getTask().getArchivePath().exists()); + try (JarFile jarFile = new JarFile(getTask().getArchivePath())) { + assertThat(jarFile + .getEntry("WEB-INF/lib-provided/spring-boot-devtools-0.1.2.jar")) + .isNotNull(); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests.java new file mode 100644 index 00000000000..5b1ac3088fd --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests.java @@ -0,0 +1,74 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for uploading Boot jars and wars using Gradle's Maven plugin. + * + * @author Andy Wilkinson + */ +public class MavenIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void bootJarCanBeUploaded() throws FileNotFoundException, IOException { + BuildResult result = this.gradleBuild.build("uploadBootArchives"); + assertThat(result.task(":uploadBootArchives").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + assertThat(artifactWithSuffix("jar")).isFile(); + assertThat(artifactWithSuffix("pom")).is(pomWith().groupId("com.example") + .artifactId(this.gradleBuild.getProjectDir().getName()).version("1.0") + .noPackaging().noDependencies()); + } + + @Test + public void bootWarCanBeUploaded() throws IOException { + BuildResult result = this.gradleBuild.build("uploadBootArchives"); + assertThat(result.task(":uploadBootArchives").getOutcome()) + .isEqualTo(TaskOutcome.SUCCESS); + assertThat(artifactWithSuffix("war")).isFile(); + assertThat(artifactWithSuffix("pom")).is(pomWith().groupId("com.example") + .artifactId(this.gradleBuild.getProjectDir().getName()).version("1.0") + .packaging("war").noDependencies()); + } + + private File artifactWithSuffix(String suffix) { + String name = this.gradleBuild.getProjectDir().getName(); + return new File(new File(this.gradleBuild.getProjectDir(), "build/repo"), + String.format("com/example/%s/1.0/%s-1.0.%s", name, name, suffix)); + } + + private PomCondition pomWith() { + return new PomCondition(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests.java new file mode 100644 index 00000000000..a2dce669f9d --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests.java @@ -0,0 +1,73 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for publishing Boot jars and wars using Gradle's Maven Publish + * plugin. + * + * @author Andy Wilkinson + */ +public class MavenPublishingIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void bootJarCanBePublished() throws FileNotFoundException, IOException { + BuildResult result = this.gradleBuild.build("publish"); + assertThat(result.task(":publish").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(artifactWithSuffix("jar")).isFile(); + assertThat(artifactWithSuffix("pom")).is(pomWith().groupId("com.example") + .artifactId(this.gradleBuild.getProjectDir().getName()).version("1.0") + .noPackaging().noDependencies()); + } + + @Test + public void bootWarCanBePublished() throws IOException { + BuildResult result = this.gradleBuild.build("publish"); + assertThat(result.task(":publish").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(artifactWithSuffix("war")).isFile(); + assertThat(artifactWithSuffix("pom")).is(pomWith().groupId("com.example") + .artifactId(this.gradleBuild.getProjectDir().getName()).version("1.0") + .packaging("war").noDependencies()); + } + + private File artifactWithSuffix(String suffix) { + String name = this.gradleBuild.getProjectDir().getName(); + return new File(new File(this.gradleBuild.getProjectDir(), "build/repo"), + String.format("com/example/%s/1.0/%s-1.0.%s", name, name, suffix)); + } + + private PomCondition pomWith() { + return new PomCondition(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/PomCondition.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/PomCondition.java new file mode 100644 index 00000000000..b3d8f293a66 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/PomCondition.java @@ -0,0 +1,111 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.bundling; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import org.assertj.core.api.Condition; +import org.assertj.core.description.Description; +import org.assertj.core.description.TextDescription; + +import org.springframework.util.FileCopyUtils; + +/** + * AssertJ {@link Condition} for asserting the contents of a pom file. + * + * @author Andy Wilkinson + */ +class PomCondition extends Condition { + + private Set expectedContents; + + private Set notExpectedContents; + + PomCondition() { + this(new HashSet(), new HashSet()); + } + + private PomCondition(Set expectedContents, Set notExpectedContents) { + super(new TextDescription("Pom file containing %s and not containing %s", + expectedContents, notExpectedContents)); + this.expectedContents = expectedContents; + this.notExpectedContents = notExpectedContents; + } + + @Override + public boolean matches(File pom) { + try { + String contents = FileCopyUtils.copyToString(new FileReader(pom)); + for (String expected : this.expectedContents) { + if (!contents.contains(expected)) { + return false; + } + } + for (String notExpected : this.notExpectedContents) { + if (contents.contains(notExpected)) { + return false; + } + } + } + catch (IOException ex) { + throw new RuntimeException(ex); + } + return true; + } + + @Override + public Description description() { + return new TextDescription("Pom file containing %s and not containing %s", + this.expectedContents, this.notExpectedContents); + } + + PomCondition groupId(String groupId) { + this.expectedContents.add(String.format("%s", groupId)); + return this; + } + + PomCondition artifactId(String artifactId) { + this.expectedContents + .add(String.format("%s", artifactId)); + return this; + } + + PomCondition version(String version) { + this.expectedContents.add(String.format("%s", version)); + return this; + } + + PomCondition packaging(String packaging) { + this.expectedContents.add(String.format("%s", packaging)); + return this; + } + + PomCondition noDependencies() { + this.notExpectedContents.add(""); + return this; + } + + PomCondition noPackaging() { + this.notExpectedContents.add(""); + return this; + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java new file mode 100644 index 00000000000..a22a9db72a5 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.tasks.run; + +import java.io.File; +import java.io.IOException; + +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.TaskOutcome; +import org.junit.Rule; +import org.junit.Test; + +import org.springframework.boot.gradle.testkit.GradleBuild; +import org.springframework.util.FileSystemUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Integration tests for the {@link BootRun} task. + * + * @author Andy Wilkinson + */ +public class BootRunIntegrationTests { + + @Rule + public final GradleBuild gradleBuild = new GradleBuild(); + + @Test + public void basicExecution() throws IOException { + File output = new File(this.gradleBuild.getProjectDir(), + "src/main/java/com/example"); + output.mkdirs(); + FileSystemUtils.copyRecursively(new File("src/test/java/com/example"), output); + new File(this.gradleBuild.getProjectDir(), "src/main/resources").mkdirs(); + BuildResult result = this.gradleBuild.build("bootRun"); + assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("1. " + urlOf("build/classes/main")); + assertThat(result.getOutput()).contains("2. " + urlOf("build/resources/main")); + assertThat(result.getOutput()).doesNotContain(urlOf("src/main/resources")); + } + + @Test + public void sourceResourcesCanBeUsed() throws IOException { + File output = new File(this.gradleBuild.getProjectDir(), + "src/main/java/com/example"); + output.mkdirs(); + FileSystemUtils.copyRecursively(new File("src/test/java/com/example"), output); + BuildResult result = this.gradleBuild.build("bootRun"); + assertThat(result.task(":bootRun").getOutcome()).isEqualTo(TaskOutcome.SUCCESS); + assertThat(result.getOutput()).contains("1. " + urlOf("src/main/resources")); + assertThat(result.getOutput()).contains("2. " + urlOf("build/classes/main")); + assertThat(result.getOutput()).doesNotContain(urlOf("build/resources/main")); + } + + @Test + public void applicationPluginMainClassNameIsUsed() throws IOException { + BuildResult result = this.gradleBuild.build("echoMainClassName"); + assertThat(result.task(":echoMainClassName").getOutcome()) + .isEqualTo(TaskOutcome.UP_TO_DATE); + assertThat(result.getOutput()) + .contains("Main class name = com.example.CustomMainClass"); + } + + @Test + public void applicationPluginJvmArgumentsAreUsed() throws IOException { + BuildResult result = this.gradleBuild.build("echoJvmArguments"); + assertThat(result.task(":echoJvmArguments").getOutcome()) + .isEqualTo(TaskOutcome.UP_TO_DATE); + assertThat(result.getOutput()) + .contains("JVM arguments = [-Dcom.foo=bar, -Dcom.bar=baz]"); + } + + private String urlOf(String path) throws IOException { + return new File(this.gradleBuild.getProjectDir().getCanonicalFile(), path).toURI() + .toURL().toString(); + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java new file mode 100644 index 00000000000..6dfde693bc8 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/testkit/GradleBuild.java @@ -0,0 +1,186 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * 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 org.springframework.boot.gradle.testkit; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; + +import io.spring.gradle.dependencymanagement.DependencyManagementPlugin; +import org.gradle.testkit.runner.BuildResult; +import org.gradle.testkit.runner.GradleRunner; +import org.junit.rules.TemporaryFolder; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; +import org.xml.sax.InputSource; + +import org.springframework.asm.ClassVisitor; +import org.springframework.boot.loader.tools.LaunchScript; +import org.springframework.util.FileCopyUtils; + +/** + * A {@link TestRule} for running a Gradle build using {@link GradleRunner}. + * + * @author Andy Wilkinson + */ +public class GradleBuild implements TestRule { + + private final TemporaryFolder temp = new TemporaryFolder(); + + private File projectDir; + + private String script; + + @Override + public Statement apply(Statement base, Description description) { + URL scriptUrl = findDefaultScript(description); + if (scriptUrl != null) { + script(scriptUrl.getFile()); + } + return this.temp.apply(new Statement() { + + @Override + public void evaluate() throws Throwable { + before(); + try { + base.evaluate(); + } + finally { + after(); + } + } + + }, description); + } + + private URL findDefaultScript(Description description) { + URL scriptUrl = getScriptForTestMethod(description); + if (scriptUrl != null) { + return scriptUrl; + } + return getScriptForTestClass(description.getTestClass()); + } + + private URL getScriptForTestMethod(Description description) { + return description.getTestClass() + .getResource(description.getTestClass().getSimpleName() + "-" + + description.getMethodName() + ".gradle"); + } + + private URL getScriptForTestClass(Class testClass) { + return testClass.getResource(testClass.getSimpleName() + ".gradle"); + } + + private void before() throws IOException { + this.projectDir = this.temp.newFolder(); + } + + private void after() { + GradleBuild.this.script = null; + } + + private String pluginClasspath() { + return absolutePath("bin") + "," + absolutePath("build/classes/main") + "," + + absolutePath("build/resources/main") + "," + + pathOfJarContaining(LaunchScript.class) + "," + + pathOfJarContaining(ClassVisitor.class) + "," + + pathOfJarContaining(DependencyManagementPlugin.class); + } + + private String absolutePath(String path) { + return new File(path).getAbsolutePath(); + } + + private String pathOfJarContaining(Class type) { + return type.getProtectionDomain().getCodeSource().getLocation().getPath(); + } + + public GradleBuild script(String script) { + this.script = script; + return this; + } + + public BuildResult build(String... arguments) { + try { + return prepareRunner(arguments).build(); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public BuildResult buildAndFail(String... arguments) { + try { + return prepareRunner(arguments).buildAndFail(); + } + catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + public GradleRunner prepareRunner(String... arguments) throws IOException { + String scriptContent = FileCopyUtils.copyToString(new FileReader(this.script)) + .replace("{version}", getBootVersion()); + FileCopyUtils.copy(scriptContent, + new FileWriter(new File(this.projectDir, "build.gradle"))); + GradleRunner gradleRunner = GradleRunner.create().withProjectDir(this.projectDir) + .forwardOutput(); + List allArguments = new ArrayList(); + allArguments.add("-PpluginClasspath=" + pluginClasspath()); + allArguments.add("-PbootVersion=" + getBootVersion()); + allArguments.addAll(Arrays.asList(arguments)); + return gradleRunner.withArguments(allArguments); + } + + public File getProjectDir() { + return this.projectDir; + } + + public void setProjectDir(File projectDir) { + this.projectDir = projectDir; + } + + private static String getBootVersion() { + return evaluateExpression( + "/*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']" + + "/text()"); + } + + private static String evaluateExpression(String expression) { + try { + XPathFactory xPathFactory = XPathFactory.newInstance(); + XPath xpath = xPathFactory.newXPath(); + XPathExpression expr = xpath.compile(expression); + String version = expr.evaluate(new InputSource(new FileReader("pom.xml"))); + return version; + } + catch (Exception ex) { + throw new IllegalStateException("Failed to evaluate expression", ex); + } + } + +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-additionalProperties.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-additionalProperties.gradle new file mode 100644 index 00000000000..4335ef8445f --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-additionalProperties.gradle @@ -0,0 +1,21 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +group = 'com.example' +version = '1.0' + +springBoot { + buildInfo { + properties { + additionalProperties = [ + 'a': 'alpha', 'b': 'bravo' + ] + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicJar.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicJar.gradle new file mode 100644 index 00000000000..92cd7455635 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicJar.gradle @@ -0,0 +1,15 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +group = 'com.example' +version = '1.0' + +springBoot { + buildInfo() +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicWar.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicWar.gradle new file mode 100644 index 00000000000..6a627257c26 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-basicWar.gradle @@ -0,0 +1,15 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'war' + +group = 'com.example' +version = '1.0' + +springBoot { + buildInfo() +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-classesDependency.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-classesDependency.gradle new file mode 100644 index 00000000000..e217894ff20 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-classesDependency.gradle @@ -0,0 +1,12 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +springBoot { + buildInfo() +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-jarWithCustomName.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-jarWithCustomName.gradle new file mode 100644 index 00000000000..adb3428ee08 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-jarWithCustomName.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' + +group = 'com.example' +version = '1.0' + +bootJar { + baseName = 'foo' +} + +springBoot { + buildInfo() +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-warWithCustomName.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-warWithCustomName.gradle new file mode 100644 index 00000000000..e679477c158 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/dsl/BuildInfoDslIntegrationTests-warWithCustomName.gradle @@ -0,0 +1,19 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'war' + +group = 'com.example' +version = '1.0' + +bootWar { + baseName = 'foo' +} + +springBoot { + buildInfo() +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForJarCanBeBuilt.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForJarCanBeBuilt.gradle new file mode 100644 index 00000000000..ed26697d0ef --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForJarCanBeBuilt.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'application' +apply plugin: 'java' + +bootJar { + mainClass = 'com.example.ExampleApplication' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForWarCanBeBuilt.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForWarCanBeBuilt.gradle new file mode 100644 index 00000000000..aa4a2a76334 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-tarDistributionForWarCanBeBuilt.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'application' +apply plugin: 'war' + +bootWar { + mainClass = 'com.example.ExampleApplication' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForJarCanBeBuilt.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForJarCanBeBuilt.gradle new file mode 100644 index 00000000000..ed26697d0ef --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForJarCanBeBuilt.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'application' +apply plugin: 'java' + +bootJar { + mainClass = 'com.example.ExampleApplication' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForWarCanBeBuilt.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForWarCanBeBuilt.gradle new file mode 100644 index 00000000000..aa4a2a76334 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests-zipDistributionForWarCanBeBuilt.gradle @@ -0,0 +1,13 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'application' +apply plugin: 'war' + +bootWar { + mainClass = 'com.example.ExampleApplication' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.gradle new file mode 100644 index 00000000000..18509a038c3 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/ApplicationPluginActionIntegrationTests.gradle @@ -0,0 +1,33 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' + +if (project.hasProperty('applyApplicationPlugin')) { + apply plugin: 'application' +} + +task('taskExists') { + doFirst { + println "$taskName exists = ${tasks.findByName(taskName) != null}" + } +} + +task('distributionExists') { + doFirst { + boolean found = project.hasProperty('distributions') && + distributions.findByName(distributionName) != null + println "$distributionName exists = $found" + } +} + +task('javaCompileEncoding') { + doFirst { + tasks.withType(JavaCompile) { + println "$name = ${options.encoding}" + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests-helpfulErrorWhenVersionlessDependencyFailsToResolve.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests-helpfulErrorWhenVersionlessDependencyFailsToResolve.gradle new file mode 100644 index 00000000000..2aeaadbc4a2 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests-helpfulErrorWhenVersionlessDependencyFailsToResolve.gradle @@ -0,0 +1,16 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' + +repositories { + mavenLocal() +} + +dependencies { + compile 'org.springframework.boot:spring-boot-starter-web' +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.gradle new file mode 100644 index 00000000000..12dca02ea44 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/DependencyManagementPluginActionIntegrationTests.gradle @@ -0,0 +1,41 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' + +if (project.hasProperty('applyDependencyManagementPlugin')) { + apply plugin: 'io.spring.dependency-management' + dependencyManagement { + resolutionStrategy { + eachDependency { + if (it.requested.group == 'org.springframework.boot') { + it.useVersion project.bootVersion + } + } + } + } +} + +repositories { + mavenLocal() +} + +task doesNotHaveDependencyManagement { + doLast { + if (project.extensions.findByName('dependencyManagement') != null) { + throw new GradleException('Found dependency management extension') + } + } +} + +task hasDependencyManagement { + doLast { + if (!dependencyManagement.managedVersions) { + throw new GradleException('No managed versions have been configured') + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.gradle new file mode 100644 index 00000000000..20fb8832f22 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/JavaPluginActionIntegrationTests.gradle @@ -0,0 +1,31 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' + +if (project.hasProperty('applyJavaPlugin')) { + apply plugin: 'java' +} + +task('taskExists') { + doFirst { + println "$taskName exists = ${tasks.findByName(taskName) != null}" + } +} + +task('componentExists') { + doFirst { + println "$componentName exists = ${components.findByName(componentName) != null}" + } +} + +task('javaCompileEncoding') { + doFirst { + tasks.withType(JavaCompile) { + println "$name = ${options.encoding}" + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.gradle new file mode 100644 index 00000000000..068722c2fec --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/MavenPluginActionIntegrationTests.gradle @@ -0,0 +1,24 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' +apply plugin: 'java' +apply plugin: 'maven' + +task('conf2ScopeMappings') { + doFirst { + tasks.getByName('uploadBootArchives').repositories.withType(MavenResolver) { + println "Conf2ScopeMappings = ${pom.scopeMappings.mappings.size()}" + } + } +} + +uploadBootArchives { + repositories { + mavenDeployer { + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.gradle new file mode 100644 index 00000000000..9bec2b8c13c --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/plugin/WarPluginActionIntegrationTests.gradle @@ -0,0 +1,23 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'org.springframework.boot' + +if (project.hasProperty('applyWarPlugin')) { + apply plugin: 'war' +} + +task('taskExists') { + doFirst { + println "$taskName exists = ${tasks.findByName(taskName) != null}" + } +} + +task('componentExists') { + doFirst { + println "$componentName exists = ${components.findByName(componentName) != null}" + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-defaultValues.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-defaultValues.gradle new file mode 100644 index 00000000000..2fe8266de8b --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests-defaultValues.gradle @@ -0,0 +1,11 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +def property(String name, Object defaultValue) { + project.hasProperty(name) ? project.getProperty(name) : defaultValue +} + +task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.gradle new file mode 100644 index 00000000000..26ce586d5b5 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/buildinfo/BuildInfoIntegrationTests.gradle @@ -0,0 +1,20 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +def property(String name, Object defaultValue) { + project.hasProperty(name) ? project.getProperty(name) : defaultValue +} + +task buildInfo(type: org.springframework.boot.gradle.tasks.buildinfo.BuildInfo) { + destinationDir file(property('buildInfoDestinationDir', project.buildDir)) + properties { + artifact = property('buildInfoArtifact', 'foo') + version = property('buildInfoVersion', '1.0') + group = property('buildInfoGroup', 'foo') + name = property('buildInfoName', 'foo') + additional = ['additional': property('buildInfoAdditional', 'foo')] + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle new file mode 100644 index 00000000000..684171c1403 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle @@ -0,0 +1,11 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' +apply plugin: 'application' + +mainClassName = 'com.example.CustomMain' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.gradle new file mode 100644 index 00000000000..b54d7a8ecb8 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests.gradle @@ -0,0 +1,16 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' + +bootJar { + mainClass = 'com.example.Application' + launchScript { + included = project.hasProperty('includeLaunchScript') ? includeLaunchScript : false + properties 'prop' : project.hasProperty('launchScriptProperty') ? launchScriptProperty : 'default' + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle new file mode 100644 index 00000000000..8da00e317bf --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-applicationPluginMainClassNameIsUsed.gradle @@ -0,0 +1,11 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'war' +apply plugin: 'org.springframework.boot' +apply plugin: 'application' + +mainClassName = 'com.example.CustomMain' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.gradle new file mode 100644 index 00000000000..3461c7fe001 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests.gradle @@ -0,0 +1,16 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'war' +apply plugin: 'org.springframework.boot' + +bootWar { + mainClass = 'com.example.Application' + launchScript { + included = project.hasProperty('includeLaunchScript') ? includeLaunchScript : false + properties 'prop' : project.hasProperty('launchScriptProperty') ? launchScriptProperty : 'default' + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootJarCanBeUploaded.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootJarCanBeUploaded.gradle new file mode 100644 index 00000000000..145bc8ac02a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootJarCanBeUploaded.gradle @@ -0,0 +1,24 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' +apply plugin: 'maven' + +bootJar { + mainClass = 'com.example.Application' +} + +group = 'com.example' +version = '1.0' + +uploadBootArchives { + repositories { + mavenDeployer { + repository(url: "file:$buildDir/repo") + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootWarCanBeUploaded.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootWarCanBeUploaded.gradle new file mode 100644 index 00000000000..89c8e25f60d --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenIntegrationTests-bootWarCanBeUploaded.gradle @@ -0,0 +1,24 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'war' +apply plugin: 'org.springframework.boot' +apply plugin: 'maven' + +bootWar { + mainClass = 'com.example.Application' +} + +group = 'com.example' +version = '1.0' + +uploadBootArchives { + repositories { + mavenDeployer { + repository(url: "file:$buildDir/repo") + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootJarCanBePublished.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootJarCanBePublished.gradle new file mode 100644 index 00000000000..fbc1cb0dba9 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootJarCanBePublished.gradle @@ -0,0 +1,29 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' +apply plugin: 'maven-publish' + +bootJar { + mainClass = 'com.example.Application' +} + +group = 'com.example' +version = '1.0' + +publishing { + repositories { + maven { + url "$buildDir/repo" + } + } + publications { + mavenBootJava(MavenPublication) { + from components.bootJava + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootWarCanBePublished.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootWarCanBePublished.gradle new file mode 100644 index 00000000000..4c71589e0c2 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/MavenPublishingIntegrationTests-bootWarCanBePublished.gradle @@ -0,0 +1,29 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'war' +apply plugin: 'org.springframework.boot' +apply plugin: 'maven-publish' + +bootWar { + mainClass = 'com.example.Application' +} + +group = 'com.example' +version = '1.0' + +publishing { + repositories { + maven { + url "$buildDir/repo" + } + } + publications { + mavenBootWeb(MavenPublication) { + from components.bootWeb + } + } +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginJvmArgumentsAreUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginJvmArgumentsAreUsed.gradle new file mode 100644 index 00000000000..96047897b24 --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginJvmArgumentsAreUsed.gradle @@ -0,0 +1,14 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'application' +apply plugin: 'org.springframework.boot' + +applicationDefaultJvmArgs = ['-Dcom.foo=bar', '-Dcom.bar=baz'] + +task echoJvmArguments { + println 'JVM arguments = ' + bootRun.jvmArgs +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginMainClassNameIsUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginMainClassNameIsUsed.gradle new file mode 100644 index 00000000000..a9163cd7d3e --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-applicationPluginMainClassNameIsUsed.gradle @@ -0,0 +1,14 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'application' +apply plugin: 'org.springframework.boot' + +mainClassName = 'com.example.CustomMainClass' + +task echoMainClassName { + println 'Main class name = ' + bootRun.main +} diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-basicExecution.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-basicExecution.gradle new file mode 100644 index 00000000000..97d0d1c7e3c --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-basicExecution.gradle @@ -0,0 +1,8 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' diff --git a/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle new file mode 100644 index 00000000000..47504d6d74a --- /dev/null +++ b/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/run/BootRunIntegrationTests-sourceResourcesCanBeUsed.gradle @@ -0,0 +1,12 @@ +buildscript { + dependencies { + classpath files(pluginClasspath.split(',')) + } +} + +apply plugin: 'java' +apply plugin: 'org.springframework.boot' + +bootRun { + sourceResources sourceSets.main +}