Add helmfile template --show-only (#1494)

Add a `--show-only` parameter to the `helmfile template` command to pass
on to the `helm template` command.

Signed-off-by: Jim Barber <jim.barber@healthengine.com.au>
This commit is contained in:
jim-barber-he 2024-05-12 07:02:02 +08:00 committed by GitHub
parent f2a0467b05
commit f73da1e2a1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 191 additions and 0 deletions

View File

@ -47,6 +47,7 @@ func NewTemplateCmd(globalCfg *config.GlobalImpl) *cobra.Command {
f.StringVar(&templateOptions.PostRenderer, "post-renderer", "", `pass --post-renderer to "helm template" or "helm upgrade --install"`)
f.StringArrayVar(&templateOptions.PostRendererArgs, "post-renderer-args", nil, `pass --post-renderer-args to "helm template" or "helm upgrade --install"`)
f.StringVar(&templateOptions.KubeVersion, "kube-version", "", `pass --kube-version to "helm template". Overrides kubeVersion in helmfile.yaml`)
f.StringArrayVar(&templateOptions.ShowOnly, "show-only", nil, `pass --show-only to "helm template"`)
return cmd
}

View File

@ -1964,6 +1964,7 @@ func (a *App) template(r *Run, c TemplateConfigProvider) (bool, []error) {
PostRenderer: c.PostRenderer(),
PostRendererArgs: c.PostRendererArgs(),
KubeVersion: c.KubeVersion(),
ShowOnly: c.ShowOnly(),
}
return st.TemplateReleases(helm, c.OutputDir(), c.Values(), args, c.Concurrency(), c.Validate(), opts)
})

View File

@ -24,6 +24,7 @@ func TestTemplate(t *testing.T) {
skipNeeds bool
includeNeeds bool
includeTransitiveNeeds bool
showOnly []string
}
type testcase struct {
@ -131,6 +132,7 @@ releases:
skipNeeds: tc.fields.skipNeeds,
includeNeeds: tc.fields.includeNeeds,
includeTransitiveNeeds: tc.fields.includeTransitiveNeeds,
showOnly: tc.fields.showOnly,
})
var gotErr string
@ -304,6 +306,18 @@ releases:
error: "err: no releases found that matches specified selector(app=test_non_existent) and environment(default), in any helmfile",
})
})
t.Run("show-only", func(t *testing.T) {
check(t, testcase{
fields: fields{
showOnly: []string{"templates/resources.yaml"},
},
selectors: []string{"name=logging"},
templated: []exectest.Release{
{Name: "logging", Flags: []string{"--show-only", "templates/resources.yaml", "--namespace", "kube-system"}},
},
})
})
}
func TestTemplate_StrictParsing(t *testing.T) {

View File

@ -2189,6 +2189,10 @@ func (c configImpl) KubeVersion() string {
return c.kubeVersion
}
func (c configImpl) ShowOnly() []string {
return nil
}
type applyConfig struct {
args string
cascade string
@ -2230,6 +2234,7 @@ type applyConfig struct {
postRendererArgs []string
kubeVersion string
suppressOutputLineRegex []string
showOnly []string
// template-only options
includeCRDs, skipTests bool
@ -2406,6 +2411,10 @@ func (a applyConfig) KubeVersion() string {
return a.kubeVersion
}
func (a applyConfig) ShowOnly() []string {
return a.showOnly
}
type depsConfig struct {
skipRepos bool
includeTransitiveNeeds bool

View File

@ -233,6 +233,7 @@ type TemplateConfigProvider interface {
OutputDir() string
IncludeCRDs() bool
KubeVersion() string
ShowOnly() []string
DAGConfig

View File

@ -0,0 +1,113 @@
processing file "helmfile.yaml" in directory "."
changing working directory to "/path/to"
first-pass rendering starting for "helmfile.yaml.part.0": inherited=&{default map[] map[]}, overrode=<nil>
first-pass uses: &{default map[] map[]}
first-pass rendering output of "helmfile.yaml.part.0":
0:
1: releases:
2: - name: logging
3: chart: incubator/raw
4: namespace: kube-system
5:
6: - name: kubernetes-external-secrets
7: chart: incubator/raw
8: namespace: kube-system
9: needs:
10: - kube-system/logging
11:
12: - name: external-secrets
13: chart: incubator/raw
14: namespace: default
15: labels:
16: app: test
17: needs:
18: - kube-system/kubernetes-external-secrets
19:
20: - name: my-release
21: chart: incubator/raw
22: namespace: default
23: labels:
24: app: test
25: needs:
26: - default/external-secrets
27:
28:
29: # Disabled releases are treated as missing
30: - name: disabled
31: chart: incubator/raw
32: namespace: kube-system
33: installed: false
34:
35: - name: test2
36: chart: incubator/raw
37: needs:
38: - kube-system/disabled
39:
40: - name: test3
41: chart: incubator/raw
42: needs:
43: - test2
44:
first-pass produced: &{default map[] map[]}
first-pass rendering result of "helmfile.yaml.part.0": {default map[] map[]}
vals:
map[]
defaultVals:[]
second-pass rendering result of "helmfile.yaml.part.0":
0:
1: releases:
2: - name: logging
3: chart: incubator/raw
4: namespace: kube-system
5:
6: - name: kubernetes-external-secrets
7: chart: incubator/raw
8: namespace: kube-system
9: needs:
10: - kube-system/logging
11:
12: - name: external-secrets
13: chart: incubator/raw
14: namespace: default
15: labels:
16: app: test
17: needs:
18: - kube-system/kubernetes-external-secrets
19:
20: - name: my-release
21: chart: incubator/raw
22: namespace: default
23: labels:
24: app: test
25: needs:
26: - default/external-secrets
27:
28:
29: # Disabled releases are treated as missing
30: - name: disabled
31: chart: incubator/raw
32: namespace: kube-system
33: installed: false
34:
35: - name: test2
36: chart: incubator/raw
37: needs:
38: - kube-system/disabled
39:
40: - name: test3
41: chart: incubator/raw
42: needs:
43: - test2
44:
merged environment: &{default map[] map[]}
WARNING: release test2 needs disabled, but disabled is not installed due to installed: false. Either mark disabled as installed or remove disabled from test2's needs
1 release(s) matching name=logging found in helmfile.yaml
processing 1 groups of releases in this order:
GROUP RELEASES
1 default/kube-system/logging
processing releases in group 1/1: default/kube-system/logging
changing working directory back to "/path/to"

View File

@ -38,6 +38,8 @@ type TemplateOptions struct {
PostRendererArgs []string
// KubeVersion is the kube-version flag
KubeVersion string
// Propagate '--show-only` to helm template
ShowOnly []string
}
// NewTemplateOptions creates a new Apply
@ -137,3 +139,8 @@ func (t *TemplateImpl) PostRendererArgs() []string {
func (t *TemplateImpl) KubeVersion() string {
return t.TemplateOptions.KubeVersion
}
// ShowOnly returns the ShowOnly.
func (t *TemplateImpl) ShowOnly() []string {
return t.TemplateOptions.ShowOnly
}

View File

@ -119,6 +119,20 @@ func (st *HelmState) appendCascadeFlags(flags []string, helm helmexec.Interface,
return flags
}
// append show-only flags to helm flags
func (st *HelmState) appendShowOnlyFlags(flags []string, showOnly []string) []string {
showOnlyFlags := []string{}
if len(showOnly) != 0 {
showOnlyFlags = showOnly
}
for _, arg := range showOnlyFlags {
if arg != "" {
flags = append(flags, "--show-only", arg)
}
}
return flags
}
type Chartify struct {
Opts *chartify.ChartifyOpts
Clean func()

View File

@ -249,3 +249,30 @@ func TestAppendSuppressOutputLineRegexFlags(t *testing.T) {
})
}
}
func TestAppendShowOnlyFlags(t *testing.T) {
tests := []struct {
name string
templateOpts []string
expected []string
}{
{
name: "cli template show only with 1 file",
templateOpts: []string{"templates/config.yaml"},
expected: []string{"--show-only", "templates/config.yaml"},
},
{
name: "cli template show only with 2 files",
templateOpts: []string{"templates/config.yaml", "templates/resources.yaml"},
expected: []string{"--show-only", "templates/config.yaml", "--show-only", "templates/resources.yaml"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
st := &HelmState{}
got := st.appendShowOnlyFlags([]string{}, tt.templateOpts)
require.Equalf(t, tt.expected, got, "appendShowOnlyFlags() = %v, want %v", got, tt.expected)
})
}
}

View File

@ -1437,6 +1437,7 @@ type TemplateOpts struct {
PostRenderer string
PostRendererArgs []string
KubeVersion string
ShowOnly []string
}
type TemplateOpt interface{ Apply(*TemplateOpts) }
@ -2691,15 +2692,18 @@ func (st *HelmState) flagsForTemplate(helm helmexec.Interface, release *ReleaseS
postRenderer := ""
var postRendererArgs []string
kubeVersion := ""
var showOnly []string
if opt != nil {
postRenderer = opt.PostRenderer
postRendererArgs = opt.PostRendererArgs
kubeVersion = opt.KubeVersion
showOnly = opt.ShowOnly
}
flags = st.appendPostRenderFlags(flags, release, postRenderer)
flags = st.appendPostRenderArgsFlags(flags, release, postRendererArgs)
flags = st.appendApiVersionsFlags(flags, release, kubeVersion)
flags = st.appendChartDownloadTLSFlags(flags, release)
flags = st.appendShowOnlyFlags(flags, showOnly)
common, files, err := st.namespaceAndValuesFlags(helm, release, workerIndex)
if err != nil {