Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
9942882
improve: add license headers to source files (#2980)
csviri Oct 9, 2025
aef4730
chore: version to 5.3.0-SNAPSHOT
csviri Oct 14, 2025
3aa3cbb
Annotation removal using locking (#3015)
shawkins Oct 30, 2025
a4949d0
improve: complete comparable resource version configs (#3027)
csviri Nov 13, 2025
22442ab
improve: run pr-s checks for v5.3 (#3042)
csviri Nov 17, 2025
658423b
fix: rebase on main after release
csviri Dec 1, 2025
d09a575
fix(javadoc): invalid method ref blocks snapshot release (#3076)
csviri Dec 1, 2025
5eb8d10
feat: record desired state in Context (#3082)
metacosm Dec 3, 2025
379e727
improve: rename junit5 module to junit (#3081)
csviri Dec 4, 2025
efc2e8f
fix: delete empty files result of rebase on main (#3093)
csviri Dec 15, 2025
700d642
feat: ReconcileUtils for strongly consistent updates (#3106)
csviri Jan 15, 2026
fdc210d
Event filtering now records resource action and previous resource (#3…
csviri Jan 21, 2026
03073ab
improve: facelift samples to use ReconcileUtils (#3135)
csviri Jan 27, 2026
e17a739
improve: move compare resource version methods to internal utils (#3137)
csviri Jan 28, 2026
f3caf00
feat: move ReconcileUtils methods to ResourceOperations accessible fr…
csviri Feb 2, 2026
258d975
improve: KubernetesDependentResource uses resource operations directl…
csviri Feb 2, 2026
4f1d011
feat: provide de-duplicated secondary resources stream on Context (#3…
metacosm Feb 3, 2026
8fd7ded
refactor: avoid creating intermediate collections when unneeded (#3156)
metacosm Feb 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ on:
paths-ignore:
- 'docs/**'
- 'adr/**'
branches: [ main, next ]
branches: [ main, next, v5.3 ]
push:
paths-ignore:
- 'docs/**'
- 'adr/**'
branches:
- main
- next
- v5.3

jobs:
sample_operators_tests:
Expand Down
2 changes: 1 addition & 1 deletion bootstrapper-maven-plugin/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.2.3-SNAPSHOT</version>
<version>5.3.0-SNAPSHOT</version>
</parent>

<artifactId>bootstrapper</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit-5</artifactId>
<artifactId>operator-framework-junit</artifactId>
<version>${josdk.version}</version>
<scope>test</scope>
</dependency>
Expand Down
4 changes: 2 additions & 2 deletions caffeine-bounded-cache-support/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.2.3-SNAPSHOT</version>
<version>5.3.0-SNAPSHOT</version>
</parent>

<artifactId>caffeine-bounded-cache-support</artifactId>
Expand All @@ -43,7 +43,7 @@
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit-5</artifactId>
<artifactId>operator-framework-junit</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
Expand Down
29 changes: 29 additions & 0 deletions docs/content/en/docs/migration/v5-3-migration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
title: Migrating from v5.2 to v5.3
description: Migrating from v5.2 to v5.3
---


## Renamed JUnit Module

If you use JUnit extension in your test just rename it from:

```
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit-5</artifactId>
<version>5.2.x<version>
<scope>test</scope>
</dependency>
```

to

```
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit</artifactId>
<version>5.3.0<version>
<scope>test</scope>
</dependency>
```
4 changes: 2 additions & 2 deletions micrometer-support/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.2.3-SNAPSHOT</version>
<version>5.3.0-SNAPSHOT</version>
</parent>

<artifactId>micrometer-support</artifactId>
Expand Down Expand Up @@ -58,7 +58,7 @@
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit-5</artifactId>
<artifactId>operator-framework-junit</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
Expand Down
4 changes: 2 additions & 2 deletions operator-framework-bom/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-bom</artifactId>
<version>5.2.3-SNAPSHOT</version>
<version>5.3.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Operator SDK - Bill of Materials</name>
<description>Java SDK for implementing Kubernetes operators</description>
Expand Down Expand Up @@ -77,7 +77,7 @@
</dependency>
<dependency>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>operator-framework-junit-5</artifactId>
<artifactId>operator-framework-junit</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
Expand Down
2 changes: 1 addition & 1 deletion operator-framework-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>io.javaoperatorsdk</groupId>
<artifactId>java-operator-sdk</artifactId>
<version>5.2.3-SNAPSHOT</version>
<version>5.3.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public <P extends HasMetadata> RegisteredController<P> register(
"Cannot register reconciler with name "
+ reconciler.getClass().getCanonicalName()
+ " reconciler named "
+ ReconcilerUtils.getNameFor(reconciler)
+ ReconcilerUtilsInternal.getNameFor(reconciler)
+ " because its configuration cannot be found.\n"
+ " Known reconcilers are: "
+ configurationService.getKnownReconcilerNames());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
import io.fabric8.kubernetes.client.utils.Serialization;
import io.javaoperatorsdk.operator.api.reconciler.Constants;
import io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration;
import io.javaoperatorsdk.operator.api.reconciler.NonComparableResourceVersionException;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;

@SuppressWarnings("rawtypes")
public class ReconcilerUtils {
public class ReconcilerUtilsInternal {

private static final String FINALIZER_NAME_SUFFIX = "/finalizer";
protected static final String MISSING_GROUP_SUFFIX = ".javaoperatorsdk.io";
Expand All @@ -46,7 +47,7 @@ public class ReconcilerUtils {
Pattern.compile(".*http(s?)://[^/]*/api(s?)/(\\S*).*"); // NOSONAR: input is controlled

// prevent instantiation of util class
private ReconcilerUtils() {}
private ReconcilerUtilsInternal() {}

public static boolean isFinalizerValid(String finalizer) {
return HasMetadata.validateFinalizer(finalizer);
Expand Down Expand Up @@ -241,4 +242,123 @@ private static boolean matchesResourceType(
}
return false;
}

/**
* Compares resource versions of two resources. This is a convenience method that extracts the
* resource versions from the metadata and delegates to {@link
* #validateAndCompareResourceVersions(String, String)}.
*
* @param h1 first resource
* @param h2 second resource
* @return negative if h1 is older, zero if equal, positive if h1 is newer
* @throws NonComparableResourceVersionException if either resource version is invalid
*/
public static int validateAndCompareResourceVersions(HasMetadata h1, HasMetadata h2) {
return validateAndCompareResourceVersions(
h1.getMetadata().getResourceVersion(), h2.getMetadata().getResourceVersion());
}

/**
* Compares the resource versions of two Kubernetes resources.
*
* <p>This method extracts the resource versions from the metadata of both resources and delegates
* to {@link #compareResourceVersions(String, String)} for the actual comparison.
*
* @param h1 the first resource to compare
* @param h2 the second resource to compare
* @return a negative integer if h1's version is less than h2's version, zero if they are equal,
* or a positive integer if h1's version is greater than h2's version
* @see #compareResourceVersions(String, String)
*/
public static int compareResourceVersions(HasMetadata h1, HasMetadata h2) {
return compareResourceVersions(
h1.getMetadata().getResourceVersion(), h2.getMetadata().getResourceVersion());
}

/**
* Compares two resource version strings using a length-first, then lexicographic comparison
* algorithm.
*
* <p>The comparison is performed in two steps:
*
* <ol>
* <li>First, compare the lengths of the version strings. A longer version string is considered
* greater than a shorter one. This works correctly for numeric versions because larger
* numbers have more digits (e.g., "100" > "99").
* <li>If the lengths are equal, perform a character-by-character lexicographic comparison until
* a difference is found.
* </ol>
*
* <p>This algorithm is more efficient than parsing the versions as numbers, especially for
* Kubernetes resource versions which are typically monotonically increasing numeric strings.
*
* <p><strong>Note:</strong> This method does not validate that the input strings are numeric. For
* validated numeric comparison, use {@link #validateAndCompareResourceVersions(String, String)}.
*
* @param v1 the first resource version string
* @param v2 the second resource version string
* @return a negative integer if v1 is less than v2, zero if they are equal, or a positive integer
* if v1 is greater than v2
* @see #validateAndCompareResourceVersions(String, String)
*/
public static int compareResourceVersions(String v1, String v2) {
int comparison = v1.length() - v2.length();
if (comparison != 0) {
return comparison;
}
for (int i = 0; i < v2.length(); i++) {
int comp = v1.charAt(i) - v2.charAt(i);
if (comp != 0) {
return comp;
}
}
return 0;
}

/**
* Compares two Kubernetes resource versions numerically. Kubernetes resource versions are
* expected to be numeric strings that increase monotonically. This method assumes both versions
* are valid numeric strings without leading zeros.
*
* @param v1 first resource version
* @param v2 second resource version
* @return negative if v1 is older, zero if equal, positive if v1 is newer
* @throws NonComparableResourceVersionException if either resource version is empty, has leading
* zeros, or contains non-numeric characters
*/
public static int validateAndCompareResourceVersions(String v1, String v2) {
int v1Length = validateResourceVersion(v1);
int v2Length = validateResourceVersion(v2);
int comparison = v1Length - v2Length;
if (comparison != 0) {
return comparison;
}
for (int i = 0; i < v2Length; i++) {
int comp = v1.charAt(i) - v2.charAt(i);
if (comp != 0) {
return comp;
}
}
return 0;
}

private static int validateResourceVersion(String v1) {
int v1Length = v1.length();
if (v1Length == 0) {
throw new NonComparableResourceVersionException("Resource version is empty");
}
for (int i = 0; i < v1Length; i++) {
char char1 = v1.charAt(i);
if (char1 == '0') {
if (i == 0) {
throw new NonComparableResourceVersionException(
"Resource version cannot begin with 0: " + v1);
}
} else if (char1 < '0' || char1 > '9') {
throw new NonComparableResourceVersionException(
"Non numeric characters in resource version: " + v1);
}
}
return v1Length;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,7 @@ private void checkIfStarted() {
public boolean allEventSourcesAreHealthy() {
checkIfStarted();
return registeredControllers.stream()
.filter(rc -> !rc.getControllerHealthInfo().unhealthyEventSources().isEmpty())
.findFirst()
.isEmpty();
.noneMatch(rc -> rc.getControllerHealthInfo().hasUnhealthyEventSources());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
import io.javaoperatorsdk.operator.api.reconciler.Reconciler;

/**
Expand Down Expand Up @@ -145,7 +145,7 @@ private String getReconcilersNameMessage() {
}

protected <R extends HasMetadata> String keyFor(Reconciler<R> reconciler) {
return ReconcilerUtils.getNameFor(reconciler);
return ReconcilerUtilsInternal.getNameFor(reconciler);
}

@SuppressWarnings("unused")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.ReconcilerUtils;
import io.javaoperatorsdk.operator.ReconcilerUtilsInternal;
import io.javaoperatorsdk.operator.api.config.Utils.Configurator;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceConfigurationResolver;
import io.javaoperatorsdk.operator.api.config.dependent.DependentResourceSpec;
Expand Down Expand Up @@ -265,7 +265,7 @@ private <P extends HasMetadata> ResolvedControllerConfiguration<P> controllerCon
io.javaoperatorsdk.operator.api.reconciler.ControllerConfiguration annotation) {
final var resourceClass = getResourceClassResolver().getPrimaryResourceClass(reconcilerClass);

final var name = ReconcilerUtils.getNameFor(reconcilerClass);
final var name = ReconcilerUtilsInternal.getNameFor(reconcilerClass);
final var generationAware =
valueOrDefaultFromAnnotation(
annotation,
Expand Down
Loading