Specify kotlin version in buildSrc kotlin convention plugin - kotlin

I am developing a Kotlin project with multiple subprojects as explained here
Building Kotlin Applications with libraries Sample (gradle.org)
Is it correct to specify the kotlin version as as shown below?
file: buildSrc/build.gradle.kts
dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:<kotlin-version>")
}
Also, is it possible to move this kotlin version to a central location for declaring project-wide dependency version (for example gradle.properties or buildSrc/**/Dependencies.kt or versions catalog)? None of the approaches mentioned seems to be supported in buildSrc/build.gradle.kts.

There are many approaches to specify the kotlin version (or versions of any dependency) at a centralized location in a Gradle Multimodule Project.
gradle.properties
buildSrc/**/Dependency.kt
versions catalog
However, if you are defining a Kotlin Convention Plugin in buildSrc, the kotlin version is not available in buildSrc/build.gradle.kts using any of the methods mentioned above so as to pick the right kotlin-gradle-plugin.
For a workaround solution, use the following.
# file:<root>/gradle.properties
kotlinVersion=1.5.31
// file:<root>/buildSrc/build.gradle.kts
import java.io.*
import java.util.*
// read gradle.properties programmatically
val props = Properties()
FileInputStream(file("../gradle.properties")).use {
props.load(it)
}
plugins {
`kotlin-dsl`
}
repositories {
gradlePluginPortal()
}
dependencies {
val kotlinVersion = props.getProperty("kotlinVersion")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlinVersion}")
}
In all other <root>/**/<subproject>/build.gradle.kts files access the kotlinVersion like
val kotlinVersion = project.properties["kotlinVersion"]
In settings.gradle.kts, access the kotlinVersion like
val kotlinVersion:String by settings
If anyone from the Gradle team reading this, please provide an API to access gradle.properties consistently across any of the build script files.

in app gradle
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
and project gradle
ext.kotlin_version = "1.6.0"

I have solved this issue by specifying kotlinVersion in gradle.properties file as below.
kotlinVersion=1.6.10
Keep gradle.properties file at outermost project level.
You can access kotlinVersion in any submodules and project as
//top level declaration
val kotlinVersion by extra(project.property("kotlinVersion"))
//usage in dependency block
"org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}"
To verify whether you are able to read it, you can specify following
println(project.property("kotlinVersion"))
This should print kotlin version as
> Configure project :
1.6.10
build.gradle.kts file
val kotlinVersion by extra(project.property("kotlinVersion"))
println("${kotlinVersion}")
group = "com.company"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
mavenLocal()
maven { url = uri("https://repo.spring.io/milestone") }
maven { url = uri("https://repo.spring.io/snapshot") }
gradlePluginPortal()
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:${kotlinVersion}")
}
gradle.properties file
kotlin.code.style=official
#kotlin.parallel.tasks.in.project=true
#kapt.incremental.apt=true
org.gradle.parallel=true
org.gradle.caching=false
org.gradle.daemon=true
org.gradle.jvmargs=-Dfile.encoding=UTF-8
kotlinVersion=1.6.10
Ref:
project_properties
extra_properties

Related

"Could not find method wrapper()" in build.gradle file generated by openapi-generator kotlin client

I have a simple spring boot project using the kotlin gradle dsl. I want to generate an OpenApi client using the openapi client generator gradle Plugin. I have successfully done so, using this configuration. Until now, this was a single project build. But when i try to include it, i get an error message "Could not find method wrapper()".
This is how i generated the client and added it's file into my source sets:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "3.0.2"
id("io.spring.dependency-management") version "1.1.0"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
id("org.openapi.generator") version "6.3.0"
}
// other dependencies
openApiGenerate {
generatorName.set("kotlin")
inputSpec.set("src/main/openapi/my-api.yml")
outputDir.set("$buildDir/generated/my-api")
packageName.set("com.myapi")
}
kotlin.sourceSets["main"].kotlin.srcDir("$buildDir/generated/my-api/src/main/kotlin")
Now i want to use this generated client in my project. It comes with it's own build.gradle (in groovy) which loads the necessary dependencies etc.
I have modified my settings.gradle.kts file accordingly:
rootProject.name = "myapp"
include("build:generated:my-api")
When i reload gradle, i get the follwing error:
> Could not find method wrapper() for arguments [build_gdswinwcvulw9afq79kj4v6h$_run_closure1#582f32f7] on project ':build:generated:my-api' of type org.gradle.api.Project.
This is due to the build.gradle file generated by the generator looking like this:
group 'org.openapitools'
version '1.0.0'
wrapper {
gradleVersion = '7.5'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
buildscript {
ext.kotlin_version = '1.7.21'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin'
apply plugin: 'maven-publish'
repositories {
maven { url "https://repo1.maven.org/maven2" }
}
test {
useJUnitPlatform()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
implementation "com.squareup.okhttp3:okhttp:4.10.0"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
}
I am using Gradle 7.6 and i am a bit out of ideas here since i am pretty new to Gradle.

How can I apply a plugin to itself using Kotlin DSL?

We have an existing plugin project which configures various things (including static analysis), where we want to apply the plugin to the project itself.
The way this currently works for plugins written in Java is, you add the Java src dir to the buildSrc project, and then classes built there can be used in the main project. So I'm trying to get the same thing working for plugins written as Kotlin scripts.
But when I try to build it, compiling buildSrc fails with:
e: C:\Users\Trejkaz\Documents\test\self-applying-gradle-plugin\src\main\kotlin\example.common.gradle.kts: (1, 1): Unresolved reference: allprojects
> Task :buildSrc:compileKotlin FAILED
What's missing in order to make this work?
Further investigation:
If I put a copy of the files in buildSrc/src/main/kotlin, that works.
If I put a copy of the files in buildSrc/src/main/kotlin2 and use srcDirs to set that directory, that fails too. So it really looks like something isn't letting me relocate sources at all.
I pushed a repo to play with this here but what follows is the contents of the build scripts in case it's ever deleted.
The main build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`java-gradle-plugin`
`kotlin-dsl`
// Matching version in Gradle
kotlin("jvm") version "1.5.31"
}
apply(from = "common-build.gradle.kts")
apply(plugin = "example.common") // 👈 trying to apply the compiled plugin here
group = "org.example"
version = "1.0-SNAPSHOT"
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
In buildSrc/build.gradle.kts, we have this - note that it adds a source dir for the sources in the main directory:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`java-gradle-plugin`
`kotlin-dsl`
// Matching version in Gradle
kotlin("jvm") version "1.5.31"
}
apply(from = "../common-build.gradle.kts")
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
kotlin {
sourceSets["main"].kotlin.srcDir("../src/main/kotlin")
}
common-build.gradle.kts has everything common to both build scripts which we've figured out how to move to a common location (notably, the KotlinCompile isn't there, later I'll figure out why I can't move that as well):
repositories {
mavenCentral()
}
dependencies {
// Needed to compile Kotlin stuff but not added by the plugin for some reason
"implementation"("org.jetbrains.kotlin:kotlin-scripting-jvm")
}
The plugin script, src/main/kotlin/example.common.gradle.kts, contains:
allprojects {
// Configure something
}
This turns out to be a bug in Gradle's kotlin-dsl plugin.
The workaround is to add the source dirs before applying the plugin.
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
`java-gradle-plugin`
`kotlin-dsl` apply false
// Matching version in Gradle
kotlin("jvm") version "1.5.31"
}
apply(from = "../common-build.gradle.kts")
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
kotlin {
sourceSets["main"].kotlin.srcDir("../src/main/kotlin")
}
// Workaround for https://github.com/gradle/gradle/issues/21052 -
// apply kotlin-dsl plugin last, because it erroneously fetches source dirs eagerly.
apply(plugin = "org.gradle.kotlin.kotlin-dsl")

Applying org.jetbrains.kotlin.jvm within custom Gradle plugin not working

I'm writing a custom Gradle plugin using Kotlin. The goal is to apply and configure certain plugins within this custom plugin. Consumers should only need to apply the custom plugin and be all set.
The problem:
I want to apply these two kotlin plugins (and other plugins) in the custom plugin (which can be applied like this normally in a Gradle build script):
kotlin("jvm") version "1.4.10"
kotlin("plugin.spring") version "1.4.10"
But when applying them from within my own plugin a couple of things goes wrong.
The jar task is not found. I get this complaint in the project consuming my plugin.
The contents of the dependencies section, e.g api, implementation etc are also causing errors, like if Gradle doesn't understand what they are.
I can, in the consuming project however, simply add the line below to the build script to get the jar task back, and make dependencies work again:
kotlin("jvm") version "1.4.10"
I also wrote a sort of debug function in the consuming Gradle build, just to see what plugins are applied. They all print true when I apply only my own plugin (or add kotlin-jvm to the script manually). Which seems to me like my own plugin is doing its job.
open class GreetingTask : DefaultTask() {
#TaskAction
fun greet() {
println("hello from GreetingTask")
println(project.pluginManager.hasPlugin("org.springframework.boot"))
println(project.pluginManager.hasPlugin("io.spring.dependency-management"))
println(project.pluginManager.hasPlugin("com.github.ben-manes.versions"))
println(project.pluginManager.hasPlugin("org.jetbrains.kotlin.jvm"))
println(project.pluginManager.hasPlugin("org.jetbrains.kotlin.plugin.spring"))
println(project.pluginManager.hasPlugin("java"))
}
}
My apply method so far in my plugin:
override fun apply(project: Project) {
configureRepositories(project)
configureTesting(project)
configureJava(project)
configureSpringBoot(project)
configureSpringDependencyManagement(project)
configureKotlin(project)
configureVersions(project)
configurePublishing(project)
}
And for setting up Kotlin:
private fun configureKotlin(project: Project) {
project.pluginManager.apply("org.jetbrains.kotlin.jvm")
project.pluginManager.apply("org.jetbrains.kotlin.plugin.spring")
project.tasks.withType(KotlinCompile::class.java).configureEach { task ->
task.kotlinOptions.freeCompilerArgs = listOf("-Xjsr305=strict")
task.kotlinOptions.jvmTarget = "11"
}
}
All the other configureXYZ seems to work out fine.
I solved it. The problem was how I applied the plugin.
This does NOT work:
build.gradle.kts
buildscript {
repositories {
mavenLocal()
gradlePluginPortal()
}
dependencies {
classpath("com.praqma:demo:1.0.0")
}
}
apply(plugin = "com.praqma.demo.DemoPlugin")
This does work:
settings.gradle.kts
pluginManagement {
repositories {
mavenLocal()
gradlePluginPortal()
}
}
build.gradle.kts
plugins {
id("gradle.demoPlugin") version "0.0.1-SNAPSHOT"
}

How to set up Kotlin PSI for IntelliJ IDEA Gradle Plugin?

I'm building a Plugin for the IntelliJ IDE to manipulate Kotlin files in a project. I've been able to write a bunch of tests to take a Kotlin file and generate a new file based on its contents. When I run this plugin in the IDE I'm unable to detect files as Kotlin files. When looking at the debugger my file says that it is a KtFile from the org.jetbrains.kotlin.psi library. But if I try to cast it to a KtFile I get an error:
java.lang.ClassCastException: org.jetbrains.kotlin.psi.KtFile cannot be cast to org.jetbrains.kotlin.psi.KtFile
So apparently the library version is off between runtime and compile time. What do I have to do to configure my plugin to use the correct Kotlin PSI at plugin runtime?
My plugin.xml looks like this:
<idea-plugin>
<id>...</id>
<name>...</name>
<vendor email="..." url="...">...</vendor>
<description><...</description>
<depends>com.intellij.modules.all</depends>
<depends>org.jetbrains.kotlin</depends>
<actions>...</actions>
</idea-plugin>
My build.gradle.kts looks like:
plugins {
id("org.jetbrains.intellij") version "0.4.16"
kotlin("jvm") version "1.3.61"
}
group = "..."
version = "..."
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("compiler-embeddable", "1.3.61"))
implementation(kotlin("gradle-plugin", "1.3.61"))
testImplementation(group = "junit", name = "junit", version = "4.12")
}
buildscript {
repositories { mavenCentral() }
dependencies {
classpath(kotlin("compiler-embeddable", "1.3.61"))
classpath(kotlin("gradle-plugin", "1.3.61"))
}
}
intellij {
version = "2019.1.4"
setPlugins("Kotlin")
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
tasks.getByName<org.jetbrains.intellij.tasks.PatchPluginXmlTask>("patchPluginXml") {
changeNotes("...")
}
I already am aware of How to include Kotlin PSI classes (e.g. KtClass) in Intellij IDEA Gradle plugin project written in Kotlin? and How to add Kotlin PSI source files to IDEA Plugin project configuration which is essentially what I want to be answered but haven't gotten anything to fix my issue. Maybe there is some documentation on this issue but it evades my searches.
Your dependencies should include implementation(kotlin("reflect")) and plugin.xml should include <depends>org.jetbrains.kotlin</depends>

How to ignore explicitly importing classes like gradle kotlin script when writing custom kotlin-dsl

In the gradle's kotlin build script, we don't need explicitly import classes or functions like plugins, repositories or dependencies in build script build.gradle.kts.
plugins {
val kotlinVersion = "1.3.10"
val springBootVersion = "2.1.0.RELEASE"
val detektVersion = "1.0.0-RC10"
id("org.springframework.boot") version springBootVersion
id("org.jetbrains.kotlin.jvm") version kotlinVersion
id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
id("io.spring.dependency-management") version "1.0.6.RELEASE"
id("io.gitlab.arturbosch.detekt") version detektVersion
}
repositories {
mavenLocal()
mavenCentral()
maven(url = uri("https://dl.bintray.com/s1m0nw1/KtsRunner"))
}
dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-script-runtime")
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
implementation("org.jetbrains.kotlin:kotlin-script-util")
implementation("org.springframework.boot:spring-boot-starter-webflux")
implementation("org.springframework.boot:spring-boot-starter-actuator")
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
implementation("cn.pilipa:pilipa-spring-boot-starter-logging:2.0.10")
implementation("de.swirtz:ktsRunner:0.0.5")
testImplementation("org.springframework.boot:spring-boot-starter-test"){
exclude(module = "junit")
}
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.cloud:spring-cloud-stream-test-support")
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntime("org.junit.jupiter:junit-jupiter-engine")
testCompile("io.kotlintest:kotlintest-runner-junit5:${kotlinTestVersion}")
testCompile("io.kotlintest:kotlintest-extensions-spring:${kotlinTestVersion}")
detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:${detektVersion}")
}
How to implement this similar feature in the custom kotlin-dsl script to implicitly import classes in kotlin-dsl script?
Gradle defines a list of implicit imports that has no mechanism for extending this list. This is the same as for build.gradle and Groovy versions as it is for the Kotlin versions.
See also: Automatic imports in Gradle plugin
Which still holds true as of today. There is a TODO remaining in the Kotlin Gradle Script source code (master branch as-of Nov 22, 2018) related to this:
// TODO: let this be contributed by :plugins