Feature flag: rolling-updates
keycloak/keycloak#36882
Golden recall: 100%
Extra findings: 4
Golden Comments (1/1 found)
| # | Comment | Severity | Status | FriendlyReviewer Detail |
|---|---|---|---|---|
| #1 | Incorrect method call for exit codes. picocli.exit() calls System.exit() directly, which is problematic in test mode |
HIGH | ✓ Found | FR found the bug and dug deeper: picocli.exit() does NOT call System.exit in test mode, so cmd.execute() returns 0 instead of 4 — the test passes when it should fail. Upgraded from Medium to HIGH. |
Supplementary Findings (6 findings)
| Finding | File | Severity | Legitimate? |
|---|---|---|---|
BREAKING CHANGE: RECREATE_UPGRADE_EXIT_CODE changed from 4 to 3 — any code checking literal 4 will misinterpret it | CompatibilityResult.java:32 | HIGH | ✓ Real undocumented breaking change |
Feature-spec setup in UpgradeTest placed after early return for null strategy — rolling-update flag not activated for that test | UpgradeTest.java:104 | HIGH | ✓ Critical test bug |
Boilerplate feature-gating duplicated in both subcommands — should be centralized in AbstractUpdatesCommand | AbstractUpdatesCommand.java:43 | MEDIUM | ✓ Unnecessary duplication |
Inconsistent exit behavior: UpdateCompatibilityCheck calls picocli.exit(), UpdateCompatibilityMetadata does not | UpdateCompatibilityMetadata.java:54 | MEDIUM | ✓ Both should follow same pattern |
printFeatureDisabled() hardcodes "rolling-updates" and is package-private — should be parameterizable and protected | AbstractUpdatesCommand.java:83 | LOW | ✓ Lack of flexibility |
testImageChange parameterized but always calls eventuallyRecreateUpgradeStatus regardless of parameter | UpgradeTest.java:66 | LOW | ✓ Unused parameter |
Honest Analysis
FriendlyReviewer's full review
As posted on the PR — the complete output from FriendlyReviewer.
Hi there 👋
| 🌥️ Tech |
|---|
| 3 high, 2 medium, 2 low |
The merge request introduces a ROLLING_UPDATES preview feature flag and associated CLI commands (UpdateCompatibilityCheck, UpdateCompatibilityMetadata) with an AbstractUpdatesCommand base class, plus an operator integration test (UpgradeTest). While the core feature addition is sound, several issues require attention:
- Breaking change:
CompatibilityResult.RECREATE_UPGRADE_EXIT_CODEchanged from 4 to 3; any consumer checking the literal value 4 will misinterpret it. - Test mode exit code masking: The feature-disabled path in both CLI commands uses
picocli.exit()which is a no-op in test mode, causing tests to incorrectly pass with exit code 0 instead of 4. - Duplicated feature-gating boilerplate: Both subcommands repeat identical logic that should be centralized in
AbstractUpdatesCommand. - Hardcoded feature name:
printFeatureDisabled()hardcodes"rolling-updates"and is package-private, hindering reuse. - Inconsistent exit behavior:
UpdateCompatibilityCheckexplicitly callspicocli.exit()on success, whileUpdateCompatibilityMetadatadoes not. - Critical operator test bug:
UpgradeTestsetsFeatureSpecafter an early return for null strategy, so the rolling-update feature is not enabled for that test case, causing expected failures. - Minor redundancy:
testImageChangeparameterization is unused since it always callseventuallyRecreateUpgradeStatus.
The Profile.java change adding the ROLLING_UPDATES enum constant is correct and follows conventions.
FriendlyReviewer detected the single golden bug and actually analyzed it more deeply: the golden described
picocli.exit()as callingSystem.exit(), but FriendlyReviewer correctly noted that in test mode the call is a no-op, socmd.execute()returns 0 instead of 4 — the test passes for the wrong reason.The 6 supplementary findings include two real HIGH-severity issues: the breaking change from exit code 4 to 3 (any consumer checking the literal value 4 will break), and the operator test bug where the feature flag setup is placed after an early return, making the test meaningless.
The finding about inconsistent exit behavior between the two subcommands is a legitimate design concern — one calls
picocli.exit(), the other does not, and there is no justification for the difference.