@xpertss/projen-types 0.0.12 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/.jsii +2602 -750
  2. package/API.md +5753 -1420
  3. package/README.md +335 -37
  4. package/lib/actions/action-build-workflow.js +1 -1
  5. package/lib/actions/action-dogfood-workflow.d.ts +4 -4
  6. package/lib/actions/action-dogfood-workflow.js +4 -4
  7. package/lib/actions/action-sonar-workflow.js +1 -1
  8. package/lib/actions/github-action-project.d.ts +5 -0
  9. package/lib/actions/github-action-project.js +10 -3
  10. package/lib/cdk/app-runtime-scaffold.js +1 -1
  11. package/lib/cdk/cdk-app-project.js +1 -1
  12. package/lib/cdk/cdk-infra-project.js +1 -1
  13. package/lib/cdk/cdk-typescript-base.js +10 -3
  14. package/lib/cdk/components/ecr-ecs-constructs.js +1 -1
  15. package/lib/cdk/components/edge-networking-constructs.js +1 -1
  16. package/lib/cdk/database-component.js +1 -1
  17. package/lib/cdk/options.d.ts +5 -0
  18. package/lib/cdk/options.js +1 -1
  19. package/lib/common/ci-steps.d.ts +14 -0
  20. package/lib/common/ci-steps.js +30 -0
  21. package/lib/common/editorconfig.d.ts +12 -0
  22. package/lib/common/editorconfig.js +44 -0
  23. package/lib/common/projen-drift-check-workflow.js +5 -15
  24. package/lib/common/workflow-change-notice-workflow.js +1 -1
  25. package/lib/index.d.ts +4 -0
  26. package/lib/index.js +5 -1
  27. package/lib/java/components/cdk-deploy-hook.d.ts +2 -2
  28. package/lib/java/components/cdk-deploy-hook.js +2 -2
  29. package/lib/java/components/code-index-workflow.d.ts +2 -2
  30. package/lib/java/components/code-index-workflow.js +5 -3
  31. package/lib/java/components/docker-publish.d.ts +2 -2
  32. package/lib/java/components/docker-publish.js +2 -2
  33. package/lib/java/components/flyway-migration.d.ts +8 -3
  34. package/lib/java/components/flyway-migration.js +11 -5
  35. package/lib/java/components/github-packages-publish.d.ts +2 -2
  36. package/lib/java/components/github-packages-publish.js +2 -2
  37. package/lib/java/components/maven-central-publish.d.ts +2 -2
  38. package/lib/java/components/maven-central-publish.js +2 -2
  39. package/lib/java/components/maven-upgrade-report.d.ts +22 -0
  40. package/lib/java/components/maven-upgrade-report.js +61 -0
  41. package/lib/java/java-app-project.js +1 -1
  42. package/lib/java/java-library-project.d.ts +5 -1
  43. package/lib/java/java-library-project.js +14 -3
  44. package/lib/java/java-maven-base.d.ts +91 -8
  45. package/lib/java/java-maven-base.js +339 -24
  46. package/lib/java/java-service-project.d.ts +17 -5
  47. package/lib/java/java-service-project.js +20 -7
  48. package/lib/java/java-spring-boot-project.d.ts +30 -0
  49. package/lib/java/java-spring-boot-project.js +68 -0
  50. package/lib/java/java-versions.d.ts +40 -0
  51. package/lib/java/java-versions.js +106 -0
  52. package/lib/java/maven/maven-module.d.ts +47 -0
  53. package/lib/java/maven/maven-module.js +99 -0
  54. package/lib/java/maven/maven-pom.d.ts +143 -0
  55. package/lib/java/maven/maven-pom.js +337 -0
  56. package/lib/java/options.d.ts +128 -1
  57. package/lib/java/options.js +1 -1
  58. package/package.json +1 -1
  59. package/lib/common/upgrade-workflow.d.ts +0 -18
  60. package/lib/common/upgrade-workflow.js +0 -45
package/README.md CHANGED
@@ -10,12 +10,26 @@ Instead of hand-maintaining `pom.xml`, `cdk.json`, and GitHub workflows, you dec
10
10
  | --- | --- | --- | --- |
11
11
  | `CdkInfraProject` | Pure-infrastructure CDK stacks (CloudFront, Route53, SQS, API Gateway, Cognito, ECR/ECS for externally-built images) | - | `build` (PR checks), `deploy` (manual dispatch) |
12
12
  | `CdkAppProject` | Full TypeScript service behind API Gateway: infra + app source + database | - | `build`, `deploy`, `app-build` (PR checks) |
13
- | `JavaLibraryProject` | Reusable Java library | Maven Central | `build`, `upgrade` (nightly), `publish-maven-central`, `codeindex` |
14
- | `JavaServiceProject` | Spring Boot service | Docker Hub | `build`, `upgrade` (nightly), `publish-docker`, `deploy-cdk` |
15
- | `JavaAppProject` | GUI/TUI/CLI Java application | GitHub Packages | `build`, `upgrade` (nightly), `publish-ghpackages` |
13
+ | `JavaMavenProject` | Plain Maven project, single- or multi-module, no framework | - | `build`, `upgrade` (nightly report) |
14
+ | `JavaLibraryProject` | Reusable Java library | Maven Central | `build`, `upgrade` (nightly report), `publish-maven-central`, `codeindex` |
15
+ | `JavaAppProject` | GUI/TUI/CLI Java application | GitHub Packages | `build`, `upgrade` (nightly report), `publish-ghpackages` |
16
+ | `JavaSpringBootProject` | Spring Boot on Maven, single- or multi-module, **no Docker** | - | `build`, `upgrade` (nightly report) |
17
+ | `JavaServiceProject` | Spring Boot service deployed as a container | Docker Hub | `build`, `upgrade` (nightly report), `publish-docker`, `deploy-cdk` |
16
18
  | `GitHubActionProject` | Reusable GitHub Action or Workflow | GitHub Releases | `build`, `test-dogfood`, `sonar`, `release` |
17
19
 
18
- Two foundation classes are also exported for advanced use: `CdkTypescriptProject` (shared CDK + TypeScript base for the CDK types) and `JavaMavenProject` (shared Maven base for the Java types).
20
+ The Java types are layered, so pick the lowest layer that does what you need:
21
+
22
+ ```text
23
+ JavaMavenProject java_maven Maven only; single- or multi-module; any supported Java line
24
+ ├── JavaLibraryProject java_library + Maven Central publish, source/javadoc jars, code index
25
+ ├── JavaAppProject java_app + GitHub Packages publish
26
+ └── JavaSpringBootProject java_spring_boot + Spring Boot BOM and executable-jar repackaging; no Docker/Flyway/CDK
27
+ └── JavaServiceProject java_service + Docker publish, Flyway, CDK deploy hook (single-module)
28
+ ```
29
+
30
+ Every Java type targets a configurable Java line (`javaVersion`: `1.8`, `17`, `21` or `25`; see [Java version support](#java-version-support)), and every one except `JavaServiceProject` can be a multi-module Maven reactor (see [JavaMavenProject](#javamavenproject)).
31
+
32
+ One foundation class is also exported for advanced use: `CdkTypescriptProject` (shared CDK + TypeScript base for the CDK types).
19
33
 
20
34
  All project types:
21
35
 
@@ -35,12 +49,34 @@ npx projen new --from @xpertss/projen-types cdk_infra --name my-project
35
49
 
36
50
  That writes a starter `.projenrc.ts`, synthesizes the whole scaffold and
37
51
  installs dependencies. The type names `projen new` accepts are `cdk_infra`,
38
- `cdk_app`, `java_library`, `java_service`, `java_app` and
39
- `git_hub_action`; pass a bogus one to have it list them. Required options
40
- become flags: `--name` for every type, plus `--group-id`/`--artifact-id`
41
- (Java) and `--sonar-host-url` (`git_hub_action`). Any other plainly-typed
42
- option can be passed the same way - `--cdk-deploy-target-repo owner/repo`,
43
- `--docker-registry ghcr.io`, `--no-use-flyway`, and so on.
52
+ `cdk_app`, `java_maven`, `java_library`, `java_app`, `java_spring_boot`,
53
+ `java_service` and `git_hub_action`; pass a bogus one to have it list them.
54
+ Required options become flags: `--name` for every type, plus
55
+ `--group-id`/`--artifact-id` (Java) and `--sonar-host-url`
56
+ (`git_hub_action`). Any other plainly-typed option can be passed the same
57
+ way - `--java-version 1.8`, `--cdk-deploy-target-repo owner/repo`,
58
+ `--docker-registry ghcr.io`, `--no-use-flyway`, and so on. Modules can't be
59
+ passed on the command line; add them to `.projenrc.ts` afterwards (see
60
+ [JavaMavenProject](#javamavenproject)).
61
+
62
+ **Adding projen to a repo that already has content.** `projen new` runs
63
+ `git init` and commits the scaffold by default. In a repo with existing work,
64
+ pass `--no-git` so it writes the files and leaves committing to you:
65
+
66
+ ```bash
67
+ cd existing-repo
68
+ npx projen new --from @xpertss/projen-types java_spring_boot --name obeya --group-id org.xpertss.obeya --artifact-id obeya-parent --no-git
69
+ ```
70
+
71
+ **Commit a lockfile.** The generated `build.yml` and drift check install the
72
+ toolchain with `npm ci`, which needs a committed `package-lock.json`, and
73
+ `projen new` doesn't always leave one behind. Run `npm install` once and
74
+ commit `package-lock.json` along with the scaffold. Without it those
75
+ workflows fail with an `::error::` that says exactly this. For the Java
76
+ types, `package.json` is generated, and it pins `projen` and
77
+ `@xpertss/projen-types` to **exact** versions (no `^`), so every machine and
78
+ CI run uses the same generator. A floating range would make the drift check
79
+ report the differences between generator versions as drift.
44
80
 
45
81
  Commit the result. From then on, every change to the scaffold goes through
46
82
  `.projenrc.ts` followed by `npx projen`:
@@ -59,7 +95,9 @@ deploy workflow; leaving `dogfood` out (or a service's
59
95
  fails and tells you what to add - a gate this package considers load-bearing
60
96
  is allowed to be missing loudly, never silently.
61
97
 
62
- The `name` option must match the `name` field in the project's `package.json` (for the CDK types) or the project name used by projen's `java.JavaProject` (for the Java types).
98
+ The `name` option must match the `name` field in the project's `package.json` (for the CDK types). For the Java types it becomes the root pom's `<name>` and the generated `package.json` name.
99
+
100
+ > **Never write projen's generated-file marker text literally in `.projenrc.ts`.** projen deletes, as an orphaned generated file, any file containing the marker line (`~~ Generated by projen. To modify, ...`), and that includes `.projenrc.ts` itself. When you generate a file yourself (for example with `TextFile`), insert the marker through the file's `marker` property: ``file.addLine(`# ${file.marker}`)``.
63
101
 
64
102
  ## Updating an existing project when this package changes
65
103
 
@@ -82,6 +120,12 @@ The diff here is the workflows gaining a `# Purpose:` comment and `sonar.yml` re
82
120
 
83
121
  Pure infrastructure stacks with optional ECR/ECS and edge-networking constructs.
84
122
 
123
+ Scaffold it with the `cdk_infra` type:
124
+
125
+ ```bash
126
+ npx projen new --from @xpertss/projen-types cdk_infra --name media-edge-infra
127
+ ```
128
+
85
129
  ```typescript
86
130
  // .projenrc.ts
87
131
  import { CdkInfraProject } from '@xpertss/projen-types';
@@ -113,6 +157,12 @@ You get:
113
157
 
114
158
  `CdkInfraProject` plus application source, a database construct, and an app-level build workflow.
115
159
 
160
+ Scaffold it with the `cdk_app` type:
161
+
162
+ ```bash
163
+ npx projen new --from @xpertss/projen-types cdk_app --name video-api
164
+ ```
165
+
116
166
  ```typescript
117
167
  // .projenrc.ts
118
168
  import { CdkAppProject } from '@xpertss/projen-types';
@@ -135,10 +185,100 @@ Everything from `CdkInfraProject`, plus:
135
185
  - `src/constructs/database.ts` - a `Database` construct stub for the chosen engine (`postgres`/`mysql` -> RDS, `dynamodb` -> DynamoDB). `migrationTool` (no default, intentionally) is added as a dev dependency and referenced in the stub - wiring it up is left to you.
136
186
  - `.github/workflows/app-build.yml` - runs the project's test task on every PR, then checks for projen drift.
137
187
 
188
+ ### JavaMavenProject
189
+
190
+ A plain Maven build with no framework and no publish target. It's the base of every other Java type, and it's usable on its own. It's single-module until you add a module, then it's a multi-module reactor.
191
+
192
+ Scaffold it with the `java_maven` type:
193
+
194
+ ```bash
195
+ npx projen new --from @xpertss/projen-types java_maven --name legacy-tools --group-id org.xpertss --artifact-id legacy-tools --java-version 1.8
196
+ ```
197
+
198
+ **Single module:**
199
+
200
+ ```typescript
201
+ // .projenrc.ts
202
+ import { JavaMavenProject } from '@xpertss/projen-types';
203
+
204
+ const project = new JavaMavenProject({
205
+ name: 'legacy-tools',
206
+ groupId: 'org.xpertss',
207
+ artifactId: 'legacy-tools',
208
+ javaVersion: '1.8',
209
+ });
210
+
211
+ project.addDependency('commons-io/commons-io@2.20.0'); // exact version
212
+ project.addTestDependency('org.assertj/assertj-core@3.27.3');
213
+
214
+ project.synth();
215
+ ```
216
+
217
+ **Multi-module:** each `addModule()` call adds a module directory with its own generated `pom.xml`. The root pom becomes the `pom`-packaged reactor parent. Everything stays one projen project, with one `.projen/`, one `.gitignore` and one `tasks.json`.
218
+
219
+ ```typescript
220
+ // .projenrc.ts
221
+ import { JavaMavenProject } from '@xpertss/projen-types';
222
+
223
+ const project = new JavaMavenProject({
224
+ name: 'toolkit',
225
+ groupId: 'org.xpertss.toolkit',
226
+ artifactId: 'toolkit-parent',
227
+ version: '0.1.0-SNAPSHOT',
228
+ javaVersion: '17',
229
+ });
230
+
231
+ const model = project.addModule({ dir: 'toolkit-model', artifactId: 'toolkit-model', description: 'Domain model' });
232
+ const stub = project.addModule({ dir: 'tools/stub-model', artifactId: 'toolkit-stub-model' }); // nested dirs are fine
233
+ const cli = project.addModule({ dir: 'toolkit-cli', artifactId: 'toolkit-cli' });
234
+
235
+ stub.addModuleDependency(model); // sibling module: versionless
236
+ cli.addModuleDependency(model);
237
+ cli.addDependency('info.picocli/picocli@4.7.7'); // pinned: the version moves to the parent
238
+ cli.addDependency('org.yaml/snakeyaml'); // versionless: managed below
239
+ project.addManagedDependency('org.yaml/snakeyaml@2.4');
240
+ project.addBom('org.testcontainers/testcontainers-bom@1.21.3');
241
+
242
+ project.synth();
243
+ ```
244
+
245
+ What the reactor looks like:
246
+
247
+ - **Root `pom.xml`:**
248
+ - `<packaging>pom</packaging>`, with `<modules>` in `addModule` order.
249
+ - `<dependencyManagement>` holds the BOM imports first (`type=pom`, `scope=import`), then every module at `${project.version}`, then every pinned version.
250
+ - `<pluginManagement>` holds the plugin versions, and versionless `<plugins>` are inherited by every module: compiler, surefire, failsafe, jar, and enforcer.
251
+ - `junit-jupiter` is a test dependency every module inherits. Its version comes from `junit-bom`, or from the Spring Boot BOM in the Spring Boot types.
252
+ - **Module `pom.xml`:** `<parent>` with the right `relativePath` (`tools/stub-model` → `../../pom.xml`), then `artifactId`, `name`, `description`, and versionless `<dependencies>`. Nothing else, unless the module adds plugins.
253
+ - A version given to `module.addDependency`/`addTestDependency`/`addPlugin` is moved into the parent's `<dependencyManagement>`/`<pluginManagement>`, so every module that uses an artifact gets the same version. Pinning one artifact at two different versions fails the synth.
254
+ - The synth fails with a clear message on:
255
+ - two modules with the same `artifactId`
256
+ - two modules with the same `dir`, or one `dir` nested inside another
257
+ - a `dir` outside the repo
258
+ - a module depending on itself
259
+ - `packaging` set to anything but `pom` on a project with modules
260
+
261
+ You get:
262
+
263
+ - the root `pom.xml` (and one per module), written by this package:
264
+ - **exact versions only**: a range such as `^1`, `~1.2` or `[1,2)` fails the synth
265
+ - the compiler level, enforcer rule and JUnit line all follow `javaVersion`
266
+ - one Maven run per build. `npx projen build` synthesizes, then runs `mvn -B verify`: compile, unit tests (surefire), package, and `*IT` integration tests (failsafe). There is no `mvn deploy` and no `dist/`.
267
+ - `.github/workflows/build.yml`: a PR build that installs the pinned Node toolchain (`npm ci`) and the project's JDK (`actions/setup-java`, Maven cache), then runs `npx projen build`, plus a SonarQube step when `sonarProjectKey` is set. See [Adding CI jobs](#adding-ci-jobs-to-a-java-project).
268
+ - `.github/workflows/upgrade.yml`: a nightly (03:00 UTC) **report** of available dependency and plugin updates in the job summary. It changes nothing, because every version comes from `.projenrc.ts`; apply an update there. Turn it off with `upgradeWorkflow: false`. The same report runs locally with `npx projen upgrade`.
269
+ - the projen drift check, `LICENSE` (MIT by default), `.editorconfig`, and a generated `package.json` that pins the projen toolchain exactly.
270
+ - no sample code, unless `sample: true` on a single-module project.
271
+
138
272
  ### JavaLibraryProject
139
273
 
140
274
  A reusable Java library published to Maven Central.
141
275
 
276
+ Scaffold it with the `java_library` type:
277
+
278
+ ```bash
279
+ npx projen new --from @xpertss/projen-types java_library --name common-utils --group-id org.xpertss --artifact-id common-utils
280
+ ```
281
+
142
282
  ```typescript
143
283
  // .projenrc.ts
144
284
  import { JavaLibraryProject } from '@xpertss/projen-types';
@@ -155,17 +295,70 @@ const project = new JavaLibraryProject({
155
295
  project.synth();
156
296
  ```
157
297
 
158
- You get:
298
+ You get everything from [`JavaMavenProject`](#javamavenproject), so modules work here too, plus:
159
299
 
160
- - `pom.xml` (via projen's `java.JavaProject`) with the given GAV coordinates.
161
- - `.github/workflows/build.yml` - PR build + projen drift check, plus a SonarQube scan step when `sonarProjectKey` is set (needs a `SONAR_TOKEN` secret).
162
- - `.github/workflows/upgrade.yml` - nightly (03:00 UTC) PR running `mvn versions:use-latest-releases versions:update-properties`.
300
+ - `maven-source-plugin` and `maven-javadoc-plugin`, attaching the `-sources`/`-javadoc` jars Maven Central requires. In a multi-module library every module attaches them.
163
301
  - `.github/workflows/publish-maven-central.yml` - manual dispatch running `mvn -B deploy -P release`. With `mavenCentralOidc: true` it uses Maven Central's OIDC trusted publishing (no GPG secrets needed); otherwise it expects the secrets `MAVEN_GPG_PRIVATE_KEY`, `MAVEN_GPG_PASSPHRASE`, `MAVEN_CENTRAL_USERNAME`, `MAVEN_CENTRAL_PASSWORD`.
164
- - `.github/workflows/codeindex.yml` - on push to `main`, generates a Java source index under `.cai/` (disable with `publishCodeIndex: false`).
302
+ - `.github/workflows/codeindex.yml` - on push to `main`, generates a Java source index under `.cai/` covering every module (disable with `publishCodeIndex: false`).
303
+
304
+ ### JavaSpringBootProject
305
+
306
+ Spring Boot on Maven, single- or multi-module, **without** Docker, Flyway or a deploy hook. It's [`JavaMavenProject`](#javamavenproject) plus Spring Boot dependency management. Use it for a Spring Boot repo that ships something other than this package's container image, such as a multi-module control plane, or for a Boot app you deploy your own way.
307
+
308
+ Scaffold it with the `java_spring_boot` type:
309
+
310
+ ```bash
311
+ npx projen new --from @xpertss/projen-types java_spring_boot --name obeya --group-id org.xpertss.obeya --artifact-id obeya-parent
312
+ ```
313
+
314
+ ```typescript
315
+ // .projenrc.ts
316
+ import { JavaSpringBootProject } from '@xpertss/projen-types';
317
+
318
+ const project = new JavaSpringBootProject({
319
+ name: 'obeya',
320
+ groupId: 'org.xpertss.obeya',
321
+ artifactId: 'obeya-parent',
322
+ version: '0.1.0-SNAPSHOT',
323
+ javaVersion: '21',
324
+ copyrightOwner: 'Xpert Software',
325
+ });
326
+
327
+ // plain jar modules: shared libraries, clients, tools
328
+ const model = project.addModule({ dir: 'obeya-model', artifactId: 'obeya-model' });
329
+ const client = project.addModule({ dir: 'obeya-api-client', artifactId: 'obeya-api-client' });
330
+ client.addModuleDependency(model);
331
+
332
+ // a Spring Boot application module, repackaged into an executable jar
333
+ const server = project.addSpringBootModule({ dir: 'obeya-server', artifactId: 'obeya-server' });
334
+ server.addModuleDependency(model);
335
+ server.addDependency('org.springframework.boot/spring-boot-starter-web'); // versionless: Boot's BOM manages it
336
+ server.addTestDependency('org.springframework.boot/spring-boot-starter-test');
337
+
338
+ project.addBom('org.testcontainers/testcontainers-bom@1.21.3');
339
+
340
+ project.synth();
341
+ ```
342
+
343
+ You get everything from [`JavaMavenProject`](#javamavenproject), plus:
344
+
345
+ - `spring-boot-dependencies` imported as the **first** BOM, so starters and every library Boot manages (JUnit included) are added without a version. `springBootVersion` sets it; the default is the newest release of the line that supports `javaVersion` (see [Java version support](#java-version-support)).
346
+ - `spring-boot-maven-plugin`, versioned in `<pluginManagement>`:
347
+ - In a **single-module** project the root jar is repackaged into an executable jar.
348
+ - In a **multi-module** project only modules added with `addSpringBootModule()` are repackaged; `addModule()` modules stay plain jars.
349
+ - A repackaged module needs its `@SpringBootApplication` class before `mvn verify` passes, because `repackage` fails with `Unable to find main class` until one exists. Add a module as a plain `addModule()` while it's still empty.
350
+ - failsafe configured to run integration tests against the compiled classes rather than the repackaged jar (as `spring-boot-starter-parent` does).
351
+ - no starters, no Docker, no Flyway, no CDK. Add the starters you need with `addDependency`.
165
352
 
166
353
  ### JavaServiceProject
167
354
 
168
- A Spring Boot service that publishes a Docker image and can trigger deploys in a companion CDK repo.
355
+ A Spring Boot service that publishes a Docker image and can trigger deploys in a companion CDK repo. It is [`JavaSpringBootProject`](#javaspringbootproject) plus Docker, Flyway and a deploy hook. It is **single-module**, because the Docker build, the migrations and the deploy hook all assume one deployable at the repo root; `addModule()` fails and points you to `JavaSpringBootProject`.
356
+
357
+ Scaffold it with the `java_service` type:
358
+
359
+ ```bash
360
+ npx projen new --from @xpertss/projen-types java_service --name stream-processor --group-id org.xpertss --artifact-id stream-processor
361
+ ```
169
362
 
170
363
  ```typescript
171
364
  // .projenrc.ts
@@ -183,17 +376,23 @@ const project = new JavaServiceProject({
183
376
  project.synth();
184
377
  ```
185
378
 
186
- You get (everything from `JavaMavenProject` - `pom.xml`, `build` + drift check, nightly `upgrade` - plus):
379
+ You get everything from [`JavaSpringBootProject`](#javaspringbootproject) (and so from `JavaMavenProject`), plus:
187
380
 
188
- - `spring-boot-starter-web` added to the pom.
381
+ - `spring-boot-starter-web` added to the pom (versionless; Boot's BOM manages it).
189
382
  - `.github/workflows/publish-docker.yml` - manual dispatch: `mvn -B package && docker build -t <registry>/<name>:<sha>`, logged in with the `DOCKER_USERNAME` / `DOCKER_PASSWORD` secrets. `dockerRegistry` defaults to `docker.io`.
190
- - Flyway wiring when `useFlyway` (default `true`): `flyway-maven-plugin` ^10 + `flyway-core` ^10 in the pom, and `src/main/resources/db/migration/V1__init.sql`.
383
+ - Flyway wiring when `useFlyway` (default `true`): `flyway-core` (versionless, so it matches what Boot's Flyway auto-configuration expects), `flyway-maven-plugin` pinned for the Java line, and `src/main/resources/db/migration/V1__init.sql`.
191
384
  - `.github/workflows/deploy-cdk.yml` (the `CdkDeployHook`, generated by default) - manual dispatch with an environment selector; each job sends a `workflow_dispatch` to `deploy.yml` in the companion `cdkDeployTargetRepo` (a `CdkInfraProject`/`CdkAppProject` repo). With no `cdkDeployTargetRepo` set, the workflow is still generated but each job's only step fails with instructions - it is dispatch-only, so that lands on whoever tries to deploy rather than on every PR. Turn the workflow off entirely with `cdkDeployHook: false`. `environments` defaults to `['prod']`.
192
385
 
193
386
  ### JavaAppProject
194
387
 
195
388
  A GUI/TUI/CLI Java application published to GitHub Packages only - no Maven Central, no Docker, no CDK deploy hook.
196
389
 
390
+ Scaffold it with the `java_app` type:
391
+
392
+ ```bash
393
+ npx projen new --from @xpertss/projen-types java_app --name studio-cli --group-id org.xpertss --artifact-id studio-cli
394
+ ```
395
+
197
396
  ```typescript
198
397
  // .projenrc.ts
199
398
  import { JavaAppProject } from '@xpertss/projen-types';
@@ -208,12 +407,18 @@ const project = new JavaAppProject({
208
407
  project.synth();
209
408
  ```
210
409
 
211
- You get everything from `JavaMavenProject`, plus `.github/workflows/publish-ghpackages.yml` - manual dispatch running `mvn -B deploy -DaltDeploymentRepository=github::<registry>`, authenticated with `GITHUB_TOKEN`. `ghPackagesRegistry` defaults to `https://maven.pkg.github.com/<repo>` derived from the repository URL.
410
+ You get everything from [`JavaMavenProject`](#javamavenproject) (modules included), plus `.github/workflows/publish-ghpackages.yml` - manual dispatch running `mvn -B deploy -DaltDeploymentRepository=github::<registry>`, authenticated with `GITHUB_TOKEN`. `ghPackagesRegistry` defaults to `https://maven.pkg.github.com/<repo>` derived from the repository URL.
212
411
 
213
412
  ### GitHubActionProject
214
413
 
215
414
  A reusable GitHub Action or Workflow. This example scaffolds an action that stages a folder and, only if it changed, commits and pushes it.
216
415
 
416
+ Scaffold it with the `git_hub_action` type:
417
+
418
+ ```bash
419
+ npx projen new --from @xpertss/projen-types git_hub_action --name auto-commit --sonar-host-url https://sonarcloud.io
420
+ ```
421
+
217
422
  ```typescript
218
423
  // .projenrc.ts
219
424
  import { GitHubActionProject } from '@xpertss/projen-types';
@@ -268,7 +473,7 @@ You get:
268
473
 
269
474
  - `action.yml` and `auto-commit.sh` are hand-written - this type only lints their content via `build.yml`'s shellcheck/yamllint/actionlint checks.
270
475
  - `.github/workflows/build.yml` - lint gate: `apt`-installed shellcheck/yamllint plus a pinned, SHA-256-verified `actionlint` release binary. Gates `main` alongside `sonar.yml`.
271
- - `.github/workflows/test-dogfood.yml` - runs the `dogfood.scenario` steps above against this repo's own `action.yml` (via `uses: .`), then the shared `cleanup`, on `workflow_dispatch`, every `pull_request`, and nightly. Omit `dogfood` and the workflow still exists, with one step that fails on every PR until you declare a scenario - AD-001 allows a dogfood to be missing loudly, never silently. A *partial* `dogfood` (a scenario with no cleanup) is a synth error.
476
+ - `.github/workflows/test-dogfood.yml` - runs the `dogfood.scenario` steps above against this repo's own `action.yml` (via `uses: ./`), then the shared `cleanup`, on `workflow_dispatch`, every `pull_request`, and nightly. Omit `dogfood` and the workflow still exists, with one step that fails on every PR until you declare a scenario - AD-001 allows a dogfood to be missing loudly, never silently. A *partial* `dogfood` (a scenario with no cleanup) is a synth error.
272
477
  - `.github/workflows/sonar.yml` - SonarCloud scan via the Scanner CLI (the quality gate blocks the PR), scanning `action.yml`/`.github/workflows/**`/`**/*.sh` explicitly.
273
478
  - `.github/workflows/release.yml` - `feat:`/`fix:` commits on `main` bump the version, tag `vX.Y.Z`, and create a GitHub Release.
274
479
  - `.github/workflows/projen-drift-check.yml` and `workflow-change-notice.yml` - drift detection and a change notice, always included.
@@ -276,6 +481,60 @@ You get:
276
481
 
277
482
  Needs the same two secrets as everything else in this package: `PROJEN_GITHUB_TOKEN` (used for automated PR comments) and `SONAR_TOKEN` (the Sonar scan). Onboard a brand-new action repo following [Getting started](#getting-started), write the `.projenrc.ts` above, then hand-write `action.yml`/`auto-commit.sh`/`test/fixtures/`.
278
483
 
484
+ ## Java version support
485
+
486
+ `javaVersion` picks the Java line a Java project targets. It defaults to `21`; the supported lines are `1.8` (alias `8`), `17`, `21` and `25`, and any other value fails the synth with that list. **Nothing in the generated build is hard-coded to one Java line.** Everything that depends on it comes from one table in this package, grouped by line:
487
+
488
+ | | `1.8` | `17` | `21` | `25` |
489
+ | --- | --- | --- | --- | --- |
490
+ | Compiler level | `maven.compiler.source`/`target` = `1.8` (javac 8 has no `--release`) | `maven.compiler.release` = `17` | `release` = `21` | `release` = `25` |
491
+ | Enforcer `requireJavaVersion` | `[1.8,)` | `[17,)` | `[21,)` | `[25,)` |
492
+ | JUnit (`junit-bom`) | 5.14.4 (JUnit 6 needs Java 17) | 6.1.3 | 6.1.3 | 6.1.3 |
493
+ | Default Spring Boot (`JavaSpringBootProject`) | 2.7.18 (Boot 3+ needs Java 17; a 3.x+ `springBootVersion` fails the synth) | 4.1.1 | 4.1.1 | 4.1.1 |
494
+ | `flyway-maven-plugin` (`JavaServiceProject`) | 9.22.3 | 13.9.0 | 13.9.0 | 13.9.0 |
495
+ | CI JDK (`actions/setup-java` `java-version`) | `8` | `17` | `21` | `25` |
496
+
497
+ Maven plugins (the same on every line, because all of them run on JDK 8): `maven-compiler-plugin` 3.16.0, `maven-surefire-plugin`/`maven-failsafe-plugin` 3.6.0, `maven-jar-plugin` 3.5.1, `maven-enforcer-plugin` 3.6.3, `maven-source-plugin` 3.4.0 and `maven-javadoc-plugin` 3.12.0 (library only), `versions-maven-plugin` 2.22.0 (the `upgrade` report).
498
+
499
+ **The enforcer.** `maven-enforcer-plugin` fails the build at the start when the JDK or Maven running it is older than the project needs. Without it you get confusing compiler errors later, or a jar built for the wrong runtime. Its Java rule always follows `javaVersion`. The Maven rule defaults to `[3.9,)`; change it with `minMavenVersion`, or drop the plugin entirely with `enforcer: false`. CI installs the matching JDK through `setup-java`, so the rule only fires on a developer machine with the wrong JDK. A Java 1.8 project builds on any newer JDK (the rule is a minimum), but the JDK 8 runtime API is guaranteed only when you build on JDK 8.
500
+
501
+ **Overriding a version.** `pluginVersions` replaces any default in the table, keyed by `groupId/artifactId`, with an exact version:
502
+
503
+ ```typescript
504
+ new JavaMavenProject({
505
+ name: 'svc',
506
+ groupId: 'org.xpertss',
507
+ artifactId: 'svc',
508
+ pluginVersions: {
509
+ 'org.apache.maven.plugins/maven-surefire-plugin': '3.5.6',
510
+ 'org.junit/junit-bom': '5.14.4',
511
+ },
512
+ });
513
+ ```
514
+
515
+ `project.pinnedVersion('org.apache.maven.plugins/maven-surefire-plugin')` returns the version in effect, for reuse in your own plugin config.
516
+
517
+ **New Java lines** are one new row in this package's version table and a release. Until a line is listed, `javaVersion` rejects it rather than guessing.
518
+
519
+ ## Adding CI jobs to a Java project
520
+
521
+ `build.yml` is exposed as `project.buildVerifyWorkflow`, so jobs are added through projen's `addJob` rather than `addOverride`. `project.ciSetupSteps` holds the steps every Maven job here needs: pinned Node, `npm ci`, and the project's JDK with a Maven cache. Every job in `build.yml` can then be made a required check on `main`.
522
+
523
+ ```typescript
524
+ import { github } from 'projen';
525
+
526
+ project.buildVerifyWorkflow.addJob('integration', {
527
+ name: 'Container integration tests',
528
+ runsOn: ['self-hosted', 'linux', 'fedora', 'podman'],
529
+ permissions: { contents: github.workflows.JobPermission.READ },
530
+ steps: [
531
+ { name: 'Checkout', uses: 'actions/checkout@v7' },
532
+ ...project.ciSetupSteps,
533
+ { name: 'Integration tests', run: 'mvn -B verify -Pcontainer-its' },
534
+ ],
535
+ });
536
+ ```
537
+
279
538
  ## Common options
280
539
 
281
540
  CDK project types (`CdkInfraProjectOptions` / `CdkAppProjectOptions`):
@@ -292,16 +551,30 @@ CDK project types (`CdkInfraProjectOptions` / `CdkAppProjectOptions`):
292
551
  | `database` | - (app only) | `DatabaseOptions` - `engine` (`postgres`/`mysql`/`dynamodb`, default `postgres`), `migrationTool` |
293
552
  | `appEntryPoint` | `src/app.ts` (app only) | Path of the generated application entrypoint |
294
553
 
295
- Java project types (`JavaLibraryProjectOptions` / `JavaServiceProjectOptions` / `JavaAppProjectOptions`):
554
+ Java project types (`JavaMavenProjectOptions` and everything built on it - `JavaLibraryProjectOptions`, `JavaAppProjectOptions`, `JavaSpringBootProjectOptions`, `JavaServiceProjectOptions`):
296
555
 
297
556
  | Option | Default | Description |
298
557
  | --- | --- | --- |
299
558
  | `name` | - (required) | Project name |
300
559
  | `groupId` | - (required) | Maven group id |
301
- | `artifactId` | - (required) | Maven artifact id |
302
- | `version` | `0.1.0` | Maven version |
560
+ | `artifactId` | - (required) | Maven artifact id (of the reactor parent, in a multi-module project) |
561
+ | `version` | `0.1.0` | Maven version; must be exact |
562
+ | `description` / `url` | - | Written to the root pom |
563
+ | `javaVersion` | `21` | Java line: `1.8`, `17`, `21`, `25` - see [Java version support](#java-version-support) |
564
+ | `javaDistribution` | `temurin` | `actions/setup-java` distribution for CI |
565
+ | `packaging` | `jar` | Root packaging while the project has no modules; a project with modules is always `pom` |
566
+ | `sample` | `false` | Starter `Main` + test under the `groupId` package (single-module only) |
567
+ | `enforcer` | `true` | `maven-enforcer-plugin` with Maven and Java version rules |
568
+ | `minMavenVersion` | `3.9` | The enforcer's `requireMavenVersion` minimum |
569
+ | `pluginVersions` | - | Exact-version overrides for this package's defaults, keyed by `groupId/artifactId` |
570
+ | `licensed` | `true` | Write a `LICENSE` |
571
+ | `license` | `MIT` | SPDX identifier for the `LICENSE` |
572
+ | `copyrightOwner` / `copyrightPeriod` | `xpertss` / current year | Named in the `LICENSE` |
573
+ | `editorconfig` | `true` | Write a projen-managed `.editorconfig` (also on the CDK and action types) |
574
+ | `upgradeWorkflow` | `true` | Generate the nightly update report (`upgrade.yml`) |
303
575
  | `sonarProjectKey` | - | SonarQube project key; the sonar step is skipped when unset |
304
576
  | `gheTokenSecret` | `PROJEN_GITHUB_TOKEN` | GitHub secret holding projen's PAT |
577
+ | `springBootVersion` | newest Boot for `javaVersion` (Spring Boot types only) | Exact Spring Boot version: the BOM and `spring-boot-maven-plugin` |
305
578
  | `cdkDeployTargetRepo` | - (service only; `deploy-cdk.yml` fails until set) | Companion CDK repo (`owner/repo`) whose `deploy.yml` the deploy hook dispatches |
306
579
  | `cdkDeployHook` | `true` (service only) | Whether to generate `deploy-cdk.yml` at all |
307
580
  | `dockerRegistry` | `docker.io` (service only) | Registry the Docker image is pushed to |
@@ -329,7 +602,7 @@ Plain strings (`'dev'`) are shorthand for `{ name: 'dev' }`.
329
602
  | `sonarHostUrl` | - (required) | URL of your SonarCloud instance (e.g. `https://sonarcloud.io`); must be reachable from github.com-hosted runners |
330
603
  | `sonarTokenSecret` | `SONAR_TOKEN` | GitHub secret holding the Sonar token |
331
604
  | `sonarPullRequestGate` | `true` | Whether `sonar.yml` also runs on `pull_request` as a pass/fail gate |
332
- | `dogfood` | - (a `test-dogfood.yml` that fails until you declare one) | `ActionDogfoodOptions` - the scenario that exercises the action end-to-end via `uses: .` |
605
+ | `dogfood` | - (a `test-dogfood.yml` that fails until you declare one) | `ActionDogfoodOptions` - the scenario that exercises the action end-to-end via `uses: ./` |
333
606
  | `license` | `MIT` | SPDX identifier for the generated `LICENSE` |
334
607
  | `gheTokenSecret` | `PROJEN_GITHUB_TOKEN` | GitHub secret holding projen's PAT |
335
608
 
@@ -343,7 +616,7 @@ interface ActionDogfoodOptions {
343
616
 
344
617
  interface ActionDogfoodStep {
345
618
  readonly name: string; // labels this step-group's generated workflow steps
346
- readonly id?: string; // step id for the `uses: .` call; default: a slug of `name`
619
+ readonly id?: string; // step id for the `uses: ./` call; default: a slug of `name`
347
620
  readonly fixtureSteps?: string[]; // shell, before the invocation (default: none)
348
621
  readonly inputs?: Record<string, string>; // `with:` for this invocation (default: none)
349
622
  readonly assertions: string[]; // shell, after the invocation - required, job fails unless all exit 0
@@ -362,6 +635,29 @@ Most actions need exactly one `scenario` step. Actions with a re-run/no-op/idemp
362
635
  | `MAVEN_GPG_PRIVATE_KEY`, `MAVEN_GPG_PASSPHRASE`, `MAVEN_CENTRAL_USERNAME`, `MAVEN_CENTRAL_PASSWORD` | `JavaLibraryProject` without `mavenCentralOidc` | Not needed with OIDC trusted publishing |
363
636
  | (your Slack webhook secret) | CDK types with `slackWebhookSecret` | Deploy notifications |
364
637
 
638
+ ## Customizing `.gitignore`
639
+
640
+ Every project type already ignores JetBrains IDE state (`/.idea/*`) and the `/spec/` directory with all of its subdirectories (local plans and specs, never committed). The Java types also ignore Maven `target/` output and Eclipse files. To ignore more, call the inherited `addGitIgnore()` method after constructing the project in your `.projenrc.ts`:
641
+
642
+ ```typescript
643
+ // .projenrc.ts
644
+ import { CdkInfraProject } from '@xpertss/projen-types';
645
+
646
+ const project = new CdkInfraProject({
647
+ name: 'my-infra',
648
+ });
649
+
650
+ project.addGitIgnore('*.log');
651
+ project.addGitIgnore('.env.*');
652
+ project.addGitIgnore('/build/');
653
+
654
+ project.synth();
655
+ ```
656
+
657
+ The same works for every type - just swap the class (e.g. `JavaServiceProject`, `GitHubActionProject`). Each call takes one standard gitignore glob pattern. There is no `gitignore` constructor option: the project types' option interfaces do not expose one, so patterns go through `addGitIgnore()` instead.
658
+
659
+ Re-run `npx projen` after editing - `.gitignore` is a generated file, so hand-editing it is caught by the drift check.
660
+
365
661
  ## Going further
366
662
 
367
663
  The project types are composed from smaller components you can also attach to your own projects:
@@ -372,23 +668,25 @@ The project types are composed from smaller components you can also attach to yo
372
668
  | `DatabaseComponent` | `NodeProject` | Database construct stub + migration tool wiring |
373
669
  | `EcrEcsConstructs` | `Project` | ECR + Fargate ECS construct helper |
374
670
  | `EdgeNetworkingConstructs` | `Project` | Per-resource edge networking construct helpers |
375
- | `MavenCentralPublish` | `JavaProject` | Manual-dispatch Maven Central publish workflow |
376
- | `DockerPublish` | `JavaProject` | Manual-dispatch Docker build+push workflow |
377
- | `GitHubPackagesPublish` | `JavaProject` | Manual-dispatch GitHub Packages publish workflow |
378
- | `FlywayMigration` | `JavaProject` | Flyway plugin/dependency + migrations directory |
379
- | `CdkDeployHook` | `JavaProject` | Manual-dispatch workflow that triggers `deploy.yml` in a companion CDK repo |
380
- | `CodeIndexWorkflow` | `JavaProject` | Code index generation on push to `main` |
671
+ | `MavenPom` | `Project` | A `pom.xml` with modules, BOM imports, dependency/plugin management, and exact versions only |
672
+ | `MavenModule` | `JavaMavenProject` | One module of a reactor (created by `addModule()`) |
673
+ | `MavenUpgradeReport` | `GitHubProject` | Nightly report-only `upgrade.yml` |
674
+ | `MavenCentralPublish` | `JavaMavenProject` | Manual-dispatch Maven Central publish workflow |
675
+ | `DockerPublish` | `JavaMavenProject` | Manual-dispatch Docker build+push workflow |
676
+ | `GitHubPackagesPublish` | `JavaMavenProject` | Manual-dispatch GitHub Packages publish workflow |
677
+ | `FlywayMigration` | `JavaSpringBootProject` | Flyway plugin/dependency + migrations directory |
678
+ | `CdkDeployHook` | `JavaMavenProject` | Manual-dispatch workflow that triggers `deploy.yml` in a companion CDK repo |
679
+ | `CodeIndexWorkflow` | `JavaMavenProject` | Code index generation on push to `main` |
381
680
  | `ActionBuildWorkflow` | `GitHubProject` | The `lint` task (shellcheck/yamllint/pinned actionlint) + `build.yml` |
382
681
  | `ActionDogfoodWorkflow` | `GitHubProject` | `test-dogfood.yml` from an `ActionDogfoodOptions` scenario |
383
682
  | `ActionSonarWorkflow` | `GitHubProject` | `sonar.yml` (SonarCloud scan via the Scanner CLI) |
384
683
 
385
- Example - adding a Docker publish to a plain projen `JavaProject`:
684
+ Example - adding a Docker publish to a `JavaMavenProject` (`JavaServiceProject` is the packaged version of this, with Spring Boot):
386
685
 
387
686
  ```typescript
388
- import { java } from 'projen';
389
- import { DockerPublish } from '@xpertss/projen-types';
687
+ import { DockerPublish, JavaMavenProject } from '@xpertss/projen-types';
390
688
 
391
- const project = new java.JavaProject({
689
+ const project = new JavaMavenProject({
392
690
  name: 'my-service',
393
691
  groupId: 'org.xpertss',
394
692
  artifactId: 'my-service',
@@ -20,7 +20,7 @@ const ACTIONLINT_SHA256 = '8aca8db96f1b94770f1b0d72b6dddcb1ebb8123cb3712530b08cc
20
20
  * the release build job, so the lint commands exist in exactly one place.
21
21
  */
22
22
  class ActionBuildWorkflow extends projen_1.Component {
23
- static [JSII_RTTI_SYMBOL_1] = { fqn: "@xpertss/projen-types.ActionBuildWorkflow", version: "0.0.12" };
23
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "@xpertss/projen-types.ActionBuildWorkflow", version: "0.0.14" };
24
24
  task;
25
25
  workflow;
26
26
  constructor(scope) {
@@ -1,7 +1,7 @@
1
1
  import { Component, github } from 'projen';
2
2
  /**
3
3
  * One invocation of the action within the dogfood scenario: optional fixture
4
- * setup, the `uses: .` call with this step's inputs, then this step's
4
+ * setup, the `uses: ./` call with this step's inputs, then this step's
5
5
  * assertions. Most actions need exactly one; actions with a re-run/no-op
6
6
  * behavior to verify (e.g. F006's reuse-the-PR path, F007's no-op-commit
7
7
  * path) declare two.
@@ -10,7 +10,7 @@ export interface ActionDogfoodStep {
10
10
  /** Label used to name this step-group's generated workflow steps. */
11
11
  readonly name: string;
12
12
  /**
13
- * Step id for the `uses: .` invocation, so a later assertion can
13
+ * Step id for the `uses: ./` invocation, so a later assertion can
14
14
  * reference this step's outputs via `${{ steps.<id>.outputs.<name> }}`.
15
15
  * @default - a slug derived from `name`, disambiguated by position
16
16
  */
@@ -22,7 +22,7 @@ export interface ActionDogfoodStep {
22
22
  */
23
23
  readonly fixtureSteps?: string[];
24
24
  /**
25
- * `with:` inputs for this invocation's local `uses: .` call.
25
+ * `with:` inputs for this invocation's local `uses: ./` call.
26
26
  * @default {}
27
27
  */
28
28
  readonly inputs?: Record<string, string>;
@@ -37,7 +37,7 @@ export interface ActionDogfoodOptions {
37
37
  }
38
38
  /**
39
39
  * Per AD-001's dogfood test: the composite action is run **against this
40
- * repo**, end-to-end, via a local `uses: .` reference - no external harness.
40
+ * repo**, end-to-end, via a local `uses: ./` reference - no external harness.
41
41
  * Builds `test-dogfood.yml` from an ordered `scenario` of invocation steps
42
42
  * (see `ActionDogfoodStep`) followed by a shared cleanup step.
43
43
  *