Skip to content

Commit 6623fd7

Browse files
mumoshuyxxhero
andauthored
Remake dry-run=server optional (#547)
* 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! * Remove redundant test case * optimze little code Signed-off-by: yxxhero <[email protected]> --------- Signed-off-by: yxxhero <[email protected]> Co-authored-by: yxxhero <[email protected]>
1 parent 83a48fe commit 6623fd7

File tree

3 files changed

+51
-89
lines changed

3 files changed

+51
-89
lines changed

cmd/upgrade.go

Lines changed: 34 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ import (
77
"fmt"
88
"log"
99
"os"
10+
"slices"
1011
"strconv"
1112
"strings"
1213

1314
jsonpatch "github.com/evanphx/json-patch"
1415
jsoniterator "github.com/json-iterator/go"
1516
"github.com/spf13/cobra"
16-
"github.com/spf13/pflag"
1717
"helm.sh/helm/v3/pkg/action"
1818
"helm.sh/helm/v3/pkg/cli"
1919
"helm.sh/helm/v3/pkg/kube"
@@ -29,6 +29,14 @@ import (
2929
"github.com/databus23/helm-diff/v3/manifest"
3030
)
3131

32+
var (
33+
validDryRunValues = []string{"server", "client", "true", "false"}
34+
)
35+
36+
const (
37+
dryRunNoOptDefVal = "client"
38+
)
39+
3240
type diffCmd struct {
3341
release string
3442
chart string
@@ -38,8 +46,6 @@ type diffCmd struct {
3846
devel bool
3947
disableValidation bool
4048
disableOpenAPIValidation bool
41-
dryRunMode string
42-
dryRunModeSpecified bool
4349
enableDNS bool
4450
namespace string // namespace to assume the release to be installed into. Defaults to the current kube config namespace.
4551
valueFiles valueFiles
@@ -62,6 +68,14 @@ type diffCmd struct {
6268
kubeVersion string
6369
useUpgradeDryRun bool
6470
diff.Options
71+
72+
// dryRunMode can take the following values:
73+
// - "none": no dry run is performed
74+
// - "client": dry run is performed without remote cluster access
75+
// - "server": dry run is performed with remote cluster access
76+
// - "true": same as "client"
77+
// - "false": same as "none"
78+
dryRunMode string
6579
}
6680

6781
func (d *diffCmd) isAllowUnreleased() bool {
@@ -73,10 +87,9 @@ func (d *diffCmd) isAllowUnreleased() bool {
7387

7488
// clusterAccessAllowed returns true if the diff command is allowed to access the cluster at some degree.
7589
//
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.
90+
// helm-diff basically have 2 modes of operation:
91+
// 1. without cluster access at all when --dry-run=true or --dry-run=client is specified.
92+
// 2. with cluster access when --dry-run is unspecified, false, or server.
8093
//
8194
// clusterAccessAllowed returns true when the mode is either 2 or 3.
8295
//
@@ -89,8 +102,7 @@ func (d *diffCmd) isAllowUnreleased() bool {
89102
//
90103
// See also https://github.com/helm/helm/pull/9426#discussion_r1181397259
91104
func (d *diffCmd) clusterAccessAllowed() bool {
92-
clientOnly := (d.dryRunModeSpecified && d.dryRunMode == "") || d.dryRunMode == "true" || d.dryRunMode == "client"
93-
return !clientOnly
105+
return d.dryRunMode == "none" || d.dryRunMode == "false" || d.dryRunMode == "server"
94106
}
95107

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

113125
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,
126+
Use: "upgrade [flags] [RELEASE] [CHART]",
127+
Short: "Show a diff explaining what a helm upgrade would change.",
128+
Long: globalUsage,
118129
Example: strings.Join([]string{
119130
" helm diff upgrade my-release stable/postgresql --values values.yaml",
120131
"",
@@ -153,71 +164,14 @@ func newChartCommand() *cobra.Command {
153164
"# Read the flag usage below for more information on --context.",
154165
"HELM_DIFF_OUTPUT_CONTEXT=5 helm diff upgrade my-release datadog/datadog",
155166
}, "\n"),
167+
Args: func(cmd *cobra.Command, args []string) error {
168+
return checkArgsLength(len(args), "release name", "chart path")
169+
},
156170
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-
}
171+
if diff.dryRunMode == "" {
172+
diff.dryRunMode = "none"
173+
} else if !slices.Contains(validDryRunValues, diff.dryRunMode) {
174+
return fmt.Errorf("flag %q must take a bool value or either %q or %q, but got %q", "dry-run", "client", "server", diff.dryRunMode)
221175
}
222176

223177
// Suppress the command usage on error. See #77 for more info
@@ -293,6 +247,9 @@ func newChartCommand() *cobra.Command {
293247
f.BoolVar(&diff.devel, "devel", false, "use development versions, too. Equivalent to version '>0.0.0-0'. If --version is set, this is ignored.")
294248
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")
295249
f.BoolVar(&diff.disableOpenAPIValidation, "disable-openapi-validation", false, "disables rendered templates validation against the Kubernetes OpenAPI Schema")
250+
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."+
251+
" --dry-run=server enables the cluster access with helm-get and the lookup template function.")
252+
f.Lookup("dry-run").NoOptDefVal = dryRunNoOptDefVal
296253
f.BoolVar(&diff.enableDNS, "enable-dns", false, "enable DNS lookups when rendering templates")
297254
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")
298255
f.StringArrayVar(&diff.postRendererArgs, "post-renderer-args", []string{}, "an argument to the post-renderer (can specify multiple)")

cmd/upgrade_test.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,44 @@ 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,
2936
},
3037
expected: false,
3138
},
3239
{
3340
name: "server-side dry-run flag",
3441
cmd: diffCmd{
35-
dryRunModeSpecified: true,
36-
dryRunMode: "server",
42+
dryRunMode: "server",
3743
},
3844
expected: true,
3945
},
4046
{
4147
name: "client-side dry-run flag",
4248
cmd: diffCmd{
43-
dryRunModeSpecified: true,
44-
dryRunMode: "client",
49+
dryRunMode: "client",
4550
},
4651
expected: false,
4752
},

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ require (
88
github.com/evanphx/json-patch v5.8.1+incompatible
99
github.com/json-iterator/go v1.1.12
1010
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d
11-
github.com/pkg/errors v0.9.1
11+
github.com/pkg/errors v0.9.1 // indirect
1212
github.com/spf13/cobra v1.8.0
1313
github.com/spf13/pflag v1.0.5
1414
github.com/stretchr/testify v1.8.4

0 commit comments

Comments
 (0)