Adding a 'provided' configuration to a kotlin/java library using gradle - gradle

I have a java library to which I've added a 'provided' configuration using gradle.
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'checkstyle'
apply from: file('../gradle/gradle-mvn-push.gradle')
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
repositories {
mavenCentral()
}
group = GROUP
version = VERSION_NAME
configurations {
provided
}
sourceSets {
main.compileClasspath += configurations.provided
test.compileClasspath += configurations.provided
test.runtimeClasspath += configurations.provided
}
javadoc.classpath += configurations.provided
idea {
module {
scopes.PROVIDED.plus += [configurations.provided]
}
}
checkstyle {
configFile = new File(rootDir, 'checkstyle.xml')
toolVersion = '6.7'
}
dependencies {
provided 'com.google.android:android:2.3.1'
compile 'com.squareup:javawriter:2.5.0'
compile 'com.workday:metajava:1.0'
}
Everything works as expected with this setup.
Now I want to start using kotlin in my library, so I modified the build script to look like this (sans pluses)
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+ dependencies {
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:0.12.613"
+ }
+}
apply plugin: 'java'
apply plugin: 'idea'
+apply plugin: 'kotlin'
apply plugin: 'checkstyle'
apply from: file('../gradle/gradle-mvn-push.gradle')
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
repositories {
mavenCentral()
}
group = GROUP
version = VERSION_NAME
configurations {
provided
}
sourceSets {
main.compileClasspath += configurations.provided
test.compileClasspath += configurations.provided
test.runtimeClasspath += configurations.provided
}
javadoc.classpath += configurations.provided
idea {
module {
scopes.PROVIDED.plus += [configurations.provided]
}
}
checkstyle {
configFile = new File(rootDir, 'checkstyle.xml')
toolVersion = '6.7'
}
dependencies {
provided 'com.google.android:android:2.3.1'
compile 'com.squareup:javawriter:2.5.0'
compile 'com.workday:metajava:1.0'
+ compile "org.jetbrains.kotlin:kotlin-stdlib:0.12.613"
}
Without even adding any kotlin files (and even if I do), the library no longer compiles saying that it can't find the classes in the provided library (android in my case).
What do I need to change to get it so that the provided dependencies are recognized again?

That's how I do it in a Gradle plugin:
private void addProvidedConfiguration() {
final Configuration provided =
addConfiguration(project.configurations, "provided")
final Javadoc javadoc =
project.tasks.getByName(JavaPlugin.JAVADOC_TASK_NAME) as Javadoc
javadoc.classpath = javadoc.classpath.plus(provided)
}
private static Configuration addConfiguration(
final ConfigurationContainer configurations, final String name) {
final Configuration compile =
configurations.getByName(JavaPlugin.COMPILE_CONFIGURATION_NAME)
final Configuration configuration = configurations.create(name)
compile.extendsFrom(configuration)
configuration.visible = false
configuration.transitive = false
configuration.allDependencies.all { final dependency ->
configurations.default.exclude(group: dependency.group, module: dependency.name)
}
return configuration
}
You can check the source code on github.

This gradle-propdeps plugin for Gradle adds provided and optional to Gradle, and also handles its integration into IntelliJ IDEA and Eclipse. It is from the Spring team and it has a lot of usage.
You should apply the kotlin plugin after propdeps.
I have not tested this with Android libraries, but it is a much safer bet than trying to roll your own. There are little special cases to handle.
An alternative plugin, also used heavily is the one from Netflix team who has many plugins available for different useful additions to Gradle. This plugin adds the same provided and optional.
This is a good reminder that the old issue Provide a 'provided' configuration for Gradle is still outstanding for 6 years, and feel free to provide your opinion there as to the lack of this feature.

Related

Gradle Multi-Project Integration Tests with Junit5

How can I create integrations tests using Gradle 5.2 and JUnit 5.3 in a multi-project build file?
This is my current build file:
buildscript {
repositories {
maven {
url "https://plugins.gradle.org/m2/"
}
}
dependencies {
classpath "gradle.plugin.com.github.spotbugs:spotbugs-gradle-plugin:1.6.10"
classpath 'org.owasp:dependency-check-gradle:5.0.0-M2'
}
}
allprojects {
defaultTasks 'clean', 'build', 'publish', 'installDist'
group = 'coyote'
version = '0.1.0'
}
subprojects {
apply plugin: 'java'
apply plugin: 'jacoco'
apply plugin: "com.github.spotbugs"
apply plugin: 'org.owasp.dependencycheck'
apply plugin: 'maven-publish'
apply plugin: 'application'
apply plugin: 'eclipse'
apply plugin: 'idea'
repositories {
jcenter()
mavenCentral()
}
dependencies {
testImplementation ("org.junit.jupiter:junit-jupiter-api:5.3.2")
testRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.3.2")
spotbugsPlugins ("com.h3xstream.findsecbugs:findsecbugs-plugin:1.8.0")
}
tasks.withType(Test) {
useJUnitPlatform()
}
apply from: "$rootDir/integration-test.gradle"
check.dependsOn jacocoTestCoverageVerification
check.dependsOn dependencyCheckAnalyze
spotbugs {
effort = "max"
reportLevel = "low"
ignoreFailures = true
showProgress = true
}
jacocoTestReport {
reports {
xml.enabled true
html.enabled true
}
}
check.dependsOn jacocoTestReport
tasks.withType(com.github.spotbugs.SpotBugsTask) {
reports {
xml.enabled false
html.enabled true
}
}
}
The integration-test.gradle file I am applying on line 46 contains the following:
sourceSets {
itest {
compileClasspath += sourceSets.main.output + configurations.testCompile
runtimeClasspath += output + compileClasspath + configurations.testRuntime
}
}
idea {
module {
testSourceDirs += sourceSets.itest.java.srcDirs
testResourceDirs += sourceSets.itest.resources.srcDirs
scopes.TEST.plus += [configurations.itestCompile]
}
}
task itest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.itest.output.classesDirs
classpath = sourceSets.itest.runtimeClasspath
outputs.upToDateWhen { false }
}
Everything seems to work well within Intellij, but JUnit5 is not being added to the classpath, so any tests in the itest directories cannot find the JUnit libraries.
Running gradlew itest fails with similar results with the JUnit classes not being found.
I have tried to add use useJUnitPlatform() directly in the itest task, but with no success. I have also tried placing everything in the build.gradle file with no success.
Eventually, I'd like to use the same pattern to define load and security testing, running them separately as part of a CI/CD pipeline so placing everything neatly in their own directories under their respective projects is preferred to mixing everything in one test directory and using tags.
This is also helping other teams model CI/CD practices, so using Gradle 5 and JUnit 5 as designed is preferred as opposed to work-arounds or hacks to make things work. It's acceptable to learn that these versions don't work together or that there are currently defects\issues preventing this approach. Hopefully this is not the issue and I'm just missing something simple.
The solution is I needed to include the JUnit 5 dependencies myself. The following is the correct integration-test.gradle file:
sourceSets {
itest {
compileClasspath += sourceSets.main.output + configurations.testCompile
runtimeClasspath += output + compileClasspath + configurations.testRuntime
}
}
idea {
module {
testSourceDirs += sourceSets.itest.java.srcDirs
testResourceDirs += sourceSets.itest.resources.srcDirs
scopes.TEST.plus += [configurations.itestCompile]
}
}
dependencies {
itestImplementation ("org.junit.jupiter:junit-jupiter-api:5.3.2")
itestRuntimeOnly ("org.junit.jupiter:junit-jupiter-engine:5.3.2")
}
task itest(type: Test) {
description = 'Runs the integration tests.'
group = 'verification'
testClassesDirs = sourceSets.itest.output.classesDirs
classpath = sourceSets.itest.runtimeClasspath
outputs.upToDateWhen { false }
}

Trying to add Applied Energistics api through build.gradle

I am starting on a minecraft mod, but I cannot get the build.gradle right.
I wanted to create a mod on top of applied energistics but I cannot get it to build when I add this mod as a gradle dependency. I looked all the dependencies up on an other repository, but when I build it gives errors like below, and some other errors on the general minecraft code base
Error:(3, 26) java: package net.minecraft.init does not exist
This is the code I have right now:
buildscript {
repositories {
jcenter()
maven { url = "http://files.minecraftforge.net/maven" }
}
dependencies {
classpath 'net.minecraftforge.gradle:ForgeGradle:2.3-SNAPSHOT'
}
}
apply plugin: 'net.minecraftforge.gradle.forge'
//Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
version = mod_version + "-" + mod_channel
group = mod_group
archivesBaseName = mod_basename
sourceCompatibility = targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
compileJava {
sourceCompatibility = targetCompatibility = '1.8'
}
minecraft {
version = minecraft_version + "-" + forge_version
replaceIn "package-info.java"
replace "#version#", project.version
replace "#modversion#", mod_version
replace "#modchannel#", mod_channel
// used when launching minecraft in dev env
mappings = mcp_mappings
}
repositories {
maven {
name 'Mobius Repo'
url "http://mobiusstrip.eu/maven"
}
maven {
name = "JEI repo"
url "http://dvs1.progwml6.com/files/maven"
}
}
dependencies {
// installable runtime dependencies
compileOnly "mcp.mobius.waila:Hwyla:${hwyla_version}"
// compile against provided APIs
compileOnly "mezz.jei:jei_${minecraft_version}:${jei_version}:api"
compileOnly "mcp.mobius.waila:Hwyla:${hwyla_version}"
// at runtime, use the full JEI jar
runtime "mezz.jei:jei_${minecraft_version}:${jei_version}"
deobfCompile "appeng:appliedenergistics2:${ae_verion}"
}
processResources {
// this will ensure that this task is redone when the versions change.
inputs.property "version", project.version
inputs.property "mcversion", project.minecraft.version
// replace stuff in mcmod.info, nothing else
from(sourceSets.main.resources.srcDirs) {
include 'mcmod.info'
// replace version and mcversion
expand 'version':project.version, 'mcversion':project.minecraft.version
}
// copy everything else except the mcmod.info
from(sourceSets.main.resources.srcDirs) {
exclude 'mcmod.info'
}
}
The version that I am trying to add is:
ae_verion=rv5-stable-8
You need to add 'api' at the end of the compile argument (used to be 'dev'). Also, iirc adding transitive=false solves dependency issues.
dependencies {
compile ("appeng:appliedenergistics2:${ae_version}:api") {
transitive = false
}
}

How to build Google protocol buffers and Kotlin using Gradle?

I'm trying to build a project that uses both Google protocol buffers and Kotlin using Gradle. I want the proto files to compile into Java source, which is then called from my Kotlin code.
My source files are arranged like this:
src/main/proto/*.proto
src/main/kotlin/*.kt
src/test/kotlin/*.kt
Here's my build.gradle file:
version '1.0-SNAPSHOT'
apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'com.google.protobuf'
repositories {
mavenCentral()
maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}
buildscript {
ext.kotlin_version = '1.1-M02'
repositories {
mavenCentral()
maven { url "http://dl.bintray.com/kotlin/kotlin-eap-1.1" }
}
dependencies {
classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.0.0'
}
}
dependencies {
compile 'com.google.protobuf:protobuf-java:3.0.0'
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
testCompile 'junit:junit:4.12'
}
When I run ./gradlew assemble I get a bunch of "Unresolved reference" errors during :compileKotlin. Afterwards I can see that there are no Java source files generated, so it appears that the proto compiler is not being invoked at all.
If I remove the apply plugin: 'kotlin' line, then ./gradlew assemble successfully generates the Java source, but of course my Kotlin source is never compiled.
How do I fix my build.gradle so that I can call my protobuf code from Kotlin?
To get protobuf-gradle-plugin and kotlin-gradle-plugin to cooperate, you need to ensure that the Java code is (re)generated before invoking the Kotlin compiler.
For Gradle's default source sets, main and test, you can do that like this:
compileKotlin.dependsOn ':generateProto'
compileTestKotlin.dependsOn ':generateTestProto'
If you are using other source sets, you'll need to make adjustments.
Older versions of protobuf-gradle-plugin also required updating sourceSets, but newer versions do not seem to require this.
// Don't do this with protobuf-gradle-plugin 0.9.0 or higher
sourceSets.main.java.srcDirs += "${protobuf.generatedFilesBaseDir}/main/java"
sourceSets.test.java.srcDirs += "${protobuf.generatedFilesBaseDir}/test/java"
For Kotlin and Android:
android {
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/debug/java'
release.java.srcDirs += 'build/generated/source/proto/release/java'
}
}
An additional source directory has to be added for every build type. In this sample there are two build types: debug and release.
If you're using grpc, another line has to be added per build type:
android {
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/debug/java'
debug.java.srcDirs += 'build/generated/source/proto/debug/grpc'
release.java.srcDirs += 'build/generated/source/proto/release/java'
release.java.srcDirs += 'build/generated/source/proto/release/grpc'
}
}
At least with Kotlin 1.0.6, protobuf-gradle-plugin 0.8.0, protobuf 3.2.x and grpc 1.x it's not required to fiddle with the task order.
if you are working with multiple build types and flavors in android and with protobuf-lite use below with kotlin.
for example I have debug and release builds with demo and prod flavors it will create demoDebug, demoRelease and prodDebug and prodRelease variants.
then use
`
android{
sourceSets {
debug.java.srcDirs += 'build/generated/source/proto/demoDebug/javalite'
debug.java.srcDirs += 'build/generated/source/proto/prodDebug/javalite'
release.java.srcDirs += 'build/generated/source/proto/demoRelease/javalite'
release.java.srcDirs += 'build/generated/source/proto/prodRelease/javalite'
}
}
`
tie the different compileKotlin with generateProto
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
if (getName() == 'compileDemoDebugKotlin')
dependsOn(':app:generateDemoDebugProto')
if (getName() == 'compileDemoReleaseKotlin')
dependsOn(':app:generateDemoReleaseProto')
if (getName() == 'compileProdDebugKotlin')
dependsOn(':app:generateProdDebugProto')
if (getName() == 'compileProdReleaseKotlin')
dependsOn(':app:generateProdReleaseProto')
}
For the gradle setup :
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'com.google.protobuf' version "0.8.17"
}
Then at the bottom of the build.gradle
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.10.0"
}
// Generates the java Protobuf-lite code for the Protobufs in this project. See
// https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
// for more information.
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option 'lite'
}
}
}
}
}

Provided scope not working in eclipse

Gradle 2.2.1
I am trying to include dependencies into a jar file that I will ship to other users. I want them to provide their own versions of some dependencies and am trying to emulate the provided scope from maven.
I have followed the tutorial here. I am able to successfully build the project from the command line (while still getting classes not found errors in eclipse) until the eclipse integration part. From the post he says to add eclipse.classpath.plusConfigurations += configurations.provided but I am getting Could not find property 'provided' on configuration container
apply plugin: 'java'
apply plugin: 'eclipse'
// this causes the error
//eclipse.classpath.plusConfigurations += configurations.provided
sourceCompatibility = 1.8
version = '1.0'
jar {
manifest {
attributes 'Implementation-Title': '...',
'Implementation-Version': version
}
}
repositories {
mavenCentral()
}
configurations {
provided
}
sourceSets {
main.compileClasspath += configurations.provided
test.compileClasspath += configurations.provided
test.runtimeClasspath += configurations.provided
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.+'
//Jackson
provided 'com.fasterxml.jackson.core:jackson-core:2.6.2'
provided 'com.fasterxml.jackson.core:jackson-annotations:2.6.2'
provided 'com.fasterxml.jackson.core:jackson-databind:2.6.2'
}
test {
systemProperties 'property': 'value'
}
uploadArchives {
repositories {
flatDir {
dirs 'repos'
}
}
}
Fixed it.
eclipse.classpath.plusConfigurations += configurations.provided
Should be an array
eclipse.classpath.plusConfigurations += [configurations.provided]

Spring Boot Tutorial doesn't work with multi project gradle setup

i get a strange behaviour (at least for me :D) when I switch from the gradle file located in https://spring.io/guides/gs/serving-web-content/ to a multi project gradle file setup.
build.gradle in root directory
//Applied to all projects.
allprojects {
apply plugin: 'eclipse'
apply plugin: 'idea'
group = 'de.test.platform'
version = '0.1'
}
subprojects {
//Currently all subprojects are also java projects. If this changes we
//need to move it into the corresponding projects
apply plugin: 'java'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenLocal()
mavenCentral()
}
idea {
module {
downloadSources = true
downloadJavadoc = false
}
}
}
idea {
project {
jdkName = '1.8'
languageLevel = '1.8'
}
}
build.gradle in sub directory frontend (thus sub project called :frontend)
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.5.RELEASE")
}
}
apply plugin: 'war'
apply plugin: 'spring-boot'
jar {
baseName = 'crowdio-frontend'
version = '0.1.0'
}
dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
testCompile("junit:junit")
}
when I run gradle bootRun and navigate to http://localhost:8080/greeting as in the tutorial i get a infinite loop error. If i change the template from greeting.html to hello.html and return hello instead of greeting in the controller greeting() action i get an 404 Error.
The template is stored in project_root/frontend/src/main/resources/templates/greeting.html
It seems like that for whatever Reason spring boot can decide on thymeleaf with the exact structure of the gradle build file like in the tutorial. However if you switch to a multi project setup you need to add
compile("org.thymeleaf:thymeleaf-spring4")
as a dependency.

Resources