如何使用 Kotlin DSL 配置 AppEngine Gradle 插件

How to configure AppEngine Gradle plugin using Kotlin DSL

https://cloud.google.com/appengine/docs/standard/java/tools/gradle-reference 中所述,AppEngine Gradle 插件提供如下配置:

appengine {  // App Engine tasks configuration
  run {      // local (dev_appserver) configuration (standard environments only)
    port = 8080                 // default
  }

  deploy {   // deploy configuration
    stopPreviousVersion = true  // default - stop the current version
    promote = true              // default - & make this the current version
  }
}

使用 build.gradlke.kts 时,这样的配置应该是什么样的?

我正在查看 AppEngine 任务,但不明白如何将其连接到正确的 Kotlin DSL 设置。

编辑

当简单地将上述块添加到 build.gradle.kts 时,IntelliJ 会抱怨:

当 运行 Gradle 从 cml 我得到:

Could not open cache directory azhqxsd1d4xoovq4o5dzec6iw (/Users/test/.gradle/caches/4.5/gradle-kotlin-dsl/azhqxsd1d4xoovq4o5dzec6iw). Internal error: unable to compile script, see log for details

EDIT2

在下面添加了 pluginsbuildscript 块:

val kotlinVersion                    = property("kotlin.version")
val javaVersion                      = "1.8"

buildscript {
    repositories {
        jcenter()
        mavenCentral()
        mavenLocal()
        maven("https://plugins.gradle.org/m2/")
        maven("https://repo.spring.io/milestone")
        maven("https://repo.spring.io/snapshot")
    }
    dependencies {
        classpath("com.google.cloud.tools:appengine-gradle-plugin:1.3.4")
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.0.BUILD-SNAPSHOT")
    }
}

apply {
    plugin("com.google.cloud.tools.appengine")
    plugin("org.springframework.boot")
}

plugins {
    val kotlinVersion = "1.2.0"
    `war`
    `idea`
    id("org.jetbrains.kotlin.jvm") version kotlinVersion
    id("org.jetbrains.kotlin.kapt") version kotlinVersion
    id("org.jetbrains.kotlin.plugin.jpa") version kotlinVersion
    id("org.jetbrains.kotlin.plugin.noarg") version kotlinVersion
    id("org.jetbrains.kotlin.plugin.spring") version kotlinVersion
    id("com.ewerk.gradle.plugins.querydsl") version "1.0.9"
    id("io.spring.dependency-management") version "1.0.3.RELEASE"
}

EDIT3

我看到这是由 kotlinDslAccessorsReport:

生成的
/**
 * 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)

但老实说,我不知道这对我有什么帮助。

为了让 kotlin-dsl 在应用插件的编译时间之前生成静态访问器,您必须使用 plugins {} 块而不是 buildscript {} 块。 buildscript {} 仍然会使依赖项对脚本 classpath 可见,但你不会得到那些。

如您所见,插件的 Maven 坐标可能与插件 ID 不同。您可以使用 pluginManagement specification (an example for Android plugin is heresettings.gradle 中处理此问题。以下是我的处理方式(并使用 war 插件进行最小应用):

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}")
      }
    }
  }
}

现在,我应用了插件,kotlin-dsl 将在脚本编译之前生成访问器。

运行 ./gradlew kotlinDslAccessorsReport 并仔细阅读它,我在输出中看到了这一点:

/**
 * 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)

现在,您可以看到 appengine { ... } 代码块将在顶层正常工作。我们只需要根据它的类型弄清楚里面可以放什么。请注意,如果我们使用 buildscript {} 而不是 plugins {},您必须自己 copy/paste 这些访问器或在构建脚本中执行类似 extensions.getByType(com.google.cloud.tools.gradle.appengine.core.AppEngineExtension::class) 的操作。

通过搜索,您可以找到 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(可能还有其他地方)的源代码。这意味着我们需要做一些 class cast 技巧才能配置这个对象。源代码是 IMO 真正弄清楚如何访问这些类型的对象的唯一方法。

下面显示了我们如何配置 deploy 扩展,它是 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
  }
}

有几种不同的方法可以实现上述目标,但这是我采用的方法。插件本身应该提供更友好的配置方法,直到 kotlin-dsl/457 is resolved, so I opened an issue

使用 appengine gradle 插件 2.0 版的类型安全方法:

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
    }
}