diff --git a/main.go b/main.go index ec459f32..67b00bda 100644 --- a/main.go +++ b/main.go @@ -539,14 +539,15 @@ func findAndIterateOverDesiredStates(fileOrDir string, converge func(*state.Helm if err != nil { return err } - allSelectorNotMatched := true + noTargetFoundForAllHelmfiles := true for _, f := range desiredStateFiles { logger.Debugf("Processing %s", f) yamlBuf, err := tmpl.NewFileRenderer(ioutil.ReadFile, "", environment.EmptyEnvironment).RenderTemplateFileToBuffer(f) if err != nil { return err } - state, helm, noReleases, err := loadDesiredStateFromFile( + + st, helm, noReleasesMatchingSelector, err := loadDesiredStateFromFile( yamlBuf.Bytes(), f, kubeContext, @@ -555,12 +556,21 @@ func findAndIterateOverDesiredStates(fileOrDir string, converge func(*state.Helm env, logger, ) - if err != nil { - return err - } - if len(state.Helmfiles) > 0 { - for _, globPattern := range state.Helmfiles { + var noTarget bool + if err != nil { + switch stateLoadErr := err.(type) { + // Addresses https://github.com/roboll/helmfile/issues/279 + case *state.StateLoadError: + switch stateLoadErr.Cause.(type) { + case *state.UndefinedEnvError: + noTarget = true + } + default: + return err + } + } else if len(st.Helmfiles) > 0 { + for _, globPattern := range st.Helmfiles { matches, err := filepath.Glob(globPattern) if err != nil { return fmt.Errorf("failed processing %s: %v", globPattern, err) @@ -573,19 +583,25 @@ func findAndIterateOverDesiredStates(fileOrDir string, converge func(*state.Helm } } return nil + } else { + noTarget = noReleasesMatchingSelector } - allSelectorNotMatched = allSelectorNotMatched && noReleases - if noReleases { + noTargetFoundForAllHelmfiles = noTargetFoundForAllHelmfiles && noTarget + if noTarget { continue } - errs := converge(state, helm) - if err := clean(state, errs); err != nil { + errs := converge(st, helm) + if err := clean(st, errs); err != nil { return err } } - if allSelectorNotMatched { - logger.Error("specified selector did not match any releases in any helmfile") + if noTargetFoundForAllHelmfiles { + logger.Errorf( + "err: no releases found that matches specified selector(%s) and environment(%s), in any helmfile", + strings.Join(selectors, ", "), + env, + ) os.Exit(2) } return nil @@ -651,7 +667,7 @@ func directoryExistsAt(path string) bool { func loadDesiredStateFromFile(yaml []byte, file string, kubeContext, namespace string, labels []string, env string, logger *zap.SugaredLogger) (*state.HelmState, helmexec.Interface, bool, error) { st, err := state.CreateFromYaml(yaml, file, env, logger) if err != nil { - return nil, nil, false, fmt.Errorf("failed to read %s: %v", file, err) + return nil, nil, false, err } if st.Context != "" { diff --git a/state/create.go b/state/create.go index 42347514..b0cbabf9 100644 --- a/state/create.go +++ b/state/create.go @@ -13,6 +13,23 @@ import ( "path/filepath" ) +type StateLoadError struct { + msg string + Cause error +} + +func (e *StateLoadError) Error() string { + return fmt.Sprintf("%s: %v", e.msg, e.Cause) +} + +type UndefinedEnvError struct { + msg string +} + +func (e *UndefinedEnvError) Error() string { + return e.msg +} + func CreateFromYaml(content []byte, file string, env string, logger *zap.SugaredLogger) (*HelmState, error) { return createFromYamlWithFileReader(content, file, env, logger, ioutil.ReadFile) } @@ -22,7 +39,7 @@ func createFromYamlWithFileReader(content []byte, file string, env string, logge state.basePath, _ = filepath.Abs(filepath.Dir(file)) if err := yaml.UnmarshalStrict(content, &state); err != nil { - return nil, err + return nil, &StateLoadError{fmt.Sprintf("failed to read %s", file), err} } state.FilePath = file @@ -38,7 +55,7 @@ func createFromYamlWithFileReader(content []byte, file string, env string, logge e, err := state.loadEnv(env, readFile) if err != nil { - return nil, err + return nil, &StateLoadError{fmt.Sprintf("failed to read %s", file), err} } state.env = *e @@ -92,7 +109,7 @@ func (state *HelmState) loadEnv(name string, readFile func(string) ([]byte, erro } } } else if name != DefaultEnv { - return nil, fmt.Errorf("environment \"%s\" is not defined in \"%s\"", name, state.FilePath) + return nil, &UndefinedEnvError{msg: fmt.Sprintf("environment \"%s\" is not defined", name)} } return &environment.Environment{Name: name, Values: envVals}, nil