From d21e87b6398b083a9d49014cef2bed870d81ba0b Mon Sep 17 00:00:00 2001 From: Shane Starcher Date: Sat, 4 Oct 2025 14:43:23 -0400 Subject: [PATCH] feat: add --skip-charts flag to build command Add a --skip-charts flag to the `helmfile build` command to allow users to skip chart preparation, following the same pattern as the list and destroy commands. This addresses an issue where `helmfile build` would run `helm template` on kustomize resources during chart preparation, even though build is meant to be a read-only inspection command. Changes: - Add SkipCharts field to BuildOptions - Add --skip-charts flag to build command CLI - Update StateConfigProvider interface to include SkipCharts() - Update PrintState() to conditionally skip withPreparedCharts when flag is set By default, the flag is false (charts are prepared) to maintain backward compatibility. Users can now run `helmfile build --skip-charts` to get fast output without chart preparation. Signed-off-by: Shane Starcher --- cmd/build.go | 1 + pkg/app/app.go | 43 +++++++++++++++++++++++++------------------ pkg/app/config.go | 1 + pkg/config/build.go | 7 +++++++ 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/cmd/build.go b/cmd/build.go index 8ea0d77b..564ea039 100644 --- a/cmd/build.go +++ b/cmd/build.go @@ -32,6 +32,7 @@ func NewBuildCmd(globalCfg *config.GlobalImpl) *cobra.Command { f := cmd.Flags() f.BoolVar(&buildOptions.EmbedValues, "embed-values", false, "Read all the values files for every release and embed into the output helmfile.yaml") + f.BoolVar(&buildOptions.SkipCharts, "skip-charts", false, "don't prepare charts when building releases") return cmd } diff --git a/pkg/app/app.go b/pkg/app/app.go index aa73fbb2..f36f541f 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -521,11 +521,7 @@ func (a *App) PrintDAGState(c DAGConfigProvider) error { func (a *App) PrintState(c StateConfigProvider) error { return a.ForEachState(func(run *Run) (_ bool, errs []error) { - err := run.withPreparedCharts("build", state.ChartPrepareOptions{ - SkipRepos: true, - SkipDeps: true, - Concurrency: 2, - }, func() { + printState := func() { if c.EmbedValues() { for i := range run.state.Releases { r := run.state.Releases[i] @@ -562,13 +558,22 @@ func (a *App) PrintState(c StateConfigProvider) error { fmt.Printf("---\n# Source: %s\n\n%+v", sourceFile, stateYaml) errs = []error{} - }) - - if err != nil { - errs = append(errs, err) } - return + if !c.SkipCharts() { + err := run.withPreparedCharts("build", state.ChartPrepareOptions{ + SkipRepos: true, + SkipDeps: true, + Concurrency: 2, + }, printState) + if err != nil { + errs = append(errs, err) + } + } else { + printState() + } + + return false, errs }, false, SetFilter(true)) } @@ -592,20 +597,22 @@ func (a *App) ListReleases(c ListConfigProvider) error { var stateReleases []*HelmRelease var err error + listReleases := func() { + rel, err := a.list(run) + if err != nil { + panic(err) + } + stateReleases = rel + } + if !c.SkipCharts() { err = run.withPreparedCharts("list", state.ChartPrepareOptions{ SkipRepos: true, SkipDeps: true, Concurrency: 2, - }, func() { - rel, err := a.list(run) - if err != nil { - panic(err) - } - stateReleases = rel - }) + }, listReleases) } else { - stateReleases, err = a.list(run) + listReleases() } if err != nil { diff --git a/pkg/app/config.go b/pkg/app/config.go index e699d86f..82961d1a 100644 --- a/pkg/app/config.go +++ b/pkg/app/config.go @@ -264,6 +264,7 @@ type StatusesConfigProvider interface { type StateConfigProvider interface { EmbedValues() bool + SkipCharts() bool } type DAGConfigProvider any diff --git a/pkg/config/build.go b/pkg/config/build.go index 26bb6bea..ec648f6a 100644 --- a/pkg/config/build.go +++ b/pkg/config/build.go @@ -4,6 +4,8 @@ package config type BuildOptions struct { // EmbedValues is true if the values should be embedded EmbedValues bool + // SkipCharts makes Build skip `withPreparedCharts` + SkipCharts bool } // NewBuildOptions creates a new Apply @@ -29,3 +31,8 @@ func NewBuildImpl(g *GlobalImpl, b *BuildOptions) *BuildImpl { func (b *BuildImpl) EmbedValues() bool { return b.BuildOptions.EmbedValues } + +// SkipCharts returns skipCharts flag +func (b *BuildImpl) SkipCharts() bool { + return b.BuildOptions.SkipCharts +}