Skip to content

feat(codereadiness): add hook for version-based flag validation#1819

Open
marcin11858 wants to merge 2 commits into
open-feature:mainfrom
marcin11858:feature/codereadiness-hook
Open

feat(codereadiness): add hook for version-based flag validation#1819
marcin11858 wants to merge 2 commits into
open-feature:mainfrom
marcin11858:feature/codereadiness-hook

Conversation

@marcin11858

Copy link
Copy Markdown

Introduce the codereadiness hook to control feature flag evaluation by comparing the application's current version with a required minimum version specified in the flag's metadata. If the comparator returns false the hook returns an error to trigger fallback to the default flag value.

This PR

Introduces the codereadiness hook under hooks/codereadiness to control feature flag evaluation based on the application's running code version.

How it works

  • Compares the application's current version with the required minimum version specified in the flag's metadata (by default, in the minCodeVersion key).
  • If the comparison fails (by default, if the current version in SemVer format is lower than the minimum or invalid), the hook throws a GeneralError to trigger the SDK's fallback mechanism, returning the flag's default value.
  • The hook supports custom comparison logic (via .comparator(...)), custom metadata keys (via .metadataMinVerKey(...)), and optional strict validation (via .validationRequired(...)).

Notes

  • Includes comprehensive JUnit 5 unit tests in CodeReadinessHookTest.java and SemVerComparatorTest.java.
  • Includes a README.md with setup, configuration examples, and dependency setup.

Follow-up Tasks

None.

How to test

Run the module unit tests using Maven from the project root:

mvn test -pl hooks/codereadiness

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@marcin11858, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 11edb532-9b1c-43dd-a42e-beeafe09900f

📥 Commits

Reviewing files that changed from the base of the PR and between 07126e5 and fb741fb.

📒 Files selected for processing (12)
  • .release-please-manifest.json
  • hooks/codereadiness/README.md
  • hooks/codereadiness/pom.xml
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHook.java
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparator.java
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/VersionComparator.java
  • hooks/codereadiness/src/test/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHookTest.java
  • hooks/codereadiness/src/test/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparatorTest.java
  • pom.xml
  • providers/flagd/test-harness
  • release-please-config.json
  • tools/flagd-api-testkit/test-harness
📝 Walkthrough

Walkthrough

Adds a new Maven module hooks/codereadiness implementing an OpenFeature CodeReadinessHook that validates a flag's minimum version metadata against a current version via a pluggable VersionComparator (default SemVerComparator), with tests, README documentation, and build/release configuration updates.

Changes

Codereadiness Hook

Layer / File(s) Summary
VersionComparator interface and SemVerComparator
hooks/codereadiness/src/main/java/.../VersionComparator.java, SemVerComparator.java, hooks/codereadiness/src/test/java/.../SemVerComparatorTest.java
Defines VersionComparator contract and SemVerComparator semver4j-based implementation with parameterized and negative-path tests.
CodeReadinessHook implementation
hooks/codereadiness/src/main/java/.../CodeReadinessHook.java
Implements builder and after() logic validating minimum-version metadata against current version, with strict/non-strict error handling.
Hook test suite
hooks/codereadiness/src/test/java/.../CodeReadinessHookTest.java
Covers pass/fail comparisons, strict-validation for missing metadata/version, custom metadata key, type/empty validation, builder null checks, and comparator error wrapping.
Module build, docs, and release wiring
hooks/codereadiness/pom.xml, hooks/codereadiness/README.md, pom.xml, .release-please-manifest.json, release-please-config.json
Adds module POM and README, registers the module in the root reactor build, and configures release-please for the new package.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant CodeReadinessHook
  participant FlagMetadata
  participant VersionComparator

  Client->>CodeReadinessHook: after(ctx, details, hints)
  CodeReadinessHook->>FlagMetadata: read minCodeVersion
  CodeReadinessHook->>VersionComparator: compare(currentVersion, minCodeVersion)
  VersionComparator-->>CodeReadinessHook: true/false or exception
  CodeReadinessHook-->>Client: pass or GeneralError
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a codereadiness hook for version-based flag validation.
Description check ✅ Passed The description matches the changeset and explains the new hook, tests, and README additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@marcin11858 marcin11858 force-pushed the feature/codereadiness-hook branch from 59cde52 to c8244d9 Compare June 30, 2026 13:09
@marcin11858 marcin11858 force-pushed the feature/codereadiness-hook branch 6 times, most recently from 3e3f136 to 07126e5 Compare July 2, 2026 13:38
@marcin11858 marcin11858 marked this pull request as ready for review July 6, 2026 09:04
@marcin11858 marcin11858 requested a review from a team as a code owner July 6, 2026 09:04
Signed-off-by: Todd Baert <todd.baert@dynatrace.com>
Signed-off-by: Marcin Wlazły <marcinwlazly@google.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHook.java (1)

17-17: 📐 Maintainability & Code Quality | 🔵 Trivial

Use the generic Hook<T> type instead of the raw type.

CodeReadinessHook implements raw Hook, and after(...) uses raw FlagEvaluationDetails and Map. The OpenFeature SDK Hook interface is generic (Hook<T>, with after(HookContext<T>, FlagEvaluationDetails<T>, Map<String, Object>)); using raw types here bypasses compiler type checking and produces unchecked-operation warnings.

♻️ Suggested fix
-public class CodeReadinessHook implements Hook {
+public class CodeReadinessHook implements Hook<Object> {
...
-    public void after(HookContext ctx, FlagEvaluationDetails details, Map hints) {
+    public void after(HookContext<Object> ctx, FlagEvaluationDetails<Object> details, Map<String, Object> hints) {

Also applies to: 47-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHook.java`
at line 17, CodeReadinessHook is using the raw Hook type and raw after(...)
parameters, which bypasses generic type safety and triggers unchecked warnings.
Update CodeReadinessHook to use the generic Hook<T> signature and make its
after(...) method consistently generic with HookContext<T> and
FlagEvaluationDetails<T>, matching the OpenFeature SDK interface. Ensure any
related Map parameter remains properly typed so the class compiles cleanly
without raw-type usage.
hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparator.java (1)

27-27: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use isGreaterThanOrEqualTo here The two comparisons can be collapsed to currentSemver.isGreaterThanOrEqualTo(minCodeVersionSemver).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparator.java`
at line 27, The version comparison in SemVerComparator is doing two separate
checks for greater-than and equality that should be combined. Update the
comparison logic in the relevant semver check to use
currentSemver.isGreaterThanOrEqualTo(minCodeVersionSemver) instead of chaining
isGreaterThan and isEqualTo, keeping the behavior the same while simplifying the
expression.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHook.java`:
- Line 17: CodeReadinessHook is using the raw Hook type and raw after(...)
parameters, which bypasses generic type safety and triggers unchecked warnings.
Update CodeReadinessHook to use the generic Hook<T> signature and make its
after(...) method consistently generic with HookContext<T> and
FlagEvaluationDetails<T>, matching the OpenFeature SDK interface. Ensure any
related Map parameter remains properly typed so the class compiles cleanly
without raw-type usage.

In
`@hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparator.java`:
- Line 27: The version comparison in SemVerComparator is doing two separate
checks for greater-than and equality that should be combined. Update the
comparison logic in the relevant semver check to use
currentSemver.isGreaterThanOrEqualTo(minCodeVersionSemver) instead of chaining
isGreaterThan and isEqualTo, keeping the behavior the same while simplifying the
expression.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 85e7081b-8066-4050-85d0-fab3c0af2747

📥 Commits

Reviewing files that changed from the base of the PR and between c5efaff and 07126e5.

📒 Files selected for processing (10)
  • .release-please-manifest.json
  • hooks/codereadiness/README.md
  • hooks/codereadiness/pom.xml
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHook.java
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparator.java
  • hooks/codereadiness/src/main/java/dev/openfeature/contrib/hooks/codereadiness/VersionComparator.java
  • hooks/codereadiness/src/test/java/dev/openfeature/contrib/hooks/codereadiness/CodeReadinessHookTest.java
  • hooks/codereadiness/src/test/java/dev/openfeature/contrib/hooks/codereadiness/SemVerComparatorTest.java
  • pom.xml
  • release-please-config.json

Introduce the codereadiness hook to control feature flag evaluation
by comparing the application's current version with a required minimum
version specified in the flag's metadata. If the comparator returns
false the hook returns an error to trigger fallback to
the default flag value.

Signed-off-by: Marcin Wlazły <marcinwlazly@google.com>
@marcin11858 marcin11858 force-pushed the feature/codereadiness-hook branch from ef5127e to fb741fb Compare July 6, 2026 09:18
this.comparator = Objects.requireNonNull(comparator, "codereadiness: comparator cannot be null");
}

public static Builder builder(String currentVersion) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither of the parameters are nullable, so why do we enforce non-null only on this one through the builder factory method?

log.debug("flag metadata is null for flag \"{}\", skipping validation", ctx.getFlagKey());
return;
}
Object minVerObj = metadata.asUnmodifiableMap().get(metadataMinVerKey);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Object minVerObj = metadata.asUnmodifiableMap().get(metadataMinVerKey);
Object minVerObj = metadata.getValue(metadataMinVerKey, Object.class);

would this also work? It would reduce the object churn, becaus we don't need to create a view on the HashMap in the background.
Or maybe

Suggested change
Object minVerObj = metadata.asUnmodifiableMap().get(metadataMinVerKey);
Object minVerObj = metadata.getString(metadataMinVerKey);

public class SemVerComparator implements VersionComparator {
@Override
public boolean compare(String currentVersion, String minCodeVersion) throws Exception {
String currentFormatted = currentVersion != null && currentVersion.startsWith("v") ? currentVersion : "v" + currentVersion;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should guard the parameters with an Objects.requireNonNull or similar before we do any operations on them

private static final boolean DEFAULT_STRICT_VALIDATION = false;
private static final VersionComparator DEFAULT_VERSION_COMPARATOR = new SemVerComparator();

private final String currentVersion;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this version cannot change, we should store the parsed version instead, and do comparisons against this stored version. This will save us some resources, becuase we don't need to parse this immutable version on every hook execution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants