diff --git a/automation/code-generator/build.gradle.kts b/automation/code-generator/build.gradle.kts index 726e248725..38c3f80572 100644 --- a/automation/code-generator/build.gradle.kts +++ b/automation/code-generator/build.gradle.kts @@ -16,6 +16,8 @@ dependencies { implementation("io.ktor:ktor-client-content-negotiation") implementation("io.ktor:ktor-serialization-kotlinx-json") implementation("io.arrow-kt:arrow-fx-coroutines:1.2.4") + implementation("org.gradle:gradle-tooling-api:8.8") + runtimeOnly("org.slf4j:slf4j-simple:1.7.10") implementation(projects.actionBindingGenerator) implementation(projects.sharedInternal) diff --git a/automation/code-generator/src/main/kotlin/io/github/typesafegithub/workflows/ToolingApiExperiment.kt b/automation/code-generator/src/main/kotlin/io/github/typesafegithub/workflows/ToolingApiExperiment.kt new file mode 100644 index 0000000000..19edd35dcb --- /dev/null +++ b/automation/code-generator/src/main/kotlin/io/github/typesafegithub/workflows/ToolingApiExperiment.kt @@ -0,0 +1,35 @@ +package io.github.typesafegithub.workflows + +import org.gradle.tooling.GradleConnector +import org.gradle.tooling.model.GradleProject +import java.io.File +import java.util.Locale + +fun main() { + GradleConnector.newConnector() + .forProjectDirectory(File("/Users/piotr/repos/github-workflows-kt")) + .connect() + .use { gradleConnector -> + val model = gradleConnector.getModel(GradleProject::class.java) + val allTasks = model.tasks + model.children.all.flatMap { it.tasks } + allTasks.forEach { task -> + println(task) + } + println("Generate the following accessors:") + allTasks.forEach { task -> + println("projects" + task.path.split(":").joinToString(".") { it.toCamelCase() }) + } + } +} + +internal fun String.toPascalCase(): String { + val hasOnlyUppercases = none { it in 'a'..'z' } + val normalizedString = if (hasOnlyUppercases) lowercase() else this + return normalizedString.replace("+", "-plus-") + .split("-", "_", " ", ".", "/") + .joinToString("") { + it.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() } + } +} + +internal fun String.toCamelCase(): String = toPascalCase().replaceFirstChar { it.lowercase() } diff --git a/buildSrc/repositories.settings.gradle.kts b/buildSrc/repositories.settings.gradle.kts index c4569846e6..8c8df651c1 100644 --- a/buildSrc/repositories.settings.gradle.kts +++ b/buildSrc/repositories.settings.gradle.kts @@ -7,6 +7,7 @@ dependencyResolutionManagement { repositories { mavenCentral() gradlePluginPortal() + maven { url = uri("https://repo.gradle.org/gradle/libs-releases") } // It has to be defined here because preferring repositories config in settings apparently removes the below // additions done by Kotlin/JS plugin. diff --git a/github-workflows-kt/build.gradle.kts b/github-workflows-kt/build.gradle.kts index 2aa56a5b23..2c3920fe0b 100644 --- a/github-workflows-kt/build.gradle.kts +++ b/github-workflows-kt/build.gradle.kts @@ -23,6 +23,8 @@ dependencies { implementation("it.krzeminski:snakeyaml-engine-kmp:3.0.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.7.0") implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.0") + implementation("io.github.reactivecircus.cache4k:cache4k:0.13.0") + implementation("ch.qos.logback:logback-classic:1.5.6") implementation(projects.sharedInternal) testImplementation("dev.zacsweers.kctfork:core:0.5.0") diff --git a/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/domain/GradleTaskPathsBuilder.kt b/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/domain/GradleTaskPathsBuilder.kt new file mode 100644 index 0000000000..acfb664d09 --- /dev/null +++ b/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/domain/GradleTaskPathsBuilder.kt @@ -0,0 +1,39 @@ +package io.github.typesafegithub.workflows.domain + +public data class GradleTask(val path: String) + +public sealed interface TaskTreeNode + +public data class TaskTreeLeaf(val name: String) : TaskTreeNode + +public data class TaskTree(val tree: Map) : TaskTreeNode + +public data class GradleTasks(val taskTree: TaskTree = + TaskTree( + tree = mapOf( + "foo" to TaskTreeLeaf("bar"), + "baz" to TaskTree( + tree = mapOf( + "goo" to TaskTreeLeaf("zoo"), + ), + ), + ), + ), val tasks: List) { + public operator fun get(name: String): GradleTasks { +// if (name !in taskTree.tree) { +// error("'$name' not in ${taskTree.tree.keys}" ) +// } + + return if (this.tasks.isEmpty()) { + GradleTasks(tasks = listOf(GradleTask(name))) + } else { + GradleTasks( + tasks = tasks.dropLast(1) + GradleTask( + path = "${tasks.last().path}:$name")) + } + } + + public operator fun plus(other: GradleTasks): GradleTasks { + return GradleTasks(tasks = this.tasks + other.tasks) + } +} diff --git a/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/dsl/JobBuilder.kt b/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/dsl/JobBuilder.kt index f3f1d24096..8e8bd914a3 100644 --- a/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/dsl/JobBuilder.kt +++ b/github-workflows-kt/src/main/kotlin/io/github/typesafegithub/workflows/dsl/JobBuilder.kt @@ -6,6 +6,7 @@ import io.github.typesafegithub.workflows.domain.CommandStep import io.github.typesafegithub.workflows.domain.Concurrency import io.github.typesafegithub.workflows.domain.Container import io.github.typesafegithub.workflows.domain.Environment +import io.github.typesafegithub.workflows.domain.GradleTasks import io.github.typesafegithub.workflows.domain.Job import io.github.typesafegithub.workflows.domain.JobOutputs import io.github.typesafegithub.workflows.domain.KotlinLogicStep @@ -159,6 +160,16 @@ public class JobBuilder( return newStep } + public fun gradle( + @Suppress("UNUSED_PARAMETER") + vararg pleaseUseNamedArguments: Unit, + name: String? = null, + tasks: GradleTasks.() -> GradleTasks, + ) { + val configuredTasks = GradleTasks(tasks = emptyList()).tasks() + println(configuredTasks.tasks.joinToString(" ") { it.path }) + } + public fun uses( @Suppress("UNUSED_PARAMETER") vararg pleaseUseNamedArguments: Unit, diff --git a/github-workflows-kt/src/test/kotlin/io/github/typesafegithub/workflows/IntegrationTest.kt b/github-workflows-kt/src/test/kotlin/io/github/typesafegithub/workflows/IntegrationTest.kt index a7ed92398a..03276e802d 100644 --- a/github-workflows-kt/src/test/kotlin/io/github/typesafegithub/workflows/IntegrationTest.kt +++ b/github-workflows-kt/src/test/kotlin/io/github/typesafegithub/workflows/IntegrationTest.kt @@ -179,6 +179,10 @@ class IntegrationTest : FunSpec({ ), continueOnError = true, ) + + gradle( + tasks = { this["foo"]["bar"] + this["goo"]["baz"] } + ) } } diff --git a/jit-binding-server/build.gradle.kts b/jit-binding-server/build.gradle.kts index d47473f267..c8835eec29 100644 --- a/jit-binding-server/build.gradle.kts +++ b/jit-binding-server/build.gradle.kts @@ -18,8 +18,6 @@ dependencies { implementation("io.opentelemetry:opentelemetry-sdk:1.39.0") implementation("io.opentelemetry:opentelemetry-exporter-otlp:1.39.0") implementation("io.opentelemetry:opentelemetry-exporter-logging:1.39.0") - implementation("io.github.reactivecircus.cache4k:cache4k:0.13.0") - implementation("ch.qos.logback:logback-classic:1.5.6") implementation(projects.mavenBindingBuilder) implementation(projects.sharedInternal)