Create a second installDist task? - gradle

During development I am using a standard-function installDist (from the application plugin) in build.gradle:
installDist{}
... but I now want to have another task which installs/distributes/deploys a "production" version to the production location, which also incorporates the version into the directory structure. I tried this:
task deployOperativeVersion( type: installDist ) {
destinationDir = file( "$productionDir/$version" )
}
Build failure output:
Build file '/home/mike/IdeaProjects/JavaFXExp2/Organiser/build.gradle' line: 98
* What went wrong:
A problem occurred evaluating root project 'Organiser'.
> class org.gradle.api.tasks.Sync_Decorated cannot be cast to class java.lang.Class
(org.gradle.api.tasks.Sync_Decorated is in unnamed module of loader org.gradle.
internal.classloader.VisitableURLClassLoader #aec6354; java.lang.Class is in module
java.base of loader 'bootstrap')
It appears that installDist is not a "type" as in Test.
How can I achieve this? Incidentally I would be really keen on having two separate tasks: to get installDist to run I've found that you only have to type ./gradlew inst ... with a task called deployXXX it would be sufficient to type ./gradlew depl.
I also tried this:
task deployOperativeVersion{
installDist{
destinationDir = file( "$operativeDir/$version" )
}
}
... which doesn't seem to have done anything. Nor this:
task deployOperativeVersion{
doFirst {
installDist {
destinationDir = file("$operativeDir/$version")
}
}
}
A bit later I thought I had indeed found the answer:
task deployOperativeVersion{
dependsOn installDist{ destinationDir=file("$productionDir/$version")
}
... but to my amazement (will I ever get to a reasonable understanding of Gradle before Hell freezes over?), including this actually appears to influence the "routine" installDist task: specifically, it stops the latter from operating normally, and means that even when I run installDist the deployment/distribution/installation still goes to productionDir/version, rather than the default location.
So then I wondered about two tasks both of which are dependent on installDist:
task deployOperativeVersion{
dependsOn installDist{ destinationDir=file("$productionDir/$version") }
}
task stdInstall{
dependsOn installDist{ destinationDir=file("build/install") }
}
... haha, no joy: I run one and it deploys OK. I then run the other... and get an error:
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':installDist'.
> The specified installation directory '/home/mike/IdeaProjects/JavaFXExp2/Organiser/build/install' is neither empty nor does it contain an installation for 'Organiser'.
If you really want to install to this directory, delete it and run the install task again.
Alternatively, choose a different installation directory.
... needless to say, this is NOT the case: under ...Organiser/build/install there is one directory only, Organiser, with /bin and /lib directories under it.

Your task should be declared as a Sync task, which is the actual type of the installDist task. The application plugin is using the distribution plugin. You can grab the content configuration from the main distribution, which is the source, or from the installDist task.
task deployOperativeVersion(type: Sync) {
destinationDir = file("${productionDir}/${version}")
with distributions.main.content
}
or
task deployOperativeVersion(type: Sync) {
destinationDir = file("${productionDir}/${version}")
with installDist
}

Related

Gradle : UP-TO-DATE task

I have task 'compileProfileObj' which mainly has to create a jar file.
Even in fresh environment setup, gradle logs outputs 'UP-TO-DATE' for this.
task compileProfileObj(type: JavaCompile, dependsOn: [generateArtifacts]) {
classpath = configurations.deployment
source fileTree(
dir: "${objDir}/app",
includes: ['com/main/**'])
destinationDir file("${proDir}/profileobjects-biz.jar")
doLast {
copy {
from "${objDir}"
include '*.xml'
exclude 'server.xml'
into "${proDir}/profileobjects-biz.jar/META-INF"
}
copy {
from "${objDir}/profileobjects"
into "${proDir}/profileobjects-biz.jar/META-INF"
}
}
}
I understand the gradle doesnot executed tasks in some cases if the tasks has successfully executed in previous build runs.
But in my case even in 1st run gradle doesn't execute this task and prints 'UP-TO-DATE'
Googling didnt help me much here.
Any suggestions in what scenarios this might happen will be really helpful.

Task with path 'build' not found in root project

I have a multiproject and after the last subproject is built, I'd like to process all jars.
Therefore I created a task in the root-project:
task install(dependsOn: 'build', type: Copy) {
doLast {
println "exec install task"
}
}
Upon calling ./gradlew install in the root directory, I'm facing this error:
FAILURE: Build failed with an exception.
* What went wrong:
Could not determine the dependencies of task ':install'.
> Task with path 'build' not found in root project 'foo'.
However, calling ./gradlew tasks shows me these tasks:
:tasks
------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------
Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
...
How can I achieve the desired functionality?
I assume, that your root project organizes the build, but does not define build action taken by itself. The build task is often defined by language plugins (in most cases via apply plugin: 'java'), but if your root project does not use any of them, it won't have a build task.
The description of the help task tasks, which you used, says:
Displays the tasks runnable from root project 'projectReports' (some of the displayed tasks may belong to subprojects).
The help task followes the same logic as the task activation via the command line. You can provide a task name and any task with the name in any subproject will be executed (thats why gradle build works).
But if you define a dependsOn dependency, the given string is evaluated as task path for a single task. Since each task name can only be used once in a project, the name is unique for tasks in the root project, but many tasks could be found, if subprojects would be considered. Therefor, one can use the syntax :<projectName>:<taskName> to identify tasks in subprojects.
Now, let's face your specific problem: If the install task should depend on the build task of one single subproject, you could use dependsOn ':<mySubproject>:build'. But I assume you want the install task to depend on each subproject build task, so I'd like to propose this approach:
task install(type: Copy) {
dependsOn subprojects*.tasks*.findByName('build').minus(null)
doLast {
println "exec install task"
}
}
This way, for each registered subproject, findByName('build') is called and the result (the found task or null) is put into a list, which is then used as task dependency list. I added the .minus(null) part to remove null entries from the list, because I am not sure how Gradle handles such entries in a dependency collection. If you are sure, that each subproject provides a build task, you can use getByName('build'), too.
EDIT: OP found the optionally recursive getTasksByName method, which suits this case even better than iterating over all subprojects manually:
dependsOn getTasksByName('build', true)

Wrong order of task execution in gradle 3.3

I want to define methods inside my script file, and use them to define build tasks for each project individual (custom library).
ext.buildDockerImage = { imageName ->
def distDir = "${getProject().getBuildDir()}/docker"
copy {
from "${project.getProjectDir()}/src/docker/"
into distDir
}
println 'Build docker image'
}
In my project build.gradle I have created a task:
apply plugin: "war"
apply plugin: "jacoco"
dependency {
// all dependencies
}
task buildDocker() {
apply from: "${project.getRootDir()}/docker/scripts.gradle"
buildDockerImage("admin")
}
The problem is that whenever I am running gradle build, this tasks executes also:
$ gradle build -xtest
Build docker image
# rest of build
As you can see , all I want is to create a custom library that will hold methods, used to create tasks for each project. But currently I cannot import those methods without breaking the build. Method buildDockerImage will work only after war file is added to build directory, so this task must be executed on demand only, I don't want to be included in the process all the time.
My questions:
how make my task to only run when I execute task manually
why, when I execute my build, script executes as first?
Your task buildDocker() defines everything in configuration phase. So when you run your gradle build this will always run.
task buildDocker() {
apply from: "${project.getRootDir()}/docker/scripts.gradle"
buildDockerImage("admin")
}
If you want to run this task as a standalone task, define your stuff in execution phase of the task. something like below
task buildDocker() {
apply from: "${project.getRootDir()}/docker/scripts.gradle"
doLast{
buildDockerImage("admin")
}
}
Read This article
This might help

Creating a post build copy task with Gradle

I am struggling with the Gradle build lifecycle; specifically with the split between the configuration and execution phases. I have read a number of sections in the Gradle manual and have seen a number of ideas online, but have not found a solution to the following problem:
I want to run a specific task to produce an artifact at the end of my java-library-distribution build that is a flattened version of the runtime configuration jars. That is, I only want to produce the artifact when I run the specific task to create the artifact.
I have created the following task:
task packageSamplerTask(type: Tar, dependsOn: distTar) {
description "Packages the build jars including dependencies as a flattened tar file. Artifact: ${distsDir}/${archivesBaseName}-${version}.tar"
from tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files
classifier = 'dist'
into "${distsDir}/${archivesBaseName}-dist-${version}.tar"
}
Although this task does produce the required artifact, the task runs during gradle's configuration phase. This behavior has the following consequences:
Irrespective of which task I run from the command line, this packageSamplerTask task is always run, often unnecessarily; and
If I clean the project, then the build fails on the next run because $distsDir doesn't exist during the configuration phase (obviously).
It appears that if I extend the Copy task in this manner I'm always going to get this kind of premature behavior.
Is there a way to use the << closure / doLast declarations to get what I want? Or is there something else I'm missing / should be doing?
Update
After further work I have clarified my requirements, and resolved my question as follows (specifically):
"I want to package my code and my code's dependencies as a flat archive of jars that can be deployed as a jMeter plugin. The package can then be installed by unpacking into the jMeter lib/ext directory, as is. The package, therefore, must not include the jMeter jars (and their dependencies) which are used for building and testing"
Because Gradle doesn't appear to support the Maven-like provided dependency management, I created a new configuration for my package which excludes the jMeter jars.
configurations {
jmpackage {
extendsFrom runtime
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_core', version: '2.11'
exclude group: 'org.apache.jmeter', name: 'ApacheJMeter_java', version: '2.11'
}
}
And then created the following task (using the closure recommendation from Peter Niederwieser):
task packageSamplerTask(type: Tar, dependsOn: assemble) {
from { libsDir }
from { configurations.jmpackage.getAsFileTree() }
classifier = 'dist'
}
This solution appears to work, and it allows me to use just theGradle java plugin, too.
The task declaration is fine, but the flattening needs to be deferred too:
...
from { tarTree("${distsDir}/${archivesBaseName}-${version}.tar").files }
Also, the Tar file should be referred to in a more abstract way. For example:
from { tarTree(distTar.archivePath).files }
First your task isn't executed in the configuration phase but like EVERY task it is configured in that phase. And your closure is just a configuration of your task (a Configuration closure, not an Action closure). That is why your code is "executed" in the configuration phase".
If you want your code to be executed in the execution phase have to write it in a doLastclosure or doFirst. But in your case it is better to keep it in a configuration closure, because you are configuring your task.
To make sure your build doesn't fail because of the missing folder, you can create it with distsDir.mkdirs().

how to override a task making it depend on one of mine in gradle

I tried following the gradle manual with their example like this but copyJars is not run at all before the eclipse task. (the eclipse task comes from the eclipse plugin)
task('copyJars') {
ext.collection = files { genLibDir.listFiles() }
delete ext.collection
copy { from configurations.compile into genLibDir }
copy { from fixedLibDir into genLibDir }
}
eclipse.dependsOn = copyJars
task('setupAll', dependsOn: 'eclipse') {
description = 'Update jars from remote repositories and then fix eclipse classpath for stbldfiles project'
}
There are some problems with this build script:
eclipse doesn't refer to the task but to the equally named model object. (Don't you get an exception for eclipse.dependsOn?)
Task copyJars does its work in the configuration phase rather than the execution phase (i.e for every build, even if the task isn't executed)
To fix that, use tasks.eclipse.dependsOn(copyJars) and task copyJars << { ... }.
Another question is if there isn't a simpler way than copying things around with copyJars and fixing up the Eclipse class path after the fact, but I'd need more information to be able to tell.

Resources