Use Gradle Project Extension Properties In Configuration Phase - plugins

When writing a custom Gradle plugin, how is it possible to access the extension properties defined in the consuming build.gradle in the custom plugin’s configuration phase?
Please see the following MWE.
build.gradle
apply plugin: 'codechecks'
codechecks {
checkstyleConfig = '/home/user/checkstyle.xml'
}
CodechecksPlugin.groovy
class CodechecksPlugin implements Plugin<Project> {
void apply(Project project) {
project.extensions.create('codechecks', CodechecksPluginExtension)
project.apply( [ plugin: 'checkstyle' ] )
project.checkstyle {
configFile = project.codechecks.checkstyleConfig
}
}
}
CodechecksPluginExtension.groovy
class CodechecksPluginExtension {
def checkstyleConfig = 'config/checkstyle/checkstyle.xml'
}
Wanted behavior: The checkstyle plugin uses the configuration file defined in the build.gradle codechecks extension.
Actual behavior: The default value in the CodechecksPluginExtension is being used because the build.gradle codechecks extension is not yet evaluated.
I already tried putting all uses of the codechecks extension in the plugins into closures but they won’t expand correctly due to class casting issues at execution phase.
Thanks for your help!

project.afterEvaluate works for me.
Try:
project.afterEvaluate {
project.checkstyle {
configFile = project.codechecks.checkstyleConfig
}
}

Related

Replacement for ScalaCompile in gradle when switching to Kotlin

I convert a project that was originally written in Scala into kotlin. It is a typical backend - frontend-design with the backend written in Scala and the Frontend in Angular (the code was written by a former co-worker who is no longer working in this project)
During the gradle-build, the e2e-tests are evaluated. For this purpose the backend is compiled in the following way:
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.tasks.scala.ScalaCompile
class ScalaCompilerPlugin implements Plugin<Project> {
void apply(Project project) {
project.configurations {
scalaCompilerPlugin
}
project.afterEvaluate {
project.tasks.withType(ScalaCompile) {
options.encoding = 'UTF-8'
if (scalaCompileOptions.additionalParameters == null) {
scalaCompileOptions.additionalParameters = []
}
scalaCompileOptions.additionalParameters <<
"-Xplugin:" + project.configurations.scalaCompilerPlugin.asPath
}
}
}
}
The 'scalaCompilerPlugin'-plugin is then added to the build.gradle-file in the backend.
plugins {
id 'scala'
id 'com.github.psxpaul.execfork' version '0.1.12'
}
apply plugin: ScalaCompilerPlugin
// ...
Since now the project is converted to Kotlin/Ktor I plan to use something like a KotlinCompiler-plugin for the same purpose, but in gradle 6.0.1, there seems to be no such plugin, and not being that firm with gradle I don't know how to add org.jetbrains.kotlin.gradle.tasks.KotlinCompile.
How can I achieve the same and start the backend during the gradle-build to run the e2e-tests during the test-runs? I am also open to suggestions to change this design.

Using sbt Avrohugger plugin in gradle

I am using https://github.com/julianpeeters/avrohugger sbt plugin to generate Scala case classes for Avro .avsc files. How can I use the same plugin in a Gradle project?
I created gradle plugin for generating Scala case classes from Avro schema and it internally uses avrohugger library.
So now it's enough to add this plugin to your project:
plugins {
id 'com.zlad.gradle.avrohugger' version '0.2.1'
}
When you want to compile Scala sources you need Scala library dependency too:
plugins {
id 'scala'
id 'com.zlad.gradle.avrohugger' version '0.2.1'
}
repositories {
mavenCentral()
}
dependencies {
compile 'org.scala-lang:scala-library:2.12.8'
}
Scala classes will be automatically generated during build before compileScala task. By default avro schema should be in src/main/avro and generated sources will be in build/generated-src/avro
You can call generateAvroScala to invoke Scala sources generation manually.
You can find all details and configuration options on gradle-avrohugger-plugin github page.
I ended up using the avrohugger-tools library in Gradle to autogenerate Scala case classes whenever my schemas were updated. Your mileage may vary, but this finally worked for me:
build.gradle.kts
import java.io.File
plugins {
scala
id("com.github.maiflai.scalatest") version "0.19"
}
version = "1.0"
configurations {
register("avrohugger-tools")
}
dependencies {
// Scala std-libs
implementation(Dependencies.Libs.Scala.library)
// AvroHugger tools JAR
"avrohugger-tools"("com.julianpeeters:avrohugger-tools_2.12:1.0.0-RC14")
// testing
testImplementation(gradleTestKit())
testImplementation("junit:junit:4.12")
testImplementation("org.scalatest:scalatest_2.12:3.0.5")
testRuntime("org.pegdown:pegdown:1.4.2")
}
fun normalizeFileSeparator(path: String) = path.replace('/', File.separatorChar)
val genAvro = task<JavaExec>("genAvro") {
val sourceAvroPath = normalizeFileSeparator("src/main/avro/")
val sourceAvroFiles = fileTree(mapOf(
"dir" to sourceAvroPath, "include" to listOf("**/*.avsc")
))
val targetPath = normalizeFileSeparator("src/gen/")
doFirst {
delete(targetPath)
}
classpath = configurations["avrohugger-tools"]
main = "avrohugger.tool.Main"
args(
"generate", "schema",
sourceAvroFiles.files.joinToString(separator=" "),
targetPath
)
inputs.files(sourceAvroFiles)
outputs.files(targetPath)
}
the<JavaPluginConvention>().sourceSets.getByName(
SourceSet.MAIN_SOURCE_SET_NAME
).java.srcDir("gen")
tasks.withType<ScalaCompile> {
dependsOn(genAvro)
}
inline fun <reified T : Task> TaskContainer.existing() = existing(T::class)
inline fun <reified T : Task> TaskContainer.register(name: String, configuration: Action<in T>) = register(name, T::class, configuration)
Note that I'm also building/test a Scala source tree in this package, so some of the Scala-specific pieces can be presumably elided.
Really hope this helps!

Gradle plugin development error passing arguments

I am trying to create a custom gradle plugin following the example here: http://www.javacodegeeks.com/2012/08/gradle-custom-plugin.html. Everything works fine as long as I dont try to provide arguments to the task, however when I attempt to add arguments, I receive the following error:
Error:(26, 0) Task of type 'com.jwoolston.finalizer.gradle.FinalizerTask_Decorated' has been instantiated directly which is not supported. Tasks can only be created using the DSL.
I've googled it but I don't seem to be getting any results related to my situation (at least not that I understand.
The plugin short id is declared in the generated jar's manifest as: finalizer-plugin.
I have the following files:
FinalizerPlugin.groovy
class FinalizerArgumentExtension {
String path = ''
}
class FinalizerPlugin implements Plugin<Project> {
#Override
void apply(Project project) {
project.extensions.create('finalizeArgs', FinalizerArgumentExtension)
project.task('finalizeTask', type: FinalizerTask)
}
}
FinalizerTask.groovy
class FinalizerTask extends DefaultTask {
#TaskAction
def executeTask() {
println "------------executeTask-------------------"
println "Source Directory : ${project.finalizeArgs.path}"
}
}
Plugin related exerpt of build.gradle of the utilizing project:
apply plugin: 'java'
apply plugin: 'maven'
version = '1.0.0'
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.11'
}
buildscript {
repositories {
maven {
url uri("file://C:\\Users\\ideal\\.m2\\repository")
}
}
dependencies {
classpath group: 'com.jwoolston.finalizer',
name: 'gradle',
version: '1.0.1-SNAPSHOT'
}
}
apply plugin: 'finalizer-plugin'
finalizeArgs {
path = "src/main/java"
}
In short, I don't understand the error. Near as I can tell, everything matches the tutorial. I am trying to simply pass in a string argument to the plugin's task.
Plugin class needs to be fixed as follows:
class FinalizerPlugin implements Plugin<Project> {
#Override
void apply(Project project) { ... }
}
Groovy only supports String interpolation for double-quoted Strings:
println "Source Directory : ${project.finalizeArgs.path}"

Gradle + Eclipse: How to not export JARs that are dependencies of a dependency?

In my build.gradle file I have the following:
...
dependencies {
...
testCompile (group: 'org.uncommons', name: 'reportng', version: '1.1.2') { exclude group: 'org.testng', module: 'testng' }
...
}
...
reportng needs velocity-1.4.jar and velocity-dep-1.4.jar, and actually the above testCompile dependency causes these 2 JARs to be fetched and to be placed into the Eclipse's .classpath file, as "exported" (that is, their checkboxes in the "Order and Export" tab of Eclipse's "Java Build Path" dialog are checked).
The fact that these 2 JARs get set as exported is a problem. I need them to still be fetched but not to be exported.
From the Gradle doc I understand that this is done by using noExportConfigurations as per their example:
apply plugin: 'java'
apply plugin: 'eclipse'
configurations {
provided
someBoringConfig
}
eclipse {
classpath {
//if you don't want some classpath entries 'exported' in Eclipse
noExportConfigurations += configurations.provided
}
}
My problem is that I don't have a configurations {} section, and while I can certainly add one, I don't know what to put in it in order to exclude from export not the whole reportng but just two of the JARs that come with it.
You'll probably want something like:
configurations {
noExport
}
dependencies {
// replace with correct values
noExport "foo:velocity:1.4"
noExport "foo:velocity-dep:1.4"
}
eclipse {
classpath {
noExportConfigurations += configurations.noExport
}
}
PS: Please don't double-post here and on http://forums.gradle.org.
Apparently, in the year and a half that has gone by since Peter's answer, noExportConfigurations is deprecated and slated to be removed in Gradle 3.0. What's more, none of the solutions in the linked Gradle forum thread allow me to remove a dependency imported from a folder, like war/WEB-INF/lib, for instance.
So after much research, I stumbled upon an example here at the end of this build.gradle file in GitHub, which reorders entries in the classpath:
withXml { xml ->
def node = xml.asNode()
node.remove( node.find { it.#path == 'org.eclipse.jst.j2ee.internal.web.container' } )
node.appendNode( 'classpathentry', [ kind: 'con', path: 'org.eclipse.jst.j2ee.internal.web.container', exported: 'true'])
}
I modified the example so that it simply removes a JAR file using the regex capabilities of the Groovy Node. Note that the xml -> part is not needed, and that this entry is a child of the file closure:
withXml {
def node = it.asNode()
node.remove( node.find { it.#path ==~ /.*velocity-1\.4\.jar/ } )
node.remove( node.find { it.#path ==~ /.*velocity-dep-1\.4\.jar/ } )
}

Make Gradle NOT use a source set directory as Eclipse source folder

I have an extra java source set in my build, called gen - as in generated sources with lots of compiler warnings in them. The gradle eclipse task configures the source directory of this set as eclipse source folder, which leads to a lot of warnings I don't want to see. Another reason is, that the generated source code should not be changed - I don't want somebody to edit it by accident, thinking it is a regular code.
The following works, but only when overwriting existing configuration with gradle eclipse.
eclipse.classpath.file {
whenMerged { classpath ->
classpath.entries.removeAll {
entry -> entry.kind == 'src' && entry.path == 'src/gen/java'
}
}
}
However, it does not work if the configuration is cleaned - gradle cleanEclipse eclipse , which is what happens when you first import the project in eclipse.
Reading the EclipseClasspath object documentation, I figure that the only other way is to use eclipse.classpath.file.withXml , but it seams too messy to edit the raw xml.
Is there any other more elegant solution?
I solved a similar scenario by adding the 'gen' directory to the main java sourceSet.
As follows
configurations {
jaxb
}
dependencies {
jaxb 'com.sun.xml.bind:jaxb-xjc:'
}
sourceSets.main.java.srcDirs 'gen'
task createGenDirs() {
file("gen").mkdirs()
}
task jaxb << {
dependsOn createGenDirs
//generate src into gen directory
}
task cleanGeneratedCode(type: Delete) {
delete file("gen")
clean.dependsOn cleanGeneratedCode
hope this helps
Here is how I achieved this (in my case, the source folders were merged and only packages differed):
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/main/java'
exclude 'com/foo/generated/**'
}
}
// This sourceset is ignored by Eclipse
gen {
java {
srcDir 'src/main/java'
include 'com/foo/generated/**'
}
}
}
// Include in a real build from Gradle rather than Eclipse
compileJava {
source sourceSets.gen.java
}
If Eclipse doesn't know about generated source that other code is using, then you might end up with compiler errors in Eclipse instead.
But maybe if there was a source directory that gradle was using to create a 2nd jar, or something like that. If you have that stuff as a separate source set, then you can exclude that from eclipse:
sourceSets {
main {
java { srcDir 'src' }
}
gen {
java { srcDir 'src-gen' }
}
}
eclipse {
classpath {
sourceSets -= [sourceSets.gen]
}
}
I have a slightly different situation where my project file references another project's source, so I don't want any code to show up in Eclipse:
sourceSets.main.java { srcDir '../other_project/src' }
eclipse {
classpath {
// remove the source set from the Eclipse classpath
sourceSets -= [sourceSets.main]
}
// Don't let the src dir show up as a linked folder either
project {
file {
withXml {
def res = it.asNode().get('linkedResources')[0]
res.link.findAll{ it.name[0].text() == 'src' }.each{
res.remove(it) }
}
}
}
}