Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .codegraph/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# CodeGraph data files β€” local to each machine, not for committing.
# Ignore everything in .codegraph/ except this file itself, so transient
# files (the database, daemon.pid, sockets, logs) never show up in git.
*
!.gitignore
2 changes: 1 addition & 1 deletion .github/workflows/gradle-wrapper-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout latest code
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/actions/wrapper-validation@v3

9 changes: 5 additions & 4 deletions .github/workflows/pre-merge.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,21 @@ jobs:
if: ${{ !contains(github.event.head_commit.message, 'ci skip') }}
steps:
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Cache Gradle Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.gradle/caches/
key: cache-gradle-cache
- name: Cache Gradle Wrapper
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.gradle/wrapper/
key: cache-gradle-wrapper
- name: Setup java
uses: actions/setup-java@v1
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Run Gradle tasks
id: gradle_run
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/publish-plugin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,19 @@ jobs:
if: ${{ !contains(github.event.head_commit.message, 'ci skip') }}
steps:
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Cache Gradle Caches
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.gradle/caches/
key: cache-gradle-cache
- name: Cache Gradle Wrapper
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ~/.gradle/wrapper/
key: cache-gradle-wrapper
- name: Setup java
uses: actions/setup-java@v3
uses: actions/setup-java@v4
with:
distribution: 'corretto'
java-version: '17'
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,8 @@
!/.idea/encodings.xml
.DS_Store
/build
*.salive
*.salive
CLAUDE.md
AGENTS.md
.claude
.omc
69 changes: 69 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Changelog

All notable changes to this project are documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.0.0] - 2026-08-17

### Changed

- Reworked the plugin for lazy configuration and dependency wiring (breaking). Removed
`rulesPluginJar`/`rulesPluginJars`, unified every external dependency into a single
`from(...)` slot API (`ktlint.cli`, `detekt.<platform>.rules`), replaced scattered
source-pattern properties with `sources { include/exclude/useDefaults }` blocks. See
[MIGRATION.md](MIGRATION.md).
- Added a bundled default for `detekt.android.rules` β€” no longer requires an implicit
`libs/detekt-rules-1.4.0.jar` pickup.

### Added

- `detekt.baseline` β€” optional baseline file to suppress pre-existing findings (e.g. for incremental
adoption on legacy modules).
- `detekt.xmlReportEnabled` / `detekt.sarifReportEnabled` β€” opt-in emitters for XML and SARIF report
formats per detekt task.
- `androidLint.enabled` β€” opt-in wiring to integrate Android Gradle Plugin lint checks into
`pipelineCheck` and `prePushCheck` aggregate tasks (off by default: lint is slow).
- `generateDefaultDetektAndroidRulesJar` task β€” materializes bundled KODE Android detekt rules jar
under `<root>/build/app-quality/detekt/rules/`.
- Full test coverage across all DSL/config surfaces, including a real Kotlin-DSL (`.gradle.kts`)
consumer test, Kotlin Multiplatform module coverage, an `org.jetbrains.compose` (Compose
Multiplatform) functional test, and a zero-config "real production shape" test mirroring the
three current adopters.
- Documentation completion: accurate README examples, full backfilled `CHANGELOG.md`.

## [1.0.8] - 2026-04-09

- Updated ktlint to a newer version, plus additional dependencies.
- Added `README.md` with project info.

## [1.0.7] - 2026-03-26

- Added logic to register the `pipelineCheck` task.

## [1.0.6] - 2026-03-25

- Added logic to provide libraries from the version catalog.

## [1.0.5] - 2026-03-25

- Reverted provider usage for detekt tasks; removed non-cacheable logic.

## [1.0.3] - 2026-03-25

- Fixed configuration-cache issues and logger usage; reworked detekt configuration logic.
- Moved logger usage to task execution via build services.

## [1.0.2] - 2026-03-24

- Fixed ktlint check to use the correct logger.
- Fixed detekt ignored build types handling.
- Added sources configuration.

## [1.0.1] - 2026-03-24

- Initial tagged release.
- Added a JVM target fallback when no Kotlin tasks are present.
- Removed a duplicate core library dependency (reused from build-publish-core).
- Fixed ktlint and config handling.
187 changes: 187 additions & 0 deletions MIGRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# Migration Guide

Upgrade notes per release. Sections list breaking changes first, then behavior changes and
new opt-in capabilities.

## 2.0.0 (dependency wiring rework) β€” migrating from 1.0.8

### Breaking: `detekt.<platform>.rulesPluginJar` removed

The single-file `rulesPluginJar: RegularFileProperty` no longer exists. Rule jars are added
through the platform's unified `rules` slot:

```kotlin
// before (1.0.8):
appQualityFoundation {
detekt.kotlin.rulesPluginJar.set(rootProject.layout.projectDirectory.file("libs/detekt-rules-1.4.0.jar"))
}

// after:
appQualityFoundation {
detekt.kotlin.rules {
from(files(rootProject.layout.projectDirectory.file("libs/detekt-rules-1.4.0.jar")))
}
}
```

### Breaking: implicit `<root>/libs/detekt-rules-1.4.0.jar` default removed β€” superseded below

Previously the plugin silently picked up `<root>/libs/detekt-rules-1.4.0.jar` when it
existed. That implicit, path-based pickup is gone. **However**, see "New: bundled default for
`detekt.android.rules`" below β€” for the common case (bundled `default.android-config.yml`,
which is the only config that activates `kode:` today) the plugin now supplies an equivalent
default again, just as an explicit, inspectable dependency slot instead of a silent file
convention. Projects with a custom detekt config that activates `kode:` (not the bundled one)
still need the explicit `rules { from(files(...)) }` shown above, or detekt fails config
validation with an unknown `kode` rule set.

### New: bundled default for `detekt.android.rules`

`detekt.android.rules` now has a real default: the plugin bundles its own `kode:` rules jar
(not published to any Maven repo β€” verified against Maven Central; the only published
`ru.kode` detekt artifact is `detekt-rules-compose`, a different ruleset) and wires it in
automatically while `useDefaults` is `true` (the default). Zero-config projects using the
plugin's bundled `default.android-config.yml` need **no action** β€” this restores the
1.0.7/1.0.8 zero-config experience for the KODE `RouteWiringMethodNaming` rule, just via an
inspectable slot instead of an implicit file convention. Only projects that explicitly set
`detekt.android.rules { useDefaults.set(false) }` need to supply their own jar/coordinate.

### New: `ktlint.cli`/`detekt.kotlin.rules`/`detekt.compose.rules` no longer require a catalog alias

These 3 slots now fall back to a coordinate baked into the plugin when the consumer's `libs`
catalog has no matching alias (or no catalog at all) β€” previously this was a hard failure
("MISSING KTLINT/DETEKT DEPENDENCY IN VERSION CATALOG" / "MISSING VERSION CATALOG"). A
matching alias in your own catalog, if present, still wins unchanged β€” **no action required**
for existing projects with the standard `ktlint-cli`/`detekt-formatting`/`detekt-compose-rules`
aliases already declared.

### New: unified dependency slots (`from(...)` from any source + `useDefaults`)

Every external dependency of the plugin β€” the ktlint CLI and each detekt platform's rule
sets β€” is now ONE uniform slot accepting every source kind:

```kotlin
appQualityFoundation {
ktlint.cli {
from(deps.ktlint.cli) // typed accessor from ANY catalog
from("com.pinterest.ktlint:ktlint-cli:1.8.0") // string coordinates
from(files("tools/ktlint-cli.jar")) // checked-in jar files
useDefaults.set(false) // drop the `libs` catalog default
}
detekt.kotlin.rules { from(files("libs/detekt-rules-1.4.0.jar")) }
detekt.compose.rules {
from("ru.kode:detekt-rules-compose:1.4.0") // published custom rules
useDefaults.set(false)
}
}
```

Semantics:
- `from(...)` is add-only; entries from all sources accumulate.
- The slot's default (the `libs` catalog aliases `ktlint-cli`, `detekt-formatting`,
`detekt-compose-rules`) is independent of user additions and included while
`useDefaults` is `true` (the default) β€” so adding your custom rules jar keeps the
default formatting rules unless you disable them.
- Zero-config projects with the standard `libs` aliases need NO changes beyond the rules-jar
migration above.

### Behavior change: configured-but-missing files fail the build

A file listed in any slot (`from(files(...))`) that does not exist on disk fails the build
with an explanatory message naming the slot. Note the validation fires whenever the
dependency set is realized β€” including IDE sync and the `dependencies` report β€” not only on
task execution.

### Breaking: `additionalSourcePatterns`/`additionalIgnoredSourcePatterns` (ktlint) and
`additionalSourcePaths`/`additionallyExcludedPaths` (detekt) replaced by `sources { }`

Both blocks' raw `ListProperty<String>` source-pattern properties are replaced by a single
`sources { }` block, mirroring the dependency slots' `include`/`exclude`/`useDefaults` shape.
The leaky `!` prefix ktlint ignores required is gone β€” `exclude` now takes bare patterns; the
plugin adds the CLI's `!` prefix internally.

```kotlin
// before (1.0.8):
appQualityFoundation {
ktlint {
additionalSourcePatterns.set(listOf("**/src/*/kotlin/**/*.kts"))
additionalIgnoredSourcePatterns.set(listOf("!**/build-logic/**"))
}
detekt {
additionalSourcePaths.set(listOf("src/custom/kotlin"))
additionallyExcludedPaths.set(listOf("tmpGenerated"))
}
}

// after:
appQualityFoundation {
ktlint.sources {
include.set(listOf("**/src/*/kotlin/**/*.kts"))
exclude.set(listOf("**/build-logic/**")) // no `!` prefix
}
detekt.sources {
include.set(listOf("src/custom/kotlin"))
exclude.set(listOf("tmpGenerated"))
}
}
```

`useDefaults.set(false)` on either block drops the plugin's bundled defaults (ktlint's
default Kotlin globs/ignore list, detekt's default per-platform source dirs) β€” same
`useDefaults` semantics as the dependency slots.

### New: `detekt.baseline`, `detekt.xmlReportEnabled`, `detekt.sarifReportEnabled`

Three new opt-in detekt configuration properties for incremental adoption and report format control:

- `baseline`: optional detekt baseline file (e.g. `detekt-baseline.xml`). Findings present in the
baseline are suppressed. Unset by default (no baseline).
- `xmlReportEnabled`: emit detekt's XML report per task. Default `false`.
- `sarifReportEnabled`: emit detekt's SARIF report per task (e.g. for GitHub code scanning). Default `false`.

Example:

```kotlin
appQualityFoundation {
detekt {
baseline.set(layout.projectDirectory.file("detekt-baseline.xml"))
xmlReportEnabled.set(true)
sarifReportEnabled.set(false)
}
}
```

### New: opt-in `androidLint.enabled` wiring

Integrate Android Gradle Plugin lint checks into `pipelineCheck` and `prePushCheck` aggregate tasks via
the new `androidLint { enabled.set(true) }` config. Off by default β€” lint is slow and most projects
already run it separately in CI.

Example:

```kotlin
appQualityFoundation {
androidLint {
enabled.set(true)
}
}
```

### Upgrade checklist for KODE projects

1. Replace every `detekt.<platform>.rulesPluginJar.set(...)` with
`detekt.<platform>.rules { from(files(...)) }`.
2. If your project relied on the implicit `libs/detekt-rules-1.4.0.jar` pickup with a
**custom** detekt config (not the plugin's bundled `default.android-config.yml`), add the
same `rules { from(files(...)) }` line. Projects using the bundled android config need no
action β€” see "New: bundled default for `detekt.android.rules`" above.
3. The `libs` catalog aliases (`ktlint-cli`, `detekt-formatting`, `detekt-compose-rules`) are
now optional β€” only needed if you want a version different from the plugin's own baked-in
default, or to disable a default entirely with `useDefaults.set(false)`.
4. Replace `ktlint.additionalSourcePatterns`/`additionalIgnoredSourcePatterns` and
`detekt.additionalSourcePaths`/`additionallyExcludedPaths` with `ktlint.sources { }` /
`detekt.sources { }` as shown above β€” drop the `!` prefix from any exclude pattern.
5. Run `./gradlew pipelineCheck` and check CI is green.
6. If your project only applies the plugin at the root and configures `verboseLogging` (the
shape used by every current adopter) β€” no action needed. That zero-config shape is now
covered by an explicit test (`RealProjectShapeTest`) and needs no changes to keep working.
Loading
Loading