Skip to content

feat: implement helm rollback command #351

@manusa

Description

@manusa

Background

helm rollback reverts a release to a previous revision. Without it, recovering from a bad install/upgrade requires uninstall + re-install, losing release history. See helm rollback docs.

Helm SDK action: action.NewRollback (upstream).

Acceptance criteria

  • Helm.rollback("release").call() rolls a release back one revision and returns the resulting Release
  • .toRevision(int) targets a specific revision; 0 (or unset) = previous
  • Flags supported: --cleanup-on-fail, --dry-run, --force, --no-hooks, --wait, --timeout, --history-max, --namespace, --debug, kube-config (path + contents)
  • Integration tests in HelmKubernetesTest.Rollback (nested class — shares the KinD container)
  • Non-existent release surfaces a meaningful IllegalStateException

Proposed Java API

Release r = Helm.rollback("my-release")
    .toRevision(2)
    .cleanupOnFail()
    .waitReady()
    .withTimeout(300)
    .withKubeConfig(kubeConfigPath)
    .call();

Implementation guide

Follow AGENTS.md → "Adding a new Helm command" for the 9-step workflow.
Reference impl to copy patterns from: StatusCommand — same shape (keyed by release name, returns Release, uses Release.parseSingle()).

Go (native/internal/helm/rollback.go)

  • Build config with NewCfg(&CfgOptions{ KubeConfig, KubeConfigContents, Namespace }) — same as status.go.
  • client := action.NewRollback(cfg). Map options: client.Version (= revision; 0 means previous), CleanupOnFail, DryRun, Force, DisableHooks, Wait, Timeout (time.Duration(seconds) * time.Second), MaxHistory.
  • client.Run(releaseName) returns only an error (no payload).
  • After success, fetch state with action.NewStatus(cfg).Run(name) and return StatusReport(rel, true, options.Debug) — same pattern as status.go.

CGO bridge (native/main.go)

  • Add struct RollbackOptions { ... } next to the other option structs.
  • Add //export Rollback wrapping helm.Rollback(...) via runCommand(func() (string, error) { ... }).

JNA + Java

  • lib/api/.../RollbackOptions.java: mirror the C struct field order exactly (@Structure.FieldOrder).
  • Add Result Rollback(RollbackOptions options) to HelmLib.
  • helm-java/.../RollbackCommand.java extends HelmCommand<Release>; call() returns parseSingle(run(hl -> hl.Rollback(...))).
  • Add Helm.rollback(String releaseName) static factory next to Helm.status(...).

Tests

  • Add as a nested Rollback class inside HelmKubernetesTest, not a separate file — the KinD container is shared via @BeforeAll. Use the static kubeConfigFile / kubeConfigContents fields.
  • Scenario suggestions:
    • Valid: toPreviousRevision (install → upgrade → rollback → assert revision == "3"), toSpecificRevision, withNamespace, withKubeConfigContents
    • Invalid: nonExistentReleaseassertThatThrownBy(cmd::call).hasMessageContaining("release: not found")
  • Skeleton:
    @Nested
    class Rollback {
      @Nested
      class Valid {
        @Test
        void toPreviousRevision() {
          helm.install().withKubeConfig(kubeConfigFile).withName("r1").call();
          helm.upgrade().withKubeConfig(kubeConfigFile).withName("r1").call();
          Release r = Helm.rollback("r1").withKubeConfig(kubeConfigFile).call();
          assertThat(r).returns("3", Release::getRevision);
        }
      }
    }

Contributor checklist

  • Java 8 syntax only (no var, Path.of, records, Map.of)
  • Apache 2.0 header on new files (or run make license)
  • @author Javadoc tag on each new class
  • DCO sign-off on every commit (git commit -s)
  • make build-native && ./mvnw test -pl helm-java -Dtest=HelmKubernetesTest passes locally

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions