Skip to content

Commit 38df431

Browse files
committed
Remake dry-run=server optional
This is a follow-up on #499 which redoes it without relying on DisableParsing. DisableParsing turned out to break far many things than I imagined!
1 parent 83a48fe commit 38df431

File tree

2 files changed

+52
-88
lines changed

2 files changed

+52
-88
lines changed

cmd/upgrade.go

Lines changed: 29 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
jsonpatch "github.com/evanphx/json-patch"
1414
jsoniterator "github.com/json-iterator/go"
1515
"github.com/spf13/cobra"
16-
"github.com/spf13/pflag"
1716
"helm.sh/helm/v3/pkg/action"
1817
"helm.sh/helm/v3/pkg/cli"
1918
"helm.sh/helm/v3/pkg/kube"
@@ -29,6 +28,10 @@ import (
2928
"github.com/databus23/helm-diff/v3/manifest"
3029
)
3130

31+
const (
32+
dryRunNoOptDefVal = "client"
33+
)
34+
3235
type diffCmd struct {
3336
release string
3437
chart string
@@ -38,8 +41,6 @@ type diffCmd struct {
3841
devel bool
3942
disableValidation bool
4043
disableOpenAPIValidation bool
41-
dryRunMode string
42-
dryRunModeSpecified bool
4344
enableDNS bool
4445
namespace string // namespace to assume the release to be installed into. Defaults to the current kube config namespace.
4546
valueFiles valueFiles
@@ -62,6 +63,14 @@ type diffCmd struct {
6263
kubeVersion string
6364
useUpgradeDryRun bool
6465
diff.Options
66+
67+
// dryRunMode can take the following values:
68+
// - "none": no dry run is performed
69+
// - "client": dry run is performed without remote cluster access
70+
// - "server": dry run is performed with remote cluster access
71+
// - "true": same as "client"
72+
// - "false": same as "none"
73+
dryRunMode string
6574
}
6675

6776
func (d *diffCmd) isAllowUnreleased() bool {
@@ -73,10 +82,9 @@ func (d *diffCmd) isAllowUnreleased() bool {
7382

7483
// clusterAccessAllowed returns true if the diff command is allowed to access the cluster at some degree.
7584
//
76-
// helm-diff basically have 3 modes of operation:
77-
// 1. no cluster access at all when --dry-run, --dry-run=client, or --dry-run=true is specified.
78-
// 2. basic cluster access when --dry-run is not specified.
79-
// 3. extra cluster access when --dry-run=server is specified.
85+
// helm-diff basically have 2 modes of operation:
86+
// 1. without cluster access at all when --dry-run=true or --dry-run=client is specified.
87+
// 2. with cluster access when --dry-run is unspecified, false, or server.
8088
//
8189
// clusterAccessAllowed returns true when the mode is either 2 or 3.
8290
//
@@ -89,8 +97,7 @@ func (d *diffCmd) isAllowUnreleased() bool {
8997
//
9098
// See also https://github.com/helm/helm/pull/9426#discussion_r1181397259
9199
func (d *diffCmd) clusterAccessAllowed() bool {
92-
clientOnly := (d.dryRunModeSpecified && d.dryRunMode == "") || d.dryRunMode == "true" || d.dryRunMode == "client"
93-
return !clientOnly
100+
return d.dryRunMode == "none" || d.dryRunMode == "false" || d.dryRunMode == "server"
94101
}
95102

96103
const globalUsage = `Show a diff explaining what a helm upgrade would change.
@@ -111,10 +118,9 @@ func newChartCommand() *cobra.Command {
111118
unknownFlags := os.Getenv("HELM_DIFF_IGNORE_UNKNOWN_FLAGS") == "true"
112119

113120
cmd := &cobra.Command{
114-
Use: "upgrade [flags] [RELEASE] [CHART]",
115-
Short: "Show a diff explaining what a helm upgrade would change.",
116-
Long: globalUsage,
117-
DisableFlagParsing: true,
121+
Use: "upgrade [flags] [RELEASE] [CHART]",
122+
Short: "Show a diff explaining what a helm upgrade would change.",
123+
Long: globalUsage,
118124
Example: strings.Join([]string{
119125
" helm diff upgrade my-release stable/postgresql --values values.yaml",
120126
"",
@@ -153,71 +159,14 @@ func newChartCommand() *cobra.Command {
153159
"# Read the flag usage below for more information on --context.",
154160
"HELM_DIFF_OUTPUT_CONTEXT=5 helm diff upgrade my-release datadog/datadog",
155161
}, "\n"),
162+
Args: func(cmd *cobra.Command, args []string) error {
163+
return checkArgsLength(len(args), "release name", "chart path")
164+
},
156165
RunE: func(cmd *cobra.Command, args []string) error {
157-
// Note that we can't just move this block to PersistentPreRunE,
158-
// because cmd.SetArgs(args) does not persist between PersistentPreRunE and RunE.
159-
// The choice is between:
160-
// 1. Doing this in RunE
161-
// 2. Doing this in PersistentPreRunE, saving args somewhere, and calling cmd.SetArgs(args) again in RunE
162-
// 2 is more complicated without much benefit, so we choose 1.
163-
{
164-
const (
165-
dryRunUsage = "--dry-run, --dry-run=client, or --dry-run=true disables cluster access and show diff as if it was install. Implies --install, --reset-values, and --disable-validation." +
166-
" --dry-run=server enables the cluster access with helm-get and the lookup template function."
167-
)
168-
169-
cmdFlags := cmd.Flags()
170-
171-
// see: https://github.com/databus23/helm-diff/issues/537
172-
cmdFlags.ParseErrorsWhitelist.UnknownFlags = unknownFlags
173-
174-
legacyDryRunFlagSet := pflag.NewFlagSet("upgrade", pflag.ContinueOnError)
175-
legacyDryRun := legacyDryRunFlagSet.Bool("dry-run", false, dryRunUsage)
176-
if err := legacyDryRunFlagSet.Parse(args); err == nil && *legacyDryRun {
177-
diff.dryRunModeSpecified = true
178-
args = legacyDryRunFlagSet.Args()
179-
} else {
180-
cmdFlags.StringVar(&diff.dryRunMode, "dry-run", "", dryRunUsage)
181-
}
182-
183-
// Here we parse the flags ourselves so that we can support
184-
// both --dry-run and --dry-run=ARG syntaxes.
185-
//
186-
// If you don't do this, then cobra will treat --dry-run as
187-
// a "flag needs an argument: --dry-run" error.
188-
//
189-
// This works becase we have `DisableFlagParsing: true`` above.
190-
// Never turn that off, or you'll get the error again.
191-
if err := cmdFlags.Parse(args); err != nil {
192-
return err
193-
}
194-
195-
args = cmdFlags.Args()
196-
197-
if !diff.dryRunModeSpecified {
198-
dryRunModeSpecified := cmd.Flags().Changed("dry-run")
199-
diff.dryRunModeSpecified = dryRunModeSpecified
200-
201-
if dryRunModeSpecified && !(diff.dryRunMode == "client" || diff.dryRunMode == "server") {
202-
return fmt.Errorf("flag %q must take an argument of %q or %q but got %q", "dry-run", "client", "server", diff.dryRunMode)
203-
}
204-
}
205-
206-
cmd.SetArgs(args)
207-
208-
// We have to do this here because we have to sort out the
209-
// --dry-run flag ambiguity to determine the args to be checked.
210-
//
211-
// In other words, we can't just do:
212-
//
213-
// cmd.Args = func(cmd *cobra.Command, args []string) error {
214-
// return checkArgsLength(len(args), "release name", "chart path")
215-
// }
216-
//
217-
// Because it seems to take precedence over the PersistentPreRunE
218-
if err := checkArgsLength(len(args), "release name", "chart path"); err != nil {
219-
return err
220-
}
166+
if diff.dryRunMode == "" {
167+
diff.dryRunMode = "none"
168+
} else if diff.dryRunMode != "true" && diff.dryRunMode != "false" && diff.dryRunMode != "client" && diff.dryRunMode != "server" {
169+
return fmt.Errorf("flag %q must take a bool value or either %q or %q, but got %q", "dry-run", "client", "server", diff.dryRunMode)
221170
}
222171

223172
// Suppress the command usage on error. See #77 for more info
@@ -293,6 +242,9 @@ func newChartCommand() *cobra.Command {
293242
f.BoolVar(&diff.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
294243
f.BoolVar(&diff.disableValidation, "disable-validation", false, "disables rendered templates validation against the Kubernetes cluster you are currently pointing to. This is the same validation performed on an install")
295244
f.BoolVar(&diff.disableOpenAPIValidation, "disable-openapi-validation", false, "disables rendered templates validation against the Kubernetes OpenAPI Schema")
245+
f.StringVar(&diff.dryRunMode, "dry-run", "", "--dry-run, --dry-run=client, or --dry-run=true disables cluster access and show diff as if it was install. Implies --install, --reset-values, and --disable-validation."+
246+
" --dry-run=server enables the cluster access with helm-get and the lookup template function.")
247+
f.Lookup("dry-run").NoOptDefVal = dryRunNoOptDefVal
296248
f.BoolVar(&diff.enableDNS, "enable-dns", false, "enable DNS lookups when rendering templates")
297249
f.StringVar(&diff.postRenderer, "post-renderer", "", "the path to an executable to be used for post rendering. If it exists in $PATH, the binary will be used, otherwise it will try to look for the executable at the given path")
298250
f.StringArrayVar(&diff.postRendererArgs, "post-renderer-args", []string{}, "an argument to the post-renderer (can specify multiple)")

cmd/upgrade_test.go

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,51 @@ func TestIsRemoteAccessAllowed(t *testing.T) {
99
expected bool
1010
}{
1111
{
12-
name: "no flags",
13-
cmd: diffCmd{},
12+
name: "no flags",
13+
cmd: diffCmd{
14+
dryRunMode: "none",
15+
},
1416
expected: true,
1517
},
1618
{
17-
name: "legacy explicit dry-run flag",
19+
name: "legacy explicit dry-run=true flag",
1820
cmd: diffCmd{
19-
dryRunModeSpecified: true,
20-
dryRunMode: "true",
21+
dryRunMode: "true",
2122
},
2223
expected: false,
2324
},
25+
{
26+
name: "legacy explicit dry-run=false flag",
27+
cmd: diffCmd{
28+
dryRunMode: "false",
29+
},
30+
expected: true,
31+
},
2432
{
2533
name: "legacy empty dry-run flag",
2634
cmd: diffCmd{
27-
dryRunModeSpecified: true,
28-
dryRunMode: "",
35+
dryRunMode: dryRunNoOptDefVal,
36+
},
37+
expected: false,
38+
},
39+
{
40+
name: "client-side dry-run flag",
41+
cmd: diffCmd{
42+
dryRunMode: "client",
2943
},
3044
expected: false,
3145
},
3246
{
3347
name: "server-side dry-run flag",
3448
cmd: diffCmd{
35-
dryRunModeSpecified: true,
36-
dryRunMode: "server",
49+
dryRunMode: "server",
3750
},
3851
expected: true,
3952
},
4053
{
4154
name: "client-side dry-run flag",
4255
cmd: diffCmd{
43-
dryRunModeSpecified: true,
44-
dryRunMode: "client",
56+
dryRunMode: "client",
4557
},
4658
expected: false,
4759
},

0 commit comments

Comments
 (0)