I have a multi project build setup. If I execute the "jar" task of any subproject, gradle checks whether it needs to rebuild a certain dependent project or not by using the org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.
Is there a way to access this information to like build a custom task or a task in a custom plugin which automatically copies the jars of theses projects to somewhere?
You should be able to use jar.didWork to determine whether the task jar actually did some work or not if I remember correctly: https://docs.gradle.org/current/javadoc/org/gradle/api/Task.html#getDidWork()
Or maybe more appropriate, use something like the following:
gradle.taskGraph.afterTask { task, state ->
// check anything on Task or TaskState, like didWork, executed, failure, noSource, skipMessage, skipped or upToDate
}
Related
I use gitflow-incremental-builder with Maven in a monorepo model. It allows me to:
Build only these modules in feature branch that differ from main branch.
Build only these modules that changed from last successful build tag.
When a library changes, build all the modules that use it.
Build a library if needed for modules, but if nothing changed, skip tests (skipTestsForUpstreamModules)
Force build all.
Changes are resolved using git log and then it affects the reactor config.
I am looking for a similar tool that will do it for Gradle.
Gradle Build Cache will automatically track the inputs and outputs of tasks and will skip any that have not changed.
Enabling Gradle Build Cache
It can be enabled locally by adding in gradle.properties
org.gradle.caching=true
or by adding a flag to the command line
./gradlew tests --build-cache
Sharing the build cache
The build cache for a project can be shared across multiple machines over HTTP. Sharing the build cache remotely isn't necessary - it can still work, even if the cache is stored locally.
Register task inputs
Gradle needs to know about the all inputs and outputs of tasks, otherwise tasks might be skipped, so make sure they are correctly registered.
For example, if some integration tests depend on an environment variable, then register the environment variable as a test-task input.
// build.gradle.kts
tasks.named("integrationTest") {
// TEST_TASK_QUALITY is used in integration tests to change <blah blah blah>
// register it as an input so Gradle knows when to re-run the tests
inputs.property("TEST_TASK_QUALITY", providers.environmentVariable("TEST_TASK_QUALITY"))
}
Stable task outputs
Gradle will use the outputs of some tasks as the inputs of other tasks. If the outputs aren't stable, then Gradle will always re-run the dependent tasks.
For that reason, it's worth enabling reproducible builds in all projects.
// build.gradle.kts
tasks.withType<AbstractArchiveTask>().configureEach {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
}
Also, consider input normalization for any custom files your project has.
I'm using Lombok in a gradle based project and the build process requires to delombok the source code before continuing with unit tests or production build. What is the best way to achieve something like that in gradle?
At the moment the generated classes are created in a /build/delombok directory.
The first thought I had was to create a new source set and a task that is based on compileJava but if I do this I will probably have to update every other gradle task to depend on my new one. Is this the right approach or is there something better?
I'm using gradle 4.10
I have several unrelated Java projects built with gradle, some of which are assembled into a jar file, others, into a war.
I'd like the assemble task of all projects to depend on the clean task since we've had issues with various old classes getting into assembled jars/wars from the build folder cache. Is there a way of doing that without adding assemble.dependsOn clean to each and every build.gradle?
You can handle this with a global hook in your ./gradle/init.gradle script. Anything you put in there is executed on every build.
In order to avoid failures on projects that don't have an assemble task you need a filter as well, something like the following will work:
allprojects {
tasks.whenTaskAdded { theTask ->
if (theTask.name.equals('assemble')) {
theTask.dependsOn clean
}
}
}
What this is doing is applying a block to all projects defined (allproject). When each task is added this will run, and when a task with the name assemble is added a dependency will be added to clean.
From your top level build.gradle
submodules {
assemble.dependsOn clean
}
This will apply the dependsOn to each subproject
I am wondering about how to perform specific tasks during a maven build: I would like to use some of my code to do some preprocessing on the data that I am shipping in the resulting jar. Generally given some input.xml in src/main/resources I would like to be able to call a java function / main method to obtain a file output.xml which is included available as a resource (and probably placed in target/classes/...). Using Makefiles this would correspond to an additional rule, I guess this could be done with an ant task as well (though I have never used ant myself). can I add such a rule to a maven project as well?
You can use the Maven Exec Plugin to run arbitrary Java code during your build.
If you should happen to have your tasks formulated as Ant targets, the Maven Antrun Plugin can be used to run those.
I've set up a Gradle task to auto generate one of the subprojects of my Gradle build on which another depends (reason for doing this: long story involving Apache Cordova!). So the root build.gradle contains this autogenerate task that creates a "CordovaLib" sub project. The build.gradle in the other sub project (that isn't autogenerated) depends on CordovaLib:
dependencies {
compile project(':CordovaLib')
}
Is there a way to execute the autogenerate task before the non-generated subproject's build.gradle is evaluated (specifically the above line)? I'm using Gradle 1.11 on JDK 1.7 and as it currently stands I can't even run gradle tasks without it failing due to the missing project.
It isn't possible to execute a task before build files have been evaluated, at least not without complications such as one build executing another build using a GradleBuild task. You are likely better off checking the generated project in to source control, or finding a solution that doesn't involve generating build scripts.
You can use init script to gradle to achieve this.
https://gradle.org/docs/current/userguide/init_scripts.html