feat: Allow overriding chart via flag (#1751)

Adds `--chart` flag for overriding the selected release's chart ad-hoc-ly like `helmfile --chart $CHART template`.
This is handy when e.g. you want to have an ArgoCD application per each release in your helmfile.yaml, while also providing the ability to customize the release's chart without touching helmfile.yaml.

See https://github.com/roboll/helmfile/issues/1690#issuecomment-812321354 for more context.

Closes #1690
This commit is contained in:
Yujun Zhang 2021-04-06 12:20:41 +08:00 committed by GitHub
parent 261367e7e9
commit a161796dc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 34 additions and 1 deletions

View File

@ -89,6 +89,10 @@ func main() {
Name: "namespace, n", Name: "namespace, n",
Usage: "Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}", Usage: "Set namespace. Uses the namespace set in the context by default, and is available in templates as {{ .Namespace }}",
}, },
cli.StringFlag{
Name: "chart, c",
Usage: "Set chart. Uses the chart set in release by default, and is available in template as {{ .Chart }}",
},
cli.StringSliceFlag{ cli.StringSliceFlag{
Name: "selector, l", Name: "selector, l",
Usage: `Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar. Usage: `Only run using the releases that match labels. Labels can take the form of foo=bar or foo!=bar.
@ -776,6 +780,10 @@ func (c configImpl) Namespace() string {
return c.c.GlobalString("namespace") return c.c.GlobalString("namespace")
} }
func (c configImpl) Chart() string {
return c.c.GlobalString("chart")
}
func (c configImpl) FileOrDir() string { func (c configImpl) FileOrDir() string {
return c.c.GlobalString("file") return c.c.GlobalString("file")
} }

View File

@ -30,6 +30,7 @@ type App struct {
Logger *zap.SugaredLogger Logger *zap.SugaredLogger
Env string Env string
Namespace string Namespace string
Chart string
Selectors []string Selectors []string
Args string Args string
ValuesFiles []string ValuesFiles []string
@ -72,6 +73,7 @@ func New(conf ConfigProvider) *App {
Logger: conf.Logger(), Logger: conf.Logger(),
Env: conf.Env(), Env: conf.Env(),
Namespace: conf.Namespace(), Namespace: conf.Namespace(),
Chart: conf.Chart(),
Selectors: conf.Selectors(), Selectors: conf.Selectors(),
Args: conf.Args(), Args: conf.Args(),
FileOrDir: conf.FileOrDir(), FileOrDir: conf.FileOrDir(),
@ -640,6 +642,7 @@ func (a *App) loadDesiredStateFromYaml(file string, opts ...LoadOpts) (*state.He
directoryExistsAt: a.directoryExistsAt, directoryExistsAt: a.directoryExistsAt,
env: a.Env, env: a.Env,
namespace: a.Namespace, namespace: a.Namespace,
chart: a.Chart,
logger: a.Logger, logger: a.Logger,
abs: a.abs, abs: a.abs,
remote: a.remote, remote: a.remote,

View File

@ -9,6 +9,7 @@ type ConfigProvider interface {
FileOrDir() string FileOrDir() string
KubeContext() string KubeContext() string
Namespace() string Namespace() string
Chart() string
Selectors() []string Selectors() []string
StateValuesSet() map[string]interface{} StateValuesSet() map[string]interface{}
StateValuesFiles() []string StateValuesFiles() []string

View File

@ -25,6 +25,7 @@ type desiredStateLoader struct {
env string env string
namespace string namespace string
chart string
readFile func(string) ([]byte, error) readFile func(string) ([]byte, error)
deleteFile func(string) error deleteFile func(string) error
@ -82,6 +83,13 @@ func (ld *desiredStateLoader) Load(f string, opts LoadOpts) (*state.HelmState, e
st.OverrideNamespace = ld.namespace st.OverrideNamespace = ld.namespace
} }
if ld.chart != "" {
if st.OverrideChart != "" {
return nil, errors.New("err: Cannot use option --chart and set attribute chart.")
}
st.OverrideChart = ld.chart
}
return st, nil return st, nil
} }

View File

@ -3,11 +3,12 @@ package app
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"strings"
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/roboll/helmfile/pkg/environment" "github.com/roboll/helmfile/pkg/environment"
"github.com/roboll/helmfile/pkg/state" "github.com/roboll/helmfile/pkg/state"
"github.com/roboll/helmfile/pkg/tmpl" "github.com/roboll/helmfile/pkg/tmpl"
"strings"
) )
func prependLineNumbers(text string) string { func prependLineNumbers(text string) string {

View File

@ -32,6 +32,7 @@ type Bus struct {
BasePath string BasePath string
StateFilePath string StateFilePath string
Namespace string Namespace string
Chart string
Env environment.Environment Env environment.Environment

View File

@ -54,6 +54,7 @@ type ReleaseSetSpec struct {
DeprecatedContext string `yaml:"context,omitempty"` DeprecatedContext string `yaml:"context,omitempty"`
DeprecatedReleases []ReleaseSpec `yaml:"charts,omitempty"` DeprecatedReleases []ReleaseSpec `yaml:"charts,omitempty"`
OverrideNamespace string `yaml:"namespace,omitempty"` OverrideNamespace string `yaml:"namespace,omitempty"`
OverrideChart string `yaml:"chart,omitempty"`
Repositories []RepositorySpec `yaml:"repositories,omitempty"` Repositories []RepositorySpec `yaml:"repositories,omitempty"`
CommonLabels map[string]string `yaml:"commonLabels,omitempty"` CommonLabels map[string]string `yaml:"commonLabels,omitempty"`
Releases []ReleaseSpec `yaml:"releases,omitempty"` Releases []ReleaseSpec `yaml:"releases,omitempty"`
@ -999,6 +1000,9 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
}, },
func(workerIndex int) { func(workerIndex int) {
for release := range jobQueue { for release := range jobQueue {
if st.OverrideChart != "" {
release.Chart = st.OverrideChart
}
// Call user-defined `prepare` hooks to create/modify local charts to be used by // Call user-defined `prepare` hooks to create/modify local charts to be used by
// the later process. // the later process.
// //
@ -2062,6 +2066,7 @@ func (st *HelmState) triggerGlobalReleaseEvent(evt string, evtErr error, helmfil
StateFilePath: st.FilePath, StateFilePath: st.FilePath,
BasePath: st.basePath, BasePath: st.basePath,
Namespace: st.OverrideNamespace, Namespace: st.OverrideNamespace,
Chart: st.OverrideChart,
Env: st.Env, Env: st.Env,
Logger: st.logger, Logger: st.logger,
ReadFile: st.readFile, ReadFile: st.readFile,
@ -2094,6 +2099,7 @@ func (st *HelmState) triggerReleaseEvent(evt string, evtErr error, r *ReleaseSpe
StateFilePath: st.FilePath, StateFilePath: st.FilePath,
BasePath: st.basePath, BasePath: st.basePath,
Namespace: st.OverrideNamespace, Namespace: st.OverrideNamespace,
Chart: st.OverrideChart,
Env: st.Env, Env: st.Env,
Logger: st.logger, Logger: st.logger,
ReadFile: st.readFile, ReadFile: st.readFile,

View File

@ -20,6 +20,7 @@ func (st *HelmState) createReleaseTemplateData(release *ReleaseSpec, vals map[st
tmplData := releaseTemplateData{ tmplData := releaseTemplateData{
Environment: st.Env, Environment: st.Env,
Namespace: st.OverrideNamespace, Namespace: st.OverrideNamespace,
Chart: st.OverrideChart,
Values: vals, Values: vals,
Release: releaseTemplateDataRelease{ Release: releaseTemplateDataRelease{
Name: release.Name, Name: release.Name,

View File

@ -34,6 +34,10 @@ type releaseTemplateData struct {
// You should better use Release.Namespace as it might work as you'd expect even if OverrideNamespace is not set. // You should better use Release.Namespace as it might work as you'd expect even if OverrideNamespace is not set.
// See releaseTemplateDataRelease.Namespace for more information. // See releaseTemplateDataRelease.Namespace for more information.
Namespace string Namespace string
// Chart is HelmState.OverrideChart.
// You should better use Release.Chart as it might work as you'd expect even if OverrideChart is not set.
// See releaseTemplateDataRelease.Chart for more information.
Chart string
} }
type releaseTemplateDataRelease struct { type releaseTemplateDataRelease struct {