Kotlin Project Guardrails
Enforce Kotlin project standards: build manifest presence, Kotlin version pinning, Gradle wrapper commit, dependency locking, test source layout, and detekt/ktlint configuration. Supports Gradle (Kotlin & Groovy DSL) and Maven (kotlin-maven-plugin).
kotlin to your lunar-config.yml:uses: github://earthly/lunar-lib/policies/kotlin@v1.0.5
Included Guardrails
This policy includes 7 guardrails that enforce standards for your devex build and ci.
build-tool-manifest-exists
Ensures the project has a recognised Kotlin build manifest:
build.gradle.kts (Gradle Kotlin DSL), build.gradle (Gradle Groovy DSL
applying a Kotlin plugin), or pom.xml with the kotlin-maven-plugin.
Required for any Kotlin project so that the build is reproducible and
tooling-discoverable.
kotlin-version-pinned
Ensures the Kotlin compiler version is declared — via the Gradle
kotlin("jvm") version "..." / id("org.jetbrains.kotlin.jvm") plugin,
<kotlin.version> in pom.xml, or a kotlin entry in
gradle/libs.versions.toml. Pinning the compiler version prevents drift
between developers and CI.
min-kotlin-version
Ensures the declared Kotlin compiler version meets the configured
minimum (default: "1.8"). Reads .lang.kotlin.version. Skips when the
version is not detected — pair with kotlin-version-pinned if you want
presence to be enforced too.
build-tool-wrapper-exists
Ensures the Gradle wrapper (gradlew + gradle/wrapper/) is committed
for Gradle projects. Wrappers pin the build tool version and give
reproducible builds without a pre-installed Gradle. Skips for Maven-only
projects.
dependencies-locked
Ensures dependencies are locked for reproducible builds via Gradle
dependency locking (gradle.lockfile). Informational by default — most
Kotlin/Gradle projects do not lock dependencies, but doing so produces
reproducible CI builds.
test-directory-exists
Ensures a src/test/kotlin directory (or the equivalent for Android /
Multiplatform layouts) exists with test sources. Skips on non-Kotlin
projects.
linter-configured
Ensures a Kotlin static-analysis / formatting tool is configured —
detekt (detekt.yml) or ktlint. These enforce consistent code quality
and formatting and are the de facto standard for Kotlin. Informational.
How Guardrails Fit into Lunar
Lunar guardrails define your engineering standards as code. They evaluate data collected by integrations and produce pass/fail checks with actionable feedback.
Policies support gradual enforcement—from silent scoring to blocking PRs or deployments—letting you roll out standards at your own pace without disrupting existing workflows.
Learn How Lunar Works →Required Integrations
This policy evaluates data gathered by one or more of the following integration(s).
Make sure to enable them in your lunar-config.yml.
Configuration
Configure this policy in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
min_kotlin_version
|
Optional |
1.8
|
Minimum required Kotlin compiler version (e.g., "1.8", "1.9", "2.0"). Compared with semantic-version semantics — "1.8" matches 1.8.x and above, but rejects 1.7.x. |
Documentation
View on GitHubKotlin Project Guardrails
Enforce Kotlin-specific project standards including build manifest presence, version pinning, wrapper commit, dependency locking, test layout, and static-analysis configuration.
Overview
This policy validates Kotlin projects against best practices for build configuration, version pinning, dependency reproducibility, testing conventions, and code quality. All checks skip gracefully on non-Kotlin projects (i.e., .lang.kotlin missing). Supports Gradle (Kotlin & Groovy DSL) and Maven (with kotlin-maven-plugin) build systems.
Policies
This plugin provides the following policies (use include to select a subset):
| Policy | Description | Failure Meaning |
|---|---|---|
build-tool-manifest-exists |
Validates build.gradle.kts, build.gradle, or pom.xml exists |
Project lacks a recognised Kotlin build manifest |
kotlin-version-pinned |
Validates the Kotlin compiler version is declared | Missing Kotlin plugin/<kotlin.version> declaration |
min-kotlin-version |
Validates declared Kotlin version meets min_kotlin_version (default 1.8) |
Kotlin version below the configured minimum |
build-tool-wrapper-exists |
Validates the Gradle wrapper is committed | Missing gradlew (Gradle projects only) |
dependencies-locked |
Validates gradle.lockfile is present |
No lockfile committed (informational) |
test-directory-exists |
Validates src/test/kotlin exists |
No test sources detected |
linter-configured |
Validates detekt or ktlint is configured | Neither detekt nor ktlint configured (informational) |
Required Data
This policy reads from the following Component JSON paths:
| Path | Type | Provided By |
|---|---|---|
.lang.kotlin |
object | kotlin collector |
.lang.kotlin.build_gradle_kts_exists |
boolean | kotlin collector |
.lang.kotlin.build_gradle_exists |
boolean | kotlin collector |
.lang.kotlin.pom_xml_exists |
boolean | kotlin collector |
.lang.kotlin.version |
string | kotlin collector |
.lang.kotlin.build_systems |
array | kotlin collector |
.lang.kotlin.gradlew_exists |
boolean | kotlin collector |
.lang.kotlin.lockfile_exists |
boolean | kotlin collector |
.lang.kotlin.test_directory_exists |
boolean | kotlin collector |
.lang.kotlin.detekt_configured |
boolean | kotlin collector |
.lang.kotlin.ktlint_configured |
boolean | kotlin collector |
Installation
Add to your lunar-config.yml:
policies:
- uses: github://earthly/lunar-lib/policies/kotlin@main
on: ["domain:your-domain"] # replace with your own domain or tags
enforcement: report-pr
# include: [build-tool-manifest-exists, kotlin-version-pinned] # Only run specific checks
Examples
Passing Example
{
"lang": {
"kotlin": {
"build_gradle_kts_exists": true,
"version": "1.9.22",
"build_systems": ["gradle"],
"gradlew_exists": true,
"lockfile_exists": true,
"test_directory_exists": true,
"detekt_configured": true,
"ktlint_configured": false
}
}
}
Failing Example
{
"lang": {
"kotlin": {
"build_gradle_kts_exists": false,
"build_gradle_exists": false,
"pom_xml_exists": false,
"version": "",
"build_systems": [],
"gradlew_exists": false,
"lockfile_exists": false,
"test_directory_exists": false,
"detekt_configured": false,
"ktlint_configured": false
}
}
}
Failure messages:
"No Kotlin build manifest found. Add build.gradle.kts (Gradle Kotlin DSL), build.gradle (Groovy DSL), or pom.xml with kotlin-maven-plugin.""Kotlin compiler version not declared. Add the Kotlin Gradle plugin with a version (e.g. kotlin(\"jvm\") version \"1.9.22\") or set <kotlin.version> in pom.xml.""Kotlin version 1.7.20 is below minimum 1.8. Update the Kotlin plugin version.""Gradle wrapper not found. Run 'gradle wrapper' and commit gradlew, gradlew.bat, and gradle/wrapper/.""No dependency lockfile found. Enable Gradle dependency locking and commit gradle.lockfile for reproducible builds.""No test sources found. Create src/test/kotlin/ and add JUnit, Kotest, or MockK tests.""No Kotlin linter configured. Add detekt (detekt.yml) or ktlint for consistent code quality."
Remediation
build-tool-manifest-exists
- For Gradle (Kotlin DSL): create
build.gradle.ktsat the repo root and apply a Kotlin plugin - For Gradle (Groovy DSL): create
build.gradleapplyingorg.jetbrains.kotlin.jvm - For Maven: add
pom.xmlwith thekotlin-maven-pluginin<plugins>
kotlin-version-pinned
- In
build.gradle.kts, add to theplugins {}block:kotlin("jvm") version "1.9.22"(or your target version) - In
build.gradle(Groovy):id 'org.jetbrains.kotlin.jvm' version '1.9.22' - In
pom.xml: set<kotlin.version>1.9.22</kotlin.version>and reference it in the kotlin-maven-plugin config
min-kotlin-version
- Update the Kotlin plugin version (or
<kotlin.version>) to a version at or abovemin_kotlin_version - Run
./gradlew build(ormvn verify) to confirm the project still compiles on the new version - Review the Kotlin changelog for any breaking language/stdlib changes between versions
build-tool-wrapper-exists
- Run
gradle wrapper --gradle-version <version>to generate the wrapper - Commit
gradlew,gradlew.bat, and thegradle/wrapper/directory - Use
./gradlewin CI so the pinned version is always used
dependencies-locked
- Enable dependency locking in
build.gradle.kts:dependencyLocking { lockAllConfigurations() } - Run
./gradlew dependencies --write-locksto generategradle.lockfile - Commit
gradle.lockfileto version control
test-directory-exists
- Create
src/test/kotlin/ - Add a test framework dependency (JUnit 5, Kotest, or MockK)
- Add at least one test file under
src/test/kotlin/
linter-configured
- For detekt, apply the plugin in
build.gradle.kts:
and commit aplugins { id("io.gitlab.arturbosch.detekt") version "1.23.5" }detekt.ymlconfig at the repo root - For ktlint, apply
id("org.jlleitschuh.gradle.ktlint") version "12.1.0" - Run
./gradlew detekt(orktlintCheck) to verify the configuration
Open Source
This policy is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore how individual guardrails work with specific integrations.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 200+ built-in guardrails.