Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions agentic-tool/build.gradle.dcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
kotlinJvmApplication {
mainClass = "org.gradle.client.agentic.AgenticToolKt"
jvmArguments += listOf("--enable-native-access=ALL-UNNAMED")

dependencies {
implementation(project(":build-action"))
implementation(project(":dcl-utils"))

implementation("org.gradle:gradle-tooling-api:9.6.0-20260511195019+0000")
implementation("org.gradle:gradle-declarative-dsl-core:9.6.0-20260511195019+0000")
implementation("org.gradle:gradle-declarative-dsl-evaluator:9.6.0-20260511195019+0000")
implementation("org.gradle:gradle-declarative-dsl-tooling-models:9.6.0-20260511195019+0000")

implementation("com.github.ajalt.clikt:clikt:5.0.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0")

runtimeOnly("org.slf4j:slf4j-simple:2.0.17")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package org.gradle.client.agentic

import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.core.Context
import com.github.ajalt.clikt.core.NoOpCliktCommand
import com.github.ajalt.clikt.core.main
import com.github.ajalt.clikt.core.subcommands
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import org.gradle.client.build.action.GetResolvedDomAction
import org.gradle.client.build.model.ResolvedDomPrerequisites
import org.gradle.internal.declarativedsl.evaluator.main.SimpleAnalysisEvaluator
import org.gradle.tooling.BuildAction
import org.gradle.tooling.GradleConnector
import java.io.File

fun main(args: Array<String>) {
MainCommand()
.subcommands(
ProjectsCommand(),
EffectiveProjectDefinitionCommand(),
SettingsDefaultsCommand(),
SettingsDefinitionCommand(),
ProjectSchemaCommand(),
ProjectTypesAndFeaturesCommand()
)
.main(args)
}

class MainCommand : NoOpCliktCommand() {
override fun help(context: Context): String =
"An agent-friendly introspection tool for Declarative Gradle projects." +
"\nEach command outputs a JSON on the standard output and has its own '<command> --help'."
}

abstract class DclCommand(name: String) : CliktCommand(name) {
protected val rootProjectDir: String by option(help = "Gradle build root project directory").default(".")
protected val documentationProvider: DocumentationProvider = SchemaEmbeddedDocumentationProvider

private val domPrerequisites: BuildAction<ResolvedDomPrerequisites> = GetResolvedDomAction()

final override fun run() {
val connector = GradleConnector.newConnector().forProjectDirectory(File(rootProjectDir).absoluteFile)
val prerequisites = try {
connector.connect().use { connection ->
connection.action(domPrerequisites).addArguments("--no-scan", "--quiet").run()
}
} finally {
connector.disconnect()
}

val analyzer = SimpleAnalysisEvaluator.withSchema(
prerequisites.settingsInterpretationSequence,
prerequisites.projectInterpretationSequence
)

val output = produceOutput(prerequisites, analyzer)
println(Json { prettyPrint = true }.encodeToString(output))
}

abstract fun produceOutput(prerequisites: ResolvedDomPrerequisites, analyzer: SimpleAnalysisEvaluator): JsonElement
}


Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.gradle.client.agentic

import org.gradle.client.build.model.ResolvedDomPrerequisites
import org.gradle.internal.declarativedsl.dom.operations.overlay.DocumentOverlayResult
import org.gradle.internal.declarativedsl.evaluator.main.AnalysisDocumentUtils
import org.gradle.internal.declarativedsl.evaluator.main.SimpleAnalysisEvaluator

fun getDomForProject(
analyzer: SimpleAnalysisEvaluator,
prerequisites: ResolvedDomPrerequisites,
projectInfo: ResolvedDomPrerequisites.ProjectInfo
): DocumentOverlayResult? {
val settingsScript = prerequisites.settingsFile.takeIf { it.canRead() }?.readText() ?: ""
val projectScript = projectInfo.projectBuildFile.takeIf { it.canRead() }?.readText() ?: ""

val settingsResult =
analyzer.evaluate(prerequisites.settingsFile.path, settingsScript)
val projectResult =
analyzer.evaluate(projectInfo.projectBuildFile.path, projectScript)

return AnalysisDocumentUtils.documentWithModelDefaults(settingsResult, projectResult)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.gradle.client.agentic

import org.gradle.declarative.dsl.schema.DataProperty
import org.gradle.declarative.dsl.schema.DataType
import org.gradle.declarative.dsl.schema.SchemaDocumentation
import org.gradle.declarative.dsl.schema.SchemaItemMetadata
import org.gradle.declarative.dsl.schema.SchemaMemberFunction

interface DocumentationProvider {
fun classDocumentation(classDataType: DataType.ClassDataType): String?
fun functionDocumentation(schemaMemberFunction: SchemaMemberFunction): String?
fun propertyDocumentation(property: DataProperty): String?
}

object SchemaEmbeddedDocumentationProvider : DocumentationProvider {
override fun classDocumentation(classDataType: DataType.ClassDataType): String? =
extractDocsFromMetadata(classDataType.metadata)

override fun functionDocumentation(schemaMemberFunction: SchemaMemberFunction): String? =
extractDocsFromMetadata(schemaMemberFunction.metadata)

override fun propertyDocumentation(property: DataProperty): String? =
extractDocsFromMetadata(property.metadata)

private fun extractDocsFromMetadata(metadata: Iterable<SchemaItemMetadata>) =
metadata
.filterIsInstance<SchemaDocumentation>()
.flatMap {
listOf(it.text) +
it.parts.map { (key, value) ->
"* `$key`: $value"
}
}
.joinToString("\n\n")
.ifBlank { null }
}
Loading
Loading