Compiling error on gradle custom plugin using external plugin (groovy files) - gradle

We are trying to create a custom plugin. In this plugin we pretend to use gradleFx plugin internally to extends some classes.
When we try to build the plugin, it fails because gradlefx classes cannot be found:
we tried to define dependencies in different ways, from the build.gradle when we apply groovy plugin, and also we tried from groovy classes like this:
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
project.dependencies {
compile 'org.gradlefx:gradlefx:1.3.3'
}
}
}
Anyway none of this works when we try to extends a gradleFx class:
import org.gradlefx.tasks.adt.AdtTask
MyTask implements AdtTask {
}
because AdtTask doesn't exists, the error we see is unable to resolve class org.gradlefx.tasks.adt.AdtTask
How's the right way to declare dependencies and extend from them in my groovy files?

Related

Use Kotlin plugins from buildSrc

How can I apply the Kotlin plugins from a buildSrc plugin?
I have a Kotlin project with a build.gradle.kts file containing this:
plugins {
application
kotlin("jvm")
kotlin("plugin.serialization")
}
I want to create a custom plugin in buildSrc:
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
class MyPlugin: Plugin<Project> {
override fun apply(project: Project) {
project.pluginManager.apply("org.gradle.application") //This works
project.pluginManager.apply("¿kotlin(jvm)?") //<-- Here is my doubt
project.pluginManager.apply("¿kotlin(plugin.serialization)?") //<-- Here is my doubt
}
}
And use it like this:
plugins {
id("com.example.myplugin")
}
To apply Gradle plugins from within buildSrc plugins you need to do two things
Add the plugins as dependencies in buildSrc/build.gradle.kts
Plugins must be added as dependencies using the Maven coordinates, not the plugin ID. The Maven coordinates of plugins can be found in the Gradle plugin portal.
https://plugins.gradle.org/plugin/org.jetbrains.kotlin.jvm
https://plugins.gradle.org/plugin/org.jetbrains.kotlin.plugin.serialization
// buildSrc/build.gradle.kts
plugins {
`kotlin-dsl`
}
dependencies {
// the Maven coordinates of the Kotlin Gradle and Serialization plugins
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.20")
implementation("org.jetbrains.kotlin:kotlin-serialization:1.7.20")
}
apply the plugins, either using the class, or the plugin ID.
(Note that kotlin("jvm") is a helper function that obscures the actual Gradle plugin ID, which is org.jetbrains.kotlin.jvm)
class MyPlugin: Plugin<Project> {
override fun apply(project: Project) {
project.pluginManager.apply("org.jetbrains.kotlin.jvm")
project.pluginManager.apply("org.jetbrains.kotlin.plugin.serialization")
// the plugin class for the Kotlin JVM & Serialization plugins
project.plugins.apply(org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper::class)
project.plugins.apply(org.jetbrains.kotlinx.serialization.gradle.SerializationGradleSubplugin::class)
}
}
(it wasn't easy to find the plugin classes - I had to dig around in the jar to find the plugin marker artifact, e.g. kotlin-serialization-1.7.20-gradle71.jar!/META-INF/gradle-plugins/org.jetbrains.kotlin.plugin.serialization.properties)
You might also like to use precompiled script plugins. They allow for writing buildSrc script plugins that much more similar to standard build.gradle.kts files, and so you can apply plugins in the plugins block.
// buildSrc/src/main/kotlin/conventions/kotlin-jvm.gradle.kts
plugins {
kotlin("jvm")
}

Unable to resolve class HTTPBuilder inside gradler task

Why do some imports work for my regular groovy files inside the project
compile group: 'org.codehaus.groovy.modules.http-builder', name:
'http-builder', version: '0.7.1'
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
When I try to use HTTPBuilder inside build.gradle is unable to resolve the class.
Am I missing a step for make them work inside a gradler task?
You need to make the http-builder module classes available to the build script classpath, using the dedicated script block buildscript:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath ("org.codehaus.groovy.modules.http-builder:http-builder:0.7.1")
}
}
See:
https://docs.gradle.org/current/userguide/tutorial_using_tasks.html#sec:build_script_external_dependencies
https://docs.gradle.org/current/dsl/org.gradle.api.Project.html#org.gradle.api.Project:buildscript(groovy.lang.Closure)

How to share boilerplate Kotlin configuration across multiple Gradle projects?

The typical Kotlin configuration in a Gradle project is very boilerplate, and I'm looking for a way of abstracting it out into an external build script so that it can be reused.
I have a working solution (below), but it feels like a bit of a hack as the kotlin-gradle-plugin doesn't work out of the box this way.
It's messy to apply any non-standard plugin from an external script as you can't apply the plugin by id, i.e.
apply plugin: 'kotlin' will result in Plugin with id 'kotlin' not found.
The simple (well, usually) workaround is to apply by the fully qualified classname of the plugin, i.e.
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
which in this case throws a nice little exception indicating that the plugin probably wasn't meant to be called this way:
Failed to determine source cofiguration of kotlin plugin.
Can not download core. Please verify that this or any parent project
contains 'kotlin-gradle-plugin' in buildscript's classpath configuration.
So I managed to hack together a plugin (just a modified version of the real plugin) which forces it to find the plugin from the current buildscript.
kotlin.gradle
buildscript {
ext.kotlin_version = "1.0.3"
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
apply plugin: CustomKotlinPlugin
import org.jetbrains.kotlin.gradle.plugin.CleanUpBuildListener
import org.jetbrains.kotlin.gradle.plugin.KotlinBasePluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPlugin
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
/**
* Wrapper around the Kotlin plugin wrapper (this code is largely a refactoring of KotlinBasePluginWrapper).
* This is required because the default behaviour expects the kotlin plugin to be applied from the project,
* not from an external buildscript.
*/
class CustomKotlinPlugin extends KotlinBasePluginWrapper {
#Override
void apply(Project project) {
// use String literal as KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY constant isn't available
System.setProperty("kotlin.environment.keepalive", "true")
// just use the kotlin version defined in this script
project.extensions.extraProperties?.set("kotlin.gradle.plugin.version", project.property('kotlin_version'))
// get the plugin using the current buildscript
def plugin = getPlugin(this.class.classLoader, project.buildscript)
plugin.apply(project)
def cleanUpBuildListener = new CleanUpBuildListener(this.class.classLoader, project)
cleanUpBuildListener.buildStarted()
project.gradle.addBuildListener(cleanUpBuildListener)
}
#Override
Plugin<Project> getPlugin(ClassLoader pluginClassLoader, ScriptHandler scriptHandler){
return new KotlinPlugin(scriptHandler, new KotlinTasksProvider(pluginClassLoader));
}
}
This can then be applied in any project (i.e. apply from: "kotlin.gradle") and you're up and running for Kotlin development.
It works, and I haven't had any issues yet, but I'm wondering if there is a better way? I'm not really keen on merging in changes to the plugin every time there's a new version of Kotlin.
Check out the nebula-kotlin-plugin. It seems very close to what you're trying to achieve there.
The problem here is that there is a known gradle bug about the inability to apply plugins by id from init scripts. That's why you need to use fully qualified class name as a workaround.
E.g. I have the following in the init script and it works:
apply plugin: org.jetbrains.kotlin.gradle.plugin.KotlinPlatformJvmPlugin
By the way, I created a gradle plugin for preparing custom gradle distributions with common setup defined in init script - custom-gradle-dist. It works perfectly for my projects, e.g. a build.gradle for a library project looks like this (this is a complete file, all repository, apply plugin, dependencies etc setup is defined in the init script):
dependencies {
compile 'org.springframework.kafka:spring-kafka'
}

specify classpath for plugin inside apply method

How to specify classpath for custom gradle plugin inside class, that implements interface Plugin?
class TaskPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('task') << {
println 'simple task'
}
}
}
I saw something similar there
https://github.com/gradle/gradle/blob/6277a4dc70fbeea83c111e75c95ba851d1e56ffc/subprojects/plugins/src/main/groovy/org/gradle/api/plugins/WarPlugin.java#L25
However I don't know how to apply it for my case. Specifically I want to use both test and main sourcesets.
I want to get rid of classpath dependencies, related to my project. Because I have the same dependencies in dependencies and in buildscript { dependencies {
Every time I add plugin I have to add classpath dependencies, which that plugin is using.
apply plugin: 'my-plugin'
task {
... do something
}
buildscript {
repositories {
flatDirs dir('.')
}
dependencies {
classpath ("my-group:my-plugin:my-version")
classpath ("dependency:dependency:dependency")
}
}
The problem is that when I specify basic dependencies (not inside buildscript) I may have the same dependencies
dependencies {
compile ("dependency:dependency:dependency")
}
Sometimes I need some compiled project dependencies compile project(":my-project") which I have to specify using classpath files("path to compiled").
How to adjust plugin implementation to remove those dependency duplicates? Like for example if I declared dependency using compile or runtime - plugin will know about it and there is no need to declare dependency in classpath explicitly.

Creating a Gradle plugin with a dependency on another (external) plugin

I want to create a plugin that automatically applies other (external plugins). This requires setting the buildscript dependency for the plugin before I call "apply plugin". However it seems like I can't add buildscript dependencies in a plugin or I get:
You can't change a configuration which is not in unresolved state!
Is there a solution to this ?
My sample (non-working) code:
import org.gradle.api.Project
import org.gradle.api.Plugin
class SamplePlugin implements Plugin<Project>{
void apply(Project project) {
project.buildscript.dependencies.add("classpath","net.sourceforge.cobertura:cobertura:1.9.4.1");
project.configure(project){
apply plugin: 'cobertura'
}
}
}
The way to go about this is to publish a pom.xml or ivy.xml along with the plugin Jar that describes the plugin's dependencies. Alternatively, you can write a script plugin that declares its dependencies in a buildscript {} section. A script plugin is simply a reusable build script that gets applied with apply from: ....

Resources