Splitting Gradle Script Guide Using Kts
Gradle Script Splitting Guide
Quick Overview
Split large .gradle.kts files into smaller, focused scripts using apply(from = "path/to/file.gradle.kts").
Basic Usage
Main Build File
// thorgKotlinMP.build.gradle.kts
plugins { /* ... */ }
// Apply additional scripts
apply(from = "gradle-scripts/test-tasks.gradle.kts")
apply(from = "gradle-scripts/compile-tasks.gradle.kts")
// Rest of main config
kotlin { /* ... */ }
Included Script
// gradle-scripts/test-tasks.gradle.kts
// ✅ Define tasks
tasks.register("myCustomTask") {
doLast {
println("Running in ${project.name}")
}
}
// ✅ Define helper functions
fun Project.findTestClass(path: String): File? {
return file("src/test/kotlin/$path").takeIf { it.exists() }
}
// ✅ Access project, tasks, subprojects
subprojects.forEach { /* ... */ }
What Works
| Feature | Available | Example |
|---|---|---|
| Define tasks | ✅ | tasks.register("myTask") { } |
| Define functions | ✅ | fun Project.helper() { } |
| Define data classes | ✅ | data class Result(val x: String) |
Access project | ✅ | project.subprojects |
Access tasks | ✅ | tasks.getByName("build") |
| Configure dependencies | ✅ | dependencies { } |
| Share variables | ⚠️ | Use extra properties (see below) |
Sharing Data Between Scripts
Using extra Properties
// Main file
extra["myConfig"] = mapOf("key" to "value")
// Included file
val config = extra["myConfig"] as Map<String, String>
Using Functions (Preferred)
// gradle-scripts/utils.gradle.kts
fun getTestDirs(): List<String> = listOf("src/test/kotlin", "src/jvmTest/kotlin")
// Main file (after apply)
val dirs = getTestDirs() // ✅ Functions are accessible
Common Pitfalls
❌ Order Matters
// WRONG: Using function before script is applied
val dirs = getTestDirs()
apply(from = "utils.gradle.kts")
// RIGHT: Apply first
apply(from = "utils.gradle.kts")
val dirs = getTestDirs()
❌ Variable Scope
// In included script - these are LOCAL to that script
val myVar = "value" // NOT accessible in main file
❌ Plugin Configuration
// Included scripts CANNOT apply plugins
// ❌ plugins { id("some-plugin") } // Error!
// ✅ Apply all plugins in main file only
⚠️ Relative Paths
// Main file at: kotlin-mp/build.gradle.kts
// Included file at: kotlin-mp/gradle-scripts/tasks.gradle.kts
// In included file, paths are relative to PROJECT ROOT (kotlin-mp/), not the script location
val file = file("src/test/kotlin/Foo.kt") // ✅ Resolves to kotlin-mp/src/test/kotlin/Foo.kt
Recommended Split Structure
kotlin-mp/
├── thorgKotlinMP.build.gradle.kts # Main: plugins, kotlin{}, dependencies{}
├── CommonBuildConfig.gradle.kts # Shared config (already exists)
└── gradle-scripts/
├── test-tasks.gradle.kts # Test-related tasks (singleJvmTest, etc.)
├── test-utils.gradle.kts # Test helper functions
├── compile-tasks.gradle.kts # Compile tasks (sanityCompile*, etc.)
└── json-tasks.gradle.kts # Utility tasks (tasksJson, etc.)
Best Practices
- Keep core config in main file:
plugins {},kotlin {},dependencies {} - One purpose per file: Group related tasks/functions together
- Use extension functions:
fun Project.helper()for reusability - Apply early: Apply includes near top of main file (after plugins)
- Document dependencies: Add comments if one script depends on another
Example Refactor
Before (600+ lines)
// thorgKotlinMP.build.gradle.kts
plugins { }
kotlin { }
// ... 200 lines of config ...
tasks.register("singleJvmTest") { /* 50 lines */ }
tasks.register("singleJvmTestAuto") { /* 80 lines */ }
fun Project.findModule() { /* 30 lines */ }
// ... more tasks ...
After
// thorgKotlinMP.build.gradle.kts (250 lines)
plugins { }
apply(from = "gradle-scripts/test-tasks.gradle.kts")
apply(from = "gradle-scripts/test-utils.gradle.kts")
kotlin { }
dependencies { }
// gradle-scripts/test-tasks.gradle.kts (130 lines)
tasks.register("singleJvmTest") { /* ... */ }
tasks.register("singleJvmTestAuto") { /* ... */ }
// gradle-scripts/test-utils.gradle.kts (30 lines)
data class TestClassLocation(val project: Project, val sourceSet: String)
fun Project.findModule() { /* ... */ }
Debugging Tips
# See evaluation order
./gradlew build --info | grep "Evaluating"
# Check if task is registered
./gradlew tasks --all | grep myTask
# Debug script errors
./gradlew build --stacktrace