Custom task type not found when importing Gradle plugin - gradle

I am facing the following conundrum for which I spent a great deal of time trying to resolve with no success so far. I have a custom Gradle plugin whose job is to start a process and run it in the background.
My code plugin code is the following:
public class TaskSpawnerPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('spawnTask', type: TaskSpawner)
}
}
And this is the task in question:
public class TaskSpawner extends DefaultTask {
#Input
String command
#Input
String ready
#Input
String workDir = '.'
TaskSpawner() {
description = 'Given a Unix like cmd, this will start it and let it run on the background'
}
#TaskAction
public void spawn() {
getLogger().quiet "Attempting to run provided command $command"
if (!(command && ready)) {
throw new GradleException("Please make sure that both the command and ready check are provided!")
}
waitFor(createProcess(workDir, command))
}
private def waitFor(Process process) {
new BufferedReader(new InputStreamReader(process.getInputStream())).withCloseable {
reader ->
def line
while ((line = reader.readLine()) != null) {
getLogger().quiet line
if (line.contains(ready)) {
getLogger().quiet "$command is ready"
break
}
}
}
}
private def static createProcess(String directory, String command) {
new ProcessBuilder(command.split(' '))
.redirectErrorStream(true)
.directory(Paths.get(directory).toFile())
.redirectError(ProcessBuilder.Redirect.INHERIT)
.redirectInput(ProcessBuilder.Redirect.INHERIT)
.redirectOutput(ProcessBuilder.Redirect.INHERIT)
.start()
}
}
The code resides under a package structure that has following package name
fts.gradle
My build script looks like this:
plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'maven-publish'
}
group = 'fts.gradle'
version = '0.3'
repositories {
jcenter()
}
dependencies {
compile gradleApi()
compile localGroovy()
}
gradlePlugin {
plugins {
greetingsPlugin {
id = 'fts.gradle.taskspawn'
implementationClass = 'fts.gradle.TaskSpawnerPlugin'
}
}
}
I build my plugin normally and deploy it on a locally hosted artifactory. My problem revolves around how to import it and use it in a project.
For the time being I do the following:
buildscript {
repositories {
maven { url "<maven_url>" }
}
dependencies {
classpath group: 'fts.gradle', name: 'task-spawner', version: '0.3'
}
}
plugins {
id 'java'
id 'application'
id 'eclipse'
}
apply plugin: 'fts.gradle'
And then I attempt to apply it using the following:
But when attempting to refresh the project this action fails:
* What went wrong:
A problem occurred evaluating project ':integration-tests'.
> Could not get unknown property 'TaskSpawner' for project ':integration-tests' of type org.gradle.api.Project.
I have read the documentation and I have tried all the various ways of creating and importing a plugin as a standalone jar but so far I've unsuccessful.
Can anyone please shed some light here? This has been driving nuts for the past days.
Note, for reference the Gradle version I use it 5.6.2

Related

Can a standalone gradle plugin export a custom task type?

I have a standalone Gradle plugin that includes a custom task type:
gradle-conventions/build.gradle
plugins {
id 'groovy-gradle-plugin'
id 'maven-publish'
}
group = 'com.example'
version = '1.0'
publishing {
repositories {
maven {
url = uri('/path/to/repo')
}
}
}
gradle-conventions/src/main/groovy/com.example.my-conventions.gradle
abstract class CustomTask extends DefaultTask {
#TaskAction
def hello() {
println "hello"
}
}
I can consume the plugin from another project, but how can I register a CustomTask? Something like this:
project/build.gradle
plugins {
id 'com.example.my-conventions' version '1.0'
}
// how do I reference CustomTask here?
tasks.register('myCustomTask', com.example.CustomTask) {
// ...
}
Is it possible to export a custom task from a custom plugin? Or must I consume custom tasks using the buildscript mechanism?
Having inspected gradle-conventions-1.0.jar, it seems that the custom task class belongs to the default package, so I can register the task as follows:
project/build.gradle
plugins {
id 'com.example.my-conventions' version '1.0'
}
tasks.register('myCustomTask', CustomTask) {
// ...
}
But this only works com.example.my-conventions.gradle contains groovy code besides the class itself, otherwise I get the error:
An exception occurred applying plugin request [id: 'com.example.my-conventions', version: '1.0']
> Failed to apply plugin 'com.example.my-conventions'.
> java.lang.ClassNotFoundException: precompiled_ComExampleMyConventions
This approach avoids relying on the buildscript mechanism (which is not recommended in the Gradle documentation).

Why is this a receiver type mismatch when it seems to match what I see in the Gradle docs?

I'm converting a build from Buildr to Gradle.
So far I have the following build script:
repositories {
jcenter()
}
allprojects {
version = "0.8.1-SNAPSHOT"
group = "org.trypticon.hex"
}
subprojects {
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "signing")
configure<JavaPluginExtension> {
sourceCompatibility = JavaVersion.VERSION_11
withJavadocJar()
withSourcesJar()
}
dependencies {
"testImplementation"("junit:junit:4.13")
}
configure<PublishingExtension> {
repositories {
maven {
url = uri(if (version.toString().contains("SNAPSHOT")) {
"https://oss.sonatype.org/content/repositories/snapshots"
} else {
"https://oss.sonatype.org/service/local/staging/deploy/maven2"
})
credentials {
username = System.getenv("DEPLOY_USER")
password = System.getenv("DEPLOY_PASS")
}
}
}
publications {
register<MavenPublication>("mavenJava") {
pom {
// omitting a bunch of metadata unrelatted to the issue
}
}
}
}
configure<SigningExtension> {
sign(publishing.publications["mavenJava"])
}
}
When I try to build, I get this:
build.gradle.kts:124:14: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public val PluginDependenciesSpec.publishing: PluginDependencySpec defined in org.gradle.kotlin.dsl
IntelliJ says that the types match and shows no error.
I started with code from the Gradle docs which said to use this:
signing {
sign(publishing.publications["mavenJava"])
}
But that fails when inside a subprojects block.
Using:
Gradle 6.8
Java 11.0.3
Further investigation:
I tried splitting the lines out to see exactly which bit the issue was on.
configure<SigningExtension> {
val e: PublishingExtension = publishing
val p: Publication = e.publications["mavenJava"]
sign(p)
}
The error points directly at publishing on the first line. Hovering over it in IDEA, it helpfully tells me that Project.publishing is a PublishingExtension, so the call shows no error. Now the question is, why is it fine when inspecting the file, but fails at runtime? I thought this was exactly the kind of thing switching to Kotlin was going to stop. :(
I had a similar problem, which I fixed by writing the following code:
configure<SigningExtension> {
val pubExt = checkNotNull(extensions.findByType(PublishingExtension::class.java))
val publication = pubExt.publications["your_publication"]
sign(publication)
}
In your case, your_publication should be replaced with mavenJava.

Use of Gradle Plugin in external .gradle file

Background:
I'm trying to use the gradle-dependency-graph-generator-plugin in a gradle build, and configure it with custom Generator configurations. When I place the configuration within the _root.gradle, our root gradle project:
buildscript {
repositories {
maven {
url artifactoryRepoURL + '/repo'
}
}
dependencies {
//...
classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0"
}
}
//...
allprojects {
//...
apply plugin: "com.vanniktech.dependency.graph.generator"
//...
}
...it works just fine. (Though, Intellij reports errors in the import, it builds and runs both on command line and in the IDE)
The Problem
I'd like to put this code in a separate gradle file, just so it's not cluttering up the root project. So I move the code to a dependencyGraph.gradle file, and include it with an
apply from: "$rootProject.projectDir/dependencyGraph.gradle"
However, I get compilation errors, class not found. So I add the buildScript and dependencies/classpath from the root project file, and try again. This time, it gives a class cast exception:
com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator cannot be cast to com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator
Its the same classname, so I assume this is some kind of classloader problem. So, how does one include a build script that references plugin classes into a project.gradle?
EDIT:
Per – #EugenMartynov 's comment, the file looks like:
buildscript {
repositories {
maven {
url artifactoryRepoURL + '/repo'
}
}
dependencies {
classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.5.0"
}
}
import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
import guru.nidi.graphviz.attribute.Color
import guru.nidi.graphviz.attribute.Style
import guru.nidi.graphviz.attribute.Label
def updateNode(node, dependency) {
def group = dependency.getModuleGroup()
def colorCodeFor = { starts, color ->
if (group.startsWith(starts)) {
node.add(Style.FILLED, Color.rgb(color))
return color
}
return null
}
def color = colorCodeFor("commons", "#ff008c")
?: colorCodeFor("org.apache", "#ff008c")
?: colorCodeFor("org.springframework", "#6db33f")
?: colorCodeFor("javax", "#ff0000")
?: colorCodeFor("com.fasterxml", "#3a772e")
?: colorCodeFor("ch.qos.logback", "#ffd0a0")
?: colorCodeFor("", String.format("#%06x", Math.abs(group.hashCode()) % (255*255*255))) // base off the group
return node
}
def colorCodedGenerator = new Generator(
"ColorCoded", // Suffix for our Gradle task.
{ dependency -> true }, // filter
{ dependency -> true }, // Include transitive dependencies.
{ node, dependency -> updateNode(node, dependency) }, // Give them some color.
{ node, project ->node.add(Style.FILLED, Color.rgb("#2cc2e4")) }, // project nodes.
)
dependencyGraphGenerator {
generators = [ Generator.ALL, colorCodedGenerator ]
}
and is applied within the allprojects block:
allprojects {
...
apply plugin: "com.vanniktech.dependency.graph.generator"
apply from: "$rootProject.projectDir/dependencyGraph.gradle"
...
}
though I also tried only within the root project. As configured, I get:
FAILURE: Build failed with an exception.
...
* What went wrong:
A problem occurred configuring root project 'dar'.
> com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator cannot be cast to com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension$Generator
This is gradle 4.9, btw

Gradle 'Unknown Property' : Importing Plugin within my Custom Plugin

I am writing a custom Plugin that has a task which makes HTTP-API Calls.
Hence within my custom plugin's build.gradle, I have included the below plugins tag
plugins {
id 'java-gradle-plugin'
id 'groovy'
id 'maven-publish'
id 'io.github.http-builder-ng.http-plugin' version '0.1.1'
}
The task within my custom-plugin is this
task makeRESTCall() {
onlyIf {
!inputList.empty
}
doLast {
//println 'Successfully made REST Call'
//println inputList
def http = groovyx.net.http.HttpBuilder.configure {
request.uri = 'http://localhost:8080'
request.contentType = 'application/json'
request.uri.path = '/api/v1/validate'
}
http.post {
request.body = inputList.toString()
response.success {resp, json ->
println json
if (!json) {
throw new GradleException("Validation Failed")
}
}
}
}
}
My custom-plugin gets built property and when i include the custom-plugin in another project and when I execute the task makeRESTCall, i get the below exception
Execution failed for task ':api:makeRESTCall'.
Could not get unknown property 'groovyx' for task ':api:makeRESTCall' of type org.gradle.api.DefaultTask.
the http-plugin that I import within my custom-plugin is not getting imported properly in my Project
In your custom plugin, you are using HTTP-Builder-NG library (groovyx.net.http.HttpBuilder class), so you need to configure a dependency to this library in your plugin project:
dependencies {
compile "io.github.http-builder-ng:http-builder-ng-core:1.0.3"
}
To make a quick test you could create the following temporary plugin in the buildSrc directory of the project you want to apply the plugin to:
buildSrc/build.gradle
dependencies {
compile "io.github.http-builder-ng:http-builder-ng-core:1.0.3"
}
repositories {
mavenCentral()
}
buildSrc/src/main/groovy/com/mycompany/MyPlugin.groovy
package com.mycompany
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
class MyPlugin implements Plugin<Project> {
void apply(Project project) {
// ... your plugin login here, with 'inputList' definition
project.task ('makeRESTCall') {
onlyIf {
!inputList.empty
}
doLast {
//println 'Successfully made REST Call'
println inputList
def http = groovyx.net.http.HttpBuilder.configure{
request.uri = 'http://localhost:8080'
request.contentType = 'application/json'
request.uri.path = '/api/v1/validate'
}
http.post {
request.body = inputList.toString()
response.success {resp, json ->
println json
if (!json) {
throw new GradleException("Validation Failed")
}
}
}
}
}
}
build.gradle
import com.mycompany.MyPlugin
apply plugin: MyPlugin
Note : I don't think you need to apply plugin id "io.github.http-builder-ng.http-plugin" version "0.1.1", unless you are using the HTTPTask that this plugin exposes, which is just a Gradle Task wrapper around groovyx.net.http.HttpBuilder

I got an error using this build.grafle file and don't know how to fix it

Here's the Error:
FAILURE: Build failed with an exception.
Where: Build file '/home/wieland/GitGradlePackaging/build.gradle' line: 22
What went wrong: A problem occurred evaluating root project 'GitGradlePackaging'.
Could not get unknown property 'org' for object of type org.gradle.api.internal.initialization.DefaultScriptHandler.
And Here's my build.gradle File:
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java project to get you started.
* For more details take a look at the Java Quickstart chapter in the Gradle
* user guide available at https://docs.gradle.org/4.6/userguide/tutorial_java_projects.html
*/
//From example: http://mrhaki.blogspot.co.at/2015/04/gradle-goodness-use-git-commit-id-in.html
buildscript {
repositories {
jcenter()
}
dependencies {
//Add dependencies for build script, so we can access Git from our build script
classpath 'org.ajoberstar:grgit:1.1.0'
}
def git = org.ajoberstar.grgit.Grgit.open(file('.'))
//To save Githash
def githash = git.head().abbreviatedId
}
plugins {
// Apply the java plugin to add support for Java
id 'java'
// Apply the application plugin to add support for building an application
id 'application'
// Apply the groovy plugin to also add support for Groovy (needed for Spock)
id 'groovy'
id 'distribution'
}
// Set version
project.version = mainProjectVersion + " - " + githash
project.ext.set("wholeVersion", "$project.version - $githash")
project.ext.set("buildtimestamp", "2000-01-01 00:00")
def versionfilename = "versioninfo.txt"
def GROUP_DEBUG = 'Debug'
// Task to print project infos
task debugInitialSettings {
group = GROUP_DEBUG
doLast {
println 'Version: ' + project.wholeVersion
println 'Timestamp: ' + project.buildtimestamp
println 'Filename: ' + project.name
}
}
// To add the githash to zip
task renameZip {
doLast {
new File ("$buildDir/distributions/$project.name-${project.version}.zip")
.renameTo ("$buildDir/distributions/$project.name-${project.wholeVersion}.zip")
}
}
distZip.finalizedBy renameZip
// To add the githash to tar
task renameTar{
doLast {
new File ("$buildDir/distributions/$project.name-${project.version}.tar")
.renameTo ("$buildDir/distributions/$project.name-${project.wholeVersion}.tar")
}
}
distTar.finalizedBy renameTar
// Define the main class for the application
mainClassName = 'App'
dependencies {
// This dependency is found on compile classpath of this component and consumers.
compile 'com.google.guava:guava:23.0'
// Use the latest Groovy version for Spock testing
testCompile 'org.codehaus.groovy:groovy-all:2.4.13'
// Use the awesome Spock testing and specification framework even with Java
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile 'junit:junit:4.12'
}
// In this section you declare where to find the dependencies of your project
repositories {
// Use jcenter for resolving your dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
}
//To generate Testreports as HTML
test {
reports {
junitXml.enabled = false
html.enabled = true
}
}
distributions {
main {
contents {
from { 'build/docs' }
into ('reports') {
from 'build/reports'
}
}
}
}
//To make sure that test and javadoc ran before zip and tar
distTar.dependsOn test
distZip.dependsOn test
distTar.dependsOn javadoc
distZip.dependsOn javadoc
Please keep in mind I have not much knowledge about gradle as I'm just starting to learn it!
Thanks in advance :)
You have to move the githash definition outside the buildscript block
buildscript {
repositories {
jcenter()
}
dependencies {
//Add dependencies for build script, so we can access Git from our build script
classpath 'org.ajoberstar:grgit:1.1.0'
}
}
def git = org.ajoberstar.grgit.Grgit.open(file('.'))
//To save Githash
def githash = git.head().abbreviatedId
The reason is that when the buildscript block is evaluated line by line, its dependencies are not yet loaded. When the rest of the script is evaluated, the dependencies of the buildscript block have already been loaded. This is actually the reason for the buildscript block existence: to be run before the rest of the build and prepare the setup.

Resources