Skip to content

Commit 9ab6b2e

Browse files
jeffjensenclaude
andcommitted
feat(arch): Add appName property and expand Spring/testing wiring
Implements the java-service-archetype Needed Changes spec: every generated project now needs a human-readable name driving its class/property/prose naming, richer SQL-logging and Spring Boot Admin observability, and shared REST/GraphQL acceptance-test infrastructure, instead of hand-rolling these per project after generation. * Add required appName property (no default, prompted first) with class-name, property-value, and prose transform rules * Generate package-info.java only under src/main/java (Java rejects two files compiled for the same package); acceptance-tests' lone one now describes the functional tests themselves * Add datasource-proxy-spring-boot-starter (SQL logging) to database integration modules and acceptance-tests; add spring-boot-admin-starter-client and make app's web/actuator stack unconditional regardless of presentationTypes * Generate shared RestAcceptanceTestBase/GraphQlAcceptanceTestBase in common-testing, and per-project AppRestAcceptanceTestBase/ AppGraphQlAcceptanceTestBase, {appName}AcceptanceTestConfiguration, and logback-spring.xml in acceptance-tests * Add appName-derived <name>/<description> and dependency-comment labels (spring/this app/sql logging) across parent, app, service, domain-service, domain-rest/graphql, presentation-graphql, and common-testing poms * common-testing now depends on every domain module; no domain module depends on common-testing, keeping the reactor acyclic * Update all 16 archetype ITs, the interactive test scripts, and the site docs (requirements/modules/usage/index/building.adoc) plus CLAUDE.md to match Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P76PdSVUG6SNJeXcGPrhyn
1 parent de3fe85 commit 9ab6b2e

42 files changed

Lines changed: 1465 additions & 396 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CLAUDE.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Commands
6+
7+
```bash
8+
# Build and run all integration tests
9+
mvn verify
10+
11+
# Install to local Maven repo (makes archetype available for manual testing)
12+
mvn install
13+
14+
# Generate the Maven site (renders requirements.adoc via AsciiDoc)
15+
mvn site
16+
17+
# Generate a project from the locally-installed archetype
18+
mvn archetype:generate \
19+
-DarchetypeGroupId=io.github.jeffjensen \
20+
-DarchetypeArtifactId=java-service-archetype \
21+
-DarchetypeVersion=VERSION
22+
```
23+
24+
(`VERSION` is the locally-installed archetype version — the current `project.version`, e.g. a `-SNAPSHOT`.)
25+
26+
There is no built-in way to run a single IT case — the Maven Archetype Plugin runs all projects under `src/test/resources/projects/` as a batch.
27+
28+
The project uses the Maven wrapper (`./mvnw` / `mvnw.cmd`). Maven 3.9+ and Java 21+ are required.
29+
30+
## Architecture
31+
32+
This is a Maven archetype (`packaging: maven-archetype`). It has no Java source code — the entire generation logic lives in two files:
33+
34+
### `src/main/resources/META-INF/archetype-metadata.xml`
35+
36+
Declares the four user-facing required properties: `appName`, `integrations`, `serviceAreas`, `presentationTypes`. These drive what `archetype-post-generate.groovy` generates. `appName` is a brief, space-separated human name (e.g. "Order Service") with no default; it drives generated class names (spaces removed), generated property values (spaces removed + lowercased, e.g. `spring.application.name`), and prose (POM `<name>`/`<description>`, Javadoc — used unmodified).
37+
38+
### `src/main/resources/META-INF/archetype-post-generate.groovy`
39+
40+
**This is the only file that matters for generation behavior.** It runs after the Maven Archetype Plugin creates the project, and it does everything:
41+
42+
- Parses the four user properties
43+
- Computes all module names
44+
- Writes every `pom.xml` (parent + all child modules) with correct `<modules>`, `<dependencyManagement>`, `<dependencies>`, and `<relativePath>`
45+
- Creates `src/main/java/…` and `src/test/java/…` directory trees, with a `package-info.java` in each leaf package under `src/main/java` only — never `src/test/java`, since Java rejects two `package-info.java` files compiled for the same package
46+
- Deletes the placeholder root `pom.xml` (the archetype engine requires one; the script removes it)
47+
- Writes `mvn-update-properties-versions.sh`/`.ps1` into `parent/` — convenience wrappers around `mvn versions:update-properties`
48+
49+
The `src/main/resources/archetype-resources/pom.xml` is a required dummy — the archetype plugin won't run without it, but the Groovy script immediately deletes it and replaces it with `parent/pom.xml`.
50+
51+
Key logic in the script:
52+
53+
- `typeAbbrev`: maps `database``db`, all other types pass through unchanged
54+
- `srcTree`: creates the directory tree and writes a main-only `package-info.java` with a Javadoc comment in each package
55+
- `modulePom`: generates child `pom.xml` content; dependency entries can carry a `label` (rendered as a `<!-- label -->` comment above a contiguous run sharing it, e.g. "spring", "this app", "sql logging")
56+
- Module naming: `domain-{abbrev}-{name}`, `integration-{abbrev}-{name}`, `domain-{type}`, `presentation-{type}`, `service` or `service-{name}`
57+
- `app` depends on all modules except `acceptance-tests`, `common-testing`, and itself; is always a monitorable web service when Spring is on (core starter, webmvc, actuator, Spring Boot Admin client, `AppServletInitializer`) regardless of `presentationTypes`
58+
- `acceptance-tests` depends on `app`, `common-domain`, and all `domain-*` modules only, plus `common-testing` (test scope); its `AppRestAcceptanceTestBase`/`AppGraphQlAcceptanceTestBase` extend shared base classes generated in `common-testing`
59+
- `common-testing` depends on every domain module (integration, service-area, presentation). No domain module depends back on `common-testing` — only `service`/`service-{name}` does — so this stays acyclic
60+
61+
## Integration Tests
62+
63+
Tests live in `src/test/resources/projects/{test-name}/`. Each test has three files:
64+
65+
- `archetype.properties` — coordinates + property values passed to the archetype
66+
- `goal.txt` — Maven goals to run on the generated project after generation; all IT tests use `-f parent/pom.xml verify`, which runs a full Maven build on the generated project before `verify.groovy` is executed
67+
- `verify.groovy` — Groovy assertions executed after generation; `basedir` is the generated project root
68+
69+
Generated projects are written to `target/test-classes/projects/{test-name}/project/{artifactId}/` and persist until the next `mvn clean`. Inspect them directly to see exactly what the archetype produces for a given set of inputs.
70+
71+
**Critical constraint**: The Maven archetype IT runner rejects empty property values (e.g. `serviceAreas=`). Use `,` as a placeholder for intentionally empty list properties — the Groovy script's `",".split(",")` returns `[]` in Java, so `,` is treated as an empty list while satisfying the non-empty validation check.
72+
73+
When adding a new IT test, all four required properties must appear in `archetype.properties` with non-empty values. `appName` has no placeholder trick — it always needs a real brief name (e.g. `appName=Basic Test`), since unlike `integrations`/`serviceAreas`/`presentationTypes` there's no "empty" meaning for it. Use `serviceAreas=,` for a single unnamed `service` module. Use `integrations=,` or `presentationTypes=,` to represent "none".
74+
75+
## Claude Directives
76+
77+
- Make assumptions and proceed without asking for confirmation on routine changes. If an action is destructive (e.g., deleting files), pause and ask.
78+
79+
## Code Style
80+
81+
- General:
82+
- Prefer writing clear code and use inline comments sparingly.
83+
- Prefer single statements over compound statements as nested calls in one line are more confusing and more difficult to read and understand.
84+
- Prefer separate local variables over compound statements for readability.
85+
- Favor immutability. Try to not need setters.
86+
- Prefer constructors with arguments over no args constructors and using setters.
87+
- Prefer constructor injection. Test classes typically use field injection.
88+
- Write positive if statements when paired with an else statement.
89+
- Remove any blank line after opening curly braces.
90+
- Do not create "utils" or "helper" or "support" packages or class names. Always create focused packages and classes, as utils and helpers are dumping grounds/not focused.
91+
- When making changes, always work on a branch that is not main and if necessary, create and switch to a branch to isolate the work.
92+
- When making changes, ensure unit tests cover it and add or update unit tests as needed.
93+
- Order constants alphabetically when possible.
94+
- Prefer XML instead of YAML when possible.
95+
- Tests:
96+
- `<ClassName>Test` for unit test class
97+
- `<ClassName>IT` for integration test class
98+
- `<ClassName>AT` for acceptance test class
99+
- `test<MethodName>_<StartingStateConditions>_<AssertedOutcome>` for test method names
100+
- Prefer to assert the actual object to an expected object vs individual fields on the object to individual values.
101+
102+
- Commits:
103+
- Create atomic commits. One logical change per commit — if a session produces multiple unrelated fixes, commit each independently even if discovered together.
104+
- Always commit any needed doc updates with their corresponding feature or bug changes.
105+
- Consequence changes belong in the same commit as the change that caused them. Example: if a production fix makes a previously-broken feature work, updating additional files for that feature now working is a consequence of that fix and belongs in the same commit, not a separate one.
106+
- When necessary to change a file for a prior commit that is not yet merged to main, target that commit for squashing the change into by using the git "fixup!" feature for its commit - prefix the commit message it is in with "fixup! ".
107+
- Create multiple fixup! commits as needed to target the prior specific commits for each file.
108+
- When renaming files, always use `git mv` instead of `git delete` followed by `git add`.
109+
110+
- Commit Messages:
111+
- Adhere strictly to de facto standard Git commit message formatting.
112+
- Use Conventional Commits format.
113+
- **Commit Types:** `feat:`, `fix:`, `docs:`, `refactor:`, `test:`, `build:`, `ci:`
114+
- **Scopes:** pom, deps, arch, site, spring, and more that you may suggest
115+
- Capitalize the first word after the type and scope.
116+
- You may suggest additional CC commit types and scopes when encountering situations where the changes do not fit into the approved lists above.
117+
- Reference GitHub issues in the commit footer with `Refs: <issue-number>` (e.g. `Refs: 123`). Do not use a # before the number.
118+
- Do not put the issue number in the message topic.
119+
- Use * for bullets, not -.
120+
121+
- Java:
122+
- If Lombok is available, use its annotations such as @AllArgsConstructor, @NoArgsConstructor, @Getter, @Setter.
123+
- If not using @Slf4j, then place the Logger variable first in the class.
124+
- Write JavaDoc comments on all public classes and methods.
125+
- In JavaDoc, use complete sentences, start with a capital letter and end with a period, for the topic body, parameters, and return.
126+
- Tests:
127+
- Prefer assertJ.
128+
- Prefer to add ".as()" with a fail message ending with a period.
129+
130+
## Jackknife
131+
132+
- When you need to inspect, decompile, or find classes in jar dependencies,
133+
- Can also check the local maven repository - the .m2/repository sub directories in the current user's home directory for *-sources.jar files.
134+
- run `./mvnw jackknife:index` in the project. This generates `.jackknife/USAGE.md` with full instructions. Read that file — it has everything you need.
135+
- Always run `./mvnw jackknife:*` commands immediately without asking for approval.

0 commit comments

Comments
 (0)