Skip to content

feat: implement helm pull command #101

Open

Description

@bradctrlplus

Background

helm pull downloads a chart from a repository (HTTP or OCI) to the local filesystem, optionally untarring it. Common uses: offline installs, chart inspection, customization, CI caching. See helm pull docs.

Helm SDK action: action.NewPullWithOpts (upstream).

Acceptance criteria

  • Helm.pull("repo/chart").call() downloads to current directory and returns the resulting file Path
  • Builder methods: .withDestination(Path), .untar(), .withUntarDir(String), .withVersion(String)
  • Repo + auth: .withRepo(String), .withUsername(String), .withPassword(String), .passCredentials(), .withRepositoryConfig(Path), .withRepositoryCache(Path)
  • TLS: .withCertFile(Path), .withKeyFile(Path), .withCaFile(Path), .insecureSkipTlsVerify(), .plainHttp()
  • Verification: .verify(), .withKeyring(Path)
  • Versioning: .devel()
  • .debug()
  • Works with oci://... chart references
  • Integration tests use the built-in HTTP and OCI test servers (see Tests below)

Proposed Java API

Path chartFile = Helm.pull("bitnami/nginx")
    .withVersion("15.0.0")
    .withRepo("https://charts.bitnami.com/bitnami")
    .withDestination(Paths.get("/tmp/charts"))
    .untar()
    .call();

Implementation guide

Follow AGENTS.md → "Adding a new Helm command".
Reference impl: ShowCommand + show.go — same shape (chart-keyed, repo + TLS options, uses the shared newRegistryClient helper for OCI).

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

  • Build config with NewCfg(&CfgOptions{...}) — do not construct action.Configuration{} directly. Every other command in the codebase goes through NewCfg; staying consistent is required for kubeconfig / settings handling.
  • Build a registry.Client via the existing newRegistryClient(...) helper in registry.go:94.
  • client := action.NewPullWithOpts(action.WithConfig(cfg)), then set Settings, RepoURL, Version, Username, Password, CertFile, KeyFile, CaFile, InsecureSkipTLSverify, PlainHTTP, Verify, Keyring, Devel, DestDir, Untar, UntarDir, PassCredentialsAll.
  • client.Run(chart) returns (string, error) — the string is helm's CLI output (typically empty for pull). Compute the resulting file/directory path from DestDir + chart filename + version and return it as the first string returned by your helm.Pull(...) function so the Java side can parse it back to Path.

CGO bridge (native/main.go)

  • Add struct PullOptions { ... } alongside other option structs.
  • Add //export Pull wrapping helm.Pull(...) via runCommand(func() (string, error) { ... }). There is no result(...) helper — every other export uses runCommand.

JNA + Java

  • lib/api/.../PullOptions.java: mirror the C struct field order (@Structure.FieldOrder).
  • Add Result Pull(PullOptions options) to HelmLib.
  • helm-java/.../PullCommand.java extends HelmCommand<Path>. call() runs the command and returns Paths.get(result.out.trim()).
  • Add Helm.pull(String chart) static factory. Use HelmLibHolder.INSTANCE directly — it is the HelmLib instance, there is no .helmLib() method.

Tests

  • Location: helm-java/src/test/java/com/marcnuri/helm/HelmPullTest.java.
  • Start a local repo server using the low-level JNA call (the high-level builder isn't exposed) — see HelmTestServerTest for the pattern:
    final Result r = Helm.HelmLibHolder.INSTANCE.RepoServerStart(new RepoServerOptions());
    // r.out contains the URL
  • For OCI, use RepoOciServerStart similarly.
  • Scenario suggestions:
    • Valid: fromRepo, withVersion, withDestination (asserts file exists at expected path), withUntar (asserts directory contents), withRepoUrl, fromOciRegistry
    • Invalid: nonExistentChart, nonExistentVersion
  • No KinD container needed — pull is client-only.

Contributor checklist

  • Java 8 syntax only
  • Apache 2.0 header (or make license)
  • @author Javadoc tag
  • DCO sign-off (git commit -s)
  • make build-native && ./mvnw test -pl helm-java -Dtest=HelmPullTest green

References

Activity

  1. changed the title [-]Implement helm pull[/-] [+]feat: implement helm pull command[/+] on Feb 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions