Not able to extend a Gradle task - gradle

I'm new with Gradle (we're switching from SBT) and using it to build apps made with Play Framework.
I need to add some filtering on the resources before Gradle processes them (I would like to inject some build properties into the configuration to make them available from the code).
I've managed to "extend" the java processResources task, but, for some reason, I cannot do the same with play processPlayBinaryPlayResources.
processPlayBinaryPlayResources {
filter ReplaceTokens, tokens: [
"applicationVersion": version
]
}
Even this doesn't work :
def playVersion = "2.6.20"
def scalaVersion = "2.12"
def javaVersion = "1.8"
apply plugin: "java"
apply plugin: "idea"
apply plugin: "play"
model {
components {
play {
platform play: playVersion, scala: scalaVersion, java: javaVersion
injectedRoutesGenerator = true
}
}
}
processPlayBinaryPlayResources {
doLast {
println("ok")
}
}
dependencies {
compile "io.vavr:vavr:0.9.2"
compile "org.imgscalr:imgscalr-lib:4.2"
compile "com.typesafe.play:play-guice_${scalaVersion}:2.6.20"
compile "com.typesafe.akka:akka-http_${scalaVersion}:10.1.5"
compile "com.typesafe.play:filters-helpers_${scalaVersion}:2.6.20"
compile "ch.qos.logback:logback-classic:1.2.3"
}
It yields :
> Could not find method processPlayBinaryPlayResources() for arguments [build_6grwx7eowye82rdqpu4qlinur$_run_closure2#582d9dbd] on root project 'myproject' of type org.gradle.api.Project.
Any idea why ?

Your assumption of finding a task processPlayBinaryPlayResources is based on that, that the java plugin automatically adds a processResources task for all source set as process<sourceset_name>Resources . This happens only when a source set is added using java pugins sourceSets method which, in this case PlayBinaryPlay is not. The play plugin uses its own DSL to configure source sets.
Therefore when you try extending processPlayBinaryPlayResources it does not happen as no such tasks by that name exists in the first place and hence while delegating it to Project, you end up with this
Could not find method processPlayBinaryPlayResources() for arguments [build_6grwx7eowye82rdqpu4qlinur$_run_closure2#582d9dbd] on root project 'myproject' of type org.gradle.api.Project.
Lastly, I would like to add that the processPlayBinaryPlayResources task is not added by the play plugin.

Related

How to lazily get main sourceSets in Gradle

I need to configure sources jar for all of my subprojects. I have the following subprojects configuration defined:
subprojects {
apply(plugin = "java-library")
val sourcesJar = tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(the<SourceSetContainer>().named("main").get().allJava)
}
tasks.named("assemble") {
dependsOn(sourcesJar)
}
}
When I try to run ./gradlew tasks I receive an exception in my subproject saying that:
Extension of type 'SourceSetContainer' does not exist. Currently registered extension types: [ExtraPropertiesExtension]
My assumption is that the access to get() method of the extension causes problems but without that I cannot refer to the allJava sources that I need. So how to achieve desired result by using configuration avoidance API?
Running on Gradle 5.2.1 with Kotlin DSL.
I found working solution. The problem is that when you call the<T>() function it is taken from the Task type which is why it complains about absent extension. The solution is to call the<T>() function on project instance like this:
subprojects {
apply {
plugin<JavaLibraryPlugin>()
}
val sourcesJar by tasks.registering(Jar::class) {
archiveClassifier.set("sources")
from(
// take extension from project instance
project.the<SourceSetContainer>().named("main").get().allJava
)
}
}

How to create a custom task in gradle to pack java and kotlin code to a jar?

We have a multi modular setup and we are sharing some tests classes between the modules (mainly Fakes implementations). Our current solution (that you can find below) works just for classes written in Java, but we are looking at supporting also shared kotlin classes.
if (isAndroidLibrary()) {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileDebugUnitTestJavaWithJavac.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = compileDebugUnitTestSources
} else {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileTestJava.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = testClasses
}
task testJar(type: Jar, dependsOn: taskToDependOn) {
classifier = 'tests'
from compileTestCommonJar.outputs
}
How can I modify the compileTestCommonJar so it supports kotlin?
Here is what we do:
In the module with shared test classes, pack the test source set output into a jar
configurations { tests }
...
task testJar(type: Jar, dependsOn: testClasses) {
baseName = "test-${project.archivesBaseName}"
from sourceSets.test.output
}
artifacts { tests testJar }
In a module that depends on the shared classes
dependencies {
testCompile project(path: ":my-project-with-shared-test-classes", configuration: "tests")
}
PS: Honestly, I would prefer to have a separate Gradle module with common test classes as it's more explicit solution.
The task compileTestCommonJar(type: JavaCompile) compiles .java files only because its the task of JavaCompile type.
There's KotlinCompile task aswell, so you would need to merge it, it basically works similary to JavaCompile but compiles .kt files only.
Said that i wouldn't use task system to share the dependencies across, i would use separate module and work with default compileTestKotlin and compileTestJava task's outputs

Use Gradle to generate Java classes from a Swagger definition into a standalone JAR

I am fairly new to both Gradle and Swagger code generator plugin for it (concretely the one that is linked from Swagger's website, i.e. https://github.com/thebignet/swagger-codegen-gradle-plugin), so I'm not sure whether my problem is with Gradle in general or with that particular plugin.
I've created a simple multi-module Spring Boot application (but the fact that I'm using Spring Boot or even Spring doesn't matter much). It's a console application; i.e. it doesn't start a webserver. In fact, it's actually a REST client consuming someone else's interface.
The application consists of four modules: spc-parent (which is just an envelope for the rest) containing spc-boot, spc-service, and spc-integration-model. Spc-boot contains just the starting point of the application, spc-service now contains a single Spring service, and spc-integration-model is meant to contain classes needed to consume the REST interface. The resulting structure will be much more complicated but I've tried to create a sort of a minimal example.
The problem lies within the spc-integration-model module. It consists of a single source file, petstore.json, and a build.gradle copied from https://github.com/thebignet/swagger-codegen-gradle-plugin (and only slightly modified). There are actually two problems (but they may have the same underlying cause).
When running gradle build (from spc-parent) for the very first time, it fails. Java sources are generated from petstore.json but they don't get compiled, which is why the service in spc-service doesn't see needed classes. However, running gradle build a second time fixes this (generated Java sources get compiled which makes it possible to compile spc-service, too).
The created JAR of spc-integration-model never contains anything besides Manifest.
My goal here is to persuade Gradle to compile the generated classes right away during the first build and also to put them into the JAR.
Now for some concrete Gradle tasks. The most interesting is spc-integration-model's build.gradle:
plugins {
id 'org.detoeuf.swagger-codegen' version '1.7.4'
id 'java'
}
apply plugin: 'org.detoeuf.swagger-codegen'
repositories {
mavenCentral()
jcenter()
}
swagger {
inputSpec = 'http://petstore.swagger.io/v2/swagger.json'
outputDir = file('build/swagger')
lang = 'java'
additionalProperties = [
'apiPackage' : 'ondra.spc.integration.client.api',
'dateLibrary' : 'java8',
'hideGenerationTimestamp': 'true',
'invokerPackage' : 'ondra.spc.integration.client',
'library' : 'resttemplate',
'modelNameSuffix' : 'Dto',
'modelPackage' : 'ondra.spc.integration.client.model'
]
importMappings = [
'Dog': 'io.swagger.petstore.client.model.Dog'
]
}
sourceSets {
swagger {
java {
srcDir file("${project.buildDir.path}/swagger/src/main/java")
}
}
}
classes.dependsOn('swagger')
ext {
spring_boot_version = springBootVersion
jackson_version = jacksonVersion
junit_version = jUnitVersion
swagger_annotations_version = swaggerAnnotationsVersion
swagger_codegen_version = swaggerCodegenVersion
}
dependencies {
swaggerCompile "org.springframework.boot:spring-boot-starter-web:$spring_boot_version"
swaggerCompile "io.swagger:swagger-annotations:$swagger_annotations_version"
compile sourceSets.swagger.output
compile "com.fasterxml.jackson.core:jackson-core:$jackson_version"
compile "com.fasterxml.jackson.core:jackson-annotations:$jackson_version"
compile "com.fasterxml.jackson.core:jackson-databind:$jackson_version"
compile "io.swagger:swagger-codegen:$swagger_codegen_version"
testCompile "junit:junit:$junit_version"
}
(Now that I'm re-reading my question I see that the local version of petstore.json is actually not used and an online version is used instead but let's leave that aside.)
The rest should be quite straightforward. spc-service:
dependencies {
compile "org.springframework:spring-context:$springVersion"
compile "org.springframework:spring-web:$springVersion"
compile project (":spc-integration-model")
}
spc-boot:
dependencies {
compile "org.springframework.boot:spring-boot:$springBootVersion"
compile "org.springframework.boot:spring-boot-autoconfigure:$springBootVersion"
compile "org.springframework:spring-web:$springVersion"
runtime "org.hibernate.validator:hibernate-validator:$hibernateVersion"
runtime "com.fasterxml.jackson.core:jackson-databind:$jacksonVersion"
compile project (":spc-service")
testCompile("org.junit.jupiter:junit-jupiter-api:$jUnitVersion")
testRuntime("org.junit.jupiter:junit-jupiter-engine:$jUnitVersion")
}
test {
useJUnitPlatform()
}
spc-parent:
subprojects {
apply plugin: 'java'
group 'ondra'
version '1.0-SNAPSHOT'
buildscript {
ext {
hibernateVersion = '6.0.9.Final'
jacksonVersion = '2.9.4'
springBootVersion = '2.0.0.RELEASE'
springVersion = '5.0.5.RELEASE'
swaggerAnnotationsVersion = '1.5.16'
swaggerCodegenVersion = '2.2.3'
jUnitVersion = '5.1.1'
}
repositories {
mavenCentral()
}
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
}
}
And spc-parent's settings.gradle:
rootProject.name = 'spc-parent'
include 'spc-boot'
include 'spc-service'
include 'spc-integration-model'
I've also put the whole application into a single archive: https://drive.google.com/open?id=1cOYIcaxnhik548w0wEGswgD2g4udATdD

Gradle: change property of task from a plugin

This is about as basic as it could be... but I haven't found the answer either here or at gradle.org or generally. NB Gradle 4.4.1, Groovy 2.4 (used by Eclipse-Gradle) or 2.6 (command line). Java 8.
In my build.gradle I have the application plugin and have set the main class:
apply plugin: 'application'
mainClassName = "core.ConsoleHandler"
... including this plugin adds 2 "dependency tasks" (if that's the right term: i.e. build is now "dependent" on them): taskZip and taskTar.
Here we see that taskZip is of type Zip... and looking up the doc for this subclass of Task here we see that one of the properties of such a Task is destinationDir... i.e. where the .zip file ends up.
All I want to do is set this to a specific directory.
I've tried (in build.gradle) things like
task application.taskZip {
destinationDir = 'D:/bobble'
}
and
taskZip {
destinationDir = 'D:/bobble'
}
and
destinationDir = 'D:/bobble'
These all produce fatal errors. What should I be doing?
It's distZip not taskZip
apply plugin: 'application'
distZip {
destinationDir = file('D:/bobble')
}
destinationDir takes a File parameter
Try something like that :
tasks.withType(taskZip) {
destinationDir = file("D:/bobble")
}

Gradle war ignores transitive dependencies when using 'configurations.runtime.asPath' in custom task

I'm facing behavior that I can't explain, using gradle 1.10 I have:
settings.gradle:
include('lib1', 'lib2', 'web')
build.gradle:
subprojects {
apply plugin: 'java'
}
project(':web') {
apply plugin: 'war'
dependencies {
compile project(':lib1')
}
task myTask(type: JavaExec, dependsOn: 'compileJava') {
main = "some.thirdparty.Class"
args "--searchPath", configurations.runtime.asPath
}
}
project(':lib1') {
dependencies {
compile project(':lib2')
}
}
project(':lib2') {
}
When I run gradle clean war I only have lib1.jar in war/build/libs/web.war/WEB-INF/lib.
To make WEB-INF/lib contain both lib1.jar and lib2.jar I have to:
move project('web') block to the end of the file
update configurations.runtime.asPath to configurations.runtime (but I need to provide class path as a path, so it is not a solution)
I read the build lifecycle description, tried to compare --debug outputs but that didn't help.
Why is this happening? And what would be a good solution to provide the module runtime class path as a path in JavaExec task please?
asPath resolves the configuration, but resolution will only work correctly if it happens at execution time rather than configuration time (in particular in the presence of project dependencies). Try to wrap the args line with doFirst { ... }.

Resources