From 4d9611ab5f71055ccd7b5e1cb2aed3c97d1213e7 Mon Sep 17 00:00:00 2001 From: Paul Williams Date: Thu, 11 Dec 2025 11:13:03 +0530 Subject: [PATCH 1/4] build: upgrade to jdk 25 --- .github/workflows/ci-for-example.yaml | 8 ++++---- .github/workflows/ci-from-template.yaml | 8 ++++---- README.md | 2 +- example/pom.xml | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-for-example.yaml b/.github/workflows/ci-for-example.yaml index 1ef12eb..22a66b8 100644 --- a/.github/workflows/ci-for-example.yaml +++ b/.github/workflows/ci-for-example.yaml @@ -15,12 +15,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/checkout@v6 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: temurin - java-version: 21 + java-version: 25 - name: Cache Maven dependencies uses: actions/cache@v4 with: diff --git a/.github/workflows/ci-from-template.yaml b/.github/workflows/ci-from-template.yaml index 718c0d7..e1441f4 100644 --- a/.github/workflows/ci-from-template.yaml +++ b/.github/workflows/ci-from-template.yaml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout PR branch - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: # checkout the pull request head ref when available, otherwise fallback to the workflow ref ref: ${{ github.head_ref || github.ref }} @@ -46,11 +46,11 @@ jobs: run: | echo "Working dir: $(pwd)" ls -la ./cart-service - - name: Set up JDK 21 - uses: actions/setup-java@v4 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: temurin - java-version: 21 + java-version: 25 - name: Cache Maven dependencies uses: actions/cache@v4 with: diff --git a/README.md b/README.md index 46aa9d1..9c8420d 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ This is a template project for hexagonal-spring-boot-java. This project is gener ## Pre-requisites - [copier](https://copier.readthedocs.io/en/stable/#installation) -- Jdk 21 +- Jdk 25 - Maven >3.9.5 ## How to contribute ? diff --git a/example/pom.xml b/example/pom.xml index eec40ac..0438944 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -9,7 +9,7 @@ 1.0-SNAPSHOT UTF-8 - 21 + 25 ${java.version} ${java.version} 6.0.1 From b440e1b1e2cc7894d51e2f927849fe5c7d67b8ab Mon Sep 17 00:00:00 2001 From: Paul Williams Date: Thu, 11 Dec 2025 11:13:41 +0530 Subject: [PATCH 2/4] ci: upgrade to jdk 25 --- example/.github/workflows/build_workflow.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/example/.github/workflows/build_workflow.yml b/example/.github/workflows/build_workflow.yml index 7ef2fa3..dad5520 100644 --- a/example/.github/workflows/build_workflow.yml +++ b/example/.github/workflows/build_workflow.yml @@ -8,14 +8,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v4 + uses: actions/checkout@v6 + - name: Set up JDK 25 + uses: actions/setup-java@v5 with: distribution: temurin java-version: 21 - name: Cache Maven dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2/repository key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} From 2b33682844e54ff3355ca8d5a1a3226eaf2254eb Mon Sep 17 00:00:00 2001 From: Paul Williams Date: Thu, 11 Dec 2025 11:14:29 +0530 Subject: [PATCH 3/4] ci(dependabot): add github actions --- .github/dependabot.yml | 39 ++++++++++++++++++++++++++-------- example/.github/dependabot.yml | 23 +++++++++++++------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 037859f..0fffce9 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,11 +1,32 @@ version: 2 updates: -- package-ecosystem: maven - directories: - - "/example/" - schedule: - interval: daily - time: "23:30" - open-pull-requests-limit: 10 - reviewers: - - devs-from-matrix/app-generator-team \ No newline at end of file + - package-ecosystem: maven + directories: + - "/example/" + schedule: + interval: daily + time: "23:30" + open-pull-requests-limit: 10 + commit-message: + prefix: "build: " + assignees: + - paul58914080 + labels: + - dependencies + - automated + reviewers: + - devs-from-matrix/app-generator-team + - package-ecosystem: github-actions + directory: "/.github/" + schedule: + interval: weekly + open-pull-requests-limit: 5 + commit-message: + prefix: "ci: " + assignees: + - paul58914080 + labels: + - ci + - automated + reviewers: + - devs-from-matrix/app-generator-team diff --git a/example/.github/dependabot.yml b/example/.github/dependabot.yml index c51d0f0..f8d94bb 100644 --- a/example/.github/dependabot.yml +++ b/example/.github/dependabot.yml @@ -1,10 +1,17 @@ version: 2 updates: -- package-ecosystem: maven - directory: "/" - schedule: - interval: daily - time: "23:30" - open-pull-requests-limit: 10 - assignees: - - paul58914080 + - package-ecosystem: maven + directory: "/" + schedule: + interval: daily + time: "23:30" + open-pull-requests-limit: 10 + commit-message: + prefix: "build: " + - package-ecosystem: github-actions + directory: "/.github/" + schedule: + interval: weekly + open-pull-requests-limit: 5 + commit-message: + prefix: "ci: " \ No newline at end of file From d7f2325ea5dd13329f08e243f459f97bb9524c8a Mon Sep 17 00:00:00 2001 From: Paul Williams Date: Thu, 11 Dec 2025 11:14:53 +0530 Subject: [PATCH 4/4] docs: update copilot instructions for JDK 25 and copier integration --- .github/copilot-instructions.md | 170 ++++++++++++++++++++++---------- 1 file changed, 118 insertions(+), 52 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 8919f8b..4468635 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,31 +2,40 @@ ## Context -- Language: Java version 21 -- Framework / Libraries: Spring Boot / JUnit 5 +- Language: Java version 25 +- Framework / Libraries: Spring Boot / JUnit 5 - Build Tool: Maven version >3.9.5 - Architecture: Clean Architecture / Hexagonal / Microservices - Coding Style: Google Java Style Guide ## Overview -This is a template project for hexagonal-spring-boot-java. This project is generated using [cookiecutter](https://cookiecutter.readthedocs.io/en). The project follows a hexagonal architecture pattern and is built using Spring Boot and Java. - -The directory `example` contains the template project which can be modified by the contributors. The changes can be tested locally and then a pull request can be raised to merge the changes to the main branch. The project is also integrated with a CI pipeline which runs the tests and builds the project on every pull request. - -The directory `{{cookiecutter.app_name}}` contains the generated project from `example` project. The project is generated using the script [generate-cookiecutter-template-from-example-project.sh](../generate-cookiecutter-template-from-example-project.sh) which is used to generate the cookiecutter template project. You should not modify this directory directly. Following are the keywords reserved for the template project and their equivalent replacements in `{{cookiecutter.app_name}}` project: - -| Keyword | Replacement | -|--------------|---------------------------------------------| -| Examples | {{cookiecutter.domain_plural_capitalized}} | -| examples | {{cookiecutter.domain_plural}} | -| Example | {{cookiecutter.domain_capitalized}} | -| example | {{cookiecutter.domain}} | -| packagename | {{cookiecutter.package_name}} | -| artifactName | {{cookiecutter.artifact_id}} | -| group-id | {{cookiecutter.group_id}} | -| EXAMPLES | {{cookiecutter.domain_plural_uppercase}} | -| EXAMPLE | {{cookiecutter.domain_uppercase}} | +This is a template project for hexagonal-spring-boot-java. This project is generated +using [copier](https://copier.readthedocs.io/en/stable/). The project follows a hexagonal architecture +pattern and is built using Spring Boot and Java. + +The directory `example` contains the template project which can be modified by the contributors. The +changes can be tested locally and then a pull request can be raised to merge the changes to the main +branch. The project is also integrated with a CI pipeline which runs the tests and builds the +project on every pull request. + +The directory `{{app_name}}` contains the generated project from `example` project. The project is +generated using the script [generate-copier-template-from-example-project.sh](../generate-copier-template-from-example-project.sh) +which is used to generate the copier template project. You should not modify this directory +directly. Following are the keywords reserved for the template project and their equivalent +replacements in `{{app_name}}` project: + +| Keyword | Replacement | +|--------------|-------------------------------| +| Examples | {{domain_plural_capitalized}} | +| examples | {{domain_plural}} | +| Example | {{domain_capitalized}} | +| example | {{domain}} | +| packagename | {{package_name}} | +| artifactName | {{artifact_id}} | +| group-id | {{group_id}} | +| EXAMPLES | {{domain_plural_uppercase}} | +| EXAMPLE | {{domain_uppercase}} | ## 🔧 General Guidelines @@ -41,7 +50,8 @@ The directory `{{cookiecutter.app_name}}` contains the generated project from `e ## File Structure And Patterns -As you are only authorized to modify the `example` directory, here is a brief overview of its structure: +As you are only authorized to modify the `example` directory, here is a brief overview of its +structure: ``` example/ @@ -52,9 +62,14 @@ example/ ├── rest-adapter/ # REST API adapter: controllers, request/response models ├── acceptance-test/ # Cucumber-based acceptance tests ``` + ### domain-api -Defines the public interfaces and models for the domain layer. This includes ports i.e. contracts to interact with the domain and the external services and domain models. It should not contain any implementation details or dependencies on frameworks. This layer is purely abstract and should not depend on any other layer. Ensure that No class in this layer depends on any other layer. The `pom.xml` of this module should not have any dependencies except for testing libraries. +Defines the public interfaces and models for the domain layer. This includes ports i.e. contracts to +interact with the domain and the external services and domain models. It should not contain any +implementation details or dependencies on frameworks. This layer is purely abstract and should not +depend on any other layer. Ensure that No class in this layer depends on any other layer. The +`pom.xml` of this module should not have any dependencies except for testing libraries. ``` example/domain-api/ @@ -79,11 +94,15 @@ example/domain-api/ #### ✅ Patterns to Follow -- The domain model class name needs to be more functional and should be placed under `model` package. -- The contracts for accessing the domain and the contracts for the domain to access the outside world should be placed under `port` package. -- The name of the contract for accessing the domain should be named as `Request*` and the name of the contract for the domain to access the outside world should be named as `Obtain*`. +- The domain model class name needs to be more functional and should be placed under `model` + package. +- The contracts for accessing the domain and the contracts for the domain to access the outside + world should be placed under `port` package. +- The name of the contract for accessing the domain should be named as `Request*` and the name of + the contract for the domain to access the outside world should be named as `Obtain*`. - Ensure all interfaces are pure abstractions, with no implementation details. -- Use default methods in interfaces only for providing simple, hard-coded stubs for testing or documentation. +- Use default methods in interfaces only for providing simple, hard-coded stubs for testing or + documentation. - The `pom.xml` should only include dependencies for testing (e.g., JUnit, Mockito, AssertJ). #### 🚫 Patterns to Avoid @@ -94,7 +113,11 @@ example/domain-api/ ### domain -Implements the core business logic and rules by adhering to the contracts of `domain-api`. It contains service implementations, domain models, and business validations. This layer should not depend on any frameworks or external libraries. It should only depend on the `domain-api` layer. Ensure that No class in this layer depends on any other layer except `domain-api`. The `pom.xml` of this module should not have any dependencies except for testing libraries. +Implements the core business logic and rules by adhering to the contracts of `domain-api`. It +contains service implementations, domain models, and business validations. This layer should not +depend on any frameworks or external libraries. It should only depend on the `domain-api` layer. +Ensure that No class in this layer depends on any other layer except `domain-api`. The `pom.xml` of +this module should not have any dependencies except for testing libraries. ``` example/domain/ @@ -117,14 +140,16 @@ example/domain/ - Name domain classes as `*Domain.java`. - Keep all code in this layer framework-agnostic -- Throw domain-specific exceptions for error cases (e.g., not found). Place domain-specific exceptions in an `exception/` subpackage and name as `*Exception.java`. +- Throw domain-specific exceptions for error cases (e.g., not found). Place domain-specific + exceptions in an `exception/` subpackage and name as `*Exception.java`. - Implement only business logic and rules; do not include persistence or framework-specific code. - Use constructor injection for dependencies (e.g., ports from `domain-api`). - Depend only on interfaces and models from `domain-api`. - Keep all code framework-agnostic and library-agnostic. - Use clear, descriptive method and class names that reflect domain concepts. - Favor readability, separation of concerns, and testability. -- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log exceptions with proper log levels and logging of exception should NEVER be skipped. +- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log + exceptions with proper log levels and logging of exception should NEVER be skipped. #### 🚫 Patterns to Avoid @@ -139,7 +164,10 @@ example/domain/ ### jpa-adapter -Implements the persistence logic using JPA. It contains repository implementations, JPA entities, and database configurations. This layer depends on `domain-api` for repository interfaces and models. It uses liquibase to easily manage the database schema and data migrations. It also uses envers for auditing the entities. +Implements the persistence logic using JPA. It contains repository implementations, JPA entities, +and database configurations. This layer depends on `domain-api` for repository interfaces and +models. It uses liquibase to easily manage the database schema and data migrations. It also uses +envers for auditing the entities. ``` example/jpa-adapter/ @@ -168,18 +196,28 @@ example/jpa-adapter/ #### ✅ Patterns to Follow - Name repository classes as `*Repository.java`. -- Name DAO interfaces as `*Dao.java` and extend `JpaRepository` (and optionally `RevisionRepository` for auditing). -- Name JPA entity classes as `*Entity.java` and annotate with `@Entity`,`@Table`; use Lombok for boilerplate. +- Name DAO interfaces as `*Dao.java` and extend `JpaRepository` (and optionally `RevisionRepository` + for auditing). +- Name JPA entity classes as `*Entity.java` and annotate with `@Entity`,`@Table`; use Lombok for + boilerplate. - Name configuration classes as `*Config.java` and annotate with `@Configuration` -- Use Dependency Injection ONLY with constructor injection and NOT via `@Autowired` on fields as it would make the code less testable. +- Use Dependency Injection ONLY with constructor injection and NOT via `@Autowired` on fields as it + would make the code less testable. - Repository implementations should only depend on domain models and interfaces from `domain-api`. - Use method references and streams for mapping entities to domain models. - Place integration tests in src/test/java/packagename/repository/ and name as `*JpaTest.java`. - Use `@DataJpaTest` and `@ActiveProfiles("test")` for JPA integration tests. - Use SQL scripts for test data setup in integration tests. -- Pre-liquibase script placed at `src/main/resources/preliquibase/default.sql` should be used for database schema and data migrations. The changelog files should be placed in `src/main/resources/db/changelog/` directory. -- The changelog files should follow the naming convention `YYYYMMDD-HHMMSS-entityname.xml` (e.g., `20240601-153000-user.xml`). Each changelog file should contain changesets for a single entity only and also audit tables should be created for each entity table. The audit tables should have the same structure as the entity table with additional columns for revision information. The audit tables should be named as `_AUD`. -- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log exceptions with proper log levels and logging of exception should NEVER be skipped. +- Pre-liquibase script placed at `src/main/resources/preliquibase/default.sql` should be used for + database schema and data migrations. The changelog files should be placed in + `src/main/resources/db/changelog/` directory. +- The changelog files should follow the naming convention `YYYYMMDD-HHMMSS-entityname.xml` (e.g., + `20240601-153000-user.xml`). Each changelog file should contain changesets for a single entity + only and also audit tables should be created for each entity table. The audit tables should have + the same structure as the entity table with additional columns for revision information. The audit + tables should be named as `_AUD`. +- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log + exceptions with proper log levels and logging of exception should NEVER be skipped. #### 🚫 Patterns to Avoid @@ -195,7 +233,8 @@ example/jpa-adapter/ ### rest-adapter -Implements the REST API layer. It contains controllers, request/response models, and API configurations. This layer depends on `domain-api` for service interfaces and models. +Implements the REST API layer. It contains controllers, request/response models, and API +configurations. This layer depends on `domain-api` for service interfaces and models. ``` example/rest-adapter/ @@ -222,14 +261,26 @@ example/rest-adapter/ #### ✅ Patterns to Follow - The RestController classes should be named as `*Resource.java`. -- The `pom.xml` of this module should have dependencies only for spring-boot-starter, open api specification and testing libraries. -- This module is built with design first approach. The API specification is defined using OpenAPI (Swagger) and the code is generated using [openapi-generator-maven-plugin](https://openapi-generator.tech/docs/plugins/). The API specification file is located at `src/main/resources/api/openapi.yaml`. Any changes to the API should be made in this file and the code should be regenerated using the command `mvn clean compile`. -- The RestController classes should implement the interfaces generated by the OpenAPI generator. The request and response models should be generated by the OpenAPI generator and should not be modified manually unless absolutely necessary. +- The `pom.xml` of this module should have dependencies only for spring-boot-starter, open api + specification and testing libraries. +- This module is built with design first approach. The API specification is defined using OpenAPI ( + Swagger) and the code is generated + using [openapi-generator-maven-plugin](https://openapi-generator.tech/docs/plugins/). The API + specification file is located at `src/main/resources/api/openapi.yaml`. Any changes to the API + should be made in this file and the code should be regenerated using the command + `mvn clean compile`. +- The RestController classes should implement the interfaces generated by the OpenAPI generator. The + request and response models should be generated by the OpenAPI generator and should not be + modified manually unless absolutely necessary. - Use `@SpringBootTest` and `@ActiveProfiles("test")` for integration tests. - Use method references and streams for mapping domain models to response objects. -- Use Dependency Injection ONLY with constructor injection and NOT via `@Autowired` on fields as it would make the code less testable. -- Handle exceptions with `@RestControllerAdvice` annotated class and return `ResponseEntity` with proper error code and body that adhere to `ProblemDetail` which has the properties defined in [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807). -- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log exceptions with proper log levels and logging of exception should NEVER be skipped. +- Use Dependency Injection ONLY with constructor injection and NOT via `@Autowired` on fields as it + would make the code less testable. +- Handle exceptions with `@RestControllerAdvice` annotated class and return + `ResponseEntity` with proper error code and body that adhere to `ProblemDetail` + which has the properties defined in [RFC 7807](https://datatracker.ietf.org/doc/html/rfc7807). +- Use `slf4j` for logging every entry and exit of the methods with proper log levels. Also, log + exceptions with proper log levels and logging of exception should NEVER be skipped. - Use ONLY dependencies required for Spring Boot, OpenAPI, and testing in pom.xml. #### 🚫 Patterns to Avoid @@ -242,12 +293,17 @@ example/rest-adapter/ - Do not log sensitive information in controllers or exception handlers. - Do not manually manage transactions in this layer. - Do not use static utility methods for mapping; prefer instance or method references. -- Do not add documentation comments to controller classes; documentation should be generated from OpenAPI spec. +- Do not add documentation comments to controller classes; documentation should be generated from + OpenAPI spec. - Do not expose internal domain exceptions directly; always map to standardized error responses. ### acceptance-test -Contains Cucumber-based acceptance tests for the template project. It verifies the application's behavior end-to-end by simulating user scenarios defined in Gherkin feature files. Step definitions implement the test logic, interacting with the application's REST API and database to ensure all layers work together as expected. This directory helps ensure that business requirements are met and prevents regressions by running automated acceptance tests in the CI pipeline. +Contains Cucumber-based acceptance tests for the template project. It verifies the application's +behavior end-to-end by simulating user scenarios defined in Gherkin feature files. Step definitions +implement the test logic, interacting with the application's REST API and database to ensure all +layers work together as expected. This directory helps ensure that business requirements are met and +prevents regressions by running automated acceptance tests in the CI pipeline. ``` example/acceptance-test/ @@ -273,7 +329,8 @@ example/acceptance-test/ - Use constructor injection for dependencies in step definition classes. - Use Cucumber hooks (`Before`, `After`) for test setup and teardown. - Use `DataTableType` for mapping Gherkin tables to domain objects. -- Keep step definitions readable and focused on scenario actions, delegating logic to domain or adapter layers. +- Keep step definitions readable and focused on scenario actions, delegating logic to domain or + adapter layers. - Place configuration classes for Cucumber in the same package as step definitions. - Use assertions from AssertJ or similar libraries for test verification. - Use method references and streams for mapping and assertions. @@ -292,7 +349,10 @@ example/acceptance-test/ ### bootstrap -Contains the main Spring Boot application class and configuration beans to bootstrap the application. It wires together the domain and adapters. This is the entry point of the application and should not contain business logic. The utmost thing this layer should do is to import the configuration classes for the adapters and domain. +Contains the main Spring Boot application class and configuration beans to bootstrap the +application. It wires together the domain and adapters. This is the entry point of the application +and should not contain business logic. The utmost thing this layer should do is to import the +configuration classes for the adapters and domain. ``` bootstrap/ @@ -316,7 +376,7 @@ bootstrap/ #### ✅ Patterns to Follow -- Name the main application class as `*Application.java` and place it in the `boot/` package. +- Name the main application class as `*Application.java` and place it in the `boot/` package. - Place configuration classes in a `config/` subpackage and name them as `*Config.java`. - Use `@SpringBootApplication` for the main class and `@Configuration` for config classes. - Use `@ComponentScan` to scan the base package for beans. @@ -335,17 +395,23 @@ bootstrap/ - Do not manually manage transactions or database connections. - Do not use static utility methods for wiring beans. - Do not modify domain models or interfaces in this layer. -- Do not add documentation comments to bootstrap classes; keep documentation in README or config files. +- Do not add documentation comments to bootstrap classes; keep documentation in README or config + files. ## Contribution Guidelines - Follow the guideline mention in [File Structure And Patterns](#file-structure-and-patterns). -- All contributions must use conventional commit messages. See https://www.conventionalcommits.org/en/v1.0.0/ for details. Example commit message: `feat(domain): add validation for example code` +- All contributions must use conventional commit messages. + See https://www.conventionalcommits.org/en/v1.0.0/ for details. Example commit message: + `feat(domain): add validation for example code` - Commit messages should always be in lower case except for proper nouns. -- Commit messages should be prefixed with the module name in parentheses. Valid module names are: `bootstrap`, `domain`, `domain-api`, `jpa-adapter`, `rest-adapter`, `acceptance-test`. +- Commit messages should be prefixed with the module name in parentheses. Valid module names are: + `bootstrap`, `domain`, `domain-api`, `jpa-adapter`, `rest-adapter`, `acceptance-test`. - Commit message should not exceed 74 characters in length. -- The body of the commit message should provide additional context about the change and optionally reference related issues. -- Branch name should start with `feature/`, `bugfix/`, `hotfix/`, or `chore/` followed by issue number and short description not exceeding 20 characters. +- The body of the commit message should provide additional context about the change and optionally + reference related issues. +- Branch name should start with `feature/`, `bugfix/`, `hotfix/`, or `chore/` followed by issue + number and short description not exceeding 20 characters. - Ensure all tests pass before submitting a pull request. - Provide clear descriptions for pull requests. - Keep changes focused and avoid mixing unrelated features or fixes in a single pull request. \ No newline at end of file