mirror of
https://github.com/helmfile/helmfile.git
synced 2026-10-18 07:43:20 +02:00
Fix the logic of helmfile deps and add tests. (#1588)
This commit is contained in:
+33
-11
@@ -105,6 +105,7 @@ func (a *App) Deps(c DepsConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
prepErr := run.withPreparedCharts("deps", state.ChartPrepareOptions{
|
||||
SkipRepos: c.SkipRepos(),
|
||||
SkipDeps: true,
|
||||
SkipResolve: true,
|
||||
}, func() {
|
||||
errs = run.Deps(c)
|
||||
@@ -122,7 +123,10 @@ func (a *App) Repos(c ReposConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
var reposErr error
|
||||
|
||||
err := run.withPreparedCharts("repos", state.ChartPrepareOptions{SkipRepos: true}, func() {
|
||||
err := run.withPreparedCharts("repos", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
reposErr = run.Repos(c)
|
||||
})
|
||||
|
||||
@@ -140,7 +144,10 @@ func (a *App) Repos(c ReposConfigProvider) error {
|
||||
|
||||
func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
err := run.withPreparedCharts("charts", state.ChartPrepareOptions{SkipRepos: true}, func() {
|
||||
err := run.withPreparedCharts("charts", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
errs = run.DeprecatedSyncCharts(c)
|
||||
})
|
||||
|
||||
@@ -166,7 +173,10 @@ func (a *App) Diff(c DiffConfigProvider) error {
|
||||
|
||||
var errs []error
|
||||
|
||||
prepErr := run.withPreparedCharts("diff", state.ChartPrepareOptions{SkipRepos: c.SkipDeps()}, func() {
|
||||
prepErr := run.withPreparedCharts("diff", state.ChartPrepareOptions{
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
msg, matched, affected, errs = a.diff(run, c)
|
||||
})
|
||||
|
||||
@@ -227,6 +237,7 @@ func (a *App) Template(c TemplateConfigProvider) error {
|
||||
prepErr := run.withPreparedCharts("template", state.ChartPrepareOptions{
|
||||
ForceDownload: !run.helm.IsHelm3(),
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
ok, errs = a.template(run, c)
|
||||
})
|
||||
@@ -246,6 +257,7 @@ func (a *App) WriteValues(c WriteValuesConfigProvider) error {
|
||||
prepErr := run.withPreparedCharts("write-values", state.ChartPrepareOptions{
|
||||
ForceDownload: !run.helm.IsHelm3(),
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
ok, errs = a.writeValues(run, c)
|
||||
})
|
||||
@@ -264,6 +276,7 @@ func (a *App) Lint(c LintConfigProvider) error {
|
||||
prepErr := run.withPreparedCharts("lint", state.ChartPrepareOptions{
|
||||
ForceDownload: true,
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
errs = run.Lint(c)
|
||||
})
|
||||
@@ -280,6 +293,7 @@ func (a *App) Sync(c SyncConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErr := run.withPreparedCharts("sync", state.ChartPrepareOptions{
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
ok, errs = a.sync(run, c)
|
||||
})
|
||||
@@ -304,6 +318,7 @@ func (a *App) Apply(c ApplyConfigProvider) error {
|
||||
err := a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
prepErr := run.withPreparedCharts("apply", state.ChartPrepareOptions{
|
||||
SkipRepos: c.SkipDeps(),
|
||||
SkipDeps: c.SkipDeps(),
|
||||
}, func() {
|
||||
matched, updated, es := a.apply(run, c)
|
||||
|
||||
@@ -338,6 +353,7 @@ func (a *App) Status(c StatusesConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
err := run.withPreparedCharts("status", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
errs = run.Status(c)
|
||||
})
|
||||
@@ -354,6 +370,7 @@ func (a *App) Delete(c DeleteConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
err := run.withPreparedCharts("delete", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
ok, errs = a.delete(run, c.Purge(), c)
|
||||
})
|
||||
@@ -370,6 +387,7 @@ func (a *App) Destroy(c DestroyConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) (ok bool, errs []error) {
|
||||
err := run.withPreparedCharts("destroy", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
ok, errs = a.delete(run, true, c)
|
||||
})
|
||||
@@ -392,6 +410,7 @@ func (a *App) Test(c TestConfigProvider) error {
|
||||
|
||||
err := run.withPreparedCharts("test", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
errs = a.test(run, c)
|
||||
})
|
||||
@@ -408,6 +427,7 @@ 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,
|
||||
}, func() {
|
||||
if c.EmbedValues() {
|
||||
for i := range run.state.Releases {
|
||||
@@ -456,6 +476,7 @@ func (a *App) ListReleases(c ListConfigProvider) error {
|
||||
err := a.ForEachState(func(run *Run) (_ bool, errs []error) {
|
||||
err := run.withPreparedCharts("list", state.ChartPrepareOptions{
|
||||
SkipRepos: true,
|
||||
SkipDeps: true,
|
||||
}, func() {
|
||||
|
||||
//var releases m
|
||||
@@ -587,14 +608,15 @@ func (a *App) loadDesiredStateFromYaml(file string, opts ...LoadOpts) (*state.He
|
||||
}
|
||||
|
||||
ld := &desiredStateLoader{
|
||||
readFile: a.readFile,
|
||||
deleteFile: a.deleteFile,
|
||||
fileExists: a.fileExists,
|
||||
env: a.Env,
|
||||
namespace: a.Namespace,
|
||||
logger: a.Logger,
|
||||
abs: a.abs,
|
||||
remote: a.remote,
|
||||
readFile: a.readFile,
|
||||
deleteFile: a.deleteFile,
|
||||
fileExists: a.fileExists,
|
||||
directoryExistsAt: a.directoryExistsAt,
|
||||
env: a.Env,
|
||||
namespace: a.Namespace,
|
||||
logger: a.Logger,
|
||||
abs: a.abs,
|
||||
remote: a.remote,
|
||||
|
||||
overrideKubeContext: a.OverrideKubeContext,
|
||||
overrideHelmBinary: a.OverrideHelmBinary,
|
||||
|
||||
@@ -2380,6 +2380,18 @@ func (a applyConfig) RetainValuesFiles() bool {
|
||||
return a.retainValuesFiles
|
||||
}
|
||||
|
||||
type depsConfig struct {
|
||||
skipRepos bool
|
||||
}
|
||||
|
||||
func (d depsConfig) SkipRepos() bool {
|
||||
return d.skipRepos
|
||||
}
|
||||
|
||||
func (d depsConfig) Args() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Mocking the command-line runner
|
||||
|
||||
type mockRunner struct {
|
||||
@@ -3961,6 +3973,147 @@ err: "foo" depends on nonexistent release "bar"
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeps(t *testing.T) {
|
||||
testcases := []struct {
|
||||
name string
|
||||
loc string
|
||||
error string
|
||||
files map[string]string
|
||||
log string
|
||||
charts []string
|
||||
}{
|
||||
//
|
||||
// complex test cases for smoke testing
|
||||
//
|
||||
{
|
||||
name: "smoke",
|
||||
loc: location(),
|
||||
files: map[string]string{
|
||||
"/path/to/helmfile.yaml": `
|
||||
repositories:
|
||||
- name: bitnami
|
||||
url: https://charts.bitnami.com/bitnami/
|
||||
releases:
|
||||
- name: example
|
||||
chart: /path/to/charts/example
|
||||
`,
|
||||
"/path/to/charts/example/Chart.yaml": `foo: FOO`,
|
||||
},
|
||||
log: `processing file "helmfile.yaml" in directory "."
|
||||
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: repositories:
|
||||
2: - name: bitnami
|
||||
3: url: https://charts.bitnami.com/bitnami/
|
||||
4: releases:
|
||||
5: - name: example
|
||||
6: chart: /path/to/charts/example
|
||||
7:
|
||||
|
||||
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: repositories:
|
||||
2: - name: bitnami
|
||||
3: url: https://charts.bitnami.com/bitnami/
|
||||
4: releases:
|
||||
5: - name: example
|
||||
6: chart: /path/to/charts/example
|
||||
7:
|
||||
|
||||
merged environment: &{default map[] map[]}
|
||||
There are no repositories defined in your helmfile.yaml.
|
||||
This means helmfile cannot update your dependencies or create a lock file.
|
||||
See https://github.com/roboll/helmfile/issues/878 for more information.
|
||||
`,
|
||||
charts: []string{"/path/to/charts/example"},
|
||||
},
|
||||
}
|
||||
|
||||
for i := range testcases {
|
||||
tc := testcases[i]
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
|
||||
var helm = &exectest.Helm{
|
||||
DiffMutex: &sync.Mutex{},
|
||||
ChartsMutex: &sync.Mutex{},
|
||||
ReleasesMutex: &sync.Mutex{},
|
||||
}
|
||||
|
||||
bs := &bytes.Buffer{}
|
||||
|
||||
func() {
|
||||
logReader, logWriter := io.Pipe()
|
||||
|
||||
logFlushed := &sync.WaitGroup{}
|
||||
// Ensure all the log is consumed into `bs` by calling `logWriter.Close()` followed by `logFlushed.Wait()`
|
||||
logFlushed.Add(1)
|
||||
go func() {
|
||||
scanner := bufio.NewScanner(logReader)
|
||||
for scanner.Scan() {
|
||||
bs.Write(scanner.Bytes())
|
||||
bs.WriteString("\n")
|
||||
}
|
||||
logFlushed.Done()
|
||||
}()
|
||||
|
||||
defer func() {
|
||||
// This is here to avoid data-trace on bytes buffer `bs` to capture logs
|
||||
if err := logWriter.Close(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
logFlushed.Wait()
|
||||
}()
|
||||
|
||||
logger := helmexec.NewLogger(logWriter, "debug")
|
||||
|
||||
app := appWithFs(&App{
|
||||
OverrideHelmBinary: DefaultHelmBinary,
|
||||
glob: filepath.Glob,
|
||||
abs: filepath.Abs,
|
||||
OverrideKubeContext: "default",
|
||||
Env: "default",
|
||||
Logger: logger,
|
||||
helms: map[helmKey]helmexec.Interface{
|
||||
createHelmKey("helm", "default"): helm,
|
||||
},
|
||||
}, tc.files)
|
||||
|
||||
depsErr := app.Deps(depsConfig{
|
||||
skipRepos: false,
|
||||
})
|
||||
|
||||
if tc.error == "" && depsErr != nil {
|
||||
t.Fatalf("unexpected error for data defined at %s: %v", tc.loc, depsErr)
|
||||
} else if tc.error != "" && depsErr == nil {
|
||||
t.Fatalf("expected error did not occur for data defined at %s", tc.loc)
|
||||
} else if tc.error != "" && depsErr != nil && tc.error != depsErr.Error() {
|
||||
t.Fatalf("invalid error: expected %q, got %q", tc.error, depsErr.Error())
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(helm.Charts, tc.charts) {
|
||||
t.Fatalf("expected charts %v, got %v", helm.Charts, tc.charts)
|
||||
}
|
||||
}()
|
||||
|
||||
if tc.log != "" {
|
||||
actual := bs.String()
|
||||
|
||||
diff, exists := testhelper.Diff(tc.log, actual, 3)
|
||||
if exists {
|
||||
t.Errorf("unexpected log for data defined %s:\nDIFF\n%s\nEOD", tc.loc, diff)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func captureStdout(f func()) string {
|
||||
reader, writer, err := os.Pipe()
|
||||
if err != nil {
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/imdario/mergo"
|
||||
"github.com/roboll/helmfile/pkg/environment"
|
||||
"github.com/roboll/helmfile/pkg/helmexec"
|
||||
@@ -11,7 +13,6 @@ import (
|
||||
"github.com/roboll/helmfile/pkg/state"
|
||||
"github.com/variantdev/vals"
|
||||
"go.uber.org/zap"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -25,12 +26,13 @@ type desiredStateLoader struct {
|
||||
env string
|
||||
namespace string
|
||||
|
||||
readFile func(string) ([]byte, error)
|
||||
deleteFile func(string) error
|
||||
fileExists func(string) (bool, error)
|
||||
abs func(string) (string, error)
|
||||
glob func(string) ([]string, error)
|
||||
getHelm func(*state.HelmState) helmexec.Interface
|
||||
readFile func(string) ([]byte, error)
|
||||
deleteFile func(string) error
|
||||
fileExists func(string) (bool, error)
|
||||
abs func(string) (string, error)
|
||||
glob func(string) ([]string, error)
|
||||
directoryExistsAt func(string) bool
|
||||
getHelm func(*state.HelmState) helmexec.Interface
|
||||
|
||||
remote *remote.Remote
|
||||
logger *zap.SugaredLogger
|
||||
@@ -144,7 +146,7 @@ func (ld *desiredStateLoader) loadFileWithOverrides(inheritedEnv, overrodeEnv *e
|
||||
}
|
||||
|
||||
func (a *desiredStateLoader) underlying() *state.StateCreator {
|
||||
c := state.NewCreator(a.logger, a.readFile, a.fileExists, a.abs, a.glob, a.valsRuntime, a.getHelm, a.overrideHelmBinary, a.remote)
|
||||
c := state.NewCreator(a.logger, a.readFile, a.fileExists, a.abs, a.glob, a.directoryExistsAt, a.valsRuntime, a.getHelm, a.overrideHelmBinary, a.remote)
|
||||
c.DeleteFile = a.deleteFile
|
||||
c.LoadFile = a.loadFile
|
||||
return c
|
||||
|
||||
Reference in New Issue
Block a user