├── .gitattributes ├── .github └── workflows │ └── linux-build-release.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── RELEASE_NOTES.md ├── build.gradle ├── gradle ├── integration-test.gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src ├── integrationTest └── groovy │ └── com │ └── bmuschko │ └── gradle │ └── cargo │ └── util │ ├── AbstractIntegrationSpec.groovy │ ├── ConfigFileIntegrationSpec.groovy │ ├── DefaultDeployableSpec.groovy │ ├── DeployableIntegrationSpec.groovy │ ├── InstallerUrlIntegrationSpec.groovy │ ├── LocallyInstalledContainerIntegrationSpec.groovy │ └── fixture │ ├── AbstractWarFixture.groovy │ ├── HelloWorldServletWarFixture.groovy │ ├── ProjectFixture.groovy │ ├── TextResourceFactoryJarFixture.groovy │ └── TextResourceLoaderServletWarFixture.groovy ├── main └── groovy │ └── com │ └── bmuschko │ └── gradle │ └── cargo │ ├── CargoBasePlugin.groovy │ ├── CargoPlugin.groovy │ ├── DeployableType.groovy │ ├── DeployableTypeFactory.groovy │ ├── convention │ ├── BinFile.groovy │ ├── CargoLocalTaskConvention.groovy │ ├── CargoPluginExtension.groovy │ ├── CargoRemoteTaskConvention.groovy │ ├── ConfigFile.groovy │ ├── ContainerProperties.groovy │ ├── Deployable.groovy │ ├── SystemProperties.groovy │ └── ZipUrlInstaller.groovy │ ├── tasks │ ├── AbstractCargoContainerTask.groovy │ ├── daemon │ │ ├── CargoDaemon.groovy │ │ ├── CargoDaemonStart.groovy │ │ └── CargoDaemonStop.groovy │ ├── local │ │ ├── CargoConfigureLocal.groovy │ │ ├── CargoRedeployLocal.groovy │ │ ├── CargoRunLocal.groovy │ │ ├── CargoStartLocal.groovy │ │ ├── CargoStopLocal.groovy │ │ └── LocalCargoContainerTask.groovy │ └── remote │ │ ├── CargoDeployRemote.groovy │ │ ├── CargoRedeployRemote.groovy │ │ ├── CargoUndeployRemote.groovy │ │ └── RemoteCargoContainerTask.groovy │ └── util │ ├── CargoAntLoggingListener.groovy │ ├── DefaultFileUtil.groovy │ ├── FileUtil.groovy │ ├── LoggingHandler.groovy │ └── ProjectInfoHelper.groovy └── test └── groovy └── com └── bmuschko └── gradle └── cargo └── util ├── CargoAntLoggingListenerSpec.groovy ├── DefaultFileUtilSpec.groovy ├── DeployableTypeFactorySpec.groovy └── LoggingHandlerSpec.groovy /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bat text eol=crlf 2 | gradlew text eol=lf -------------------------------------------------------------------------------- /.github/workflows/linux-build-release.yml: -------------------------------------------------------------------------------- 1 | name: Build and Release [Linux] 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | name: Build 7 | runs-on: ubuntu-18.04 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v1 11 | - name: Set up Java 12 | uses: actions/setup-java@v1 13 | with: 14 | java-version: 11 15 | - name: Compilation 16 | uses: eskatos/gradle-command-action@v1 17 | with: 18 | arguments: classes 19 | - name: Unit tests 20 | uses: eskatos/gradle-command-action@v1 21 | with: 22 | arguments: test 23 | - name: Integration tests 24 | uses: eskatos/gradle-command-action@v1 25 | with: 26 | arguments: integrationTest 27 | - name: Assemble artifact 28 | uses: eskatos/gradle-command-action@v1 29 | with: 30 | arguments: assemble 31 | - name: Store artifact 32 | uses: actions/upload-artifact@v2 33 | with: 34 | name: gradle-tomcat-plugin.jar 35 | path: build/libs/*.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | out 3 | *.iml 4 | *.ipr 5 | *.iws 6 | .idea 7 | .gradle 8 | /bin/ 9 | /.project 10 | /.classpath 11 | /.settings -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gradle Cargo plugin [![Build Status](https://github.com/bmuschko/gradle-cargo-plugin/workflows/Build%20and%20Release%20%5BLinux%5D/badge.svg)](https://github.com/bmuschko/gradle-cargo-plugin/actions?query=workflow%3A%22Build+and+Release+%5BLinux%5D%22) 2 | 3 | ![Cargo Logo](https://codehaus-cargo.github.io/cargo/attachments/cargo-banner-left.png) 4 | 5 | 6 | 7 | 12 | 13 | 14 | 20 | 21 |
8 | Over the past couple of years this plugin has seen many releases. Thanks to everyone involved! 9 | Unfortunately, I don't have much time to contribute anymore. In practice this means far less activity, 10 | responsiveness on issues and new releases from my end. 11 |
15 | I am 16 | actively looking for contributors 17 | willing to take on maintenance and implementation of the project. If you are interested and would love to see this 18 | plugin continue to thrive, shoot me a mail. 19 |
22 | 23 | The plugin provides deployment capabilities for web applications to local and remote containers in any given 24 | Gradle build by leveraging the [Cargo Ant tasks](https://codehaus-cargo.github.io/cargo/Ant+support.html). The plugin supports WAR and EAR 25 | artifacts. 26 | 27 | The typical use case for this plugin is to support deployment during development. Keep in mind that Cargo uses hot deployment 28 | which over time fills up the PermGen memory of the JVM process running your container. Continuously deploying an artifact will 29 | inevitablity lead to a `java.lang.OutOfMemoryError`. Cargo does support container management capabilities (starting/stopping 30 | of remote containers) via the so-called [Cargo daemon](https://codehaus-cargo.github.io/cargo/Cargo+Daemon.html). However, in continuous deployment 31 | scenarios you often want to need perform more complex operations. 32 | 33 | ## Usage 34 | 35 | To use the plugin's functionality, you will need to add the its binary artifact to your build script's classpath and apply 36 | the plugin. 37 | 38 | ### Adding the plugin binary to the build 39 | 40 | The plugin JAR needs to be defined in the classpath of your build script. It is available on the Gradle plugin portal. The following code snippet 41 | shows an example on how to retrieve it with the `buildscript` syntax: 42 | 43 | buildscript { 44 | repositories { 45 | gradlePluginPortal() 46 | } 47 | 48 | dependencies { 49 | classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0' 50 | } 51 | } 52 | 53 | ### Provided plugins 54 | 55 | The JAR file comes with two plugins: 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 |
Plugin IdentifierDepends OnTypeDescription
com.bmuschko.cargo-base-CargoBasePluginProvides Cargo custom task types, pre-configures classpath and deployables.
com.bmuschko.cargocom.bmuschko.cargo-baseCargoPluginProvides a set of local and remote Cargo tasks and exposes extension for configuration.
77 | 78 | The `com.bmuschko.cargo` plugin helps you get started quickly. If you only need to deal with a single container product, this is the 79 | preferrable option. Most plugin users will go with this option. To use the Cargo plugin, include the following code snippet 80 | in your build script: 81 | 82 | apply plugin: 'com.bmuschko.cargo' 83 | 84 | If you need full control over your deployment tasks, you will want to use the `com.bmuschko.cargo-base` plugin. The downside is that each task 85 | has to be configured individually in your build script. To use the Cargo base plugin, include the following code snippet 86 | in your build script: 87 | 88 | apply plugin: 'com.bmuschko.cargo-base' 89 | 90 | ### Configuring the Cargo version 91 | 92 | The `com.bmuschko.cargo-base` plugin already sets up the dependencies for Cargo. In order to do so, it chooses a default 93 | version of the libraries. Alternatively, you can define a custom version of the Cargo libraries. To do so, please use 94 | the `cargo` configuration name in your `dependencies` closure, and keep the below in mind: 95 | * Remote deployment functionality will only work with a Cargo version >= 1.1.0 due to a bug in the library (see [CARGO-962](https://codehaus-cargo.atlassian.net/browse/CARGO-962) for more information). 96 | * Setting configuration properties will only work with a Cargo version >= 1.9.10 due to missing feature in the library (see [CARGO-1578](https://codehaus-cargo.atlassian.net/browse/CARGO-1578) for more information). 97 | The following example demonstrates how to use the version 1.9.10 of the Cargo libraries: 98 | 99 | ``` 100 | dependencies { 101 | def cargoVersion = '1.9.10' 102 | cargo "org.codehaus.cargo:cargo-core-uberjar:$cargoVersion", 103 | "org.codehaus.cargo:cargo-licensed-dtds:$cargoVersion", 104 | "org.codehaus.cargo:cargo-ant:$cargoVersion" 105 | } 106 | ``` 107 | 108 | ## Tasks 109 | 110 | The `cargo` plugin pre-defines the following tasks out-of-the-box: 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 |
Task NameDepends OnTypeDescription
cargoDeployRemote-CargoDeployRemoteDeploys a deployable to remote container.
cargoUndeployRemote-CargoUndeployRemoteUndeploys a deployable from remote container.
cargoRedeployRemote-CargoRedeployRemoteRedeploys a deployable to remote container.
cargoRunLocal-CargoRunLocalStarts the local container, deploys a deployable and waits for the user to press CTRL + C to stop.
cargoStartLocal-CargoStartLocalStarts the local container, deploys a deployable and then do other tasks (for example, execute tests).
cargoRedeployLocal-CargoRedeployLocalRedeploys a deployable on local container.
cargoStopLocal-CargoStopLocalStops local container.
cargoConfigureLocal-CargoConfigureLocalConfigures the local container.
168 | 169 | ## Project layout 170 | 171 | The Cargo plugin uses the same layout as the War plugin. 172 | 173 | ## Extension properties 174 | 175 | The Cargo plugin defines the following convention properties in the `cargo` closure: 176 | 177 | * `containerId`: The container ID you are targeting. Please see the [list of supported containers](https://codehaus-cargo.github.io/cargo/Home.html) on the Cargo website. 178 | * `port`: The TCP port the container responds on (defaults to 8080). 179 | 180 | Within `cargo` you can define optional properties for the 1..n deployment artifacts in a closure named `deployable`. Each 181 | deployment artifact would be specified in its own closure: 182 | 183 | * `file`: Any type that can be passed to [Project.files(Object...)](https://docs.gradle.org/current/javadoc/org/gradle/api/Project.html#files-java.lang.Object...-) and resolves to a single file or a directory including arbitrary artifacts, exploded WAR directories and dependency configurations to be deployed to container (defaults to project/module artifact - WAR or EAR file). 184 | * `context`: The URL context the container is handling your web application on (defaults to WAR/EAR name). 185 | 186 | Keep in mind that you do not have to define the `deployable` closure if you just want to deploy the artifact defined by your 187 | Gradle project/module. 188 | 189 | Within `cargo` you can define properties for remote containers in a closure named `remote`: 190 | 191 | * `protocol`: The protocol of the remote container (defaults to `http`). 192 | * `hostname`: The hostname of the remote container. 193 | * `username`: The username credential for the remote container (optional). 194 | * `password`: The password credential for the remote container (optional). 195 | 196 | Within `cargo` you can define properties for local containers in a closure named `local`: 197 | 198 | * `jvmArgs`: The JVM arguments for a local container. 199 | * `outputFile`: The log file of your local container (defaults to writing to the console). 200 | * `logFile`: The Cargo log file of your local container (defaults to writing to the console). 201 | * `logLevel`: The log level to run the container with (optional). The valid levels are `low`, `medium` and `high`. 202 | * `homeDir`: The home directory of your local container installation. 203 | * `configHomeDir`: The home directory of your local container's configuration. 204 | * `configFile`: The [configuration files](https://codehaus-cargo.github.io/cargo/Configuration+files+option.html) you want to add to your 205 | container's configuration. The `configFile` is a closure itself and requires you to provide the attributes `files` and `toDir`. 206 | A [`FileCollection`](http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/FileCollection.html) should be used as `files` attribute and `toDir` should be a `String`. 207 | Multiple configuration file destinations can be defined by creating more than one `configFile` closure. 208 | * `rmiPort`: The port to use when communicating with this server, for example to start and stop it. 209 | * `startStopTimeout`: The timeout (in ms) in which to determine if the container is successfully started or stopped (defaults to 120000ms). 210 | * `extraClasspath`: A [`FileCollection`](http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/FileCollection.html) 211 | that provides extra elements to the local [container classpath](http://cargo.codehaus.org/Container+Classpath) (optional). 212 | * `sharedClasspath`: A [`FileCollection`](http://www.gradle.org/docs/current/javadoc/org/gradle/api/file/FileCollection.html) 213 | that provides extra elements to the [application classpath](https://codehaus-cargo.github.io/cargo/Application+Classpath.html), and not to the 214 | local container (optional). 215 | 216 | ### Container properties 217 | 218 | Within `local` and `remote` you can define container-specific properties. These properties can be looked up on 219 | the Cargo homepage. The following example shows how to set the AJP port for a local Tomcat container: 220 | 221 | cargo { 222 | local { 223 | containerProperties { 224 | property 'cargo.tomcat.ajp.port', 9099 225 | } 226 | } 227 | } 228 | 229 | ### System properties 230 | 231 | Local containers can use system properties passed to it. The following example shows how to set a single system property named `myproperty`: 232 | 233 | cargo { 234 | local { 235 | systemProperties { 236 | property 'myproperty', 'myvalue' 237 | } 238 | } 239 | } 240 | 241 | ### Automatically bootstrapping a local container 242 | 243 | If you decide to use the [ZIP installer](https://codehaus-cargo.github.io/cargo/Installer.html) Cargo will automatically download your container. You can 244 | define its properties in the closure `installer`. The installer only applies to "local" Cargo tasks. 245 | 246 | * `installUrl`: The URL to download the container distribution from. 247 | * `downloadDir`: Target directory to download the container distribution to. 248 | * `extractDir`: Directory to extract the downloaded container distribution to. 249 | 250 | Please refer to the individual configuration properties on the Cargo homepage. All of these properties can be overridden 251 | by project properties. The name of the project properties is the same as in the Cargo manual. 252 | 253 | If you wish to benefit from Gradle dependency cache when resolving container distributions you can use a configuration instead of a url when configuring the installer: 254 | 255 | configurations { 256 | tomcat 257 | } 258 | 259 | dependencies { 260 | tomcat "org.apache.tomcat:tomcat:9.0.14@zip" 261 | } 262 | 263 | cargo { 264 | local { 265 | installer { 266 | installConfiguration = configurations.tomcat 267 | } 268 | } 269 | } 270 | 271 | ### Example 272 | 273 | cargo { 274 | containerId = 'tomcat6x' 275 | port = 9090 276 | 277 | deployable { 278 | context = 'myawesomewebapp' 279 | } 280 | 281 | remote { 282 | hostname = 'cloud.internal.it' 283 | username = 'superuser' 284 | password = 'secretpwd' 285 | } 286 | 287 | local { 288 | homeDir = file('/home/user/dev/tools/apache-tomcat-6.0.32') 289 | outputFile = file('build/output.log') 290 | startStopTimeout = 60000 291 | 292 | containerProperties { 293 | property 'cargo.tomcat.ajp.port', 9099 294 | } 295 | } 296 | } 297 | 298 | ## FAQ 299 | 300 | **I want to automatically assemble my project's artifact when executing a Cargo deployment task.** 301 | 302 | The task `cargoRunLocal` does not automatically depend on the `assemble` task. The reason behind that is that you might 303 | not want to deploy your project's artifact or your project does not generate a WAR or EAR file. Instead you might want 304 | to deploy one or more external artifacts. If your workflow looks like "compile the code", "generate the artifact" and "deploy" 305 | then you make a Cargo deployment task depends on the `assemble` task. Here's one example: 306 | 307 | cargoRunLocal.dependsOn assemble 308 | 309 | **I am working on a multi-project build. Can I apply the same Cargo configuration to all of my web projects?** 310 | 311 | Gradle allows for filtering subprojects by certain criteria. To inject the relevant configuration from the root project 312 | of your build, you will need to identify all subprojects that apply the War plugin (of course the same concept works 313 | for Ear projects). Use the `configure` method to apply the Cargo plugin and your configuration as shown in the following 314 | code snippet: 315 | 316 | def webProjects() { 317 | subprojects.findAll { subproject -> subproject.plugins.hasPlugin('war') } 318 | } 319 | 320 | gradle.projectsEvaluated { 321 | configure(webProjects()) { 322 | apply plugin: 'com.bmuschko.cargo' 323 | 324 | cargo { 325 | containerId = 'tomcat7x' 326 | 327 | remote { 328 | hostname = 'localhost' 329 | username = 'manager' 330 | password = 'manager' 331 | } 332 | } 333 | } 334 | } 335 | 336 | **I would like to deploy multiple artifacts to my container. How do I do that?** 337 | 338 | You would specify each artifact in a separate `deployable` closure. Each of the closures should assign a unique URL context. 339 | The following example demonstrates how a Cargo setup with three different artifacts deployed to a local Tomcat: 340 | 341 | cargo { 342 | containerId = 'tomcat6x' 343 | port = 9090 344 | 345 | deployable { 346 | file = file('/home/foo/bar/web-services.war') 347 | context = 'web-services' 348 | } 349 | 350 | deployable { 351 | file = file('/home/foo/bar/web-app.war') 352 | context = 'web-app' 353 | } 354 | 355 | deployable { 356 | file = file('/home/foo/bar/enterprise-app.ear') 357 | context = 'enterprise-app' 358 | } 359 | 360 | local { 361 | homeDir = file('/home/user/dev/tools/apache-tomcat-6.0.32') 362 | } 363 | } 364 | 365 | **Is there a way to let Cargo automatically install the container I'd like to use?** 366 | 367 | Cargo allows for defining a container that gets automatically downloaded and installed on your local disk. All you need to 368 | do is to specify the `installer` closure. The following code snippet downloads, installs and uses Tomcat 7: 369 | 370 | cargo { 371 | containerId = 'tomcat7x' 372 | 373 | local { 374 | installer { 375 | installUrl = 'http://apache.osuosl.org/tomcat/tomcat-7/v7.0.27/bin/apache-tomcat-7.0.27.zip' 376 | downloadDir = file("$buildDir/download") 377 | extractDir = file("$buildDir/extract") 378 | } 379 | } 380 | } 381 | 382 | **I'd like to add a configuration file to my local container. How do I do that?** 383 | 384 | For local containers a closure named `configFile` can be used that defines the source files and directory you would like 385 | to use the file from at runtime. If you need to copy files into more than one destinations just create multiple `configFile` closures. 386 | 387 | cargo { 388 | containerId = 'jboss5x' 389 | 390 | local { 391 | configFile { 392 | files = project.files('src/main/jboss5/login-config.xml') 393 | toDir = 'conf' 394 | } 395 | 396 | configFile { 397 | files = project.files('src/main/jboss5/login-config.xml', 'src/main/jboss5/sample-users.properties') 398 | toDir = 'conf/props' 399 | } 400 | } 401 | } 402 | 403 | To add binary file(s) you should use `file` closure(s) instead: 404 | 405 | cargo { 406 | containerId = 'glassfish3x' 407 | 408 | local { 409 | file { 410 | file = file('../config/db/mysql-connector-java-5.1.23-bin.jar') 411 | toDir = 'lib' 412 | } 413 | } 414 | } 415 | 416 | **I want to set up and configure my own Cargo task for more than one container. Can this be done?** 417 | 418 | Absolutely. The Cargo base plugin provides all tasks needed to set up deployment tasks. All you need to do is to create one 419 | or more tasks and configure the mandatory properties. The following example shows how to set up local container tasks 420 | for Tomcat and Jetty: 421 | 422 | apply plugin: 'com.bmuschko.cargo-base' 423 | 424 | task myTomcatRun(type: com.bmuschko.gradle.cargo.tasks.local.CargoRunLocal) { 425 | containerId = 'tomcat7x' 426 | homeDir = file('/home/user/dev/tools/apache-tomcat-7.0.42') 427 | } 428 | 429 | task myJettyRun(type: com.bmuschko.gradle.cargo.tasks.local.CargoRunLocal) { 430 | containerId = 'jetty9x' 431 | homeDir = file('/home/user/dev/tools/jetty-distribution-9.0.4.v20130625') 432 | } 433 | 434 | **I'd like to create deployment tasks for a rolling deployment to multiple remote containers. How do I do this?** 435 | 436 | Gradle allows for dynamically creating tasks based on your build script logic. The following example shows how to create 437 | three Tomcat deployment tasks and how to configure them with the help of a simple data structure. At the end of the script we 438 | also add another task that triggers the deployment to all remote containers. 439 | 440 | class RemoteContainer { 441 | String name 442 | String hostname 443 | Integer port 444 | String username 445 | String password 446 | } 447 | 448 | def remoteContainers = [new RemoteContainer(name: 'tomcat1', hostname: 'remote-tomcat1', 449 | port: 9090, username: 'admin', password: 's3cr3t'), 450 | new RemoteContainer(name: 'tomcat2', hostname: 'remote-tomcat2', 451 | port: 8050, username: 'deployer', password: 'qwerty'), 452 | new RemoteContainer(name: 'tomcat3', hostname: 'remote-tomcat3', 453 | port: 8888, username: 'su', password: 'powerful')] 454 | 455 | apply plugin: 'com.bmuschko.cargo-base' 456 | 457 | remoteContainers.each { config -> 458 | task "deployRemote${config.name.capitalize()}"(type: com.bmuschko.gradle.cargo.tasks.remote.CargoDeployRemote) { 459 | description = "Deploys WAR to remote Tomcat '${config.name}'." 460 | containerId = 'tomcat7x' 461 | hostname = config.hostname 462 | port = config.port 463 | username = config.username 464 | password = config.password 465 | } 466 | } 467 | 468 | task deployToAllRemoteTomcats { 469 | dependsOn remoteContainers.collect { "deployRemote${it.name.capitalize()}" } 470 | description = 'Deploys to all remote Tomcat containers.' 471 | group = 'deployment' 472 | } 473 | 474 | **Before a remote deployment I would like to restart my container. Can this be done?** 475 | 476 | Yes, this is possible with the help of the [Cargo daemon](https://codehaus-cargo.github.io/cargo/Cargo+Daemon.html) functionality. Please 477 | refer to the Cargo online documentation for setting up the Cargo daemon JVM process and configuring a container. With 478 | this plugin, you can use custom tasks to start and stop a container. The following example stops, starts and then redeploys 479 | an artifact. 480 | 481 | apply plugin: 'com.bmuschko.cargo' 482 | 483 | cargo { 484 | ... 485 | } 486 | 487 | ext.tomcat7HandleId = 'tomcat7' 488 | 489 | task cargoDaemonStop(type: com.bmuschko.gradle.cargo.tasks.daemon.CargoDaemonStop) { 490 | handleId = tomcat7HandleId 491 | } 492 | 493 | task cargoDaemonStart(type: com.bmuschko.gradle.cargo.tasks.daemon.CargoDaemonStart) { 494 | handleId = tomcat7HandleId 495 | } 496 | 497 | cargoDaemonStart.mustRunAfter cargoDaemonStop 498 | cargoRedeployRemote.dependsOn cargoDaemonStop, cargoDaemonStart 499 | 500 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | ### Version 2.9.0 (February 19, 2022) 2 | 3 | * Upgrade to Codehaus Cargo 1.9.10 - [Pull request 205](https://github.com/bmuschko/gradle-cargo-plugin/pull/205). 4 | * 5 | ### Version 2.8.0 (December 17, 2020) 6 | 7 | * Version upgrades for Codehaus Cargo and Java - [Pull request 204](https://github.com/bmuschko/gradle-cargo-plugin/pull/204). 8 | 9 | ### Version 2.7.1 (February 5, 2020) 10 | 11 | * Upgrade to Codehaus Cargo 1.7.10 - [Pull request 199](https://github.com/bmuschko/gradle-cargo-plugin/pull/199). 12 | 13 | ### Version 2.7.0 (December 14, 2019) 14 | 15 | * Add cargo-licensed-dtds to the dependencies and documentation - [Pull request 198](https://github.com/bmuschko/gradle-cargo-plugin/pull/198). 16 | 17 | ### Version 2.6.2 (December 12, 2019) 18 | 19 | * Upgrade to Cargo Ant tasks version 1.7.9 to ensure Gradle 6.0-compatibility - [Issue 196](https://github.com/bmuschko/gradle-cargo-plugin/issues/196). 20 | 21 | ### Version 2.6.1 (March 6, 2019) 22 | 23 | * Deployable should be declarable without a context - [Pull request 193](https://github.com/bmuschko/gradle-cargo-plugin/pull/193). 24 | 25 | ### Version 2.6 (February 10, 2019) 26 | 27 | * Allow use of use of locally installed container - [Pull request 191](https://github.com/bmuschko/gradle-cargo-plugin/pull/191). 28 | * **Breaking Change!** Rename timeout parameter to ensure compatibility with Gradle's built-in timeout - [Pull request 188](https://github.com/bmuschko/gradle-cargo-plugin/pull/188). 29 | 30 | ### Version 2.5 (January 29, 2018) 31 | 32 | * Support using a configuration as a source of the container for ZIP installer - [Pull request 176](https://github.com/bmuschko/gradle-cargo-plugin/pull/176). 33 | * Allow using outputs and configurations as deployables - [Pull request 178](https://github.com/bmuschko/gradle-cargo-plugin/pull/178). 34 | * **Breaking Change!** Support using task outputs and configurations as config files - [Pull request 180](https://github.com/bmuschko/gradle-cargo-plugin/pull/180). 35 | 36 | ### Version 2.4 (July 29, 2018) 37 | 38 | * Allow setting timeout to 0 - [Pull request 169](https://github.com/bmuschko/gradle-cargo-plugin/pull/169). 39 | * Upgrade to Cargo Ant tasks version 1.6.8. 40 | * Upgrade to Gradle Wrapper 4.9. 41 | 42 | ### Version 2.3 (January 2, 2018) 43 | 44 | * Introduce task for configuring local container - [Pull request 144](https://github.com/bmuschko/gradle-cargo-plugin/pull/144). 45 | * Upgrade to Cargo Ant tasks version 1.6.6. 46 | * Upgrade to Gradle Wrapper 4.4.1. 47 | 48 | ### Version 2.2.3 (June 4, 2016) 49 | 50 | * Remove use of Gradle internal methods. 51 | * Upgrade to Gradle Wrapper 2.13. 52 | 53 | ### Version 2.2.2 (December 4, 2015) 54 | 55 | * Expose properties for configuring a local embedded container - [Pull request 141](https://github.com/bmuschko/gradle-cargo-plugin/pull/141). 56 | 57 | ### Version 2.2.1 (September 6, 2015) 58 | 59 | * Fix typo in task description - [Pull request 135](https://github.com/bmuschko/gradle-cargo-plugin/pull/135). 60 | * Fixed configFile and file destination dir specification - [Pull request 121](https://github.com/bmuschko/gradle-cargo-plugin/pull/121). 61 | * Align `logFile` extension property with task property name - [Issue 110](https://github.com/bmuschko/gradle-cargo-plugin/issues/110). 62 | * Removed "magic" project properties. 63 | 64 | ### Version 2.2 (August 31, 2015) 65 | 66 | * Upgrade to Gradle Wrapper 2.6. 67 | * Removed container ID validation - [Issue 134](https://github.com/bmuschko/gradle-cargo-plugin/issues/134). 68 | * Cargo home directory is not an `@Input`, hashing can run into problems with locked files - [Pull request 133](https://github.com/bmuschko/gradle-cargo-plugin/pull/133). 69 | 70 | ### Version 2.1.1 (May 16, 2015) 71 | 72 | * Upgrade to Gradle Wrapper 2.4. 73 | * Introduced redeploy task for local containers - [Pull request 126](https://github.com/bmuschko/gradle-cargo-plugin/pull/126). 74 | 75 | ### Version 2.1 (March 30, 2015) 76 | 77 | * Upgrade to Cargo Ant tasks version 1.4.13. 78 | * Support for exploded WAR deployment - [Issue 115](https://github.com/bmuschko/gradle-cargo-plugin/issues/115). 79 | 80 | ### Version 2.0.3 (December 7, 2014) 81 | 82 | * Set Java target compatibility back to 1.6 - [Pull request 113](https://github.com/bmuschko/gradle-cargo-plugin/pull/113). 83 | 84 | ### Version 2.0.2 (November 15, 2014) 85 | 86 | * Directory for property `configHomeDir` is created automatically if it doesn't exist - [Issue 101](https://github.com/bmuschko/gradle-cargo-plugin/issues/101). 87 | * Upgrade to Cargo version 1.4.10. 88 | * Don't use `AntClassLoader` as parent classloader for daemon tasks. 89 | 90 | ### Version 2.0.1 (October 13, 2014) 91 | 92 | * Fix implementation class of Cargo plugin identifier - [Issue 107](https://github.com/bmuschko/gradle-cargo-plugin/issues/107). 93 | 94 | ### Version 2.0 (October 11, 2014) 95 | 96 | * Upgrade to Gradle Wrapper 2.1. 97 | * Changed package name to `com.bmuschko.gradle.vagrant`. 98 | * Changed group ID to `com.bmuschko`. 99 | * Adapted plugin IDs to be compatible with Gradle's plugin portal. 100 | 101 | ### Version 1.5.2 (October 11, 2014) 102 | 103 | * Deployment task should never be up-to-date - [Issue 103](https://github.com/bmuschko/gradle-cargo-plugin/issues/103). 104 | * Support for JBoss74x (aka EAP 6.3.x) container - [Pull request 105](https://github.com/bmuschko/gradle-cargo-plugin/pull/105). 105 | 106 | ### Version 1.5.1 (August 29, 2014) 107 | 108 | * Provide `equals`/`hashCode` for POJO input properties [Issue 97](https://github.com/bmuschko/gradle-cargo-plugin/issues/97). 109 | 110 | ### Version 1.5 (April 2, 2014) 111 | 112 | * Support for starting and stopping containers with the help of Cargo daemon. 113 | 114 | ### Version 1.4.1 (March 22, 2014) 115 | 116 | * `cargoStartLocal` and `cargoRunLocal` fail if log file doesn't exist - [Issue 83](https://github.com/bmuschko/gradle-cargo-plugin/issues/83). 117 | * Renamed property `output` to `outputFile`. 118 | * Some of the input properties needed to be `Serializable`. 119 | 120 | ### Version 1.4 (February 15, 2014) 121 | 122 | * Added sharedClasspath and extraClasspath support for local containers - [Pull request 73](https://github.com/bmuschko/gradle-cargo-plugin/pull/77). 123 | 124 | ### Version 1.3 (January 25, 2014) 125 | 126 | * Broke out base plugin to allow full control for creating and configuring deployment tasks. 127 | * The Cargo libraries now get pre-configured. A custom Cargo version can still be assigned via the configuration `cargo`. 128 | 129 | ### Version 1.2.2 (January 06, 2013) 130 | 131 | * Fix input annotation for `configHomeDir` property - [Pull request 73](https://github.com/bmuschko/gradle-cargo-plugin/pull/73). 132 | 133 | ### Version 1.2.1 (December 28, 2013) 134 | 135 | * Fixed missing property `UNDEPLOY_ACTION` on remote task - [Issue 72](https://github.com/bmuschko/gradle-cargo-plugin/issues/72). 136 | 137 | ### Version 1.2 (December 24, 2013) 138 | 139 | * Create custom task types for each action - [Issue 20](https://github.com/bmuschko/gradle-cargo-plugin/issues/20). 140 | 141 | ### Version 1.1 (December 16, 2013) 142 | 143 | * Adding support of the cargo timeout property - [Pull request 66](https://github.com/bmuschko/gradle-cargo-plugin/pull/66). 144 | * Harden validation code for deployables - [Issue 67](https://github.com/bmuschko/gradle-cargo-plugin/issues/67). 145 | * Add support for passing system properties to container - [Issue 68](https://github.com/bmuschko/gradle-cargo-plugin/issues/68). 146 | 147 | ### Version 1.0 (December 15, 2013) 148 | 149 | * Allow configuring container using generic properties. 150 | * Update of supported containers. 151 | * Upgrade to Gradle Wrapper 1.9. 152 | 153 | ### Version 0.6.1 (July 21, 2013) 154 | 155 | * Support for Jetty 9.x - [Pull request 48](https://github.com/bmuschko/gradle-cargo-plugin/pull/48). 156 | * Fix deprecation warnings in gradle 1.6 - [Pull request 48](https://github.com/bmuschko/gradle-cargo-plugin/pull/42). 157 | * Adding support for specifying configuration home - [Pull request 40](https://github.com/bmuschko/gradle-cargo-plugin/pull/40). 158 | 159 | ### Version 0.6 (April 16, 2013) 160 | 161 | * Avoid having to assign the WAR file for a remote undeploy action - [Issue 30](https://github.com/bmuschko/gradle-cargo-plugin/issues/30). 162 | * _Note:_ This release requires you to use Cargo >= 1.3.3. 163 | 164 | ### Version 0.5.9 (March 8, 2013) 165 | 166 | * Added configuration option for binary files - [Pull request 33](https://github.com/bmuschko/gradle-cargo-plugin/pull/32). 167 | 168 | ### Version 0.5.8 (February 25, 2013) 169 | 170 | * Capturing Cargo Ant logging - [Pull request 33](https://github.com/bmuschko/gradle-cargo-plugin/pull/33). 171 | * Upgrade to Gradle Wrapper 1.4. 172 | 173 | ### Version 0.5.7 (January 13, 2013) 174 | 175 | * Avoid masking exceptions thrown in build.gradle - [Issue 29](https://github.com/bmuschko/gradle-cargo-plugin/issues/29). 176 | * Some of the container-specific task property classes did not implement TaskProperty - [Issue 27](https://github.com/bmuschko/gradle-cargo-plugin/issues/27). 177 | 178 | ### Version 0.5.6 (October 14, 2012) 179 | 180 | * Expose convention property for setting the RMI port - [Issue 21](https://github.com/bmuschko/gradle-cargo-plugin/issues/21). 181 | 182 | ### Version 0.5.5 (August 4, 2012) 183 | 184 | * Provides support for configuration files - [Issue 14](https://github.com/bmuschko/gradle-cargo-plugin/issues/14). 185 | 186 | ### Version 0.5.4 (July 8, 2012) 187 | 188 | * The ZIP URL installer convention property wasn't set correctly for the default local container implementation. 189 | * Checking if all properties are set for the ZIP URL installer closure before applying it. 190 | * Refactored duplicated code for setting the convention properties of a local container. 191 | 192 | ### Version 0.5.3 (July 7, 2012) 193 | 194 | * Support for ZIP artifact installer - [Issue 15](https://github.com/bmuschko/gradle-cargo-plugin/issues/15). 195 | * Upgrade to Gradle Wrapper 1.0. 196 | * Use Groovy @Slf4j annotation for logging. 197 | 198 | ### Version 0.5.2 (December 5, 2011) 199 | 200 | * Fixed minor bug in documentation and code about setting local container-specific properties. 201 | 202 | ### Version 0.5.1 (December 3, 2011) 203 | 204 | * Provide convention properties for Cargo and container log files. 205 | 206 | ### Version 0.5 (November 27, 2011) 207 | 208 | * Allow deployment of multiple artifacts - [Issue 9](https://github.com/bmuschko/gradle-cargo-plugin/issues/9). _Note:_ This slightly 209 | changes the structure of the convention properties. Please check the documentation! 210 | 211 | ### Version 0.4 (November 27, 2011) 212 | 213 | * Support for JVM arguments in local containers. 214 | * Support for configuration properties specific to local container product. 215 | * The deployable artifact can either be a WAR or an EAR file. _Note:_ This release requires your project to run with Gradle >= [1.0-m4](http://wiki.gradle.org/display/GRADLE/Gradle+1.0-milestone-4+Release+Notes). 216 | * Upgrade to Gradle Wrapper 1.0-m6. 217 | 218 | ### Version 0.3 (June 26, 2011) 219 | 220 | * Exposed local run task introduced in Cargo 1.1.1. The plugin does not favor the [deprecation](http://cargo.codehaus.org/Ant+support) 221 | of the `wait` convention property. It got removed completely. Please use `cargoRunLocal` or `cargoStartLocal` depending on 222 | your use case. 223 | * _Note:_ This release requires you to use Cargo >= 1.1.1. 224 | 225 | ### Version 0.2 (May 30, 2011) 226 | 227 | * Added property for setting `cargo.protocol` to remote container tasks. 228 | 229 | ### Version 0.1 (May 27, 2011) 230 | 231 | * Initial release. 232 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'groovy' 3 | id 'maven-publish' 4 | id 'java-gradle-plugin' 5 | id 'com.gradle.plugin-publish' version '0.20.0' 6 | id 'org.ajoberstar.git-publish' version '2.1.3' 7 | } 8 | 9 | apply from: "$rootProject.projectDir/gradle/integration-test.gradle" 10 | 11 | def compatibilityVersion = JavaVersion.VERSION_1_8 12 | sourceCompatibility = compatibilityVersion 13 | targetCompatibility = compatibilityVersion 14 | group = 'com.bmuschko' 15 | version = '2.9.0' 16 | 17 | repositories { 18 | mavenCentral() 19 | } 20 | 21 | dependencies { 22 | def cargoVersion = '1.9.10' 23 | implementation "org.codehaus.cargo:cargo-daemon-client:$cargoVersion" 24 | testImplementation('org.spockframework:spock-core:1.3-groovy-2.4') { 25 | exclude group: 'org.codehaus.groovy' 26 | } 27 | testImplementation "org.codehaus.cargo:cargo-ant:$cargoVersion" 28 | } 29 | 30 | task sourcesJar(type: Jar) { 31 | archiveClassifier = 'sources' 32 | from sourceSets.main.allSource 33 | } 34 | 35 | task groovydocJar(type: Jar) { 36 | dependsOn groovydoc 37 | archiveClassifier = 'groovydoc' 38 | from groovydoc.destinationDir 39 | } 40 | 41 | task javadocJar(type: Jar) { 42 | dependsOn javadoc 43 | archiveClassifier = 'javadoc' 44 | from javadoc.destinationDir 45 | } 46 | 47 | artifacts { 48 | archives sourcesJar 49 | archives groovydocJar 50 | archives javadocJar 51 | } 52 | 53 | gradlePlugin { 54 | plugins { 55 | cargoBasePlugin { 56 | id = 'com.bmuschko.cargo-base' 57 | implementationClass = 'com.bmuschko.gradle.cargo.CargoBasePlugin' 58 | } 59 | cargoPlugin { 60 | id = 'com.bmuschko.cargo' 61 | implementationClass = 'com.bmuschko.gradle.cargo.CargoPlugin' 62 | } 63 | } 64 | } 65 | 66 | pluginBundle { 67 | website = "https://github.com/bmuschko/gradle-cargo-plugin" 68 | vcsUrl = "https://github.com/bmuschko/gradle-cargo-plugin" 69 | tags = ['deployment', 'container', 'web', 'ear', 'cargo'] 70 | 71 | mavenCoordinates { 72 | groupId = project.group.toString() 73 | artifactId = project.name 74 | version = project.version.toString() 75 | } 76 | 77 | plugins { 78 | cargoBasePlugin { 79 | displayName = 'Gradle Cargo Base Plugin' 80 | description = 'Plugin that provides Cargo custom task types, pre-configures classpath and deployables.' 81 | } 82 | cargoPlugin { 83 | displayName = 'Gradle Cargo Plugin' 84 | description = 'Plugin that provides a set of local and remote Cargo tasks and exposes extension for configuration.' 85 | } 86 | } 87 | } 88 | 89 | gitPublish { 90 | repoUri = 'git@github.com:bmuschko/gradle-cargo-plugin.git' 91 | branch = 'gh-pages' 92 | 93 | contents { 94 | from(javadoc.outputs.files) { 95 | into 'docs/javadoc' 96 | } 97 | from(groovydoc.outputs.files) { 98 | into 'docs/groovydoc' 99 | } 100 | } 101 | } 102 | 103 | gitPublishCopy.dependsOn javadoc, groovydoc -------------------------------------------------------------------------------- /gradle/integration-test.gradle: -------------------------------------------------------------------------------- 1 | sourceSets { 2 | integrationTest { 3 | groovy.srcDir file('src/integTest/groovy') 4 | resources.srcDir file('src/integTest/resources') 5 | compileClasspath += sourceSets.main.output + configurations.testRuntimeClasspath 6 | runtimeClasspath += output + compileClasspath 7 | } 8 | } 9 | 10 | task integrationTest(type: Test) { 11 | description = 'Runs the integration tests.' 12 | group = 'verification' 13 | testClassesDirs = sourceSets.integrationTest.output.classesDirs 14 | classpath = sourceSets.integrationTest.runtimeClasspath 15 | mustRunAfter test 16 | } 17 | 18 | check.dependsOn integrationTest 19 | 20 | dependencies { 21 | integrationTestImplementation "io.github.http-builder-ng:http-builder-ng-core:1.0.3" 22 | } -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bmuschko/gradle-cargo-plugin/12940deb48fa93e033a922db96ed3f5eb7956ad5/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'gradle-cargo-plugin' -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/AbstractIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import groovyx.net.http.HttpBuilder 4 | import org.gradle.testkit.runner.BuildResult 5 | import org.gradle.testkit.runner.GradleRunner 6 | import org.junit.Rule 7 | import org.junit.rules.TemporaryFolder 8 | import spock.lang.Specification 9 | 10 | abstract class AbstractIntegrationSpec extends Specification { 11 | 12 | protected final static String WAR_CONTEXT = 'test-servlet' 13 | 14 | @Rule 15 | TemporaryFolder testProjectDir 16 | 17 | File buildScript 18 | 19 | void setup() { 20 | buildScript = testProjectDir.newFile('build.gradle') << """ 21 | plugins { 22 | id 'com.bmuschko.cargo' 23 | } 24 | """ 25 | } 26 | 27 | void configureCargoInstaller() { 28 | buildScript << """ 29 | configurations { 30 | tomcat 31 | } 32 | 33 | dependencies { 34 | tomcat "org.apache.tomcat:tomcat:9.0.14@zip" 35 | } 36 | 37 | cargo { 38 | containerId = "tomcat9x" 39 | 40 | local { 41 | installer { 42 | installConfiguration = configurations.tomcat 43 | downloadDir = file("\$buildDir/download") 44 | extractDir = file("\$buildDir/extract") 45 | } 46 | } 47 | } 48 | """ 49 | } 50 | 51 | BuildResult runBuild(String... arguments) { 52 | GradleRunner.create() 53 | .withProjectDir(testProjectDir.root) 54 | .withArguments("-s", *arguments) 55 | .withPluginClasspath() 56 | .forwardOutput() 57 | .build() 58 | } 59 | 60 | String requestServletResponseText() { 61 | HttpBuilder.configure { 62 | request.uri = "http://localhost:8080/$WAR_CONTEXT" 63 | }.get() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/ConfigFileIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.util.fixture.TextResourceFactoryJarFixture 4 | import com.bmuschko.gradle.cargo.util.fixture.TextResourceLoaderServletWarFixture 5 | import groovyx.net.http.HttpBuilder 6 | 7 | class ConfigFileIntegrationSpec extends AbstractIntegrationSpec { 8 | 9 | private final String TEXT_RESOURCE_NAME = "test/resource" 10 | private final String TEXT_RESOURCE_VALUE = "test resource value" 11 | 12 | void setup() { 13 | def textResourceFactoryJarFixture = new TextResourceFactoryJarFixture(testProjectDir.root, ":textResourceFactory") 14 | def textResourceLoaderServletWarFixture = new TextResourceLoaderServletWarFixture(testProjectDir.root, ":textResourceLoader") 15 | 16 | configureCargoInstaller() 17 | 18 | buildScript << """ 19 | import groovy.xml.MarkupBuilder 20 | 21 | repositories { 22 | mavenCentral() 23 | } 24 | 25 | configurations { 26 | war 27 | extraClasspath 28 | } 29 | 30 | dependencies { 31 | war project(path: '${textResourceLoaderServletWarFixture.projectPath}', configuration: 'archives') 32 | extraClasspath project('$textResourceFactoryJarFixture.projectPath') 33 | } 34 | 35 | cargo { 36 | local { 37 | extraClasspath = configurations.extraClasspath 38 | } 39 | 40 | deployable { 41 | file = configurations.war 42 | context = '$WAR_CONTEXT' 43 | } 44 | } 45 | 46 | task writeContextXml { 47 | def contextXml = new File(buildDir, "context.xml") 48 | 49 | outputs.file(contextXml) 50 | 51 | doLast { 52 | contextXml.withWriter { writer -> 53 | new MarkupBuilder(writer).Context { 54 | Resource( 55 | name: "$TEXT_RESOURCE_NAME", 56 | factory: "TextResourceFactory", 57 | value: "$TEXT_RESOURCE_VALUE" 58 | ) 59 | } 60 | } 61 | } 62 | } 63 | """ 64 | } 65 | 66 | void cleanup() { 67 | runBuild "cargoStopLocal" 68 | } 69 | 70 | void "can use a file collection as a config files source"() { 71 | given: 72 | buildScript << """ 73 | cargo { 74 | local { 75 | configFile { 76 | files = writeContextXml.outputs.files 77 | toDir = "conf" 78 | } 79 | } 80 | } 81 | """ 82 | 83 | when: 84 | runBuild "cargoStartLocal" 85 | 86 | then: 87 | requestTextResourceValue(TEXT_RESOURCE_NAME) == TEXT_RESOURCE_VALUE 88 | } 89 | 90 | String requestTextResourceValue(String resourceName) { 91 | HttpBuilder.configure { 92 | request.uri = "http://localhost:8080/$WAR_CONTEXT" 93 | request.uri.query = [resourceName: resourceName] 94 | }.get() 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/DefaultDeployableSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.util.fixture.HelloWorldServletWarFixture 4 | 5 | class DefaultDeployableSpec extends AbstractIntegrationSpec { 6 | 7 | HelloWorldServletWarFixture servletWarFixture 8 | 9 | void setup() { 10 | servletWarFixture = new HelloWorldServletWarFixture(testProjectDir.root, ":") 11 | configureCargoInstaller() 12 | } 13 | 14 | void cleanup() { 15 | runBuild "cargoStopLocal" 16 | } 17 | 18 | def "project artifact is configured as a deployable including task dependencies"() { 19 | given: 20 | buildScript << """ 21 | cargo { 22 | deployable { 23 | context = '$WAR_CONTEXT' 24 | } 25 | } 26 | """ 27 | 28 | when: 29 | runBuild "cargoStartLocal" 30 | 31 | then: 32 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 33 | } 34 | 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/DeployableIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.util.fixture.HelloWorldServletWarFixture 4 | 5 | class DeployableIntegrationSpec extends AbstractIntegrationSpec { 6 | 7 | HelloWorldServletWarFixture servletWarFixture 8 | 9 | void setup() { 10 | servletWarFixture = new HelloWorldServletWarFixture(testProjectDir.root, ":$WAR_CONTEXT") 11 | configureCargoInstaller() 12 | buildScript << """ 13 | import com.bmuschko.gradle.cargo.tasks.local.LocalCargoContainerTask 14 | 15 | repositories { 16 | mavenCentral() 17 | } 18 | 19 | configurations { 20 | war 21 | } 22 | 23 | dependencies { 24 | war project(path: '${servletWarFixture.projectPath}', configuration: 'archives') 25 | } 26 | """ 27 | } 28 | 29 | void cleanup() { 30 | runBuild "cargoStopLocal" 31 | } 32 | 33 | def "can use a file as a deployable"() { 34 | given: 35 | buildScript << """ 36 | task configureCargoDeployable { 37 | inputs.files(configurations.war) 38 | 39 | doLast { 40 | cargo { 41 | deployable { 42 | file = configurations.war.singleFile 43 | context = '$WAR_CONTEXT' 44 | } 45 | } 46 | } 47 | } 48 | 49 | tasks.withType(LocalCargoContainerTask) { 50 | dependsOn configureCargoDeployable 51 | } 52 | """ 53 | 54 | when: 55 | runBuild "cargoStartLocal" 56 | 57 | then: 58 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 59 | } 60 | 61 | def "can use a file collection as a deployable"() { 62 | given: 63 | buildScript << """ 64 | cargo { 65 | deployable { 66 | file = configurations.war 67 | context = '$WAR_CONTEXT' 68 | } 69 | } 70 | """ 71 | 72 | when: 73 | runBuild "cargoStartLocal" 74 | 75 | then: 76 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 77 | } 78 | 79 | def "can deploy without context parameter"() { 80 | given: 81 | buildScript << """ 82 | cargo { 83 | deployable { 84 | file = configurations.war 85 | } 86 | } 87 | """ 88 | 89 | when: 90 | runBuild "cargoStartLocal" 91 | 92 | then: 93 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/InstallerUrlIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.util.fixture.HelloWorldServletWarFixture 4 | 5 | class InstallerUrlIntegrationSpec extends AbstractIntegrationSpec { 6 | 7 | HelloWorldServletWarFixture servletWarFixture 8 | 9 | void setup() { 10 | servletWarFixture = new HelloWorldServletWarFixture(testProjectDir.root, ":$WAR_CONTEXT") 11 | buildScript << """ 12 | import com.bmuschko.gradle.cargo.tasks.local.LocalCargoContainerTask 13 | 14 | repositories { 15 | mavenCentral() 16 | } 17 | 18 | configurations { 19 | war 20 | } 21 | 22 | dependencies { 23 | war project(path: '${servletWarFixture.projectPath}', configuration: 'archives') 24 | } 25 | 26 | cargo { 27 | containerId = "tomcat9x" 28 | 29 | local { 30 | installer { 31 | downloadDir = file("\$buildDir/download") 32 | extractDir = file("\$buildDir/extract") 33 | } 34 | } 35 | } 36 | 37 | cargo { 38 | deployable { 39 | file = configurations.war 40 | context = '$WAR_CONTEXT' 41 | } 42 | } 43 | """ 44 | } 45 | 46 | void cleanup() { 47 | runBuild "cargoStopLocal" 48 | } 49 | 50 | void "url can be used to configure installer source"() { 51 | given: 52 | buildScript << """ 53 | cargo { 54 | local { 55 | installer { 56 | installUrl = "https://repo1.maven.org/maven2/org/apache/tomcat/tomcat/9.0.14/tomcat-9.0.14.zip" 57 | } 58 | } 59 | } 60 | """ 61 | when: 62 | runBuild "cargoStartLocal" 63 | 64 | then: 65 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 66 | } 67 | 68 | void "configuration can be used to configure installer source"() { 69 | given: 70 | buildScript << """ 71 | configurations { 72 | tomcat 73 | } 74 | 75 | dependencies { 76 | tomcat "org.apache.tomcat:tomcat:9.0.14@zip" 77 | } 78 | 79 | cargo { 80 | local { 81 | installer { 82 | installConfiguration = configurations.tomcat 83 | } 84 | } 85 | } 86 | """ 87 | when: 88 | runBuild "cargoStartLocal" 89 | 90 | then: 91 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/LocallyInstalledContainerIntegrationSpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.util.fixture.HelloWorldServletWarFixture 4 | 5 | class LocallyInstalledContainerIntegrationSpec extends AbstractIntegrationSpec{ 6 | 7 | HelloWorldServletWarFixture servletWarFixture 8 | 9 | def setup() { 10 | servletWarFixture = new HelloWorldServletWarFixture(testProjectDir.root, ":$WAR_CONTEXT") 11 | } 12 | 13 | void cleanup() { 14 | runBuild "cargoStopLocal" 15 | } 16 | 17 | def "can use a locally installed container"() { 18 | buildScript << """ 19 | repositories { 20 | mavenCentral() 21 | } 22 | 23 | configurations { 24 | tomcat 25 | war 26 | } 27 | 28 | dependencies { 29 | tomcat "org.apache.tomcat:tomcat:9.0.14@zip" 30 | war project(path: '${servletWarFixture.projectPath}', configuration: 'archives') 31 | } 32 | 33 | task installTomcat(type: Copy) { 34 | from { zipTree(configurations.tomcat.singleFile) } 35 | into "\$buildDir/tomcat-home" 36 | eachFile { FileCopyDetails fileCopyDetails -> 37 | def original = fileCopyDetails.relativePath 38 | //strip the top level directory 39 | fileCopyDetails.relativePath = new RelativePath(original.file, *original.segments[1..-1]) 40 | } 41 | } 42 | 43 | cargo { 44 | containerId = "tomcat9x" 45 | 46 | deployable { 47 | file = configurations.war 48 | context = '$WAR_CONTEXT' 49 | } 50 | 51 | local { 52 | homeDir = installTomcat.outputs.files.singleFile 53 | } 54 | } 55 | 56 | cargoStartLocal.dependsOn installTomcat 57 | """ 58 | 59 | when: 60 | runBuild "cargoStartLocal" 61 | 62 | then: 63 | requestServletResponseText() == HelloWorldServletWarFixture.RESPONSE_TEXT 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/fixture/AbstractWarFixture.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util.fixture 2 | 3 | import groovy.transform.InheritConstructors 4 | 5 | @InheritConstructors 6 | abstract class AbstractWarFixture extends ProjectFixture { 7 | 8 | private final static String WEB_XML_FILENAME = 'web.xml' 9 | 10 | abstract String getServletClassName() 11 | abstract String getServletClassSource() 12 | 13 | protected void configure() { 14 | super.configure() 15 | writeWebXml() 16 | writeBuild() 17 | writeSources() 18 | } 19 | 20 | protected void writeWebXml() { 21 | new File(projectDir, WEB_XML_FILENAME) << """\ 22 | | 23 | | 24 | | 25 | | $servletClassName 26 | | $servletClassName 27 | | 28 | | 29 | | $servletClassName 30 | | / 31 | | 32 | | 33 | """.stripMargin() 34 | } 35 | 36 | protected void writeBuild() { 37 | new File(projectDir, "build.gradle") << """ 38 | apply plugin: 'war' 39 | 40 | repositories { 41 | mavenCentral() 42 | } 43 | 44 | dependencies { 45 | providedCompile "javax.servlet:javax.servlet-api:4.0.1" 46 | } 47 | 48 | war { 49 | webXml = file("$WEB_XML_FILENAME") 50 | } 51 | """ 52 | } 53 | 54 | protected void writeSources() { 55 | def sourcesDirectory = new File(projectDir, 'src/main/java') 56 | sourcesDirectory.mkdirs() 57 | 58 | new File(sourcesDirectory, "${servletClassName}.java") << servletClassSource 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/fixture/HelloWorldServletWarFixture.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util.fixture 2 | 3 | import groovy.transform.InheritConstructors 4 | 5 | @InheritConstructors 6 | class HelloWorldServletWarFixture extends AbstractWarFixture { 7 | 8 | public final static String RESPONSE_TEXT = 'Hello World!' 9 | 10 | String getServletClassName() { 11 | "HelloWorld" 12 | } 13 | 14 | String getServletClassSource() { 15 | """ 16 | import javax.servlet.http.HttpServlet; 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.io.IOException; 20 | 21 | public class $servletClassName extends HttpServlet { 22 | @Override 23 | protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 24 | response.setContentType("text/plain"); 25 | response.getWriter().print("$RESPONSE_TEXT"); 26 | } 27 | } 28 | """ 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/fixture/ProjectFixture.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util.fixture 2 | 3 | class ProjectFixture { 4 | 5 | protected final File rootProjectDir 6 | protected final List projectPathSegments 7 | 8 | ProjectFixture(File rootProjectDir, String projectPath) { 9 | this.rootProjectDir = rootProjectDir 10 | this.projectPathSegments = projectPath.tokenize(":").findAll() 11 | configure() 12 | } 13 | 14 | protected void configure() { 15 | addProjectToSettings() 16 | projectDir.mkdirs() 17 | } 18 | 19 | protected void addProjectToSettings() { 20 | new File(rootProjectDir, "settings.gradle") << """ 21 | include '$projectPath' 22 | """ 23 | } 24 | 25 | protected File getProjectDir() { 26 | projectPathSegments ? new File(rootProjectDir, projectPathSegments.join('/')) : rootProjectDir 27 | } 28 | 29 | String getProjectPath() { 30 | ":${projectPathSegments.join(":")}" 31 | } 32 | 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/fixture/TextResourceFactoryJarFixture.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util.fixture 2 | 3 | import groovy.transform.InheritConstructors 4 | 5 | @InheritConstructors 6 | class TextResourceFactoryJarFixture extends ProjectFixture { 7 | 8 | private static final String CLASS_NAME = "TextResourceFactory" 9 | 10 | protected void configure() { 11 | super.configure() 12 | writeBuild() 13 | writeSources() 14 | } 15 | 16 | private void writeBuild() { 17 | new File(projectDir, "build.gradle") << """ 18 | apply plugin: 'java' 19 | """ 20 | } 21 | 22 | private void writeSources() { 23 | def sourcesDirectory = new File(projectDir, 'src/main/java') 24 | sourcesDirectory.mkdirs() 25 | 26 | new File(sourcesDirectory, "${CLASS_NAME}.java") << """ 27 | import javax.naming.Context; 28 | import javax.naming.Name; 29 | import javax.naming.Reference; 30 | import javax.naming.spi.ObjectFactory; 31 | import java.util.Hashtable; 32 | 33 | public class $CLASS_NAME implements ObjectFactory { 34 | @Override 35 | public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) { 36 | Reference reference = (Reference) obj; 37 | return reference.get("value").getContent().toString(); 38 | } 39 | } 40 | """ 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/integrationTest/groovy/com/bmuschko/gradle/cargo/util/fixture/TextResourceLoaderServletWarFixture.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util.fixture 2 | 3 | import groovy.transform.InheritConstructors 4 | 5 | @InheritConstructors 6 | class TextResourceLoaderServletWarFixture extends AbstractWarFixture { 7 | 8 | String getServletClassName() { 9 | "TextResourceLoader" 10 | } 11 | 12 | String getServletClassSource() { 13 | """ 14 | import javax.naming.Context; 15 | import javax.naming.InitialContext; 16 | import javax.naming.NamingException; 17 | import javax.servlet.http.HttpServlet; 18 | import javax.servlet.http.HttpServletRequest; 19 | import javax.servlet.http.HttpServletResponse; 20 | import java.io.IOException; 21 | 22 | public class $servletClassName extends HttpServlet { 23 | 24 | @Override 25 | protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { 26 | String resourceName = request.getParameter("resourceName"); 27 | 28 | response.setContentType("text/plain"); 29 | response.getWriter().print(lookupTextResource(resourceName)); 30 | } 31 | 32 | private String lookupTextResource(String name) { 33 | try { 34 | Context context = (Context) new InitialContext().lookup("java:comp/env"); 35 | return (String) context.lookup(name); 36 | } catch (NamingException e) { 37 | throw new RuntimeException(e); 38 | } 39 | } 40 | } 41 | """ 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/CargoBasePlugin.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo 17 | 18 | import com.bmuschko.gradle.cargo.convention.Deployable 19 | import com.bmuschko.gradle.cargo.tasks.AbstractCargoContainerTask 20 | import com.bmuschko.gradle.cargo.tasks.daemon.CargoDaemon 21 | import com.bmuschko.gradle.cargo.util.ProjectInfoHelper 22 | import org.gradle.api.Plugin 23 | import org.gradle.api.Project 24 | import org.gradle.api.Task 25 | 26 | /** 27 | *

A {@link org.gradle.api.Plugin} that provides custom task types for deploying WAR/EAR files to local and remote web containers. 28 | * The plugin pre-configures the dependencies on the external Cargo libraries. You will still need to define at least 29 | * one repository that the plugin can use to look for the libraries.

30 | */ 31 | class CargoBasePlugin implements Plugin { 32 | static final String CONFIGURATION_NAME = 'cargo' 33 | static final String DAEMON_CONFIGURATION_NAME = 'cargoDaemon' 34 | static final String CARGO_DEFAULT_VERSION = '1.9.10' 35 | 36 | @Override 37 | void apply(Project project) { 38 | project.configurations.create(CONFIGURATION_NAME) 39 | .setVisible(false) 40 | .setTransitive(true) 41 | .setDescription('The Cargo Ant libraries to be used for this project.') 42 | 43 | project.configurations.create(DAEMON_CONFIGURATION_NAME) 44 | .setVisible(false) 45 | .setTransitive(true) 46 | .setDescription('The Cargo daemon client libraries to be used for this project.') 47 | 48 | configureAbstractContainerTask(project) 49 | } 50 | 51 | private void configureAbstractContainerTask(Project project) { 52 | project.tasks.withType(AbstractCargoContainerTask) { 53 | conventionMapping.map('classpath') { 54 | def config = project.configurations[CONFIGURATION_NAME] 55 | 56 | if(config.dependencies.empty) { 57 | project.dependencies { 58 | cargo "org.codehaus.cargo:cargo-core-uberjar:$CARGO_DEFAULT_VERSION", 59 | "org.codehaus.cargo:cargo-licensed-dtds:$CARGO_DEFAULT_VERSION", 60 | "org.codehaus.cargo:cargo-ant:$CARGO_DEFAULT_VERSION" 61 | } 62 | } 63 | 64 | config 65 | } 66 | 67 | conventionMapping.map('deployables') { resolveDeployables(project) } 68 | } 69 | 70 | project.tasks.withType(CargoDaemon) { 71 | conventionMapping.map('classpath') { 72 | def config = project.configurations[DAEMON_CONFIGURATION_NAME] 73 | 74 | if(config.dependencies.empty) { 75 | project.dependencies { 76 | cargoDaemon "org.codehaus.cargo:cargo-daemon-client:$CARGO_DEFAULT_VERSION" 77 | } 78 | } 79 | 80 | config 81 | } 82 | } 83 | } 84 | 85 | private List resolveDeployables(Project project) { 86 | def deployables = [] 87 | 88 | Task projectDeployable = ProjectInfoHelper.getProjectDeployableTask(project) 89 | 90 | if(projectDeployable) { 91 | deployables << new Deployable(files: projectDeployable.outputs.files) 92 | } 93 | 94 | deployables 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/CargoPlugin.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo 17 | 18 | import com.bmuschko.gradle.cargo.convention.CargoPluginExtension 19 | import com.bmuschko.gradle.cargo.convention.Deployable 20 | import com.bmuschko.gradle.cargo.tasks.AbstractCargoContainerTask 21 | import com.bmuschko.gradle.cargo.tasks.local.* 22 | import com.bmuschko.gradle.cargo.tasks.remote.CargoDeployRemote 23 | import com.bmuschko.gradle.cargo.tasks.remote.CargoRedeployRemote 24 | import com.bmuschko.gradle.cargo.tasks.remote.CargoUndeployRemote 25 | import com.bmuschko.gradle.cargo.tasks.remote.RemoteCargoContainerTask 26 | import com.bmuschko.gradle.cargo.util.ProjectInfoHelper 27 | import org.gradle.api.InvalidUserDataException 28 | import org.gradle.api.Plugin 29 | import org.gradle.api.Project 30 | import org.gradle.api.Task 31 | import org.gradle.api.execution.TaskExecutionGraph 32 | 33 | /** 34 | *

A {@link org.gradle.api.Plugin} that provides pre-configured tasks for deploying WAR/EAR files to local and remote web containers.

35 | */ 36 | class CargoPlugin implements Plugin { 37 | static final String EXTENSION_NAME = 'cargo' 38 | 39 | @Override 40 | void apply(Project project) { 41 | project.plugins.apply(CargoBasePlugin) 42 | 43 | CargoPluginExtension cargoPluginExtension = project.extensions.create(EXTENSION_NAME, CargoPluginExtension, project) 44 | 45 | configureAbstractContainerTask(project, cargoPluginExtension) 46 | configureRemoteContainerTasks(project, cargoPluginExtension) 47 | configureLocalContainerTasks(project, cargoPluginExtension) 48 | checkValidContainerId(project, cargoPluginExtension) 49 | } 50 | 51 | private void configureAbstractContainerTask(Project project, CargoPluginExtension cargoPluginExtension) { 52 | project.tasks.withType(AbstractCargoContainerTask) { 53 | conventionMapping.map('containerId') { cargoPluginExtension.containerId } 54 | conventionMapping.map('port') { cargoPluginExtension.port } 55 | conventionMapping.map('deployables') { resolveDeployables(project, cargoPluginExtension) } 56 | } 57 | } 58 | 59 | private void configureLocalContainerConventionMapping(Project project, CargoPluginExtension cargoPluginExtension) { 60 | project.tasks.withType(LocalCargoContainerTask) { 61 | conventionMapping.map('jvmArgs') { cargoPluginExtension.local.jvmArgs } 62 | conventionMapping.map('logLevel') { cargoPluginExtension.local.logLevel } 63 | conventionMapping.map('homeDir') { cargoPluginExtension.local.homeDir } 64 | conventionMapping.map('configType') { cargoPluginExtension.local.configType } 65 | conventionMapping.map('configHomeDir') { cargoPluginExtension.local.configHomeDir } 66 | conventionMapping.map('outputFile') { cargoPluginExtension.local.outputFile } 67 | conventionMapping.map('logFile') { cargoPluginExtension.local.logFile } 68 | conventionMapping.map('rmiPort') { cargoPluginExtension.local.rmiPort } 69 | conventionMapping.map('startStopTimeout') { cargoPluginExtension.startStopTimeout } 70 | conventionMapping.map('zipUrlInstaller') { cargoPluginExtension.local.zipUrlInstaller } 71 | conventionMapping.map('configFiles') { cargoPluginExtension.local.configFiles } 72 | conventionMapping.map('files') { cargoPluginExtension.local.files } 73 | conventionMapping.map('containerProperties') { cargoPluginExtension.local.containerProperties.properties } 74 | conventionMapping.map('systemProperties') { cargoPluginExtension.local.systemProperties.properties } 75 | conventionMapping.map('extraClasspath') { cargoPluginExtension.local.extraClasspath } 76 | conventionMapping.map('sharedClasspath') { cargoPluginExtension.local.sharedClasspath } 77 | } 78 | } 79 | 80 | private void setRemoteContainerConventionMapping(Project project, CargoPluginExtension cargoPluginExtension) { 81 | project.tasks.withType(RemoteCargoContainerTask) { 82 | conventionMapping.map('protocol') { cargoPluginExtension.remote.protocol } 83 | conventionMapping.map('hostname') { cargoPluginExtension.remote.hostname } 84 | conventionMapping.map('username') { cargoPluginExtension.remote.username } 85 | conventionMapping.map('password') { cargoPluginExtension.remote.password } 86 | conventionMapping.map('containerProperties') { cargoPluginExtension.remote.containerProperties.properties } 87 | } 88 | } 89 | 90 | private void configureRemoteContainerTasks(Project project, CargoPluginExtension cargoPluginExtension) { 91 | setRemoteContainerConventionMapping(project, cargoPluginExtension) 92 | project.task('cargoDeployRemote', type: CargoDeployRemote) 93 | project.task('cargoUndeployRemote', type: CargoUndeployRemote) 94 | project.task('cargoRedeployRemote', type: CargoRedeployRemote) 95 | } 96 | 97 | private void configureLocalContainerTasks(Project project, CargoPluginExtension cargoPluginExtension) { 98 | configureLocalContainerConventionMapping(project, cargoPluginExtension) 99 | project.task('cargoRunLocal', type: CargoRunLocal) 100 | project.task('cargoStartLocal', type: CargoStartLocal) 101 | project.task('cargoStopLocal', type: CargoStopLocal) 102 | project.task('cargoRedeployLocal', type: CargoRedeployLocal) 103 | project.task('cargoConfigureLocal', type: CargoConfigureLocal) 104 | } 105 | 106 | private void checkValidContainerId(Project project, CargoPluginExtension cargoPluginExtension) { 107 | project.gradle.taskGraph.whenReady { TaskExecutionGraph taskGraph -> 108 | if(containsCargoTask(taskGraph)) { 109 | if(!cargoPluginExtension.containerId) { 110 | throw new InvalidUserDataException('Container ID was not defined.') 111 | } 112 | } 113 | } 114 | } 115 | 116 | private boolean containsCargoTask(TaskExecutionGraph taskGraph) { 117 | taskGraph.allTasks.findAll { task -> task instanceof AbstractCargoContainerTask }.size() > 0 118 | } 119 | 120 | private List resolveDeployables(Project project, CargoPluginExtension cargoConvention) { 121 | def deployables = [] 122 | 123 | Task projectDeployable = ProjectInfoHelper.getProjectDeployableTask(project) 124 | 125 | if (cargoConvention.deployables.size() == 0) { 126 | if (projectDeployable) { 127 | deployables << new Deployable(files: projectDeployable.outputs.files) 128 | } 129 | } else { 130 | cargoConvention.deployables.each { deployable -> 131 | if (!deployable.files && projectDeployable) { 132 | deployable.files = projectDeployable.outputs.files 133 | } 134 | 135 | deployables << deployable 136 | } 137 | } 138 | 139 | deployables 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/DeployableType.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo 17 | 18 | import groovy.util.logging.Slf4j 19 | 20 | /** 21 | * Type of deployable. 22 | */ 23 | @Slf4j 24 | enum DeployableType { 25 | WAR('war'), EAR('ear'), EXPLODED('war') 26 | 27 | final String type 28 | 29 | private DeployableType(String type) { 30 | this.type = type 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/DeployableTypeFactory.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo 2 | 3 | import com.bmuschko.gradle.cargo.util.DefaultFileUtil 4 | import com.bmuschko.gradle.cargo.util.FileUtil 5 | 6 | @Singleton 7 | class DeployableTypeFactory { 8 | FileUtil fileUtil = new DefaultFileUtil() 9 | 10 | DeployableType getType(File file) { 11 | String filenameExtension = fileUtil.getExtension(file) 12 | 13 | switch(filenameExtension) { 14 | case 'war': return DeployableType.WAR 15 | case 'ear': return DeployableType.EAR 16 | case '': return DeployableType.EXPLODED 17 | default: throw new IllegalArgumentException("Unknown deployable type for file extension '$filenameExtension'") 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/BinFile.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | /** 19 | * Defines a binary file to be used in a local container. 20 | */ 21 | class BinFile implements Serializable { 22 | 23 | /** 24 | * This specifies the path to the file that should be used. 25 | * Can also specify a directory path if a whole directory needs to be copied over. 26 | */ 27 | File file 28 | 29 | /** 30 | * This specified the name the directory that the file should be copied to relative to the configurations home. 31 | */ 32 | String toDir 33 | 34 | @Override 35 | boolean equals(o) { 36 | if (this.is(o)) return true 37 | if (getClass() != o.class) return false 38 | 39 | BinFile binFile = (BinFile) o 40 | 41 | if (file != binFile.file) return false 42 | if (toDir != binFile.toDir) return false 43 | 44 | return true 45 | } 46 | 47 | @Override 48 | int hashCode() { 49 | int result 50 | result = (file != null ? file.hashCode() : 0) 51 | result = 31 * result + (toDir != null ? toDir.hashCode() : 0) 52 | return result 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/CargoLocalTaskConvention.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | import org.gradle.api.file.FileCollection 19 | 20 | /** 21 | * Defines Cargo local task convention. 22 | */ 23 | class CargoLocalTaskConvention { 24 | 25 | String jvmArgs 26 | String logLevel 27 | File homeDir 28 | String configType 29 | File configHomeDir 30 | File outputFile 31 | File logFile 32 | Integer rmiPort 33 | ZipUrlInstaller zipUrlInstaller = new ZipUrlInstaller() 34 | def configFiles = [] 35 | def files = [] 36 | ContainerProperties containerProperties = new ContainerProperties() 37 | SystemProperties systemProperties = new SystemProperties() 38 | FileCollection extraClasspath 39 | FileCollection sharedClasspath 40 | 41 | def installer(Closure closure) { 42 | closure.resolveStrategy = Closure.DELEGATE_FIRST 43 | closure.delegate = zipUrlInstaller 44 | closure() 45 | } 46 | 47 | def configFile(Closure closure) { 48 | closure.resolveStrategy = Closure.DELEGATE_FIRST 49 | ConfigFile configFile = new ConfigFile() 50 | closure.delegate = configFile 51 | configFiles << configFile 52 | closure() 53 | } 54 | 55 | def file(Closure closure) { 56 | closure.resolveStrategy = Closure.DELEGATE_FIRST 57 | BinFile file = new BinFile() 58 | closure.delegate = file 59 | files << file 60 | closure() 61 | } 62 | 63 | def containerProperties(Closure closure) { 64 | closure.resolveStrategy = Closure.DELEGATE_FIRST 65 | closure.delegate = containerProperties 66 | closure() 67 | } 68 | 69 | def systemProperties(Closure closure) { 70 | closure.resolveStrategy = Closure.DELEGATE_FIRST 71 | closure.delegate = systemProperties 72 | closure() 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/CargoPluginExtension.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | import org.gradle.api.Project 19 | 20 | /** 21 | * Defines Cargo extension. 22 | */ 23 | class CargoPluginExtension { 24 | 25 | private final Project project 26 | 27 | String containerId 28 | Integer port = 8080 29 | Integer startStopTimeout 30 | def deployables = [] 31 | CargoRemoteTaskConvention remote = new CargoRemoteTaskConvention() 32 | CargoLocalTaskConvention local = new CargoLocalTaskConvention() 33 | 34 | CargoPluginExtension(Project project) { 35 | this.project = project 36 | } 37 | 38 | def cargo(Closure closure) { 39 | closure.delegate = this 40 | closure() 41 | } 42 | 43 | def deployable(Closure closure) { 44 | closure.resolveStrategy = Closure.DELEGATE_FIRST 45 | def deployableClosureDelegate = new DeployableClosureDelegate(project) 46 | closure.delegate = deployableClosureDelegate 47 | deployables << deployableClosureDelegate.deployable 48 | closure() 49 | } 50 | 51 | def remote(Closure closure) { 52 | closure.resolveStrategy = Closure.DELEGATE_FIRST 53 | closure.delegate = remote 54 | closure() 55 | } 56 | 57 | def local(Closure closure) { 58 | closure.resolveStrategy = Closure.DELEGATE_FIRST 59 | closure.delegate = local 60 | closure() 61 | } 62 | 63 | private static class DeployableClosureDelegate { 64 | 65 | @Delegate 66 | final Deployable deployable = new Deployable() 67 | private final Project project 68 | 69 | DeployableClosureDelegate(Project project) { 70 | this.project = project 71 | } 72 | 73 | void setFile(Object file) { 74 | deployable.files = project.files(file) 75 | } 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/CargoRemoteTaskConvention.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | /** 19 | * Defines Cargo remote task convention. 20 | */ 21 | class CargoRemoteTaskConvention { 22 | String protocol = 'http' 23 | String hostname 24 | String username 25 | String password 26 | ContainerProperties containerProperties = new ContainerProperties() 27 | 28 | def containerProperties(Closure closure) { 29 | closure.resolveStrategy = Closure.DELEGATE_FIRST 30 | closure.delegate = containerProperties 31 | closure() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/ConfigFile.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | import org.gradle.api.file.FileCollection 19 | import org.gradle.api.tasks.Input 20 | import org.gradle.api.tasks.InputFiles 21 | 22 | /** 23 | * Defines ConfigFile convention. 24 | */ 25 | class ConfigFile { 26 | 27 | /** 28 | * This specifies the files that should be copied over. 29 | * Can also specify directories if whole directories need to be copied over. 30 | */ 31 | @InputFiles 32 | FileCollection files 33 | 34 | /** 35 | * This specified the name the directory that the file should be copied to relative to the configurations home. 36 | */ 37 | @Input 38 | String toDir 39 | } 40 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/ContainerProperties.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | /** 19 | * Container-specific properties. 20 | */ 21 | class ContainerProperties { 22 | Map properties = [:] 23 | 24 | void property(String key, Object value) { 25 | properties[key] = value 26 | } 27 | 28 | void properties(Map properties) { 29 | this.properties.putAll(properties) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/Deployable.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | 19 | import org.gradle.api.file.FileCollection 20 | import org.gradle.api.tasks.Input 21 | import org.gradle.api.tasks.InputFiles 22 | import org.gradle.api.tasks.Internal 23 | import org.gradle.api.tasks.Optional 24 | 25 | /** 26 | * Defines Deployable convention. 27 | */ 28 | class Deployable implements Serializable { 29 | 30 | @InputFiles 31 | FileCollection files 32 | 33 | @Input 34 | @Optional 35 | String context 36 | 37 | @Internal 38 | File getFile() { 39 | files?.singleFile 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/SystemProperties.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | /** 19 | * Properties that can be passed on to the local container. 20 | */ 21 | class SystemProperties { 22 | Map properties = [:] 23 | 24 | void property(String key, Object value) { 25 | properties[key] = value 26 | } 27 | 28 | void properties(Map properties) { 29 | this.properties.putAll(properties) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/convention/ZipUrlInstaller.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.convention 17 | 18 | import org.gradle.api.file.FileCollection 19 | import org.gradle.api.tasks.Input 20 | import org.gradle.api.tasks.InputFiles 21 | import org.gradle.api.tasks.Internal 22 | import org.gradle.api.tasks.Optional 23 | import org.gradle.api.tasks.OutputDirectory 24 | 25 | import java.util.function.Supplier 26 | 27 | /** 28 | * ZIP URL installer properties. 29 | * 30 | * @see Installer documentation 31 | */ 32 | class ZipUrlInstaller { 33 | 34 | private Supplier installUrlSupplier = { null } 35 | 36 | @Input 37 | @Optional 38 | String installUrl 39 | 40 | @InputFiles 41 | @Optional 42 | FileCollection installConfiguration 43 | 44 | @OutputDirectory 45 | @Optional 46 | File downloadDir 47 | 48 | @OutputDirectory 49 | @Optional 50 | File extractDir 51 | 52 | @Internal 53 | String getConfiguredInstallUrl() { 54 | installUrlSupplier.get() 55 | } 56 | 57 | @Internal 58 | boolean isValid() { 59 | configuredInstallUrl && downloadDir && extractDir 60 | } 61 | 62 | void setInstallUrl(String installUrl) { 63 | this.installUrl = installUrl 64 | this.installConfiguration = null 65 | installUrlSupplier = { installUrl } 66 | } 67 | 68 | void setInstallConfiguration(FileCollection configuration) { 69 | this.installUrl = null 70 | this.installConfiguration = configuration 71 | installUrlSupplier = { configuration.singleFile.toURI().toURL().toString() } 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/AbstractCargoContainerTask.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks 17 | 18 | import com.bmuschko.gradle.cargo.convention.Deployable 19 | import com.bmuschko.gradle.cargo.util.LoggingHandler 20 | import org.gradle.api.DefaultTask 21 | import org.gradle.api.InvalidUserDataException 22 | import org.gradle.api.file.FileCollection 23 | import org.gradle.api.tasks.Input 24 | import org.gradle.api.tasks.InputFiles 25 | import org.gradle.api.tasks.Nested 26 | import org.gradle.api.tasks.Optional 27 | import org.gradle.api.tasks.TaskAction 28 | 29 | /** 30 | * Abstract container task. 31 | */ 32 | abstract class AbstractCargoContainerTask extends DefaultTask { 33 | static final String CARGO_TASK_GROUP = 'deployment' 34 | static final CARGO_TASKS = 'cargo.tasks' 35 | static final CARGO_SERVLET_PORT = 'cargo.servlet.port' 36 | static final CARGO_CONTEXT = 'context' 37 | 38 | /** 39 | * The Cargo container identifier. 40 | */ 41 | @Input 42 | String containerId 43 | 44 | /** 45 | * The action to run for the container. 46 | */ 47 | @Input 48 | String action 49 | 50 | /** 51 | * Port on which the Servlet/JSP container listens to. 52 | */ 53 | @Input 54 | Integer port = 8080 55 | 56 | @Input 57 | @Optional 58 | String context 59 | 60 | /** 61 | * The classpath containing the Cargo Ant tasks. 62 | */ 63 | @InputFiles 64 | FileCollection classpath 65 | 66 | /** 67 | * The list of deployable artifacts. 68 | */ 69 | @Nested 70 | List deployables = [] 71 | 72 | /** 73 | * Container properties. 74 | */ 75 | @Input 76 | Map containerProperties = [:] 77 | 78 | AbstractCargoContainerTask() { 79 | group = CARGO_TASK_GROUP 80 | 81 | // No matter what the inputs and outputs make sure that run tasks are never up-to-date 82 | outputs.upToDateWhen { 83 | false 84 | } 85 | } 86 | 87 | @TaskAction 88 | void start() { 89 | validateConfiguration() 90 | 91 | LoggingHandler.withAntLoggingListener(ant) { 92 | runAction() 93 | } 94 | } 95 | 96 | void validateConfiguration() { 97 | if(!getDeployables()) { 98 | throw new InvalidUserDataException('No deployables assigned!') 99 | } 100 | } 101 | 102 | protected void setContainerSpecificProperties() { 103 | logger.info "Container properties = ${getContainerProperties()}" 104 | 105 | getContainerProperties().each { key, value -> 106 | ant.property(name: key, value: value) 107 | } 108 | } 109 | 110 | protected abstract void runAction() 111 | } 112 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/daemon/CargoDaemon.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.daemon 17 | 18 | import org.gradle.api.DefaultTask 19 | import org.gradle.api.UncheckedIOException 20 | import org.gradle.api.file.FileCollection 21 | import org.gradle.api.tasks.Input 22 | import org.gradle.api.tasks.InputFiles 23 | import org.gradle.api.tasks.Optional 24 | import org.gradle.api.tasks.TaskAction 25 | 26 | import java.lang.reflect.Constructor 27 | 28 | abstract class CargoDaemon extends DefaultTask { 29 | @InputFiles 30 | FileCollection classpath 31 | 32 | /** 33 | * Protocol on which the container is listening to. Defaults to 'http'. 34 | */ 35 | @Input 36 | String protocol = 'http' 37 | 38 | /** 39 | * Host name on which the container listens to. Defaults to 'localhost'. 40 | */ 41 | @Input 42 | String hostname = 'localhost' 43 | 44 | /** 45 | * Port on which the daemon listens to. 46 | */ 47 | @Input 48 | Integer port = 18000 49 | 50 | /** 51 | * Username to use to authenticate against a remote container. 52 | */ 53 | @Input 54 | @Optional 55 | String username 56 | 57 | /** 58 | * Password to use to authenticate against a remote container. 59 | */ 60 | @Input 61 | @Optional 62 | String password 63 | 64 | /** 65 | * The handle ID identifying a specific container configuration. 66 | */ 67 | @Input 68 | String handleId 69 | 70 | @TaskAction 71 | void messageDaemon() { 72 | withCargoDaemonClassLoader { URLClassLoader classLoader -> 73 | def daemonClient = createDaemonClient(classLoader) 74 | performDaemonOperation(daemonClient, classLoader) 75 | } 76 | } 77 | 78 | def createDaemonClient(URLClassLoader classLoader) { 79 | URL daemonURL = new URL("${getProtocol()}://${getHostname()}:${getPort()}") 80 | Class daemonClientClass = classLoader.loadClass('org.codehaus.cargo.tools.daemon.DaemonClient') 81 | def daemonClient 82 | 83 | if(!isBlank(getUsername()) && !isBlank(getPassword())) { 84 | Constructor daemonClientConstructor = daemonClientClass.getConstructor(URL, String, String) 85 | daemonClient = daemonClientConstructor.newInstance(daemonURL, getUsername(), getPassword()) 86 | } 87 | else if(!isBlank(getUsername())) { 88 | Constructor daemonClientConstructor = daemonClientClass.getConstructor(URL, String) 89 | daemonClient = daemonClientConstructor.newInstance(daemonURL, getUsername()) 90 | } 91 | else { 92 | Constructor daemonClientConstructor = daemonClientClass.getConstructor(URL) 93 | daemonClient = daemonClientConstructor.newInstance(daemonURL) 94 | } 95 | 96 | daemonClient 97 | } 98 | 99 | private boolean isBlank(String parameter) { 100 | parameter != null && parameter.length() > 0 101 | } 102 | 103 | abstract void performDaemonOperation(daemonClient, URLClassLoader classLoader) 104 | 105 | private void withCargoDaemonClassLoader(Closure c) { 106 | ClassLoader originalClassLoader = getClass().classLoader 107 | URLClassLoader cargoDaemonClassloader = createCargoDaemonClassLoader() 108 | 109 | try { 110 | Thread.currentThread().contextClassLoader = cargoDaemonClassloader 111 | c(cargoDaemonClassloader) 112 | } 113 | finally { 114 | Thread.currentThread().contextClassLoader = originalClassLoader 115 | } 116 | } 117 | 118 | private URLClassLoader createCargoDaemonClassLoader() { 119 | new URLClassLoader(toURLArray(getClasspath().files), ClassLoader.systemClassLoader.parent) 120 | } 121 | 122 | private URL[] toURLArray(Collection files) { 123 | List urls = new ArrayList(files.size()) 124 | 125 | for(File file : files) { 126 | try { 127 | urls.add(file.toURI().toURL()) 128 | } 129 | catch(MalformedURLException e) { 130 | throw new UncheckedIOException(e) 131 | } 132 | } 133 | 134 | urls.toArray(new URL[urls.size()]); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/daemon/CargoDaemonStart.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.daemon 17 | 18 | /** 19 | * Starts the configured container via the Cargo daemon process. 20 | */ 21 | class CargoDaemonStart extends CargoDaemon { 22 | @Override 23 | void performDaemonOperation(daemonClient, URLClassLoader classLoader) { 24 | logger.info "Starting container with handle ID '${getHandleId()}' over daemon URL '${daemonClient.getURL()}'." 25 | Class daemonStartClass = classLoader.loadClass('org.codehaus.cargo.tools.daemon.DaemonStart') 26 | def request = daemonStartClass.newInstance() 27 | request.handleId = getHandleId() 28 | daemonClient.start(request) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/daemon/CargoDaemonStop.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.daemon 17 | 18 | /** 19 | * Stops the configured container via the Cargo daemon process. 20 | */ 21 | class CargoDaemonStop extends CargoDaemon { 22 | @Override 23 | void performDaemonOperation(daemonClient, URLClassLoader classLoader) { 24 | logger.info "Stopping container with handle ID '${getHandleId()}' over daemon URL '${daemonClient.getURL()}'." 25 | daemonClient.stop(getHandleId()) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/CargoConfigureLocal.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.tasks.local 2 | 3 | class CargoConfigureLocal extends LocalCargoContainerTask { 4 | CargoConfigureLocal() { 5 | action = 'configure' 6 | description = 'Configures the local container.' 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/CargoRedeployLocal.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.local 17 | 18 | /** 19 | * Redeploys a deployable on local container. 20 | */ 21 | class CargoRedeployLocal extends LocalCargoContainerTask { 22 | CargoRedeployLocal() { 23 | action = 'redeploy' 24 | description = 'Redeploys a deployable on local container.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/CargoRunLocal.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.local 17 | 18 | /** 19 | * Starts the local container, deploys web application to it and wait for the user to press CTRL + C to stop. 20 | */ 21 | class CargoRunLocal extends LocalCargoContainerTask { 22 | CargoRunLocal() { 23 | action = 'run' 24 | description = 'Starts the container, deploys a deployable and waits for the user to press CTRL + C to stop.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/CargoStartLocal.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.local 17 | 18 | /** 19 | * Starts the local container, deploys web application to it and then do other tasks (for example, execute tests). 20 | */ 21 | class CargoStartLocal extends LocalCargoContainerTask { 22 | CargoStartLocal() { 23 | action = 'start' 24 | description = 'Starts the container, deploys a deployable and then do other tasks (for example, execute tests).' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/CargoStopLocal.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.local 17 | 18 | /** 19 | * Stops local container. 20 | */ 21 | class CargoStopLocal extends LocalCargoContainerTask { 22 | CargoStopLocal() { 23 | action = 'stop' 24 | description = 'Stops local container.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/local/LocalCargoContainerTask.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.local 17 | 18 | import com.bmuschko.gradle.cargo.DeployableType 19 | import com.bmuschko.gradle.cargo.DeployableTypeFactory 20 | import com.bmuschko.gradle.cargo.convention.BinFile 21 | import com.bmuschko.gradle.cargo.convention.ConfigFile 22 | import com.bmuschko.gradle.cargo.convention.Deployable 23 | import com.bmuschko.gradle.cargo.convention.ZipUrlInstaller 24 | import com.bmuschko.gradle.cargo.tasks.AbstractCargoContainerTask 25 | import org.gradle.api.InvalidUserDataException 26 | import org.gradle.api.file.FileCollection 27 | import org.gradle.api.tasks.* 28 | 29 | /** 30 | * Deploys WAR to local container. 31 | */ 32 | class LocalCargoContainerTask extends AbstractCargoContainerTask { 33 | /** 34 | * Level representing the quantity of information we wish to log. 35 | */ 36 | @Input 37 | @Optional 38 | String logLevel 39 | 40 | /** 41 | * JVM args to be used when starting/stopping containers. 42 | */ 43 | @Input 44 | @Optional 45 | String jvmArgs 46 | 47 | /** 48 | * The container's installation home directory. 49 | */ 50 | @Internal 51 | @Optional 52 | File homeDir 53 | 54 | /** 55 | * The Cargo configuration home directory. 56 | */ 57 | @Internal 58 | @Optional 59 | File configHomeDir 60 | 61 | /** 62 | * The Cargo configuration type. 63 | */ 64 | @Internal 65 | @Optional 66 | String configType 67 | 68 | /** 69 | * The path to a file where container logs are saved. 70 | */ 71 | @OutputFile 72 | @Optional 73 | File outputFile 74 | 75 | /** 76 | * The path to a file where Cargo logs are saved. 77 | */ 78 | @OutputFile 79 | @Optional 80 | File logFile 81 | 82 | /** 83 | * The port to use when communicating with this server. 84 | */ 85 | @Input 86 | @Optional 87 | Integer rmiPort 88 | 89 | /** 90 | * Timeout after which the container start/stop is deemed failed. 91 | */ 92 | @Input 93 | @Optional 94 | Integer startStopTimeout 95 | 96 | /** 97 | * The system properties passed-on the container. 98 | */ 99 | @Input 100 | Map systemProperties = [:] 101 | 102 | /** 103 | * The list of configuration files. 104 | */ 105 | @Nested 106 | List configFiles = [] 107 | 108 | /** 109 | * The list of binary files. 110 | */ 111 | @Input 112 | List files = [] 113 | 114 | /** 115 | * Configurable ZIP URL installer instance for automatically downloading a container. 116 | */ 117 | @Nested 118 | ZipUrlInstaller zipUrlInstaller = new ZipUrlInstaller() 119 | 120 | /** 121 | * Additional libraries for your application's classpath that are not exposed to the container. 122 | */ 123 | @InputFiles 124 | @Optional 125 | FileCollection sharedClasspath 126 | 127 | /** 128 | * Additional libraries added to the container's classpath. 129 | */ 130 | @InputFiles 131 | @Optional 132 | FileCollection extraClasspath 133 | 134 | @Override 135 | void validateConfiguration() { 136 | super.validateConfiguration() 137 | 138 | if(!getDeployables().isEmpty()) { 139 | getDeployables().each { deployable -> 140 | if(deployable.file && !deployable.file.exists()) { 141 | throw new InvalidUserDataException("Deployable " 142 | + (deployable.file == null ? "null" : deployable.file.canonicalPath) 143 | + " does not exist") 144 | } 145 | } 146 | 147 | logger.info "Deployable artifacts = ${getDeployables().collect { it.file.canonicalPath }}" 148 | } 149 | 150 | if(!getConfigFiles().isEmpty()) { 151 | getConfigFiles().each { configFile -> 152 | configFile.files.each { file -> 153 | if (!file.exists()) { 154 | throw new InvalidUserDataException("Config file " + file.canonicalPath + " does not exist") 155 | } 156 | } 157 | } 158 | 159 | logger.info "Config files = ${getConfigFiles().collect { it.files*.canonicalPath + " -> " + it.toDir }}" 160 | } 161 | 162 | if (!getFiles().isEmpty()) { 163 | getFiles().each { binFile -> 164 | if (!binFile.file || !binFile.file.exists()) { 165 | throw new InvalidUserDataException("Binary File " 166 | + (binFile.file == null ? "null" : binFile.file.canonicalPath) 167 | + " does not exist") 168 | } 169 | } 170 | logger.info "Binary files = ${getFiles().collect { it.file.canonicalPath + " -> " + it.toDir }}" 171 | } 172 | 173 | if (getConfigType()) { 174 | if (!['standalone','existing'].contains(getConfigType())) { 175 | throw new InvalidUserDataException("Configuration type " + getConfigType() + " is not supported, use 'standalone' or 'existing'") 176 | } 177 | } 178 | } 179 | 180 | @Input 181 | @Optional 182 | protected String getHomeDirPath() { 183 | getHomeDir()?.canonicalPath 184 | } 185 | 186 | @Override 187 | void runAction() { 188 | logger.info "Starting action '${getAction()}' for local container '${getContainerId()}'" 189 | 190 | ant.taskdef(resource: AbstractCargoContainerTask.CARGO_TASKS, classpath: getClasspath().asPath) 191 | ant.cargo(getCargoAttributes()) { 192 | ant.configuration(getConfigurationAttributes()) { 193 | property(name: AbstractCargoContainerTask.CARGO_SERVLET_PORT, value: getPort()) 194 | 195 | if(getJvmArgs()) { 196 | ant.property(name: 'cargo.jvmargs', value: getJvmArgs()) 197 | } 198 | 199 | if(getLogLevel()) { 200 | ant.property(name: 'cargo.logging', value: getLogLevel()) 201 | } 202 | 203 | if(getRmiPort()) { 204 | ant.property(name: 'cargo.rmi.port', value: getRmiPort()) 205 | } 206 | 207 | setContainerSpecificProperties() 208 | 209 | getDeployables().each { Deployable deployable -> 210 | DeployableType deployableType = DeployableTypeFactory.instance.getType(deployable.file) 211 | 212 | if(deployable.context) { 213 | ant.deployable(type: deployableType.type, file: deployable.file) { 214 | ant.property(name: AbstractCargoContainerTask.CARGO_CONTEXT, value: deployable.context) 215 | } 216 | } 217 | else { 218 | ant.deployable(type: deployableType.type, file: deployable.file) 219 | } 220 | } 221 | 222 | getConfigFiles().each { configFile -> 223 | configFile.files.each { file -> 224 | ant.configfile(file: file, todir: configFile.toDir) 225 | } 226 | } 227 | 228 | getFiles().each { binFile -> 229 | ant.file(file: binFile.file, todir: binFile.toDir) 230 | } 231 | } 232 | 233 | setSystemProperties() 234 | 235 | if(getZipUrlInstaller().isValid()) { 236 | ant.zipUrlInstaller(installUrl: getZipUrlInstaller().configuredInstallUrl, downloadDir: getZipUrlInstaller().downloadDir, 237 | extractDir: getZipUrlInstaller().extractDir) 238 | } 239 | 240 | if(getExtraClasspath()) { 241 | ant.extraClasspath() { 242 | getExtraClasspath().addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet) 243 | } 244 | } 245 | 246 | if(getSharedClasspath()) { 247 | ant.sharedClasspath() { 248 | getSharedClasspath().addToAntBuilder(ant, 'fileset', FileCollection.AntType.FileSet) 249 | } 250 | } 251 | } 252 | } 253 | 254 | @Input 255 | protected Map getConfigurationAttributes() { 256 | def config = [:] 257 | 258 | if(getConfigHomeDir()) { 259 | if(!getConfigHomeDir().exists()) { 260 | ant.mkdir(getConfigHomeDir()) 261 | } 262 | 263 | config['home'] = getConfigHomeDir().absolutePath 264 | } 265 | 266 | if(getConfigType()) { 267 | config['type'] = getConfigType() 268 | } 269 | 270 | return config 271 | } 272 | 273 | private Map getCargoAttributes() { 274 | def cargoAttributes = ['containerId': getContainerId(), 'action': getAction()] 275 | if (getStartStopTimeout() >= 0) { 276 | cargoAttributes['timeout'] = getStartStopTimeout() 277 | } 278 | 279 | if(!getZipUrlInstaller().isValid()) { 280 | cargoAttributes['home'] = homeDirPath 281 | } 282 | 283 | if(getOutputFile()) { 284 | cargoAttributes['output'] = getOutputFile() 285 | } 286 | 287 | if(getLogFile()) { 288 | cargoAttributes['log'] = getLogFile() 289 | } 290 | 291 | cargoAttributes 292 | } 293 | 294 | void setSystemProperties() { 295 | logger.info "System properties = ${getSystemProperties()}" 296 | 297 | getSystemProperties().each { key, value -> 298 | ant.sysproperty(key: key, value: value) 299 | } 300 | } 301 | } 302 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/remote/CargoDeployRemote.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.remote 17 | 18 | /** 19 | * Deploys web application to remote container. 20 | */ 21 | class CargoDeployRemote extends RemoteCargoContainerTask { 22 | CargoDeployRemote() { 23 | action = 'deploy' 24 | description = 'Deploys a deployable to remote container.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/remote/CargoRedeployRemote.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.remote 17 | 18 | /** 19 | * Redeploys web application to remote container. 20 | */ 21 | class CargoRedeployRemote extends RemoteCargoContainerTask { 22 | CargoRedeployRemote() { 23 | action = 'redeploy' 24 | description = 'Redeploys a deployable to remote container.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/remote/CargoUndeployRemote.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.remote 17 | 18 | /** 19 | * Undeploys a web application from remote container. 20 | */ 21 | class CargoUndeployRemote extends RemoteCargoContainerTask { 22 | CargoUndeployRemote() { 23 | action = 'undeploy' 24 | description = 'Undeploys a deployable from remote container.' 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/tasks/remote/RemoteCargoContainerTask.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.tasks.remote 17 | 18 | import com.bmuschko.gradle.cargo.DeployableType 19 | import com.bmuschko.gradle.cargo.DeployableTypeFactory 20 | import com.bmuschko.gradle.cargo.convention.Deployable 21 | import com.bmuschko.gradle.cargo.tasks.AbstractCargoContainerTask 22 | import org.gradle.api.InvalidUserDataException 23 | import org.gradle.api.tasks.Input 24 | 25 | /** 26 | * Deploys WAR to remote container. 27 | */ 28 | class RemoteCargoContainerTask extends AbstractCargoContainerTask { 29 | static final String UNDEPLOY_ACTION = 'undeploy' 30 | 31 | /** 32 | * Protocol on which the container is listening to. Defaults to 'http'. 33 | */ 34 | @Input 35 | String protocol = 'http' 36 | 37 | /** 38 | * Host name on which the container listens to. Defaults to 'localhost'. 39 | */ 40 | @Input 41 | String hostname = 'localhost' 42 | 43 | /** 44 | * Username to use to authenticate against a remote container. 45 | */ 46 | @Input 47 | String username 48 | 49 | /** 50 | * Password to use to authenticate against a remote container. 51 | */ 52 | @Input 53 | String password 54 | 55 | @Override 56 | void validateConfiguration() { 57 | super.validateConfiguration() 58 | 59 | if(getAction() != UNDEPLOY_ACTION) { 60 | getDeployables().each { deployable -> 61 | if(deployable.file && !deployable.file.exists()) { 62 | throw new InvalidUserDataException("Deployable " 63 | + (deployable.file == null ? "null" : deployable.file.canonicalPath) 64 | + " does not exist") 65 | } 66 | 67 | if(DeployableType.EXPLODED == DeployableTypeFactory.instance.getType(deployable.file)) { 68 | throw new InvalidUserDataException("Deployable type: EXPLODED is invalid for remote deployment") 69 | } 70 | 71 | logger.info "Deployable artifacts = ${getDeployables().collect { it.file.canonicalPath }}" 72 | } 73 | } 74 | } 75 | 76 | @Override 77 | void runAction() { 78 | logger.info "Starting action '${getAction()}' for remote container '${getContainerId()}' on '${getProtocol()}://${getHostname()}:${getPort()}'" 79 | 80 | ant.taskdef(resource: AbstractCargoContainerTask.CARGO_TASKS, classpath: getClasspath().asPath) 81 | ant.cargo(containerId: getContainerId(), type: 'remote', action: getAction()) { 82 | configuration(type: 'runtime') { 83 | property(name: 'cargo.protocol', value: getProtocol()) 84 | property(name: 'cargo.hostname', value: getHostname()) 85 | property(name: AbstractCargoContainerTask.CARGO_SERVLET_PORT, value: getPort()) 86 | setContainerSpecificProperties() 87 | 88 | if(getUsername() && getPassword()) { 89 | property(name: 'cargo.remote.username', value: getUsername()) 90 | property(name: 'cargo.remote.password', value: getPassword()) 91 | } 92 | 93 | getDeployables().each { Deployable deployable -> 94 | DeployableType deployableType = DeployableTypeFactory.instance.getType(deployable.file) 95 | 96 | if(deployable.context) { 97 | // For the undeploy action do not set a file attribute 98 | if(getAction() == UNDEPLOY_ACTION) { 99 | ant.deployable(type: deployableType.type) { 100 | property(name: AbstractCargoContainerTask.CARGO_CONTEXT, value: deployable.context) 101 | } 102 | } 103 | else { 104 | ant.deployable(type: deployableType.type, file: deployable.file) { 105 | property(name: AbstractCargoContainerTask.CARGO_CONTEXT, value: deployable.context) 106 | } 107 | } 108 | } 109 | else { 110 | ant.deployable(type: deployableType.type, file: deployable.file) 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/util/CargoAntLoggingListener.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.apache.tools.ant.BuildEvent 19 | import org.apache.tools.ant.BuildListener 20 | import org.apache.tools.ant.Project 21 | import org.apache.tools.ant.Task 22 | import org.gradle.api.logging.Logger 23 | import org.gradle.api.logging.Logging 24 | 25 | /** 26 | * Cargo Ant build listener. 27 | */ 28 | class CargoAntLoggingListener implements BuildListener { 29 | Logger logger = Logging.getLogger(CargoAntLoggingListener) 30 | static final String ANT_CARGO_TASK_NAME = 'org.codehaus.cargo.ant.CargoTask' 31 | 32 | @Override 33 | void buildStarted(BuildEvent buildEvent) {} 34 | 35 | @Override 36 | void buildFinished(BuildEvent buildEvent) {} 37 | 38 | @Override 39 | void targetStarted(BuildEvent buildEvent) {} 40 | 41 | @Override 42 | void targetFinished(BuildEvent buildEvent) {} 43 | 44 | @Override 45 | void taskStarted(BuildEvent buildEvent) {} 46 | 47 | @Override 48 | void taskFinished(BuildEvent buildEvent) {} 49 | 50 | /** 51 | * Wraps the subclasses action code in a listener that raises info priority Ant task messages to 52 | * be lifecycle messages for Gradle. This allows messages from the Ant task, such as 53 | * "Press Ctrl-C to stop the container..." to be passed through. 54 | * 55 | * @param buildEvent Build event 56 | */ 57 | @Override 58 | void messageLogged(BuildEvent buildEvent) { 59 | if(buildEvent.task && isCargoTask(buildEvent.task) && isInfoPriority(buildEvent.priority)) { 60 | logger.lifecycle(buildEvent.message) 61 | } 62 | } 63 | 64 | private boolean isCargoTask(Task task) { 65 | task.class.canonicalName == ANT_CARGO_TASK_NAME 66 | } 67 | 68 | private boolean isInfoPriority(int priority) { 69 | priority == Project.MSG_INFO 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/util/DefaultFileUtil.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | /** 19 | * Filename utilities. 20 | */ 21 | class DefaultFileUtil implements FileUtil { 22 | @Override 23 | String getExtension(File file) { 24 | if(!file.exists()) { 25 | throw new IllegalArgumentException("File '$file.canonicalPath' does not exist") 26 | } 27 | 28 | if(file.isDirectory()) { 29 | return '' 30 | } 31 | 32 | String filename = file.canonicalPath 33 | int index = filename.lastIndexOf('.') 34 | 35 | if (index > 0) { 36 | return filename.substring(index + 1) 37 | } 38 | 39 | '' 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/util/FileUtil.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | interface FileUtil { 19 | String getExtension(File file) 20 | } 21 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/util/LoggingHandler.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.apache.tools.ant.BuildListener 19 | import org.gradle.api.AntBuilder 20 | 21 | /** 22 | * Logging handler support. 23 | */ 24 | class LoggingHandler { 25 | /** 26 | * Attaches Ant logging handler for closure execution. 27 | * 28 | * @param antBuilder Ant builder 29 | * @param c Closure 30 | */ 31 | static void withAntLoggingListener(AntBuilder antBuilder, Closure c) { 32 | BuildListener listener = new CargoAntLoggingListener() 33 | 34 | try { 35 | antBuilder.project.addBuildListener(listener) 36 | c() 37 | } 38 | finally { 39 | antBuilder.project.removeBuildListener(listener) 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/groovy/com/bmuschko/gradle/cargo/util/ProjectInfoHelper.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.gradle.api.Project 19 | import org.gradle.api.Task 20 | import org.gradle.api.plugins.WarPlugin 21 | import org.gradle.plugins.ear.EarPlugin 22 | 23 | /** 24 | * Provides helper method for retrieving project information. 25 | */ 26 | final class ProjectInfoHelper { 27 | private ProjectInfoHelper() {} 28 | 29 | static Task getProjectDeployableTask(Project project) { 30 | if(project.plugins.hasPlugin(WarPlugin.WAR_TASK_NAME)) { 31 | return project.tasks.getByName(WarPlugin.WAR_TASK_NAME) 32 | } 33 | else if(project.plugins.hasPlugin(EarPlugin.EAR_TASK_NAME)) { 34 | return project.tasks.getByName(EarPlugin.EAR_TASK_NAME) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/groovy/com/bmuschko/gradle/cargo/util/CargoAntLoggingListenerSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.apache.tools.ant.BuildEvent 19 | import org.apache.tools.ant.BuildListener 20 | import org.apache.tools.ant.Project 21 | import org.apache.tools.ant.Task 22 | import org.apache.tools.ant.taskdefs.Copy 23 | import org.codehaus.cargo.ant.CargoTask 24 | import org.gradle.api.logging.Logger 25 | import spock.lang.Specification 26 | 27 | /** 28 | * Cargo Ant build listener unit tests. 29 | */ 30 | class CargoAntLoggingListenerSpec extends Specification { 31 | BuildListener buildListener 32 | 33 | def setup() { 34 | buildListener = new CargoAntLoggingListener() 35 | } 36 | 37 | void "Message not logged for non-Cargo Ant task"() { 38 | given: 39 | Task antCopyTask = new Copy() 40 | BuildEvent buildEvent = new BuildEvent(antCopyTask) 41 | buildEvent.message = 'Cargo started' 42 | Logger mockLogger = Mock(Logger) 43 | buildListener.logger = mockLogger 44 | when: 45 | buildListener.messageLogged(buildEvent) 46 | then: 47 | 0 * mockLogger.lifecycle('Cargo started') 48 | } 49 | 50 | void "Message not logged for Cargo Ant task with debug priority"() { 51 | given: 52 | Task antCargoTask = new CargoTask() 53 | BuildEvent buildEvent = new BuildEvent(antCargoTask) 54 | buildEvent.message = 'Cargo started' 55 | buildEvent.priority = Project.MSG_DEBUG 56 | Logger mockLogger = Mock(Logger) 57 | buildListener.logger = mockLogger 58 | when: 59 | buildListener.messageLogged(buildEvent) 60 | then: 61 | 0 * mockLogger.lifecycle('Cargo started') 62 | } 63 | 64 | void "Message logged for Cargo Ant task with info priority"() { 65 | given: 66 | Task antCargoTask = new CargoTask() 67 | BuildEvent buildEvent = new BuildEvent(antCargoTask) 68 | buildEvent.message = 'Cargo started' 69 | buildEvent.priority = Project.MSG_INFO 70 | Logger mockLogger = Mock(Logger) 71 | buildListener.logger = mockLogger 72 | when: 73 | buildListener.messageLogged(buildEvent) 74 | then: 75 | 1 * mockLogger.lifecycle('Cargo started') 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/test/groovy/com/bmuschko/gradle/cargo/util/DefaultFileUtilSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.junit.Rule 19 | import org.junit.rules.TemporaryFolder 20 | import spock.lang.Specification 21 | import spock.lang.Unroll 22 | 23 | /** 24 | * Filename utilities unit tests. 25 | */ 26 | class DefaultFileUtilSpec extends Specification { 27 | @Rule 28 | TemporaryFolder temporaryFolder = new TemporaryFolder() 29 | 30 | FileUtil fileUtil = new DefaultFileUtil() 31 | 32 | def "throws exception for non-existent file"() { 33 | when: 34 | fileUtil.getExtension(new File('unknownfile')) 35 | 36 | then: 37 | thrown(IllegalArgumentException) 38 | } 39 | 40 | @Unroll 41 | def "get file extension for file with name '#filename'"() { 42 | when: 43 | String extension = fileUtil.getExtension(temporaryFolder.newFile(filename)) 44 | 45 | then: 46 | extension == expectedExtension 47 | 48 | where: 49 | filename | expectedExtension 50 | 'test.war' | 'war' 51 | 'test' | '' 52 | } 53 | 54 | @Unroll 55 | def "get file extension for directory with name '#dirname'"() { 56 | when: 57 | String extension = fileUtil.getExtension(temporaryFolder.newFolder(dirname)) 58 | 59 | then: 60 | extension == expectedExtension 61 | 62 | where: 63 | dirname | expectedExtension 64 | 'test' | '' 65 | 'test-1.0' | '' 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/test/groovy/com/bmuschko/gradle/cargo/util/DeployableTypeFactorySpec.groovy: -------------------------------------------------------------------------------- 1 | package com.bmuschko.gradle.cargo.util 2 | 3 | import com.bmuschko.gradle.cargo.DeployableType 4 | import com.bmuschko.gradle.cargo.DeployableTypeFactory 5 | import spock.lang.Specification 6 | import spock.lang.Unroll 7 | 8 | class DeployableTypeFactorySpec extends Specification { 9 | FileUtil fileUtil = Mock() 10 | 11 | def setup() { 12 | DeployableTypeFactory.instance.fileUtil = fileUtil 13 | } 14 | 15 | @Unroll 16 | def "determines type for '#description'"() { 17 | given: 18 | File givenFile = new File(givenFilename) 19 | 20 | when: 21 | DeployableType deployableType = DeployableTypeFactory.instance.getType(givenFile) 22 | 23 | then: 24 | 1 * fileUtil.getExtension(givenFile) >> fileExtension 25 | deployableType.type == expectedDeployableType.type 26 | 27 | where: 28 | givenFilename | fileExtension | expectedDeployableType | description 29 | '/User/ben/app/myapp.war' | 'war' | DeployableType.WAR | 'WAR file' 30 | '/User/ben/app/myapp.ear' | 'ear' | DeployableType.EAR | 'EAR file' 31 | '/User/ben/app/myapp' | '' | DeployableType.EXPLODED | 'exploded WAR' 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/test/groovy/com/bmuschko/gradle/cargo/util/LoggingHandlerSpec.groovy: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2011 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.bmuschko.gradle.cargo.util 17 | 18 | import org.gradle.api.Project 19 | import org.gradle.testfixtures.ProjectBuilder 20 | import spock.lang.Specification 21 | 22 | /** 23 | * Logging handler unit tests. 24 | */ 25 | class LoggingHandlerSpec extends Specification { 26 | Project project 27 | 28 | def setup() { 29 | project = ProjectBuilder.builder().build() 30 | } 31 | 32 | void "Closure is executed"() { 33 | expect: 34 | project.ant.project.buildListeners.find { it.class == org.apache.tools.ant.BuildListener } == null 35 | boolean test = false 36 | when: 37 | LoggingHandler.withAntLoggingListener(project.ant) { 38 | test = true 39 | } 40 | then: 41 | test 42 | project.ant.project.buildListeners.find { it.class == org.apache.tools.ant.BuildListener } == null 43 | } 44 | } 45 | --------------------------------------------------------------------------------