migrate buildSrc plugins to includedBuild plugins
This commit is contained in:
parent
805d4c8170
commit
f12a505d22
40 changed files with 159 additions and 112 deletions
|
|
@ -5,6 +5,35 @@ plugins {
|
|||
kotlin("jvm") version embeddedKotlinVersion
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(platform(libs.kotlin.bom))
|
||||
implementation("org.jetbrains.kotlin:kotlin-serialization")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
implementation("org.jetbrains.kotlin:kotlin-compiler-embeddable")
|
||||
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${libs.versions.kotlin.get()}")
|
||||
|
||||
implementation(platform(libs.kotlinx.coroutines.bom))
|
||||
implementation(libs.kotlinx.coroutines.core)
|
||||
|
||||
implementation(platform(libs.kotlinxSerialization.bom))
|
||||
implementation(libs.kotlinxSerialization.core)
|
||||
implementation(libs.kotlinxSerialization.json)
|
||||
|
||||
implementation("com.github.node-gradle:gradle-node-plugin:${libs.versions.gradleNodePlugin.get()}")
|
||||
|
||||
implementation(platform(libs.kotest.bom))
|
||||
implementation("io.kotest:kotest-framework-multiplatform-plugin-gradle")
|
||||
|
||||
implementation("io.kvision:io.kvision.gradle.plugin:${libs.versions.kvision.get()}")
|
||||
|
||||
implementation("net.swiftzer.semver:semver:${libs.versions.semver.get()}")
|
||||
|
||||
implementation(platform(libs.okio.bom))
|
||||
implementation(libs.okio.core)
|
||||
|
||||
implementation(libs.kotlinx.cli)
|
||||
}
|
||||
|
||||
val gradleJvmTarget = "11"
|
||||
|
||||
kotlin {
|
||||
|
|
|
|||
|
|
@ -8,3 +8,11 @@ pluginManagement {
|
|||
plugins {
|
||||
id("kafkatorio.convention.settings.repositories")
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
versionCatalogs {
|
||||
create("libs") {
|
||||
from(files("../../gradle/libs.versions.toml"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package kafkatorio.conventions
|
||||
|
||||
|
||||
plugins {
|
||||
base
|
||||
idea
|
||||
}
|
||||
|
||||
|
||||
group = rootProject.group
|
||||
version = rootProject.version
|
||||
|
||||
|
||||
tasks.withType<WriteProperties>().configureEach {
|
||||
encoding = Charsets.UTF_8.name()
|
||||
comment = " Do not edit manually. This file was created with task '$name'"
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||
exclude("**/.secret.*")
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package kafkatorio.conventions
|
||||
|
||||
import io.kvision.gradle.KVisionExtension
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.kotlin.dsl.configure
|
||||
import org.gradle.kotlin.dsl.findByType
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
|
||||
|
||||
|
||||
object Versions {
|
||||
const val node = "14.19.1"
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* `kotlin-js` adds a directory in the root-dir for the Yarn lock.
|
||||
* That's a bit annoying. It's a little neater if it's in the
|
||||
* gradle dir, next to the version-catalog.
|
||||
*/
|
||||
fun Project.relocateKotlinJsStore() {
|
||||
|
||||
afterEvaluate {
|
||||
rootProject.extensions.configure<YarnRootExtension> {
|
||||
lockFileDirectory = project.rootDir.resolve("gradle/kotlin-js-store")
|
||||
}
|
||||
}
|
||||
|
||||
// rootProject.plugins.withType(YarnPlugin::class) {
|
||||
// rootProject.the<YarnRootExtension>().lockFileDirectory =
|
||||
// project.rootDir.resolve("gradle/kotlin-js-store")
|
||||
// }
|
||||
|
||||
// KVision tries to be clever too
|
||||
project.extensions.findByType<KVisionExtension>()?.apply {
|
||||
enableHiddenKotlinJsStore.set(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
package kafkatorio.conventions.infra
|
||||
|
||||
import kafkatorio.tasks.DockerEnvUpdateTask
|
||||
import kafkatorio.extensions.DOCKER_COMPOSE_TASK_GROUP
|
||||
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
|
||||
|
||||
plugins {
|
||||
base
|
||||
id("kafkatorio.conventions.infra.process-runner")
|
||||
}
|
||||
|
||||
|
||||
val dockerComposeProjectName: String by extra(rootProject.name)
|
||||
val dockerSrcDir: Directory by extra(layout.projectDirectory.dir("src"))
|
||||
|
||||
|
||||
val dockerUp by tasks.registering(Exec::class) {
|
||||
group = DOCKER_COMPOSE_TASK_GROUP
|
||||
|
||||
dependsOn(tasks.assemble)
|
||||
logging.captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
|
||||
workingDir = dockerSrcDir.asFile
|
||||
commandLine = parseSpaceSeparatedArgs(""" docker-compose up -d """)
|
||||
}
|
||||
|
||||
|
||||
val dockerDown by tasks.registering(Exec::class) {
|
||||
group = DOCKER_COMPOSE_TASK_GROUP
|
||||
|
||||
logging.captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
|
||||
workingDir = dockerSrcDir.asFile
|
||||
commandLine = parseSpaceSeparatedArgs(""" docker-compose down """)
|
||||
}
|
||||
|
||||
|
||||
val dockerRemove by tasks.registering(Exec::class) {
|
||||
group = DOCKER_COMPOSE_TASK_GROUP
|
||||
|
||||
logging.captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
|
||||
workingDir = dockerSrcDir.asFile
|
||||
commandLine = parseSpaceSeparatedArgs(""" docker-compose rm --stop -v -f """)
|
||||
}
|
||||
|
||||
|
||||
tasks.matching { it.name == "processRun" }.configureEach { dependsOn(dockerUp, dockerEnvUpdate) }
|
||||
tasks.matching { it.name == "processKill" }.configureEach { dependsOn(dockerDown) }
|
||||
|
||||
|
||||
val dockerEnvUpdate by tasks.registering(DockerEnvUpdateTask::class) {
|
||||
dotEnvFile.set(dockerSrcDir.file(".env"))
|
||||
|
||||
properties(
|
||||
"COMPOSE_PROJECT_NAME" to dockerComposeProjectName,
|
||||
"KAFKATORIO_VERSION" to project.version,
|
||||
"REGISTRY_HOST" to providers.gradleProperty("dockerContainerRegistryHost"),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
tasks.assemble { dependsOn(dockerEnvUpdate) }
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package kafkatorio.conventions.infra
|
||||
|
||||
import org.gradle.kotlin.dsl.extra
|
||||
import org.gradle.kotlin.dsl.registering
|
||||
|
||||
plugins {
|
||||
id("kafkatorio.conventions.base")
|
||||
}
|
||||
|
||||
val processRunnerTaskGroup: String by extra("processes")
|
||||
|
||||
val processRun by tasks.registering(Task::class) {
|
||||
group = processRunnerTaskGroup
|
||||
}
|
||||
|
||||
val processKill by tasks.registering(Task::class) {
|
||||
group = processRunnerTaskGroup
|
||||
}
|
||||
|
||||
val processRestart by tasks.registering {
|
||||
group = processRunnerTaskGroup
|
||||
|
||||
dependsOn(processKill)
|
||||
finalizedBy(processRun)
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package kafkatorio.conventions.lang
|
||||
|
||||
//import dev.adamko.kafkatorio.Versions
|
||||
import kafkatorio.conventions.relocateKotlinJsStore
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.npm.NpmProject
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
|
||||
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.npm.tasks.RootPackageJsonTask
|
||||
|
||||
|
||||
plugins {
|
||||
kotlin("js")
|
||||
id("kafkatorio.conventions.base")
|
||||
}
|
||||
|
||||
//dependencies {
|
||||
// implementation(
|
||||
// project.dependencies.platform(
|
||||
// "org.jetbrains.kotlin-wrappers:kotlin-wrappers-bom:${Versions.kotlinWrappers}"
|
||||
// )
|
||||
// )
|
||||
//}
|
||||
|
||||
//val rootPackageJson by rootProject.tasks.getting(RootPackageJsonTask::class)
|
||||
|
||||
//fun NpmTask.setNodeModulesPath(path: String): Unit =
|
||||
// environment.put("NODE_PATH", path)
|
||||
//
|
||||
//fun NpmTask.setNodeModulesPath(folder: File): Unit =
|
||||
// setNodeModulesPath(folder.normalize().absolutePath)
|
||||
|
||||
// https://github.com/node-gradle/gradle-node-plugin/issues/150
|
||||
// https://github.com/lamba92/kotlingram/blob/master/examples/js-bot/build.gradle.kts
|
||||
|
||||
//val nodePath: Directory by extra {
|
||||
// val file = rootPackageJson.rootPackageJson.parentFile.normalize()
|
||||
// logger.info("Kotlin/JS NODE_PATH: $file")
|
||||
// project.layout.dir(project.provider { file }).get()
|
||||
//}
|
||||
|
||||
//val nodeModulesDir: Directory by extra {
|
||||
// val file = nodePath.dir(NpmProject.NODE_MODULES)
|
||||
// logger.info("Kotlin/JS NODE_MODULES: $file")
|
||||
// file
|
||||
//}
|
||||
|
||||
|
||||
relocateKotlinJsStore()
|
||||
|
||||
|
||||
//plugins.withType<NodeJsRootPlugin> {
|
||||
// configure<NodeJsRootExtension> {
|
||||
// nodeVersion = "16.0.0"
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//afterEvaluate {
|
||||
// rootProject.extensions.configure<NodeJsRootExtension> {
|
||||
// // https://github.com/rjaros/kvision/issues/410
|
||||
// versions.webpackCli.version = "4.10.0"
|
||||
// versions.webpackDevServer.version = "4.9.2"
|
||||
// }
|
||||
//
|
||||
// rootProject.extensions.configure<YarnRootExtension> {
|
||||
// resolution("http-proxy-middleware", "^2.0.6")
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
package kafkatorio.conventions.lang
|
||||
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
|
||||
plugins {
|
||||
id("kafkatorio.conventions.base")
|
||||
kotlin("jvm")
|
||||
}
|
||||
|
||||
val projectKotlinTarget = "1.7"
|
||||
val projectJvmTarget = "11"
|
||||
|
||||
|
||||
dependencies {
|
||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||
|
||||
testImplementation("io.kotest:kotest-runner-junit5")
|
||||
testImplementation("io.kotest:kotest-assertions-core")
|
||||
testImplementation("io.kotest:kotest-property")
|
||||
testImplementation("io.kotest:kotest-assertions-json")
|
||||
|
||||
testImplementation("io.mockk:mockk")
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<KotlinCompile>().configureEach {
|
||||
|
||||
kotlinOptions {
|
||||
jvmTarget = projectJvmTarget
|
||||
apiVersion = projectKotlinTarget
|
||||
languageVersion = projectKotlinTarget
|
||||
}
|
||||
|
||||
kotlinOptions.freeCompilerArgs += listOf(
|
||||
// "-Xcontext-receivers",
|
||||
"-opt-in=kotlin.RequiresOptIn",
|
||||
"-opt-in=kotlin.ExperimentalStdlibApi",
|
||||
"-opt-in=kotlin.time.ExperimentalTime",
|
||||
// "-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi",
|
||||
// "-opt-in=kotlinx.serialization.ExperimentalSerializationApi",
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
tasks.compileTestKotlin {
|
||||
kotlinOptions.freeCompilerArgs += "-opt-in=io.kotest.common.ExperimentalKotest"
|
||||
}
|
||||
|
||||
|
||||
kotlin {
|
||||
jvmToolchain {
|
||||
languageVersion.set(JavaLanguageVersion.of(projectJvmTarget))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
|
||||
plugins.withType<ApplicationPlugin>().configureEach {
|
||||
project.extensions.getByType<JavaApplication>().apply {
|
||||
applicationDefaultJvmArgs += listOf("-Dkotlinx.coroutines.debug")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package kafkatorio.conventions.lang
|
||||
|
||||
import kafkatorio.conventions.relocateKotlinJsStore
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootExtension
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
|
||||
//import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
|
||||
|
||||
|
||||
plugins {
|
||||
id("kafkatorio.conventions.base")
|
||||
// id("dev.adamko.kafkatorio.lang.node")
|
||||
kotlin("multiplatform")
|
||||
// id("io.kotest.multiplatform") // disabled because of https://github.com/kotest/kotest/issues/3141
|
||||
}
|
||||
|
||||
|
||||
relocateKotlinJsStore()
|
||||
|
||||
|
||||
//plugins.withType<NodeJsRootPlugin> {
|
||||
// configure<NodeJsRootExtension> {
|
||||
// nodeVersion = "16.0.0"
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//
|
||||
//afterEvaluate {
|
||||
// rootProject.extensions.configure<NodeJsRootExtension> {
|
||||
// // https://github.com/rjaros/kvision/issues/410
|
||||
// versions.webpackCli.version = "4.10.0"
|
||||
// versions.webpackDevServer.version = "4.9.2"
|
||||
// }
|
||||
//
|
||||
// rootProject.extensions.configure<YarnRootExtension> {
|
||||
// resolution("http-proxy-middleware", "^2.0.6")
|
||||
// }
|
||||
//}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package kafkatorio.conventions.lang
|
||||
|
||||
import com.github.gradle.node.npm.task.NpmInstallTask
|
||||
import kafkatorio.conventions.Versions
|
||||
import kafkatorio.tasks.UpdatePackageJson
|
||||
import kotlinx.serialization.json.put
|
||||
|
||||
|
||||
plugins {
|
||||
id("com.github.node-gradle.node")
|
||||
id("kafkatorio.conventions.base")
|
||||
}
|
||||
|
||||
|
||||
node {
|
||||
download.set(true)
|
||||
version.set(Versions.node)
|
||||
|
||||
distBaseUrl.set(null as String?) // set by dependencyResolutionManagement
|
||||
}
|
||||
|
||||
val projectVersion: Provider<String> = providers.provider { "${project.version}" }
|
||||
|
||||
val updatePackageJson by tasks.registering(UpdatePackageJson::class) {
|
||||
// group = NodePlugin.NODE_GROUP
|
||||
// description = "Read the package.json file and update the version and name, based on the project."
|
||||
|
||||
inputs.property("projectVersion", projectVersion)
|
||||
// propertiesToCheck.put("version", projectVersion)
|
||||
|
||||
updateExpectedJson {
|
||||
put("version", projectVersion.get())
|
||||
}
|
||||
|
||||
// check to see if the properties are already up-to-date
|
||||
// outputs.upToDateWhen(areJsonPropertiesUpToDate(packageJsonFile, propertiesToCheck))
|
||||
// onlyIf(!areJsonPropertiesUpToDate(packageJsonFile, propertiesToCheck))
|
||||
|
||||
// doLast {
|
||||
// val packageJsonContent = packageJsonFile.get().asFile.readText()
|
||||
// val packageJson = jsonMapper.parseToJsonElement(packageJsonContent).jsonObject
|
||||
//
|
||||
// val newJsonProps = propertiesToCheck.get().mapValues { (_, newVal) -> JsonPrimitive(newVal) }
|
||||
//
|
||||
// val packageJsonUpdate = JsonObject(packageJson + newJsonProps)
|
||||
// val packageJsonContentUpdated =
|
||||
// jsonMapper
|
||||
// .encodeToString(packageJsonUpdate)
|
||||
// .suffixIfNot("\n")
|
||||
//
|
||||
// logger.debug(packageJsonContentUpdated)
|
||||
//
|
||||
// packageJsonFile.get().asFile.writer().useToRun {
|
||||
// write(packageJsonContentUpdated)
|
||||
// }
|
||||
//
|
||||
// }
|
||||
}
|
||||
|
||||
tasks.assemble { dependsOn(updatePackageJson) }
|
||||
|
||||
tasks.withType<NpmInstallTask>().configureEach {
|
||||
dependsOn(updatePackageJson)
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package kafkatorio.distributions
|
||||
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.attributes.Bundling
|
||||
import org.gradle.api.attributes.Bundling.BUNDLING_ATTRIBUTE
|
||||
import org.gradle.api.attributes.Category
|
||||
import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE
|
||||
import org.gradle.api.attributes.LibraryElements
|
||||
import org.gradle.api.attributes.LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE
|
||||
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.kotlin.dsl.named
|
||||
|
||||
|
||||
fun Configuration.asProvider() {
|
||||
isVisible = false
|
||||
isCanBeResolved = false
|
||||
isCanBeConsumed = true
|
||||
}
|
||||
|
||||
|
||||
fun Configuration.asConsumer() {
|
||||
isVisible = false
|
||||
isCanBeResolved = true
|
||||
isCanBeConsumed = false
|
||||
}
|
||||
|
||||
|
||||
fun Configuration.factorioModAttributes(objects: ObjectFactory): Configuration =
|
||||
attributes {
|
||||
attribute(USAGE_ATTRIBUTE, objects.named("factorio"))
|
||||
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES_AND_RESOURCES))
|
||||
attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EMBEDDED))
|
||||
}
|
||||
|
||||
|
||||
fun Configuration.typescriptAttributes(objects: ObjectFactory): Configuration =
|
||||
attributes {
|
||||
attribute(USAGE_ATTRIBUTE, objects.named("typescript"))
|
||||
attribute(CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
|
||||
attribute(LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.OBJECTS))
|
||||
attribute(BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL))
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
package kafkatorio.extensions
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.FileCopyDetails
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RelativePath
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.specs.NotSpec
|
||||
import org.gradle.api.specs.Spec
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.application.CreateStartScripts
|
||||
import org.gradle.kotlin.dsl.register
|
||||
import org.gradle.plugins.ide.idea.model.IdeaModule
|
||||
import org.gradle.process.ExecSpec
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.YarnRootExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.js.yarn.yarn
|
||||
import org.jetbrains.kotlin.incremental.md5
|
||||
|
||||
|
||||
operator fun <T> Spec<T>.not(): NotSpec<T> = NotSpec(this)
|
||||
|
||||
|
||||
//fun isProcessRunning(process: String, ignoreCase: Boolean = true): Spec<Task> =
|
||||
// Spec<Task> {
|
||||
// ByteArrayOutputStream().use { outputStream ->
|
||||
// project.exec {
|
||||
// }
|
||||
// outputStream.toString().contains(process, ignoreCase)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
/** exclude generated Gradle code, so it doesn't clog up search results */
|
||||
fun IdeaModule.excludeGeneratedGradleDsl(layout: ProjectLayout) {
|
||||
excludeDirs.addAll(
|
||||
layout.files(
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-accessors",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-accessors/kotlin",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-accessors/kotlin/gradle",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders/kotlin",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-external-plugin-spec-builders/kotlin/gradle",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-plugins",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-plugins/kotlin",
|
||||
"buildSrc/build/generated-sources/kotlin-dsl-plugins/kotlin/dev",
|
||||
"buildSrc/build/pluginUnderTestMetadata",
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// https://stackoverflow.com/a/70317110/4161471
|
||||
fun Project.execCapture(spec: ExecSpec.() -> Unit): String {
|
||||
return ByteArrayOutputStream().use { outputStream ->
|
||||
exec {
|
||||
this.spec()
|
||||
this.standardOutput = outputStream
|
||||
}
|
||||
val output = outputStream.toString().trim()
|
||||
logger.lifecycle(output)
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** https://youtrack.jetbrains.com/issue/KT-50848 */
|
||||
fun Project.yarn(configure: YarnRootExtension.() -> Unit) = with(yarn, configure)
|
||||
|
||||
|
||||
fun Directory.filesChecksum(): Long = asFileTree
|
||||
.files
|
||||
.map { it.readBytes() + it.absolutePath.toByteArray() }
|
||||
.fold(byteArrayOf()) { acc, bytes -> acc + bytes }
|
||||
.md5()
|
||||
|
||||
|
||||
/** Drop the first [count] directories from the path */
|
||||
fun FileCopyDetails.dropDirectories(count: Int): RelativePath =
|
||||
RelativePath(true, *relativePath.segments.drop(count).toTypedArray())
|
||||
|
||||
|
||||
/** Drop the first directory from the path */
|
||||
fun FileCopyDetails.dropDirectory(): RelativePath =
|
||||
dropDirectories(1)
|
||||
|
||||
|
||||
/** https://github.com/gradle/gradle/issues/16543 */
|
||||
fun Project.taskProvider(taskName: String): Provider<Task> = providers.provider {
|
||||
taskName
|
||||
}.flatMap {
|
||||
tasks.named(it)
|
||||
}
|
||||
|
||||
|
||||
const val DOCKER_COMPOSE_TASK_GROUP = "docker-compose"
|
||||
|
||||
|
||||
fun Project.registerStartScriptTask(
|
||||
appName: String,
|
||||
configureStartScripts: CreateStartScripts.() -> Unit = {},
|
||||
): TaskProvider<CreateStartScripts> =
|
||||
tasks.register<CreateStartScripts>("startScript$appName") {
|
||||
|
||||
val jarTask = tasks.getByName(JavaPlugin.JAR_TASK_NAME)
|
||||
val runtimeClasspath = configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME)
|
||||
dependsOn(jarTask)
|
||||
dependsOn(runtimeClasspath)
|
||||
|
||||
applicationName = appName
|
||||
outputDir = layout.buildDirectory.dir("scripts").get().asFile
|
||||
classpath = jarTask.outputs.files + runtimeClasspath
|
||||
configureStartScripts()
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import kafkatorio.extensions.filesChecksum
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.property
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
|
||||
|
||||
@CacheableTask
|
||||
@Suppress("UnstableApiUsage")
|
||||
abstract class DockerComposeExec @Inject constructor(
|
||||
private val executor: ExecOperations,
|
||||
private val objects: ObjectFactory,
|
||||
private val providers: ProviderFactory,
|
||||
) : DefaultTask() {
|
||||
|
||||
@get:InputDirectory
|
||||
@get:SkipWhenEmpty
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:NormalizeLineEndings
|
||||
abstract val dockerComposeDir: DirectoryProperty
|
||||
|
||||
@get:Input
|
||||
abstract val command: Property<String>
|
||||
|
||||
@get:Input
|
||||
val dockerIsActive: Property<Boolean> = objects.property<Boolean>().convention(
|
||||
providers.exec {
|
||||
commandLine = parseSpaceSeparatedArgs("docker info")
|
||||
isIgnoreExitValue = true
|
||||
}.result.map {
|
||||
it.exitValue == 0
|
||||
}
|
||||
)
|
||||
|
||||
@get:OutputFile
|
||||
val stateFile: RegularFileProperty = objects.fileProperty().convention {
|
||||
temporaryDir.resolve("docker-files.md5")
|
||||
}
|
||||
|
||||
init {
|
||||
group = DOCKER_COMPOSE_GROUP
|
||||
logging.captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
|
||||
super.onlyIf { task ->
|
||||
require(task is DockerComposeExec)
|
||||
task.dockerIsActive.getOrElse(false)
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun exec() {
|
||||
executor.exec {
|
||||
workingDir = dockerComposeDir.asFile.get()
|
||||
commandLine = parseSpaceSeparatedArgs(command.get())
|
||||
}
|
||||
|
||||
val inputChecksum = dockerComposeDir.get().filesChecksum()
|
||||
stateFile.get().asFile.writeText("$inputChecksum")
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val DOCKER_COMPOSE_GROUP: String = "docker-compose"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import javax.inject.Inject
|
||||
import kafkatorio.extensions.DOCKER_COMPOSE_TASK_GROUP
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.WriteProperties
|
||||
|
||||
|
||||
@CacheableTask
|
||||
open class DockerEnvUpdateTask @Inject constructor(
|
||||
private val objects: ObjectFactory
|
||||
) : WriteProperties() {
|
||||
|
||||
@Internal
|
||||
val dotEnvFile: RegularFileProperty = objects.fileProperty()
|
||||
|
||||
init {
|
||||
group = DOCKER_COMPOSE_TASK_GROUP
|
||||
super.setOutputFile(dotEnvFile)
|
||||
super.getLogging().captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.tasks.JavaExec
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.work.DisableCachingByDefault
|
||||
|
||||
|
||||
@DisableCachingByDefault(because = "caching makes regenerating more difficult")
|
||||
abstract class GenerateTypeScriptTask @Inject constructor(
|
||||
private val fileOps: FileSystemOperations,
|
||||
) : JavaExec() {
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val output: DirectoryProperty
|
||||
|
||||
init {
|
||||
group = "kt2ts"
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
fileOps.delete { delete(temporaryDir) }
|
||||
temporaryDir.mkdirs()
|
||||
|
||||
super.exec()
|
||||
|
||||
fileOps.sync {
|
||||
from(temporaryDir)
|
||||
into(output)
|
||||
include("**/*.ts")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import kafkatorio.tasks.UpdatePackageJson.Companion.foldParseToJsonObject
|
||||
import kafkatorio.tasks.UpdatePackageJson.Companion.parseToJsonObject
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.specs.ExplainingSpec
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
|
||||
|
||||
object JsonPropertiesUpToDateSpec : ExplainingSpec<Task> {
|
||||
|
||||
private val logger: Logger = Logging.getLogger(this::class.java)
|
||||
|
||||
override fun isSatisfiedBy(element: Task?): Boolean {
|
||||
val reason = whyUnsatisfied(element)
|
||||
|
||||
if (reason != null) {
|
||||
logger.lifecycle("JsonProperties not up to date:\n$reason")
|
||||
}
|
||||
|
||||
return reason == null
|
||||
}
|
||||
|
||||
|
||||
// Returns a description explaining why the task is outdated,
|
||||
// or null if the task is up to date
|
||||
override fun whyUnsatisfied(task: Task?): String? {
|
||||
require(task is UpdatePackageJson) { "$task is not a UpdatePackageJson task" }
|
||||
|
||||
val current = task.packageJsonFile.asFile.orNull?.parseToJsonObject()
|
||||
?: return "no package.json file"
|
||||
|
||||
val updates = task.expectedJsonUpdates.orNull?.toList()?.foldParseToJsonObject()
|
||||
?: return "no package.json updates"
|
||||
|
||||
val expected = JsonObject(current + updates)
|
||||
|
||||
if (current != expected) {
|
||||
return (current.keys + expected.keys)
|
||||
.asSequence()
|
||||
.distinct()
|
||||
.sorted()
|
||||
.mapNotNull {
|
||||
val currentVal = current[it]
|
||||
val expectedVal = expected[it]
|
||||
|
||||
if (currentVal == expectedVal) {
|
||||
null
|
||||
} else {
|
||||
"'$it' - expected:$expectedVal, actual:$currentVal"
|
||||
}
|
||||
}.joinToString(separator = "\n\t", prefix = "package.json is not up to date.\n\t")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import kafkatorio.extensions.execCapture
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.intellij.lang.annotations.Language
|
||||
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
|
||||
|
||||
abstract class KafkaConsumerGroupsTask : DefaultTask() {
|
||||
|
||||
@get:Input
|
||||
val bootstrapServer: String = "localhost:9092"
|
||||
@get:Input
|
||||
val kafkaDockerContainerName: String = "kafka"
|
||||
|
||||
@get:Internal
|
||||
protected val bootstrapArg = "--bootstrap-server $bootstrapServer"
|
||||
|
||||
abstract class ResetAll : KafkaConsumerGroupsTask() {
|
||||
|
||||
@get:Input
|
||||
@Language("Shell Script")
|
||||
val resetCommand: String =
|
||||
"""
|
||||
/kafka/bin/kafka-consumer-groups.sh --execute --reset-offsets --all-topics --to-earliest $bootstrapArg
|
||||
""".trimIndent()
|
||||
|
||||
@TaskAction
|
||||
fun reset() {
|
||||
getAllGroups().forEach { group ->
|
||||
logger.lifecycle("Resetting group $group\n---")
|
||||
dockerExec("$resetCommand --group $group")
|
||||
logger.lifecycle("---")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DeleteAll : KafkaConsumerGroupsTask() {
|
||||
|
||||
@get:Input
|
||||
@Language("Shell Script")
|
||||
val deleteCommand: String =
|
||||
"""
|
||||
/kafka/bin/kafka-consumer-groups.sh --delete $bootstrapArg
|
||||
""".trimIndent()
|
||||
|
||||
@TaskAction
|
||||
fun reset() {
|
||||
val groups = getAllGroups().joinToString(" ") { group -> "--group $group" }
|
||||
dockerExec("$deleteCommand $groups")
|
||||
}
|
||||
}
|
||||
|
||||
@Internal
|
||||
protected fun getAllGroups(): List<String> = dockerExec(
|
||||
"""
|
||||
/kafka/bin/kafka-consumer-groups.sh --list $bootstrapArg
|
||||
""".trimIndent()
|
||||
).lines()
|
||||
.filter { it.trim().isNotBlank() }
|
||||
|
||||
|
||||
// fun reset(applicationId: String) = """
|
||||
// /kafka/bin/kafka-streams-application-reset.sh --application-id $applicationId --force --to-earliest
|
||||
// """.trimIndent()
|
||||
|
||||
protected fun dockerExec(
|
||||
@Language("Shell Script")
|
||||
cmd: String
|
||||
): String = project.execCapture {
|
||||
logging.captureStandardOutput(LogLevel.LIFECYCLE)
|
||||
commandLine = parseSpaceSeparatedArgs(""" docker exec $kafkaDockerContainerName $cmd """)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.specs.ExplainingSpec
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.process.ExecOperations
|
||||
|
||||
/** Checks if a process is running. Windows only. */
|
||||
class ProcessRunningSpec(
|
||||
private val executor: ExecOperations,
|
||||
private val process: String,
|
||||
private val ignoreCase: Boolean = true,
|
||||
) : ExplainingSpec<Task> {
|
||||
|
||||
override fun isSatisfiedBy(element: Task?): Boolean = whyUnsatisfied(element) == null
|
||||
|
||||
override fun whyUnsatisfied(element: Task?): String? {
|
||||
return when (element) {
|
||||
null -> "task is null"
|
||||
!is Exec -> "task ${this::class.simpleName} is not ${Exec::class.simpleName}"
|
||||
else -> {
|
||||
return ByteArrayOutputStream().use { outputStream ->
|
||||
|
||||
executor.exec {
|
||||
commandLine("tasklist") // Windows only for now...
|
||||
standardOutput = outputStream
|
||||
}
|
||||
|
||||
if (outputStream.toString().contains(process, ignoreCase)) {
|
||||
null
|
||||
} else {
|
||||
"found $process in tasklist"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import com.github.gradle.node.npm.task.NpmTask
|
||||
import javax.inject.Inject
|
||||
import org.gradle.api.file.ConfigurableFileTree
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.FileSystemOperations
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.IgnoreEmptyDirectories
|
||||
import org.gradle.api.tasks.InputDirectory
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.util.parseSpaceSeparatedArgs
|
||||
|
||||
@CacheableTask
|
||||
abstract class TypescriptToLuaTask @Inject constructor(
|
||||
private val fs: FileSystemOperations
|
||||
) : NpmTask() {
|
||||
|
||||
@get:InputDirectory
|
||||
@get:SkipWhenEmpty
|
||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||
@get:NormalizeLineEndings
|
||||
@get:IgnoreEmptyDirectories
|
||||
abstract val sourceFiles: DirectoryProperty
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract val outputDirectory: DirectoryProperty
|
||||
|
||||
init {
|
||||
super.setGroup(BasePlugin.BUILD_GROUP)
|
||||
super.setDescription("Convert Typescript To Lua")
|
||||
super.execOverrides { standardOutput = System.out }
|
||||
super.npmCommand.set(listOf("run", "build"))
|
||||
super.ignoreExitValue.set(false)
|
||||
super.args.set(parseSpaceSeparatedArgs("-- --outDir $temporaryDir"))
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
fun tstl() {
|
||||
fs.delete { delete(temporaryDir) }
|
||||
temporaryDir.mkdirs()
|
||||
|
||||
super.exec()
|
||||
|
||||
fs.sync {
|
||||
from(temporaryDir)
|
||||
into(outputDirectory)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package kafkatorio.tasks
|
||||
|
||||
import com.github.gradle.node.NodePlugin
|
||||
import kafkatorio.*
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.JsonObjectBuilder
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.api.tasks.CacheableTask
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.kotlin.dsl.support.useToRun
|
||||
import org.jetbrains.kotlin.util.suffixIfNot
|
||||
|
||||
|
||||
@CacheableTask
|
||||
abstract class UpdatePackageJson @Inject constructor(
|
||||
private val providers: ProviderFactory,
|
||||
) : DefaultTask(),
|
||||
ProviderFactory by providers {
|
||||
|
||||
/** Cumulative updates - will be combined one by one, then applied to [packageJsonFile] */
|
||||
@get:Input
|
||||
internal abstract val expectedJsonUpdates: ListProperty<String>
|
||||
|
||||
@get:OutputFile
|
||||
abstract val packageJsonFile: RegularFileProperty
|
||||
|
||||
|
||||
init {
|
||||
group = NodePlugin.NPM_GROUP
|
||||
description = "Update package.json properties"
|
||||
|
||||
outputs.upToDateWhen(JsonPropertiesUpToDateSpec)
|
||||
}
|
||||
|
||||
|
||||
@TaskAction
|
||||
fun exec() {
|
||||
val packageJsonFile = packageJsonFile.asFile.get()
|
||||
val expectedJsonUpdates: List<String> = expectedJsonUpdates.get().toList()
|
||||
|
||||
logger.lifecycle("updating package.json ${packageJsonFile.canonicalFile}")
|
||||
|
||||
val expectedJson = expectedJsonUpdates.fold(JsonObject(emptyMap())) { acc, update ->
|
||||
val updateJson = jsonMapper.parseToJsonElement(update).jsonObject
|
||||
JsonObject(acc + updateJson)
|
||||
}
|
||||
|
||||
val updatedPackageJson = JsonObject(
|
||||
packageJsonFile.parseToJsonObject() + expectedJson
|
||||
)
|
||||
|
||||
val packageJsonContentFormatted =
|
||||
jsonMapper
|
||||
.encodeToString(updatedPackageJson)
|
||||
|
||||
// change empty arrays/objects, because `npm install` also formats package.json,
|
||||
// but slightly differently to kxs.
|
||||
.replace(": {\n }", ": {}")
|
||||
.replace(": [\n ]", ": []")
|
||||
|
||||
.suffixIfNot("\n")
|
||||
|
||||
logger.info(packageJsonContentFormatted)
|
||||
|
||||
packageJsonFile.writer().useToRun {
|
||||
write(packageJsonContentFormatted)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Update [expectedJson] by merging [updateJsonProvider] with the existing value. */
|
||||
fun updateExpectedJson(
|
||||
expectedJsonUpdate: JsonObjectBuilder.() -> Unit
|
||||
) {
|
||||
val expectedJsonUpdateProvider = provider {
|
||||
buildJsonObject(expectedJsonUpdate).toString()
|
||||
}
|
||||
|
||||
expectedJsonUpdates.add(expectedJsonUpdateProvider)
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val jsonMapper = Json {
|
||||
prettyPrint = true
|
||||
prettyPrintIndent = " "
|
||||
}
|
||||
|
||||
|
||||
internal fun File.parseToJsonObject(): JsonObject =
|
||||
jsonMapper.parseToJsonElement(readText()).jsonObject
|
||||
|
||||
|
||||
internal fun Property<String>.parseToJsonObject(): JsonObject =
|
||||
jsonMapper.parseToJsonElement(get()).jsonObject
|
||||
|
||||
|
||||
internal fun List<String>.foldParseToJsonObject(): JsonObject =
|
||||
fold(JsonObject(emptyMap())) { acc, update ->
|
||||
val updateJson = jsonMapper.parseToJsonElement(update).jsonObject
|
||||
JsonObject(acc + updateJson)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue