test: add test for prepare charts with template args

Signed-off-by: Kerstin Albers <kerstinzuzej@gmail.com>
This commit is contained in:
Kerstin Albers 2025-02-21 13:47:46 +01:00
parent 2e52967d68
commit 228aab70a9
3 changed files with 134 additions and 11 deletions

View File

@ -8,6 +8,7 @@ import (
"strings"
"github.com/fatih/color"
"github.com/helmfile/chartify"
"github.com/helmfile/helmfile/pkg/helmexec"
"github.com/helmfile/helmfile/pkg/state"
@ -42,6 +43,14 @@ func (r *Run) askForConfirmation(msg string) bool {
return AskForConfirmation(msg)
}
type Chartifier struct {
runner *chartify.Runner
}
func (c *Chartifier) Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
return c.runner.Chartify(release, dirOrChart, opts...)
}
func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurrency int, opts state.ChartPrepareOptions) (map[state.PrepareChartKey]string, error) {
// Skip chart preparation for certain commands
skipCommands := []string{"write-values", "list"}
@ -49,7 +58,15 @@ func (r *Run) prepareChartsIfNeeded(helmfileCommand string, dir string, concurre
return nil, nil
}
releaseToChart, errs := r.state.PrepareCharts(r.helm, dir, concurrency, helmfileCommand, opts)
chartifier := &Chartifier{
runner: chartify.New(
chartify.HelmBin(r.state.DefaultHelmBinary),
chartify.KustomizeBin(r.state.DefaultKustomizeBinary),
chartify.UseHelm3(true),
chartify.WithLogf(r.state.Logger().Debugf)),
}
releaseToChart, errs := r.state.PrepareCharts(r.helm, chartifier, dir, concurrency, helmfileCommand, opts)
if len(errs) > 0 {
return nil, fmt.Errorf("%v", errs)
}

View File

@ -1209,6 +1209,16 @@ type PrepareChartKey struct {
Namespace, Name, KubeContext string
}
func (st *HelmState) Logger() *zap.SugaredLogger {
return st.logger
}
type Chartifier interface {
// Chartify creates a temporary Helm chart from a directory or a remote chart, and applies various transformations.
// Returns the full path to the temporary directory containing the generated chart if succeeded.
Chartify(release, dirOrChart string, opts ...chartify.ChartifyOption) (string, error)
}
// PrepareCharts creates temporary directories of charts.
//
// Each resulting "chart" can be one of the followings:
@ -1220,10 +1230,10 @@ type PrepareChartKey struct {
// When running `helmfile template` on helm v2, or `helmfile lint` on both helm v2 and v3,
// PrepareCharts will download and untar charts for linting and templating.
//
// Otheriwse, if a chart is not a helm chart, it will call "chartify" to turn it into a chart.
// Otherwise, if a chart is not a helm chart, it will call "chartify" to turn it into a chart.
//
// If exists, it will also patch resources by json patches, strategic-merge patches, and injectors.
func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) {
func (st *HelmState) PrepareCharts(helm helmexec.Interface, chartifier Chartifier, dir string, concurrency int, helmfileCommand string, opts ChartPrepareOptions) (map[PrepareChartKey]string, []error) {
if !opts.SkipResolve {
updated, err := st.ResolveDeps()
if err != nil {
@ -1317,13 +1327,6 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
skipDeps := (!isLocal && !chartFetchedByGoGetter) || skipDepsGlobal || skipDepsRelease || skipDepsDefault
if chartification != nil && helmfileCommand != "pull" {
c := chartify.New(
chartify.HelmBin(st.DefaultHelmBinary),
chartify.KustomizeBin(st.DefaultKustomizeBinary),
chartify.UseHelm3(true),
chartify.WithLogf(st.logger.Debugf),
)
chartifyOpts := chartification.Opts
if skipDeps {
@ -1357,7 +1360,7 @@ func (st *HelmState) PrepareCharts(helm helmexec.Interface, dir string, concurre
}
chartifyOpts.SetFlags = append(chartifyOpts.SetFlags, flags...)
out, err := c.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts))
out, err := chartifier.Chartify(release.Name, chartPath, chartify.WithChartifyOpts(chartifyOpts))
if err != nil {
results <- &chartPrepareResult{err: err}
return

View File

@ -4,11 +4,13 @@ import (
"fmt"
"io"
"os"
"path"
"path/filepath"
"reflect"
"testing"
"github.com/Masterminds/semver/v3"
"github.com/helmfile/chartify"
"github.com/helmfile/vals"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -2974,6 +2976,107 @@ func TestDiffpareSyncReleases(t *testing.T) {
}
}
// capturingChartifier implements state.Chartifier for tests.
type capturingChartifier struct {
mChartify func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error)
capturedArgs []chartifyArgs
}
type chartifyArgs struct {
release string
dirOrChart string
opts []chartify.ChartifyOption
}
func (c *capturingChartifier) Chartify(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
c.capturedArgs = append(c.capturedArgs, chartifyArgs{release: release, dirOrChart: dirOrChart, opts: opts})
return c.mChartify(release, dirOrChart, opts...)
}
func TestPrepareCharts_invokesChartifierWithTemplateArgs(t *testing.T) {
tests := []struct {
name string
chartifier *capturingChartifier
dir string
concurrency int
command string
opts ChartPrepareOptions
expectedArgs []chartifyArgs
helmDefaults *HelmSpec
}{
{
name: "template command",
chartifier: &capturingChartifier{
mChartify: func(release string, dirOrChart string, opts ...chartify.ChartifyOption) (string, error) {
return "someTempDir", nil
},
},
dir: "someChartPath",
concurrency: 1,
command: "template",
opts: ChartPrepareOptions{
SkipDeps: true,
TemplateArgs: "someArgs",
},
helmDefaults: &HelmSpec{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpDir, err := os.MkdirTemp("", "test-prepare-charts-*")
if err != nil {
t.Fatalf("setup temp test dir: %v", err)
}
defer os.RemoveAll(tmpDir)
err = os.Mkdir(path.Join(tmpDir, tt.dir), 0755)
if err != nil {
t.Fatalf("setup chart dir: %v", err)
}
release := ReleaseSpec{
Name: tt.name,
}
releases := []ReleaseSpec{
release,
}
state := &HelmState{
basePath: tmpDir,
ReleaseSetSpec: ReleaseSetSpec{
Releases: releases,
HelmDefaults: *tt.helmDefaults,
},
logger: logger,
valsRuntime: valsRuntime,
fs: filesystem.DefaultFileSystem(),
RenderedValues: map[string]any{},
}
helm := &exectest.Helm{
Lists: map[exectest.ListKey]string{},
Helm3: true,
}
_, errs := state.PrepareCharts(helm, tt.chartifier, path.Join(tmpDir, tt.dir), tt.concurrency, tt.command, tt.opts)
require.Len(t, errs, 0)
require.Len(t, tt.chartifier.capturedArgs, 1)
appliedChartifyOpts := &chartify.ChartifyOpts{}
for _, o := range tt.chartifier.capturedArgs[0].opts {
err = o.SetChartifyOption(appliedChartifyOpts)
if err != nil {
t.Fatalf("set captured chartify options: %v", err)
}
}
require.Equal(t, tt.opts.TemplateArgs, appliedChartifyOpts.TemplateArgs)
})
}
}
func TestPrepareSyncReleases(t *testing.T) {
tests := []struct {
name string