Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions cmd/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,38 +130,50 @@ func compatibleHelm3Version() error {
return nil
}

func getRelease(release, namespace string) ([]byte, error) {
func getRelease(release, namespace, kubeContext string) ([]byte, error) {
args := []string{"get", "manifest", release}
if namespace != "" {
args = append(args, "--namespace", namespace)
}
if kubeContext != "" {
args = append(args, "--kube-context", kubeContext)
}
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
return outputWithRichError(cmd)
}

func getHooks(release, namespace string) ([]byte, error) {
func getHooks(release, namespace, kubeContext string) ([]byte, error) {
args := []string{"get", "hooks", release}
if namespace != "" {
args = append(args, "--namespace", namespace)
}
Comment on lines +145 to 149
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

The new kubeContext plumbing in the Helm CLI helper functions (e.g., getRelease/getHooks/getRevision/getChart) is not covered by tests, even though we use a fake HELM_BIN in main_test.go to assert exact argument lists. It would be good to add tests that run a diff command with --kube-context and extend the stubs to expect the --kube-context flag so regressions in how the context is forwarded to Helm are caught early.

Copilot uses AI. Check for mistakes.
if kubeContext != "" {
args = append(args, "--kube-context", kubeContext)
}
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
return outputWithRichError(cmd)
}

func getRevision(release string, revision int, namespace string) ([]byte, error) {
func getRevision(release string, revision int, namespace, kubeContext string) ([]byte, error) {
args := []string{"get", "manifest", release, "--revision", strconv.Itoa(revision)}
if namespace != "" {
args = append(args, "--namespace", namespace)
}
if kubeContext != "" {
args = append(args, "--kube-context", kubeContext)
}
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
return outputWithRichError(cmd)
}

func getChart(release, namespace string) (string, error) {
func getChart(release, namespace, kubeContext string) (string, error) {
args := []string{"get", "all", release, "--template", "{{.Release.Chart.Name}}"}
if namespace != "" {
args = append(args, "--namespace", namespace)
}
if kubeContext != "" {
args = append(args, "--kube-context", kubeContext)
}
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
out, err := outputWithRichError(cmd)
if err != nil {
Expand Down Expand Up @@ -190,6 +202,9 @@ func (d *diffCmd) template(isUpgrade bool) ([]byte, error) {
if d.namespace != "" {
flags = append(flags, "--namespace", d.namespace)
}
if d.kubeContext != "" {
flags = append(flags, "--kube-context", d.kubeContext)
}
Comment on lines 191 to +207
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

template now appends --kube-context (and --namespace) to the Helm CLI flags, but there is no test asserting that these flags are actually passed through. Please add coverage (using the fake HELM_BIN harness) for a helm diff upgrade invocation with --kube-context so changes to this flag wiring do not silently break context selection.

Copilot uses AI. Check for mistakes.
if d.postRenderer != "" {
flags = append(flags, "--post-renderer", d.postRenderer)
}
Expand Down Expand Up @@ -412,6 +427,12 @@ func (d *diffCmd) writeExistingValues(f *os.File, all bool) error {
if all {
args = append(args, "--all")
}
if d.namespace != "" {
args = append(args, "--namespace", d.namespace)
}
if d.kubeContext != "" {
args = append(args, "--kube-context", d.kubeContext)
Comment on lines +430 to +434
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

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

writeExistingValues now forwards --namespace and --kube-context to helm get values, but this behavior is not exercised by tests. Consider adding a test path that triggers value reuse (e.g., --reuse-values/--reset-then-reuse-values) with --kube-context set and updating the fake Helm stubs to expect these flags, to ensure existing-values resolution stays aligned with the selected kube context.

Copilot uses AI. Check for mistakes.
}
cmd := exec.Command(os.Getenv("HELM_BIN"), args...)
debugPrint("Executing %s", strings.Join(cmd.Args, " "))
defer func() {
Expand Down
10 changes: 6 additions & 4 deletions cmd/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
)

type release struct {
kubeContext string
detailedExitCode bool
releases []string
includeTests bool
Expand Down Expand Up @@ -63,6 +64,7 @@ func releaseCmd() *cobra.Command {
releaseCmd.Flags().BoolVar(&diff.detailedExitCode, "detailed-exitcode", false, "return a non-zero exit code when there are changes")
releaseCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
releaseCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
releaseCmd.Flags().StringVar(&diff.kubeContext, "kube-context", "", "name of the kubeconfig context to use")
AddDiffOptions(releaseCmd.Flags(), &diff.Options)

releaseCmd.SuggestionsMinimumDistance = 1
Expand All @@ -82,11 +84,11 @@ func (d *release) differentiateHelm3() error {
namespace1 = strings.Split(release1, "/")[0]
release1 = strings.Split(release1, "/")[1]
}
releaseResponse1, err := getRelease(release1, namespace1)
releaseResponse1, err := getRelease(release1, namespace1, d.kubeContext)
if err != nil {
return err
}
releaseChart1, err := getChart(release1, namespace1)
releaseChart1, err := getChart(release1, namespace1, d.kubeContext)
if err != nil {
return err
}
Expand All @@ -97,11 +99,11 @@ func (d *release) differentiateHelm3() error {
namespace2 = strings.Split(release2, "/")[0]
release2 = strings.Split(release2, "/")[1]
}
releaseResponse2, err := getRelease(release2, namespace2)
releaseResponse2, err := getRelease(release2, namespace2, d.kubeContext)
if err != nil {
return err
}
releaseChart2, err := getChart(release2, namespace2)
releaseChart2, err := getChart(release2, namespace2, d.kubeContext)
if err != nil {
return err
}
Expand Down
10 changes: 6 additions & 4 deletions cmd/revision.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

type revision struct {
release string
kubeContext string
detailedExitCode bool
revisions []string
includeTests bool
Expand Down Expand Up @@ -70,6 +71,7 @@ func revisionCmd() *cobra.Command {
revisionCmd.Flags().BoolVar(&diff.detailedExitCode, "detailed-exitcode", false, "return a non-zero exit code when there are changes")
revisionCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
revisionCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
revisionCmd.Flags().StringVar(&diff.kubeContext, "kube-context", "", "name of the kubeconfig context to use")
AddDiffOptions(revisionCmd.Flags(), &diff.Options)

revisionCmd.SuggestionsMinimumDistance = 1
Expand All @@ -85,14 +87,14 @@ func (d *revision) differentiateHelm3() error {
}
switch len(d.revisions) {
case 1:
releaseResponse, err := getRelease(d.release, namespace)
releaseResponse, err := getRelease(d.release, namespace, d.kubeContext)

if err != nil {
return err
}

revision, _ := strconv.Atoi(d.revisions[0])
revisionResponse, err := getRevision(d.release, revision, namespace)
revisionResponse, err := getRevision(d.release, revision, namespace, d.kubeContext)
if err != nil {
return err
}
Expand All @@ -110,12 +112,12 @@ func (d *revision) differentiateHelm3() error {
revision1, revision2 = revision2, revision1
}

revisionResponse1, err := getRevision(d.release, revision1, namespace)
revisionResponse1, err := getRevision(d.release, revision1, namespace, d.kubeContext)
if err != nil {
return err
}

revisionResponse2, err := getRevision(d.release, revision2, namespace)
revisionResponse2, err := getRevision(d.release, revision2, namespace, d.kubeContext)
if err != nil {
return err
}
Expand Down
6 changes: 4 additions & 2 deletions cmd/rollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

type rollback struct {
release string
kubeContext string
detailedExitCode bool
revisions []string
includeTests bool
Expand Down Expand Up @@ -60,6 +61,7 @@ func rollbackCmd() *cobra.Command {
rollbackCmd.Flags().BoolVar(&diff.detailedExitCode, "detailed-exitcode", false, "return a non-zero exit code when there are changes")
rollbackCmd.Flags().BoolVar(&diff.includeTests, "include-tests", false, "enable the diffing of the helm test hooks")
rollbackCmd.Flags().BoolVar(&diff.normalizeManifests, "normalize-manifests", false, "normalize manifests before running diff to exclude style differences from the output")
rollbackCmd.Flags().StringVar(&diff.kubeContext, "kube-context", "", "name of the kubeconfig context to use")
AddDiffOptions(rollbackCmd.Flags(), &diff.Options)

rollbackCmd.SuggestionsMinimumDistance = 1
Expand All @@ -74,15 +76,15 @@ func (d *rollback) backcastHelm3() error {
excludes = []string{}
}
// get manifest of the latest release
releaseResponse, err := getRelease(d.release, namespace)
releaseResponse, err := getRelease(d.release, namespace, d.kubeContext)

if err != nil {
return err
}

// get manifest of the release to rollback
revision, _ := strconv.Atoi(d.revisions[0])
revisionResponse, err := getRevision(d.release, revision, namespace)
revisionResponse, err := getRevision(d.release, revision, namespace, d.kubeContext)
if err != nil {
return err
}
Expand Down
12 changes: 8 additions & 4 deletions cmd/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ type diffCmd struct {
// - "server": dry run is performed with remote cluster access
// - "true": same as "client"
// - "false": same as "none"
dryRunMode string
dryRunMode string
kubeContext string
}

func (d *diffCmd) isAllowUnreleased() bool {
Expand Down Expand Up @@ -211,7 +212,7 @@ func newChartCommand() *cobra.Command {
var kubeconfig string
f.StringVar(&kubeconfig, "kubeconfig", "", "This flag is ignored, to allow passing of this top level flag to helm")
f.BoolVar(&diff.threeWayMerge, "three-way-merge", false, "use three-way-merge to compute patch and generate diff output")
// f.StringVar(&diff.kubeContext, "kube-context", "", "name of the kubeconfig context to use")
f.StringVar(&diff.kubeContext, "kube-context", "", "name of the kubeconfig context to use")
f.StringVar(&diff.chartVersion, "version", "", "specify the exact chart version to use. If this is not specified, the latest version is used")
f.StringVar(&diff.chartRepo, "repo", "", "specify the chart repository url to locate the requested chart")
f.BoolVar(&diff.detailedExitCode, "detailed-exitcode", false, "return a non-zero exit code when there are changes")
Expand Down Expand Up @@ -270,7 +271,7 @@ func (d *diffCmd) runHelm3() error {
}

if d.clusterAccessAllowed() {
releaseManifest, err = getRelease(d.release, d.namespace)
releaseManifest, err = getRelease(d.release, d.namespace, d.kubeContext)
}

var newInstall bool
Expand All @@ -295,6 +296,9 @@ func (d *diffCmd) runHelm3() error {
var actionConfig *action.Configuration
if d.threeWayMerge || d.takeOwnership {
actionConfig = new(action.Configuration)
if d.kubeContext != "" {
envSettings.KubeContext = d.kubeContext
}
if err := actionConfig.Init(envSettings.RESTClientGetter(), envSettings.Namespace(), os.Getenv("HELM_DRIVER")); err != nil {
log.Fatalf("%+v", err)
}
Expand All @@ -313,7 +317,7 @@ func (d *diffCmd) runHelm3() error {
currentSpecs := make(map[string]*manifest.MappingResult)
if !newInstall && d.clusterAccessAllowed() {
if !d.noHooks && !d.threeWayMerge {
hooks, err := getHooks(d.release, d.namespace)
hooks, err := getHooks(d.release, d.namespace, d.kubeContext)
if err != nil {
return err
}
Expand Down
Loading
Loading