feat: Add missingFileHandlerConfig.ignoreMissingGitBranch (#645)

This commit is contained in:
Yusuke Kuoka 2023-01-23 18:27:00 +09:00 committed by GitHub
parent 60e024ee3b
commit ec60ac815b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 9 deletions

View File

@ -236,6 +236,10 @@ releases:
version: ~1.24.1 # the semver of the chart. range constraint is supported
condition: vault.enabled # The values lookup key for filtering releases. Corresponds to the boolean value of `vault.enabled`, where `vault` is an arbitrary value
missingFileHandler: Warn # set to either "Error" or "Warn". "Error" instructs helmfile to fail when unable to find a values or secrets file. When "Warn", it prints the file and continues.
missingFileHandlerConfig:
# Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error.
# See https://github.com/helmfile/helmfile/issues/392
ignoreMissingGitBranch: true
# Values files used for rendering the chart
values:
# Value files passed via --values
@ -400,6 +404,10 @@ environments:
# Use "Warn", "Info", or "Debug" if you want helmfile to not fail when a values file is missing, while just leaving
# a message about the missing file at the log-level.
missingFileHandler: Error
missingFileHandlerConfig:
# Ignores missing git branch error so that the Debug/Info/Warn handler can treat a missing branch as non-error.
# See https://github.com/helmfile/helmfile/issues/392
ignoreMissingGitBranch: true
# kubeContext to use for this environment
kubeContext: kube-context

View File

@ -227,7 +227,7 @@ func (c *StateCreator) loadEnvValues(st *HelmState, name string, failOnMissingEn
if len(envSpec.Secrets) > 0 {
var envSecretFiles []string
for _, urlOrPath := range envSpec.Secrets {
resolved, skipped, err := st.storage().resolveFile(envSpec.MissingFileHandler, "environment values", urlOrPath)
resolved, skipped, err := st.storage().resolveFile(envSpec.MissingFileHandler, "environment values", urlOrPath, envSpec.MissingFileHandlerConfig.resolveFileOptions()...)
if err != nil {
return nil, err
}

View File

@ -13,4 +13,6 @@ type EnvironmentSpec struct {
// Use "Warn", "Info", or "Debug" if you want helmfile to not fail when a values file is missing, while just leaving
// a message about the missing file at the log-level.
MissingFileHandler *string `yaml:"missingFileHandler,omitempty"`
// MissingFileHandlerConfig is composed of various settings for the MissingFileHandler
MissingFileHandlerConfig MissingFileHandlerConfig `yaml:"missingFileHandlerConfig,omitempty"`
}

View File

@ -82,10 +82,19 @@ type ReleaseSetSpec struct {
// non-existent path. The default behavior is to print a warning. Note the
// differing default compared to other MissingFileHandlers.
MissingFileHandler string `yaml:"missingFileHandler,omitempty"`
// MissingFileHandlerConfig is composed of various settings for the MissingFileHandler
MissingFileHandlerConfig MissingFileHandlerConfig `yaml:"missingFileHandlerConfig,omitempty"`
LockFile string `yaml:"lockFilePath,omitempty"`
}
type MissingFileHandlerConfig struct {
// IgnoreMissingGitBranch is set to true in order to let the missing file handler
// treat missing git branch errors like `pathspec 'develop' did not match any file(s) known to git` safe
// and ignored when the handler is set to Warn or Info.
IgnoreMissingGitBranch bool `yaml:"ignoreMissingGitBranch,omitempty"`
}
// helmStateAlias is helm state alias
type helmStateAlias HelmState
@ -2721,13 +2730,19 @@ func (st *HelmState) removeFiles(files []string) {
}
}
func (c MissingFileHandlerConfig) resolveFileOptions() []resolveFileOption {
return []resolveFileOption{
ignoreMissingGitBranch(c.IgnoreMissingGitBranch),
}
}
func (st *HelmState) generateTemporaryReleaseValuesFiles(release *ReleaseSpec, values []interface{}, missingFileHandler *string) ([]string, error) {
generatedFiles := []string{}
for _, value := range values {
switch typedValue := value.(type) {
case string:
paths, skip, err := st.storage().resolveFile(missingFileHandler, "values", typedValue)
paths, skip, err := st.storage().resolveFile(missingFileHandler, "values", typedValue, st.MissingFileHandlerConfig.resolveFileOptions()...)
if err != nil {
return generatedFiles, err
}
@ -2828,7 +2843,7 @@ func (st *HelmState) generateSecretValuesFiles(helm helmexec.Interface, release
switch value := v.(type) {
case string:
paths, skip, err = st.storage().resolveFile(release.MissingFileHandler, "secrets", release.ValuesPathPrefix+value)
paths, skip, err = st.storage().resolveFile(release.MissingFileHandler, "secrets", release.ValuesPathPrefix+value, st.MissingFileHandlerConfig.resolveFileOptions()...)
if err != nil {
return nil, err
}
@ -3282,7 +3297,7 @@ func (st *HelmState) LoadYAMLForEmbedding(release *ReleaseSpec, entries []interf
case string:
var values map[string]interface{}
paths, skip, err := st.storage().resolveFile(missingFileHandler, "values", pathPrefix+t)
paths, skip, err := st.storage().resolveFile(missingFileHandler, "values", pathPrefix+t, st.MissingFileHandlerConfig.resolveFileOptions()...)
if err != nil {
return nil, err
}

View File

@ -5,6 +5,7 @@ import (
"net/url"
"path/filepath"
"sort"
"strings"
"go.uber.org/zap"
@ -30,17 +31,42 @@ func NewStorage(forFile string, logger *zap.SugaredLogger, fs *filesystem.FileSy
}
}
func (st *Storage) resolveFile(missingFileHandler *string, tpe, path string) ([]string, bool, error) {
type resolveFileConfig struct {
IgnoreMissingGitBranch bool
}
type resolveFileOption func(*resolveFileConfig)
func ignoreMissingGitBranch(v bool) func(c *resolveFileConfig) {
return func(c *resolveFileConfig) {
c.IgnoreMissingGitBranch = v
}
}
func (st *Storage) resolveFile(missingFileHandler *string, tpe, path string, opts ...resolveFileOption) ([]string, bool, error) {
title := fmt.Sprintf("%s file", tpe)
var files []string
var err error
var (
files []string
err error
conf resolveFileConfig
)
for _, o := range opts {
o(&conf)
}
if remote.IsRemote(path) {
r := remote.NewRemote(st.logger, "", st.fs)
fetchedFilePath, err := r.Fetch(path, "values")
if err != nil {
return nil, false, err
// https://github.com/helmfile/helmfile/issues/392
if conf.IgnoreMissingGitBranch && strings.Contains(err.Error(), "' did not match any file(s) known to git") {
st.logger.Debugf("Ignored missing git branch error: %v", err)
} else {
return nil, false, err
}
}
if st.fs.FileExistsAt(fetchedFilePath) {

View File

@ -16,10 +16,12 @@ func TestStorage_resolveFile(t *testing.T) {
missingFileHandler *string
title string
path string
opts []resolveFileOption
}
cacheDir := remote.CacheDir()
infoHandler := MissingFileHandlerInfo
warnHandler := MissingFileHandlerWarn
errorHandler := MissingFileHandlerError
tests := []struct {
@ -49,6 +51,55 @@ func TestStorage_resolveFile(t *testing.T) {
wantSkipped: false,
wantErr: true,
},
{
name: "non existing branch in repo produce error",
args: args{
path: "git::https://github.com/helmfile/helmfile.git@examples/values/non-existing-file.yaml?ref=inexistent-branch-for-test",
title: "values",
missingFileHandler: &infoHandler,
},
wantSkipped: false,
wantErr: true,
},
{
name: "non existing branch in repo produce info when ignoreMissingGitBranch=true",
args: args{
path: "git::https://github.com/helmfile/helmfile.git@examples/values/non-existing-file.yaml?ref=inexistent-branch-for-test",
title: "values",
missingFileHandler: &infoHandler,
opts: []resolveFileOption{
ignoreMissingGitBranch(true),
},
},
wantSkipped: true,
wantErr: false,
},
{
name: "non existing branch in repo produce warn when ignoreMissingGitBranch=true",
args: args{
path: "git::https://github.com/helmfile/helmfile.git@examples/values/non-existing-file.yaml?ref=inexistent-branch-for-test",
title: "values",
missingFileHandler: &warnHandler,
opts: []resolveFileOption{
ignoreMissingGitBranch(true),
},
},
wantSkipped: true,
wantErr: false,
},
{
name: "non existing branch in repo produce error with error handler even if ignoreMissingGitBranch=true",
args: args{
path: "git::https://github.com/helmfile/helmfile.git@examples/values/non-existing-file.yaml?ref=inexistent-branch-for-test",
title: "values",
missingFileHandler: &errorHandler,
opts: []resolveFileOption{
ignoreMissingGitBranch(true),
},
},
wantSkipped: false,
wantErr: true,
},
{
name: "existing remote value fetched",
args: args{
@ -75,7 +126,7 @@ func TestStorage_resolveFile(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
st := NewStorage(cacheDir, helmexec.NewLogger(io.Discard, "debug"), filesystem.DefaultFileSystem())
files, skipped, err := st.resolveFile(tt.args.missingFileHandler, tt.args.title, tt.args.path)
files, skipped, err := st.resolveFile(tt.args.missingFileHandler, tt.args.title, tt.args.path, tt.args.opts...)
if (err != nil) != tt.wantErr {
t.Errorf("resolveFile() error = %v, wantErr %v", err, tt.wantErr)
return