How do I run a task created by a plugin in gradle - groovy

I've written a gradle plugin that adds a custom task called generateTestDocs, which depends on the task groovydoc, which itself is created by the groovy plugin.
//MyPlugin.groovy
#Override
void apply(Project project) {
project.apply(plugin: 'groovy')
project.task(type: GenerateTestDocsTask, dependsOn: ':groovydoc', 'generateTestDocs')
}
project.tasks.groovydoc.doFirst {
println "I should see this message but I don't"
}
I'm trying to test this plugin by running the task generateTestDocs
#Test
void testRunGenerateTestDocs() {
Project project = ProjectBuilder.builder().build()
project.apply(plugin: 'my.gradle.plugin')
project.tasks.generateTestDocs.actions*.execute(project.tasks.generateTestDocs)
}
For the last line in my test, I'd like to instead just say project.task.generateTestDocs.execute() and have it run the task with all of its dependencies, but that doesn't seem to work. The documentation for writing gradle plugins only shows assertions like assertTrue(project.tasks.hello instanceof GreetingTask) which shows the task is added to the project, but doesn't show how to run that task.

ProjectBuilder is only meant for unit tests. To run a build as part of a test, you'll need to use the Gradle tooling API, or a third-party plugin such as nebula-test (which builds upon the tooling API).

I faced the same question, I solved this by add
apply plugin: CustomPluginName
in current gradle.build :
apply plugin: 'groovy'
...
// in this case Plugin name is MyPlugin
apply plugin: MyPlugin

Related

Get a PsiFile inside a Gradle plugin task

I am working on a Gradle plugin that will/should inspect some code using Psi (https://www.jetbrains.org/intellij/sdk/docs/basics/architectural_overview/psi.html). I know how to use Psi if it was an IntelliJ plugin, but I don't know where to start in the context of a Gradle task.
The Gradle task API would look like this:
generateRibStateTree {
rootRibBuilderFile = file("$rootDir/app/src/main/java/com/coca/jorge/root/RootBuilder.kt")
reportDirectoryFile = file("$rootDir/reports") // your desired directory here
}
The goal is to receive the rooRibBuilderFile in a java.io.File object, but then I do not know how to start parsing that file with Psi. Any ideas?

How to depend another project's androidTestCompile?

I have a multi-project test issue: I want one project to depend on another project's androidTestCompile.
I have tried this way:
androidTestCompile project(':CommonTest').sourceSets.androidTest
But android studio says it could not find property androidTest on SourceSet container.
Help
Here's an approach that might work. I've not tried it as I don't have a multi-project Android project. You'll need to tweak the code for your project names and specify the dependsOn in your current projects task for Android Tests.
task action(dependsOn: ":producer:action") << {
println("Consuming message: ${rootProject.producerMessage}")
}
See the topic 24.6.1.2. Declaring dependencies in https://docs.gradle.org/current/userguide/multi_project_builds.html
Another clue is in the Gradle Java Tutorial which explains how to establish dependencies between projects in a multi-project build https://docs.gradle.org/current/userguide/tutorial_java_projects.html#N14E23
dependencies {
compile project(':shared')
}
So I'd hazard a guess that something like
dependencies {
androidTestCompile project(':CommonTest')
}
(which you've tried, albeit with more parameters) is on the right track.

What the difference in applying gradle plugin

I don't understand gradle plugins block
apply plugin: 'someplugin1'
apply plugin: 'maven'
and other one:
plugins {
id 'org.hidetake.ssh' version '1.1.2'
}
In first block We have some plugin name. in second one package and version. I don't understand where I should use first block and when second one.
The plugins block is the newer method of applying plugins, and they must be available in the Gradle plugin repository. The apply approach is the older, yet more flexible method of adding a plugin to your build.
The new plugins method does not work in multi-project configurations (subprojects, allprojects), but will work on the build configuration for each child project.
I would think that as functionality progresses, the plugins configuration method will overtake the older approach, but at this point both can be and are used concurrently.
As already mentioned by #cjstehno the apply plugin is a legacy method that you should avoid.
With the introduction of the plugins DSL, users should have little reason to use the legacy method of applying plugins. It is documented here in case a build author cannot use the plugins DSL due to restrictions in how it currently works.
With the new plugins block method, you can add a plugin and control when to apply it using an optional parameter apply:
plugins {
id «plugin id» version «plugin version» [apply «false»]
}
You would still use the legacy method in situations where you want to apply an already added but not applied plugin in your plugins block. E.g, in the master project a plugin xyz is added but not applied and it should be applied only in a subproject subPro:
plugins {
id "xyz" version "1.0.0" apply false
}
subprojects { subproject ->
if (subproject.name == "subPro") {
apply plugin: 'xyz'
}
}
Notice that you don't need the version anymore. The version is required in the plugins block unless you are using one of the Core Gradle plugins, such as java, scala, ...
I spent some time understanding the difference while trying to create a Spring Boot application, and that's why I am answering this again after a while. The following example for using Spring Boot plugin helped me a lot:
What should currently be used:
plugins {
id "org.springframework.boot" version "2.0.1.RELEASE"
}
What had been used before Gradle 2.1:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "org.springframework.boot:spring-boot-gradle-plugin:2.0.1.RELEASE"
}
}
apply plugin: "org.springframework.boot"
These are two different ways to use Gradle plugin。
The apply plugin way: First resolve plugin you needed from root build.gradle like:
buildscript {
repositories {
// other repositories...
mavenCentral()
}
dependencies {
// other plugins...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.44'
}
Then in the build.gradle of your Android Gradle modules apply the plugin:
apply plugin: 'com.android.application'
apply plugin: 'com.google.dagger.hilt.android'
The plugins way:combine resovle and apply where in your root build.gradle like:
plugins {
// other plugins...
id 'com.google.dagger.hilt.android' version '2.44' apply false
}
Then in the build.gradle of your Android Gradle modules apply the plugin:
plugins {
// other plugins...
id 'com.android.application'
id 'com.google.dagger.hilt.android'
}
android {
// ...
}
Now ( In Gradle 6) you can give repositories name for plugins without using build script.
In settings.gradle, we can add plugin pluginManagement
pluginManagement {
repositories {
maven {
url '../maven-repo'
}
gradlePluginPortal()
ivy {
url '../ivy-repo'
}
}
}
Reference: https://docs.gradle.org/current/userguide/plugins.html#sec:custom_plugin_repositories
I would like to point out though, that is it not required for a plugin to be published remotely to be able to use it!
It can also be a UNPUBLISHED locally available plugin (be it convention plugins or otherwise) just as well.
In case one wishes to refer to such an unpublished locally-available plugin,
you'll have to include it's so-called "build" within the desired component/build (identified via the settings.gradle(.kts)-file) like so:
pluginManagement {
includeBuild '<path-to-the-plugin-dir-containing-the-settings-file>'
}
Afther that is done, one may use the local plugin within the plugins {}-DSL-block via its pluginId.
If the plugin needs a version then it's safer to put the version number in the pluginManagement block in your settings.gradle file, rather than in plugins block.
By safer I mean that you won't encounter an error like plugin request for plugin already on the classpath must not include a version. That can happen if you includeFlat a project into another project that uses the same plugin and your plugin versions are in the plugins block.
So rather than:
plugins {
id 'pl.allegro.tech.build.axion-release' version '1.10.3'
}
Do:
plugins {
id 'pl.allegro.tech.build.axion-release'
}
and then in your settings.gradle file:
pluginManagement {
plugins {
id 'pl.allegro.tech.build.axion-release' version '1.10.3'
}
}
I'm going to add a little twist to what's been said. Gradle introduced the concept of a plugins block as a technique to speed up and optimize the build process. Here's what Gradle's documentation says:
This way of adding plugins to a project is much more than a more convenient syntax. The plugins DSL is processed in a way which allows Gradle to determine the plugins in use very early and very quickly. This allows Gradle to do smart things such as:
Optimize the loading and reuse of plugin classes.
Provide editors detailed information about the potential properties and values in the buildscript for editing assistance.
This requires that plugins be specified in a way that Gradle can easily and quickly extract, before executing the rest of the build script. It also requires that the definition of plugins to use be somewhat static.
It's not just a newer way of dealing with plugins, it's a way of improving the build process and/or user's editing experience.
In order for it to work, it needs to be specified at the top of the build, but it also needs to be specified after the buildscript block if one is included. Why is that? Because the code in the build scripts is evaluated in the order its written. The buildscript block must be evaluated before the plugins block is evaluated. Remember, the buildscript block is about setting up of the plugin environment. Hence the rule that the plugins block must be specified after the buildscript block.
The new plugins block not only specifies the plugins that the project is using, but it also specifies whether the plugin is applied. By default, all plugins in the plugins block are automatically applied, unless it is specifically declared not to be applied (i.e., adding "apply false" after the plugin declaration in the plugins block).
So why would you declare a plugin and not apply it. There are two main reasons that I can think of:
1.) so you can declare the version of the plugin you want used. After you've declared a plugin, the plugin is now on the "classpath". Once a plugin is on the classpath you no longer need to specify the version of the plugin when you apply it later. In multiproject builds, that makes supporting buildscripts a little easier. (i.e., you only have one place where the plugin version is specified.)
2.) Sometimes, you may have a plugin, that requires certain things defined before they are applied. In that case, you can declare a plugin in the plugins block, and defer the plugin from being applied until after you define the things that the plugin requires as input. For example, I have a custom plugin that looks for a configuration named "mavenResource". In the dependencies block I'll added a dependency like: "mavenResource(maven_coordinate)". That plugin will find all the dependencies contained in the mavenResource configuration and copy the associated maven artifact to the projects "src/main/resources" directory. As you can see, I don't want to apply that plugin until after the mavenResource configuration is added to that project, and the mavenResource dependencies are defined. Hence, I define my custom plugin the plugins block, and I apply it after the project dependencies have been defined. So, the concept that applying a plugin is old style and wrong is a misconception.
Some of you might wonder what it means to apply a plugin. It's pretty straightforward. It means that you call the plugin's apply function passing it the Gradle Project object for the project where the plugin is being applied. What the plugin does from there on is totally at the discretion of the plugin. Most commonly, the apply function usually creates some Gradle tasks and adds them to the Gradle build task dependency graph. When Gradle starts its execution phase, those tasks will get executed at the appropriate time in the build process. The plugin apply function can also do things like deferring some of it work until afterEvaluate. That's a way to allow other things in the build script to be setup even though they are defined later on in the buildscript. So, you might ask why I didn't do that trick in my custom plugin. What I've observed is that the next subproject starts processing after the root project finishes being evaluated. In my case, I needed the resource added before the next subproject began. So, there was a race condition, that I avoided by not doing the afterEvaluate technique and specifically applying the plugin once the things I needed setup was completed.

How can I specify a Groovy CompilerConfig using Gradle?

I have a Groovy project, where I would like to enable this CompilerConfig:
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
ast(groovy.transform.TypeChecked)
}
How can I enable this using Gradle?
Beginning from Gradle 2.1 it is possible, see the corresponding release notes.
This is especially useful for working with Groovy on Android, see this presentation. E.g. you could add the #CompileStatic to each class with the following code:
File build.gradle
compileGroovy {
groovyOptions.configurationScript = file("gradle/config.groovy")
}
File gradle/config.groovy
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
For more options, see the GroovyCompileOptions and Groovy Customizer Builder.
Gradle's GroovyCompile task doesn't currently support passing a CompilerConfiguration instance or --configscript option. See http://forums.gradle.org/gradle/topics/ability_to_specify_a_compilerconfiguration_instance_for_groovycompile_task for a related discussion.

Is it possible to use classes compiled by Gradle buildSrc in main Groovy project?

Classes compiled by buildSrc/build.gradle are not resolved at runtime when they are used in main PROJECT classes.
My Groovy project structure looks like this:
-PROJECT
-buildSrc/
-build.gradle
-/src/main/groovy
- com.company.global.test.report
-src/test/groovy
-build.gradle
Is there something I can add to the top-level PROJECT/build.gradle to allow the classes compiled by it to use the classes compiled by buildSrc/build.gradle?
buildSrc is its own build (not project) that gets executed before the main build. Its sole purpose is to make some classes (plugins, tasks, regular classes) available to the build scripts of the main build. Hence you could call it a "meta-build".
Technically, it would be possible to add the compiled classes of buildSrc to the compile or runtime class path of a project in the main build, but I don't recommend to do it. There is very likely a better way to achieve your goals (but I don't know what those are).
Here is how to do it with Gradle 2.12:
In your_project/buildSrc/build.gradle
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
// Thanks to this, IDE like IntelliJ will provide you with "Navigate to sources"
artifacts {
archives sourcesJar
}
In your_project/build.gradle
ext.buildSrcJars = fileTree("$rootDir/buildSrc/build/libs") { include("*.jar") exclude("*sources.jar")}
// Works in every subproject
dependencies {
compile buildSrcJars
}

Resources