Skip to content

Commit 78377b0

Browse files
authored
Merge pull request #6 from stride-nyc/jdrew/update-claude.md
update the readme and claude documentation
2 parents 676843c + 2e331a0 commit 78377b0

3 files changed

Lines changed: 36 additions & 31 deletions

File tree

‎CLAUDE.md‎

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,20 @@
1-
# CLAUDE.md
2-
3-
Guidance for Claude Code (and other agents) working in this repository.
4-
5-
## What this is
6-
7-
A Java project template: Gradle (Kotlin DSL), Checkstyle, PMD, google-java-format (via Spotless), JaCoCo, SLF4J/Logback, and a unit/integration test split (`src/test` vs `src/int-test`). See `README.md` for the full command reference.
8-
9-
## Conventions to follow
10-
11-
- **Logging: SLF4J, never `System.out`/`System.err`.** Get a logger with `private static final Logger LOG = LoggerFactory.getLogger(ThisClass.class);` and use parameterized messages (`LOG.info("thing happened: {}", value)`), not string concatenation. PMD's `SystemPrintln` rule (bestpractices, unexcluded) will fail the build on raw console I/O in `src/main`.
12-
- **Formatting is not manual.** Don't hand-format Java files or argue with Checkstyle about whitespace/import order — run `./gradlew spotlessApply` and let google-java-format do it. Checkstyle and PMD are deliberately scoped to things the formatter doesn't cover (naming, imports, coding problems, bug patterns); they're not fighting the formatter.
13-
- **Unit vs integration tests are not interchangeable.** `src/test` (the `test` task) is for fast, isolated unit tests. `src/int-test` (the `intTest` task) is for broader/slower tests. Don't add integration-style tests under `src/test`, and don't assume `./gradlew test` alone exercises integration coverage — see the JaCoCo note below.
14-
- **The 80%-line / 70%-branch coverage gate (`jacocoTestCoverageVerification`) is intentionally wired to combined unit + integration execution data** (`executionData(tasks.test.get(), intTestTask.get())` in `build.gradle.kts`). If you add a new source set or test task, JaCoCo's default conventions won't pick it up automatically — you have to wire its exec data in explicitly, the same way, or coverage numbers will silently look wrong (lower than reality) without the gate failing to catch it, or vice versa.
15-
- **PR descriptions must list Jira story keys** per `.github/pull_request_template.md` — that's the org's convention (see the Trident Jira Project Management Playbook), not something to improvise away.
16-
17-
## Known gotchas / do-not-"fix"-without-checking
18-
19-
- **`googleJavaFormat("1.28.0")` is pinned deliberately, not stale.** Spotless 8.9.0's reflective glue adapter (`GoogleJavaFormatFormatterFunc`) breaks against newer google-java-format releases (1.37.0 reproducibly threw `InvocationTargetException` in testing here). If you bump Spotless, re-verify the gjf version still works before bumping it too — don't just grab "latest" for both.
20-
- **`gradle/gradle-daemon-jvm.properties` pins the Gradle daemon itself to JDK 25**, separately from the project's `java.toolchain` (also 25). This was necessary because an ambient JDK 27 on the dev machine caused flaky in-process formatter failures. Don't remove this file assuming the project toolchain setting alone is enough — they serve different purposes (daemon JVM vs. compile/run JVM).
21-
- **PMD's `classpath` is explicitly given the toolchain's `jrt-fs.jar`** (`build.gradle.kts`, near the PMD config) to stop it from guessing "current platform" JDK classes and printing a warning every run. If PMD warnings about aux classpath reappear after a Gradle/PMD version bump, check this block still resolves correctly rather than re-adding `PMD_JAVA_DISABLE_AUX_CLASSPATH_WARNINGS` workarounds (that env var doesn't reliably propagate into PMD's forked worker process anyway — verified in testing).
22-
- **`LoosePackageCoupling` and `GuardLogStatement` are deliberately excluded from PMD's design/bestpractices rules** (`config/pmd/ruleset.xml`) — the former needs explicit package config to be meaningful, the latter is largely redundant once logging is parameterized via SLF4J. Don't silently re-add them without updating the ruleset's comments explaining why they're off.
23-
24-
## Before considering a change "done"
25-
26-
Run `./gradlew check` (compiles, formats-checks, Checkstyle, PMD, unit + integration tests, coverage gate) clean before reporting work finished. CI (`.github/workflows/ci.yml`) runs the same tasks as separate matrix jobs so each shows up as its own PR check.
1+
# Project
2+
templateJavaProject — Java template
3+
Gradle (Kotlin DSL), Java 25 (see `gradle/gradle-daemon-jvm.properties`), JUnit 6, SLF4J/Logback
4+
5+
## Build Commands
6+
- Verify everything: `./gradlew check` (compile, format check, Checkstyle, PMD, unit + integration tests, coverage gate)
7+
- Test: `./gradlew test`
8+
- Integration test: `./gradlew intTest`
9+
- Format: `./gradlew spotlessApply`
10+
11+
## Package Structure
12+
com.example.app — application code (`src/main`)
13+
src/test — unit tests (JUnit 6), run by `test`
14+
src/int-test — integration tests, run by `intTest`, not part of `test`
15+
16+
## Key Conventions
17+
- Logging via SLF4J (`LoggerFactory`) — never `System.out`/`System.err`
18+
- Formatting via Spotless + google-java-format — run `spotlessApply`, don't hand-format
19+
- Coverage gate requires 80% line / 70% branch, combined across unit + integration tests
20+
- PRs must list Jira story keys per `.github/pull_request_template.md`

‎README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ A Java project template with Gradle (Kotlin DSL), Checkstyle, PMD, [google-java-
55
## Requirements
66

77
- The [Gradle Wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) (`./gradlew`) is checked in — you don't need Gradle installed locally.
8-
- No JDK needs to be pre-installed either: the project targets **Java 25** via a Gradle toolchain, and the `foojay-resolver-convention` plugin (`settings.gradle.kts`) will auto-download a matching JDK if one isn't already on your machine.
9-
- The Gradle **daemon** itself is also pinned to JDK 25, via `gradle/gradle-daemon-jvm.properties` (generated with `./gradlew updateDaemonJvm --jvm-version=25`). This keeps the build tooling (Spotless/google-java-format in particular) running on a JDK it's actually compatible with, regardless of whatever JDK happens to be on your `PATH`.
8+
- No JDK needs to be pre-installed either: the project targets **Java 25**, and the `foojay-resolver-convention` plugin (`settings.gradle.kts`) will auto-download a matching JDK if one isn't already on your machine.
9+
- The Java version is defined in exactly one place: `gradle/gradle-daemon-jvm.properties`. It pins the Gradle **daemon** itself (keeping build tooling like Spotless/google-java-format on a JDK it's actually compatible with, regardless of what's on your `PATH`), and `build.gradle.kts` reads that same file to set the project's `java.toolchain`. To bump the Java version, run `./gradlew updateDaemonJvm --jvm-version=<version>` — don't edit a version number directly in `build.gradle.kts`, there isn't one.
1010

1111
## Project layout
1212

‎build.gradle.kts‎

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ plugins {
33
jacoco
44
checkstyle
55
pmd
6-
id("com.diffplug.spotless") version "8.9.0"
6+
id("com.diffplug.spotless") version "8.10.4"
77
}
88

99
group = "com.example"
@@ -13,9 +13,20 @@ repositories {
1313
mavenCentral()
1414
}
1515

16+
val daemonJvmLanguageVersion =
17+
providers
18+
.fileContents(layout.projectDirectory.file("gradle/gradle-daemon-jvm.properties"))
19+
.asText
20+
.map { text ->
21+
val version =
22+
text.lineSequence().firstOrNull { it.startsWith("toolchainVersion=") }?.substringAfter("=")
23+
?: error("toolchainVersion not found in gradle/gradle-daemon-jvm.properties")
24+
JavaLanguageVersion.of(version)
25+
}
26+
1627
java {
1728
toolchain {
18-
languageVersion.set(JavaLanguageVersion.of(25))
29+
languageVersion.set(daemonJvmLanguageVersion)
1930
}
2031
}
2132

@@ -137,7 +148,7 @@ tasks.withType<Pmd>().configureEach {
137148
spotless {
138149
java {
139150
target("src/*/java/**/*.java")
140-
googleJavaFormat("1.28.0")
151+
googleJavaFormat("1.36.1")
141152
removeUnusedImports()
142153
trimTrailingWhitespace()
143154
endWithNewline()

0 commit comments

Comments
 (0)