Where can I put my custom task class in Gradle - gradle

It's easy to write a custom plugin and include it in the build script
apply from: "utilities.gradle"
For test purpose this file is in the same directory as the build.gradle
Calling a task defined in utilities.gradle from build.gradle works without any hassle.
In utilities gradle is also a plugin defined - configuring it from build.gradle just works.
But if I define a custom task in utilities.gradle calling it is no problem but if I want to use that custom taks in build.gradle it says
> Could not find property 'GreetingTask' on root project 'TestGradle'.
utilities.gradle:
task hello(type: GreetingTask)
class GreetingTask extends DefaultTask {
#TaskAction
def greet() {
println 'hello from GreetingTask'
}
}
build.gradle
task hellox(type: GreetingTask)
Ok... I read the documentation here: http://www.gradle.org/docs/current/userguide/custom_tasks.html
It says the custom task is not visible outside...
But then... how to share custom tasks with the team without making a Jar for everything.
What I want is to place the utilities.gradle on a network drive and share it with the other.
pls help

There is a special $rootDir/buildSrc directory which is its own build. All classes that this build produces are available to all build scripts in the "main" build. The buildSrc build has a default build.gradle, but you can add your own. By default, Java classes are expected under src/main/java, and Groovy classes under src/main/groovy. You can read more about buildSrc in the Gradle User Guide.
To share classes across multiple builds, a separate plugin project that publishes a Jar is the way to go.

Related

Gradle subprojects: how do I execute `check` only on main project?

I added a subproject to my gradle project and now whenever I execute the target check, it also runs the tests on my subproject.
I was hoping that I could run the check-task on the main project by specifying it as absolute task as
gradle :check
or
gradle ::check
but both commandlines still execute all tests.
Any idea?
There is no way around this, so you would need to restructure your build (I think check task of the parent is by definition a aggregate of the sub-projects). You can have sub-projects depending on each other, I assume that might be what you want to model in your build.
Let's assume you have the sub-projects core and myModule.
If you want myModule to depend on (and use the output of) core, you add a project dependency to myModule:
dependencies {
compile project(':core')
}
This will also setup the task dependencies correctly.
you can access the task-graph of a subproject from the main projects `build.gradle' and disable tasks.
This way you can disable the task when you call it on the main project, but it will still be enabled when you call the build file of the subproject directly:
project('subproject') {
//disable 'check' and 'test' task
gradle.taskGraph.whenReady {
tasks.find {it.name=="check"}.enabled=false
tasks.find {it.name=="test"}.enabled=false
}
}

How to execute gradle task during project import in Intellij Idea

Let's assume my build.gradle file contains task generateSources which as name suggests generates additional java files. It's easy to ensure that generateSources is executed before compileJava: compileJava.dependsOn generateSources. How can I make sure generateSources is called when importing project into Intellij Idea as well?
To elaborate on #vladimir-sitnikov's answer: I added the idea-ext-plugin to my root project:
apply plugin: 'org.jetbrains.gradle.plugin.idea-ext'
// ...
buildscript {
dependencies {
classpath "org.jetbrains.gradle.plugin.idea-ext:org.jetbrains.gradle.plugin.idea-ext.gradle.plugin:0.7"
}
}
Because without that I wasn't able to use it in my sub project, but now it works like this:
idea.project.settings.taskTriggers {
beforeSync tasks.getByName("generateSources")
}
Adding the plugin to the sub-project only didn't do it.
Note: The plugin's documentation is kind of limited, but in "DSL spec v. 0.2" is stated
beforeSync - before each Gradle project sync. Will NOT be executed on initial import
Didn't try that, but it works with existing projects.
This can be done via id("org.jetbrains.gradle.plugin.idea-ext") plugin (https://github.com/JetBrains/gradle-idea-ext-plugin).
See sample code in Gradle sources: https://github.com/gradle/gradle/blob/135fb4751faf2736c231636e8a2a92d47706a3b9/buildSrc/subprojects/ide/src/main/kotlin/org/gradle/gradlebuild/ide/IdePlugin.kt#L147
You can set the task in Gradle tool window: Execute Before Sync:

Can we define more than a single Plugin class in a Gradle buildSrc

I have a pretty typical Gradle library project that contains a collection of modules (either Android or pure Java) that depend on some common configuration.
This common configuration is abstracted into a "publishConfig.gradle" file (which is read in via apply in those build.gradle files that need it) and some custom Tasks captured in a buildSrc. This question is about the latter.
The buildSrc is a single module/project consisting of source (as Groovy) in a specific package as a single Groovy file with two classes: the class that implements Plugin and the plugin extension class. e.g.:
org.clvrmnky.gradle.plugins.LibraryPlugin
This configuration and the defined Tasks work without error. No problem there.
Now I want to add additional custom tasks for a different reason (remember, this is all part of a shared custom configuration for a growing number of submodules to the root project) so I added a parallel class file that defines a new plugin class implementing Plugin. e.g.:
org.clvrmnky.gradle.plugins.BuildBreaker
For reference, here is the class and task definition snippet:
[...]
public class BuildBreaker implements Plugin<Project> {
static def authString = fetchSonarAuthString()
#Override
void apply(Project project) {
project.extensions.create("buildbreaker", BuildBreakerExtension)
project.task([
description: 'Fail this task if the Sonarqube Quality Gate does not pass.',
dependsOn: ["sonarqube"]
], 'breakOnBadQualityGate') {
[...]
That is, the class and task methods are defined similarly, but have different String identifiers.
However, when I do this, the new Tasks I define are not visible to the root project or any submodule of the project:
PS C:\rd\SOPLibs\Commons> .\gradlew.bat breakOnBadQualityGate
:buildSrc:compileJava UP-TO-DATE
:buildSrc:compileGroovy UP-TO-DATE
[...]
FAILURE: Build failed with an exception.
* What went wrong:
Task 'breakOnBadQualityGate' not found in root project 'Commons'.
* Try:
Run gradlew tasks to get a list of available tasks. Run with --stacktrace option
to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
The build directory contains classes for all the source, and there is a lib jar that contains these classes which I presume is being supplied to the Gradle classpath at runtime. That is, this is building and packaging without error.
I've seen hints that you need to tweak the buildSrc build.gradle on multi-project buildSrc projects so that all the jars are on the classpath at runtime, but in this case we have a single jarfile with multiple Plugin tasks.
I've also tried moving the BuildBreaker class to a separate package, but this did not solve the problem.
Can we not implement more than one Plugin class in a single buildSrc, even if they have different classnames? Or do I have to split these out into multiple buildSrc projects?
You can define as many plugins and tasks as you like in buildSrc. But nothing will take effect until you
apply plugin: foo.bar.MyPlugin
Or
task foo(type: com.foo.MyTask) {...}

Executing integration tests in gradle

Me and my team are working on a project with a lot of modules. We are using gradle for the project and everyone is new to gradle. We have a Main parent project i.e, parent build with the details of project dependencies. We want to add the integration_test task configuration to all the modules so that we can call the command gradle integration_test. So is there any way or concept of writing the configuration in the main module and make the child projects import the same configuration.
FYI: I tried it by directly adding it to the main project but got an error saying the classpath for the files which I specified does not exists. Any help or thought would be appreciated. Thanks in advance.
Is there a particular reason to split "integration tests" from the standard test task?
If so, you can run the same script for all subprojects from the main project's build file: https://docs.gradle.org/current/userguide/multi_project_builds.html#sec:subproject_configuration
For instance:
subprojects {
task integrationTest {
// whatever you need
}
}
I am note sure if this is what you talk about in the last paragraph. If so, please attache the error message you get.
It is also possible to "import" some configuration by subprojects, but the above definition is better in most scenarios.

How to compile single class dependency in gradle outside the main project

I have a gradle project that contains only Selenium/TestNG test classes. They are executed against a deployed war application. All works fine and now I'm adding a java utility that will query the test base and print list of tests that belong to a given TestNG group. The utility should be compiled and executed separate from the main project, as users may want to query the test base before test execution.
I added the following to build.gradle:
task listgroups(dependsOn:'buildUtil' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java")
}
task buildUtil {
compile {
source = "src/test/java/util"
}
}
However, when calling listgroups task, I'm getting the following error:
C:\console-bg1>g listgroups
FAILURE: Build failed with an exception.
(...)
* What went wrong:
A problem occurred evaluating root project 'console-bg1'.
> Could not find method compile() for arguments [build_4emu7duna2isgubc1k8uts8k9
8$_run_closure6_closure11#d210ab] on root project 'console-bg1'.
I'm not sure how to resolve this issue and needless to say, haven't found an answer online so far. Any pointers appreciated.
The problem is in the buildUtil task, as the error suggests. The buildUtil declares a compile closure, but such closure does not exist for the default task.
Let me try to clarify what your setup is. The util.TestGroupScanner source is in the src/test/java/util directory, which you want to compile separately from other source (presumably src/main/java and src/test/java). The buildUtil task is supposed to compile sources in src/test/java/util, and the listgroups task executes the scanner utility on sources src/test/java folder.
In this case, I'd suggest you declare a new source set for your utility sources, like this:
sourceSets {
util {
java {
srcDir 'src/test/java/util'
}
}
}
This will automatically create a compile task called compileUtilJava for you, that will compile those sources. I also think you'll want to include utility classes in the classpath when executing your tool, which can be retrieved by sourceSets.util.output.classesDir. So now your listgroups task will look like:
task listgroups(dependsOn: 'compileUtilJava' ) <<{
ant.java(classname: 'util.TestGroupScanner', fork: true,
classpath: "src/test/java:" + sourceSets.util.output.classesDir)
}
One thing I have noticed about your setup, is that src/test/java/util source folder is nested under src/test/java. Gradle will assume src/test/java to be the default folder for your project test, and will therefore automatically include it, and all of its children when running tests. Since you want to keep your utility folder separate from the default setup, I would recommend you put it in src/testutil/java, to avoid any clashes. If you do, don't forget to update the sourceSets setup above with the correct source path.
To solve this with gradle, I suggest to create a specific sourceset for your util class and add a task of type JavaExec that executes this class for printing your testng groups. Have a look at the following snippet:
apply plugin:'java'
...
...
configurations{
testUtilCompile.extendsFrom testCompile
}
...
...
sourceSets{
testUtil{
java {
srcDir "src/test/java"
include "util/**"
}
}
}
task printGroups(type:JavaExec){
main = "util.TestGroupScanner"
classpath = sourceSets.testUtil.runtimeClasspath
}
regards,
René

Resources