From a7bd0974f650081e89af09d0cbbd7402ebec491b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Tue, 3 Feb 2026 13:21:31 +0100 Subject: [PATCH 1/9] feat: add AGENTS.md and CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- AGENTS.md | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 238 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..6a1efbe764 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,237 @@ +# AI Agents Guide for Java Operator SDK + +This document provides guidance for AI coding agents working with the Java Operator SDK codebase. + +## Project Overview + +Java Operator SDK is a production-ready framework for building Kubernetes Operators in Java. It provides: +- A controller runtime for reconciliation loops +- Support for dependent resources and workflows +- Testing utilities for operator development +- Integration with Fabric8 Kubernetes Client + +**Key Technologies:** +- Java 17+ (currently Java 25) +- Maven for build management +- Fabric8 Kubernetes Client for K8s API access +- JUnit 5 for testing +- GitHub Actions for CI/CD + +## Project Structure + +### Core Modules + +``` +java-operator-sdk/ +├── operator-framework-core/ # Core reconciliation engine and API +├── operator-framework/ # Main operator framework implementation +├── operator-framework-junit5/ # Testing utilities and extensions +├── operator-framework-bom/ # Bill of Materials for dependency management +├── micrometer-support/ # Metrics integration +├── open-telemetry-support/ # Distributed tracing support +├── caffeine-bounded-cache-support/ # Caching implementation +├── bootstrapper-maven-plugin/ # Maven plugin for bootstrapping +└── test-index-processor/ # Test utilities for annotation processing +``` + +### Key Packages + +- `io.javaoperatorsdk.operator.api.reconciler` - Core reconciler interfaces and annotations +- `io.javaoperatorsdk.operator.processing` - Event processing and workflow engine +- `io.javaoperatorsdk.operator.processing.dependent` - Dependent resource management +- `io.javaoperatorsdk.operator.api.config` - Configuration interfaces +- `io.javaoperatorsdk.operator.junit` - Testing support classes + +## Building and Testing + +### Build Commands + +```bash +# Full build with tests +./mvnw clean install + +# Build without tests +./mvnw clean install -DskipTests + +# Build without annotation processing (faster for development) +./mvnw clean install -Pno-apt + +# Parallel build (uses 1 thread per CPU core) +./mvnw -T1C clean install + +# Check code formatting +./mvnw spotless:check + +# Apply code formatting +./mvnw spotless:apply + +# Check license headers +./mvnw -N license:check +``` + +### Test Execution + +```bash +# Run unit tests only +./mvnw test + +# Run integration tests +./mvnw verify -Pit + +# Run specific test class +./mvnw test -Dtest=ClassName + +# Run specific test method +./mvnw test -Dtest=ClassName#methodName +``` + +### Performance Tests + +Performance tests are located in `operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/performance/` + +Results are saved to `target/performance_test_result.json` and include: +- Test duration in milliseconds +- Number of processors +- Maximum memory allocation +- Dynamic test parameters + +## Code Conventions + +### Code Style + +- **Formatting:** The project uses Spotless with Google Java Format +- **License Headers:** All source files must have Apache 2.0 license headers +- **Line Length:** 100 characters maximum +- **Indentation:** 2 spaces (no tabs) + +### Naming Conventions + +- **Reconcilers:** End with `Reconciler` (e.g., `MyResourceReconciler`) +- **Dependent Resources:** End with `DependentResource` (e.g., `ConfigMapDependentResource`) +- **Test Classes:** End with `Test` for unit tests, `IT` for integration tests +- **Custom Resources:** Typically structured as `{Name}Spec`, `{Name}Status`, `{Name}` (the CR class) + +### API Design + +- Use builder patterns for complex configurations +- Prefer immutable objects where possible +- Use annotations for declarative configuration (`@ControllerConfiguration`, `@KubernetesDependent`, etc.) +- Follow fluent API design for DSLs + +## Testing Guidelines + +### Unit Tests + +- Use JUnit 5 +- Mock Kubernetes API interactions using Fabric8's mock server or Mockito +- Test reconciliation logic in isolation +- Place in `src/test/java` + +### Integration Tests + +- Use `LocallyRunOperatorExtension` or `OperatorExtension` from `operator-framework-junit5` +- Test against real Kubernetes API (typically via test cluster or mock server) +- Suffix with `IT` (e.g., `MyReconcilerIT`) +- Located in `src/test/java` or `src/it/java` + +### Test Resources + +- Kubernetes manifests in `src/test/resources` or `src/it/resources` +- Use `@KubernetesResourceYaml` annotation to load test resources +- Custom resources should extend `CustomResource` + +## Common Patterns + +### Reconciler Implementation + +Reconcilers implement the `Reconciler` interface: + +```java +@ControllerConfiguration +public class MyReconciler implements Reconciler { + + @Override + public UpdateControl reconcile( + MyCustomResource resource, Context context) { + // Reconciliation logic + return UpdateControl.noUpdate(); + } +} +``` + +### Dependent Resources + +Dependent resources use the `DependentResource` interface or extend base classes: + +```java +@KubernetesDependent +public class ConfigMapDependent extends CRUDKubernetesDependentResource { + + @Override + protected ConfigMap desired(Primary primary, Context context) { + // Return desired state + } +} +``` + +### Error Handling + +- Use `UpdateControl` with `rescheduleAfter()` for retriable errors +- Throw `RuntimeException` for non-retriable errors +- Update resource status to reflect error conditions +- Use structured logging (SLF4J) + +## Making Changes + +### Before Submitting a PR + +1. Run `./mvnw spotless:apply` to format code +2. Run `./mvnw clean install` to ensure all tests pass +3. Add tests for new functionality +4. Update documentation if adding/changing APIs +5. Follow existing code patterns and conventions + +### PR Guidelines + +- Keep changes focused and atomic +- Write clear commit messages (imperative mood: "Add feature" not "Added feature") +- Reference issues in commit messages when applicable +- Ensure CI checks pass (format, license, tests) + +## Common Issues and Solutions + +### Build Issues + +- **Annotation processing errors:** Try building with `-Pno-apt` first +- **Test failures:** Check if Kubernetes context is needed for ITs +- **Formatting failures:** Run `./mvnw spotless:apply` before committing + +### Test Issues + +- **Integration tests hanging:** Check for resource leaks or improper cleanup +- **Flaky tests:** Ensure proper synchronization using `StatusChecker` or similar patterns +- **Performance test variance:** Results depend on available CPU/memory + +## Resources + +- **Documentation:** https://javaoperatorsdk.io/ +- **GitHub:** https://github.com/operator-framework/java-operator-sdk +- **Slack:** [#java-operator-sdk](https://kubernetes.slack.com/archives/CAW0GV7A5) on Kubernetes Slack +- **Discord:** https://discord.gg/DacEhAy +- **Fabric8 Client:** https://github.com/fabric8io/kubernetes-client + +## Performance Considerations + +- Use caching appropriately (see `caffeine-bounded-cache-support`) +- Implement proper resource watches and informers +- Consider rate limiting for external API calls +- Use parallel processing where appropriate (`-T1C` for Maven builds) +- Monitor memory usage in performance tests + +## Additional Notes for AI Agents + +- The codebase uses extensive use of Java generics for type safety +- Context objects provide access to client, informers, and event sources +- The framework handles K8s API retries and conflict resolution automatically +- Prefer using `ResourceOperations` from context over direct client calls +- Status updates are handled separately from spec reconciliation diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..c317064255 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md From fa8f8e2dbbbae2c2dc804a26f733c76c1d666a48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:02:37 +0100 Subject: [PATCH 2/9] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- AGENTS.md | 50 ++++++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 32 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6a1efbe764..f41f6b1513 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -42,7 +42,7 @@ java-operator-sdk/ - `io.javaoperatorsdk.operator.api.config` - Configuration interfaces - `io.javaoperatorsdk.operator.junit` - Testing support classes -## Building and Testing +## Working Effectively ### Build Commands @@ -85,30 +85,26 @@ java-operator-sdk/ ./mvnw test -Dtest=ClassName#methodName ``` -### Performance Tests - -Performance tests are located in `operator-framework/src/test/java/io/javaoperatorsdk/operator/baseapi/performance/` - -Results are saved to `target/performance_test_result.json` and include: -- Test duration in milliseconds -- Number of processors -- Maximum memory allocation -- Dynamic test parameters - ## Code Conventions ### Code Style -- **Formatting:** The project uses Spotless with Google Java Format -- **License Headers:** All source files must have Apache 2.0 license headers -- **Line Length:** 100 characters maximum -- **Indentation:** 2 spaces (no tabs) +- Formatting: The project uses Spotless with Google Java Format +- License Headers: All source files must have Apache 2.0 license headers +- Line Length: 100 characters maximum +- Indentation: 2 spaces (no tabs) +- Prefer `var` to avoid type declarations, except for very short type names like `int`, `long` , `String` etc. +- Always use imports for classes instead of full class references. Import classes at the top of the file and use simple class names throughout the code. +- Add unit and/or integration tests for new functionality whenever reasonably possible +- Avoid excessive logging, only add logs to critical parts. Avoid both logging errors and throwing exceptions at the same time. Throwing the error is enough it is logged already somewhere else. +- Do not add comments to the code, except in case of very long or complex logic. +- Always use proper imports instead of fully qualified class names in code. Only use fully qualified names when absolutely necessary to avoid naming collisions. ### Naming Conventions - **Reconcilers:** End with `Reconciler` (e.g., `MyResourceReconciler`) - **Dependent Resources:** End with `DependentResource` (e.g., `ConfigMapDependentResource`) -- **Test Classes:** End with `Test` for unit tests, `IT` for integration tests +- **Test Classes:** End with `Test` for unit tests, `IT` for integration tests, `E2E` for end-to-end testing. - **Custom Resources:** Typically structured as `{Name}Spec`, `{Name}Status`, `{Name}` (the CR class) ### API Design @@ -122,23 +118,21 @@ Results are saved to `target/performance_test_result.json` and include: ### Unit Tests -- Use JUnit 5 -- Mock Kubernetes API interactions using Fabric8's mock server or Mockito +- Use JUnit 6 +- Mock Kubernetes API interactions using Fabric8's mock server or Mockito; or service layer directly - Test reconciliation logic in isolation - Place in `src/test/java` ### Integration Tests - Use `LocallyRunOperatorExtension` or `OperatorExtension` from `operator-framework-junit5` -- Test against real Kubernetes API (typically via test cluster or mock server) +- Test against real Kubernetes API (typically via test cluster like minikube or kind) - Suffix with `IT` (e.g., `MyReconcilerIT`) -- Located in `src/test/java` or `src/it/java` +- Located in `src/test/java` ### Test Resources -- Kubernetes manifests in `src/test/resources` or `src/it/resources` -- Use `@KubernetesResourceYaml` annotation to load test resources -- Custom resources should extend `CustomResource` +- Kubernetes manifests in `src/test/resources` ## Common Patterns @@ -194,7 +188,7 @@ public class ConfigMapDependent extends CRUDKubernetesDependentResource Date: Thu, 12 Feb 2026 09:09:31 +0100 Subject: [PATCH 3/9] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 120000 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index c317064255..0000000000 --- a/CLAUDE.md +++ /dev/null @@ -1 +0,0 @@ -AGENTS.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 0000000000..ac534a3109 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENT.md \ No newline at end of file From 6da32ff1fed08d90ee0b8257ed42864bd0908721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:10:45 +0100 Subject: [PATCH 4/9] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- AGENTS.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index f41f6b1513..f6bc91924e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,9 +53,6 @@ java-operator-sdk/ # Build without tests ./mvnw clean install -DskipTests -# Build without annotation processing (faster for development) -./mvnw clean install -Pno-apt - # Parallel build (uses 1 thread per CPU core) ./mvnw -T1C clean install From 34bafeeb46e99459755d680da2ba3fecdd793188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:11:35 +0100 Subject: [PATCH 5/9] wip MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Attila Mészáros --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index f6bc91924e..ee230271c5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -73,7 +73,7 @@ java-operator-sdk/ ./mvnw test # Run integration tests -./mvnw verify -Pit +./mvnw verify -Pintegration-tests # Run specific test class ./mvnw test -Dtest=ClassName From c16e528fe23de0451292f9502c612df35949ac2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:12:30 +0100 Subject: [PATCH 6/9] Update AGENTS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ee230271c5..10a8c89263 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -91,11 +91,10 @@ java-operator-sdk/ - Line Length: 100 characters maximum - Indentation: 2 spaces (no tabs) - Prefer `var` to avoid type declarations, except for very short type names like `int`, `long` , `String` etc. -- Always use imports for classes instead of full class references. Import classes at the top of the file and use simple class names throughout the code. +- Always use proper imports for classes instead of fully qualified class references. Import classes at the top of the file and use simple class names throughout the code, only using fully qualified names when absolutely necessary to avoid naming collisions. - Add unit and/or integration tests for new functionality whenever reasonably possible - Avoid excessive logging, only add logs to critical parts. Avoid both logging errors and throwing exceptions at the same time. Throwing the error is enough it is logged already somewhere else. - Do not add comments to the code, except in case of very long or complex logic. -- Always use proper imports instead of fully qualified class names in code. Only use fully qualified names when absolutely necessary to avoid naming collisions. ### Naming Conventions From 9c8cc6d14a45127e6efafe46d6bff6d0cf10c2cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:12:42 +0100 Subject: [PATCH 7/9] Update AGENTS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 10a8c89263..4b21876743 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -212,7 +212,7 @@ public class ConfigMapDependent extends CRUDKubernetesDependentResource Date: Thu, 12 Feb 2026 09:12:58 +0100 Subject: [PATCH 8/9] Update AGENTS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 4b21876743..8d29e061d0 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,10 +11,10 @@ Java Operator SDK is a production-ready framework for building Kubernetes Operat - Integration with Fabric8 Kubernetes Client **Key Technologies:** -- Java 17+ (currently Java 25) +- Java 17 (compilation target), validated in CI against Java 17, 21, and 25 - Maven for build management - Fabric8 Kubernetes Client for K8s API access -- JUnit 5 for testing +- JUnit 6 (via `org.junit:junit-bom`) for testing - GitHub Actions for CI/CD ## Project Structure From 0db680bc4c96012e8ad8307d246faec10dc3a1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Thu, 12 Feb 2026 09:13:23 +0100 Subject: [PATCH 9/9] Update AGENTS.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 8d29e061d0..62e19f3b69 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -90,7 +90,7 @@ java-operator-sdk/ - License Headers: All source files must have Apache 2.0 license headers - Line Length: 100 characters maximum - Indentation: 2 spaces (no tabs) -- Prefer `var` to avoid type declarations, except for very short type names like `int`, `long` , `String` etc. +- Prefer `var` to avoid type declarations, except for very short type names like `int`, `long`, `String` etc. - Always use proper imports for classes instead of fully qualified class references. Import classes at the top of the file and use simple class names throughout the code, only using fully qualified names when absolutely necessary to avoid naming collisions. - Add unit and/or integration tests for new functionality whenever reasonably possible - Avoid excessive logging, only add logs to critical parts. Avoid both logging errors and throwing exceptions at the same time. Throwing the error is enough it is logged already somewhere else.