Skip to content

refactor(api)!: KubeService throws unchecked domain exceptions (#500)#505

Merged
alexmond merged 1 commit into
mainfrom
feat/api-freeze-kubeservice-exceptions
Jun 25, 2026
Merged

refactor(api)!: KubeService throws unchecked domain exceptions (#500)#505
alexmond merged 1 commit into
mainfrom
feat/api-freeze-kubeservice-exceptions

Conversation

@alexmond

Copy link
Copy Markdown
Owner

First slice of #500 (0.4.0 API freeze) — eliminating throws Exception from the public surface, starting with the KubeService contract.

Why (1.0 blocker)

KubeService declared throws Exception on all 9 methods. After a 1.0 semver commitment that's impossible to narrow without breaking every caller's catch blocks, and it leaked the kubernetes-client ApiException out of HelmKubeService — pinning the client major version into jhelm's API.

What changed

  • KubeService — dropped throws Exception; documents the unchecked JhelmException hierarchy (KubernetesOperationException / ReleaseStorageException / WaitTimeoutException) via @throws.
  • HelmKubeService — translates the client's checked ApiExceptionKubernetesOperationException (preserving the HTTP status code) on every read/delete path; handles InterruptedException in waitForReady; wraps manifest-parse failures. No longer leaks ApiException.
  • RetryableKubeService / ObservableKubeService — dropped throws Exception. The retry predicate already classifies KubernetesOperationException via isTransient(), so retry/observe behavior is unchanged.

⚠️ Breaking change

KubeService methods no longer declare throws Exception. Callers catching the checked Exception should catch JhelmException (or a subtype). Behavior is otherwise identical — this is part of the deliberate pre-1.0 API freeze.

Verification

  • 184 jhelm-kube unit tests green (incl. HelmKubeServiceTest, RetryableKubeServiceTest, ObservableKubeServiceTest)
  • format / PMD / Checkstyle clean on core + kube; full reactor compiles
  • Cluster integration tests run in CI (kind)

Part of #500.

🤖 Generated with Claude Code

…xception (#500)

First slice of the 0.4.0 API freeze. The KubeService contract declared
`throws Exception` on all 9 methods — impossible to narrow after a 1.0 semver
commitment without breaking every caller's catch blocks, and it leaked the
kubernetes-client `ApiException` out of HelmKubeService.

- KubeService: drop `throws Exception`; document the unchecked JhelmException
  hierarchy (KubernetesOperationException / ReleaseStorageException /
  WaitTimeoutException) via @throws instead.
- HelmKubeService: translate the client's checked ApiException into
  KubernetesOperationException (preserving the HTTP status code) in every
  read/delete path; handle InterruptedException in waitForReady; wrap manifest
  parse failures. The public surface no longer leaks ApiException.
- RetryableKubeService / ObservableKubeService: drop `throws Exception`; the
  retry predicate already classifies KubernetesOperationException via
  isTransient(), so retry/observe behaviour is unchanged.

BREAKING CHANGE: KubeService methods no longer declare `throws Exception`.
Callers catching the checked Exception should catch JhelmException (or a
subtype) instead. Behaviour is otherwise identical.

Verified: 184 jhelm-kube unit tests green; format/PMD/Checkstyle clean; full
reactor compiles. Cluster integration tests run in CI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U5yvjG89AqMHPAGJawSmg9
@alexmond alexmond added this to the 0.4.0 milestone Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor
Overall Project 81.24% -0.22% 🍏
Files changed 62.61% 🍏

Module Coverage
jhelm-kube 81.64% -1.27% 🍏
Files
Module File Coverage
jhelm-kube ObservableKubeService.java 97.31% -0.45%
RetryableKubeService.java 96.89% 🍏
HelmKubeService.java 74.62% -2.91% 🍏

@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 50.00000% with 13 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...g/alexmond/jhelm/kube/service/HelmKubeService.java 52.17% 11 Missing ⚠️
...mond/jhelm/kube/service/ObservableKubeService.java 50.00% 1 Missing ⚠️
...xmond/jhelm/kube/service/RetryableKubeService.java 0.00% 0 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@alexmond alexmond merged commit 24da2af into main Jun 25, 2026
1 of 2 checks passed
@alexmond alexmond deleted the feat/api-freeze-kubeservice-exceptions branch June 25, 2026 12:49
@github-actions

Copy link
Copy Markdown
Contributor
Overall Project 81.24% -0.22% 🍏
Files changed 62.61% 🍏

Module Coverage
jhelm-kube 81.64% -1.27% 🍏
Files
Module File Coverage
jhelm-kube ObservableKubeService.java 97.31% -0.45%
RetryableKubeService.java 96.89% 🍏
HelmKubeService.java 74.62% -2.91% 🍏

alexmond added a commit that referenced this pull request Jun 26, 2026
…) (#512)

Second slice of the 0.4.0 API freeze (after #505 did KubeService). Every
public method in core/action/* declared `throws Exception`, which is
impossible to narrow after a 1.0 semver commitment and leaks checked IO/
serialization exceptions out of the public surface.

- ChartLoader.load(File): drop `throws IOException`; wrap internal IO in the
  unchecked ChartLoadException at the public boundary (private loadFromDir
  keeps the IO, also keeps both methods under the MethodLength limit).
- Action layer: drop `throws Exception` from all public methods. Pure
  KubeService delegators (list/status/history/get/rollback/uninstall/test)
  need no body change since #505 already made KubeService unchecked.
- Where a real checked exception remained, wrap into the JhelmException
  hierarchy: Files/tar/HTTP IOException (Create/Package/Verify/SearchHub) and
  Jackson serialization -> JhelmException; the still-checked collaborators
  (HookExecutor.run, PostRenderProcessor.process, LifecycleListener.onEvent)
  are caught and wrapped at the call site (narrowly scoped, so specific
  subtypes like DeploymentFailedException still propagate from the main path).
- Callers: CreateCommand `catch (IOException)` -> `catch (JhelmException)`;
  three tests swap `assertThrows`/Mockito stubs from IOException to
  JhelmException.

BREAKING CHANGE: core/action/* and ChartLoader.load no longer declare
`throws Exception`/`throws IOException`. Callers catching the checked
Exception should catch JhelmException (or a subtype). Behaviour is otherwise
identical.

Verified: full reactor build green — jhelm-core 499, jhelm-cli 171,
jhelm-rest 55 tests, 0 failures; PMD/Checkstyle clean.


Claude-Session: https://claude.ai/code/session_01U5yvjG89AqMHPAGJawSmg9

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
alexmond added a commit that referenced this pull request Jun 26, 2026
Third slice of the 0.4.0 API freeze. HelmKubeService.listPods and
installConfigMap were the last two public methods declaring the
kubernetes-client checked `ApiException`, pinning the client major version
into jhelm's public API (the interface methods were already cleaned in #505).

- listPods: translate ApiException -> KubernetesOperationException (preserving
  the HTTP status code); drop `throws ApiException`.
- installConfigMap: replace the broad `catch (Exception)` + raw re-throw with
  a precise `catch (ApiException)`. The 409 replace path is extracted to a
  private replaceConfigMap that also translates its ApiException (it was a
  second uncaught leak). Drop `throws ApiException`.
- Test: testInstallConfigMapThrowsOnOtherApiError now asserts
  KubernetesOperationException instead of ApiException.

Both methods have no production callers (test-only today) but are intentional
public API with unit + integration coverage, so they're wrapped, not removed.

BREAKING CHANGE: HelmKubeService.listPods/installConfigMap no longer declare
`throws ApiException`; failures surface as the unchecked
KubernetesOperationException (carrying the HTTP status). The kubernetes-client
ApiException no longer appears anywhere on jhelm's public method surface.

Verified: jhelm-kube 191 tests green; jhelm-cli/jhelm-rest build clean;
PMD/Checkstyle clean.


Claude-Session: https://claude.ai/code/session_01U5yvjG89AqMHPAGJawSmg9

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant