How to configure AppEngine Gradle plugin using Kotlin DSL
In order to have kotlin-dsl
generate static accessors before compile time for applied plugins you must use the plugins {}
block and not the buildscript {}
block. buildscript {}
will still make the dependencies visible to the script classpath, but you will not get those.
As you noticed, the plugin's Maven coordinates that may be different than the plugin Id. You can handle this in the settings.gradle
with the pluginManagement
specification (an example for Android plugin is here. Here is how I handle that (and using war
plugin for minimal application):
build.gradle,kts
plugins {
id("com.google.cloud.tools.appengine") version "1.3.4"
`war`
}
settings.gradle
pluginManagement {
repositories {
gradlePluginPortal()
google()
}
resolutionStrategy {
eachPlugin {
if (requested.id.id == "com.google.cloud.tools.appengine") {
useModule("com.google.cloud.tools:appengine-gradle-plugin:${requested.version}")
}
}
}
}
Now, I have the plugin applied and kotlin-dsl
will generate the accessors before script compilation.
Running ./gradlew kotlinDslAccessorsReport
and perusing through it I see this in the output:
/**
* Retrieves the [appengine][com.google.cloud.tools.gradle.appengine.core.AppEngineExtension] project extension.
*/
val Project.`appengine`: com.google.cloud.tools.gradle.appengine.core.AppEngineExtension get() =
extensions.getByName("appengine") as com.google.cloud.tools.gradle.appengine.core.AppEngineExtension
/**
* Configures the [appengine][com.google.cloud.tools.gradle.appengine.core.AppEngineExtension] project extension.
*/
fun Project.`appengine`(configure: com.google.cloud.tools.gradle.appengine.core.AppEngineExtension.() -> Unit): Unit =
extensions.configure("appengine", configure)
Now, you can see that the appengine { ... }
code block will work correctly in the top level. We just need to figure out what can go inside of it based on its type. Note that if we were using buildscript {}
instead of plugins {}
, you would have to either copy/paste these accessors yourself or do something like extensions.getByType(com.google.cloud.tools.gradle.appengine.core.AppEngineExtension::class)
in your build script.
Doing some searching you can find the source code for AppEngineExtension
on GitHub. Unfortunately, it does not have any methods or fields on it. It is basically used as an "extension holder" class, in that other extensions are added to it here and here (and probably other places). This means that we need to do some class cast tricks to be able to configure this object. The source code is IMO the only way to really figure out how to access these kinds of objects.
Below shows how we can configure the deploy
extension, which is a DeployExtension
and how we can configure the run
extension, which is a RunExtension
.
import com.google.cloud.tools.gradle.appengine.core.DeployExtension
import com.google.cloud.tools.gradle.appengine.standard.RunExtension
appengine {
((this as org.gradle.api.plugins.ExtensionAware).extensions.getByName("run") as RunExtension).apply {
port = 8080
}
((this as org.gradle.api.plugins.ExtensionAware).extensions.getByName("deploy") as DeployExtension).apply {
stopPreviousVersion = true // default - stop the current version
promote = true
}
}
There are a few different ways to accomplish the above, but that is the approach I took. The plugin itself should offer friendlier methods for configuration until kotlin-dsl/457 is resolved, so I opened an issue
Type-safe approach using version 2.0 of the appengine gradle plugin:
import com.google.cloud.tools.gradle.appengine.standard.AppEngineStandardExtension
buildscript {
repositories {
jcenter()
}
dependencies {
classpath("com.google.cloud.tools:appengine-gradle-plugin:2.0.0-rc5")
}
}
plugins {
java
war
kotlin("jvm") version "..."
}
repositories {
jcenter()
}
apply {
plugin("com.google.cloud.tools.appengine")
}
configure<AppEngineStandardExtension> {
deploy {
projectId = "..."
version = "..."
stopPreviousVersion = true // etc
}
}