parent
8acbbc596d
commit
0186254e79
8
main.go
8
main.go
|
|
@ -329,6 +329,10 @@ func main() {
|
||||||
Value: 0,
|
Value: 0,
|
||||||
Usage: "output NUM lines of context around changes",
|
Usage: "output NUM lines of context around changes",
|
||||||
},
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "detailed-exitcode",
|
||||||
|
Usage: "return a non-zero exit code 2 instead of 0 when there were changes detected AND the changes are synced successfully",
|
||||||
|
},
|
||||||
cli.StringFlag{
|
cli.StringFlag{
|
||||||
Name: "args",
|
Name: "args",
|
||||||
Value: "",
|
Value: "",
|
||||||
|
|
@ -625,11 +629,11 @@ func action(do func(*app.App, configImpl) error) func(*cli.Context) error {
|
||||||
|
|
||||||
a := app.New(conf)
|
a := app.New(conf)
|
||||||
|
|
||||||
a.ErrorHandler = func(err error) error {
|
if err := do(a, conf); err != nil {
|
||||||
return toCliError(implCtx, err)
|
return toCliError(implCtx, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return do(a, conf)
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
|
||||||
|
|
@ -40,8 +41,6 @@ type App struct {
|
||||||
|
|
||||||
FileOrDir string
|
FileOrDir string
|
||||||
|
|
||||||
ErrorHandler func(error) error
|
|
||||||
|
|
||||||
readFile func(string) ([]byte, error)
|
readFile func(string) ([]byte, error)
|
||||||
fileExists func(string) (bool, error)
|
fileExists func(string) (bool, error)
|
||||||
glob func(string) ([]string, error)
|
glob func(string) ([]string, error)
|
||||||
|
|
@ -144,9 +143,31 @@ func (a *App) Sync(c SyncConfigProvider) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Apply(c ApplyConfigProvider) error {
|
func (a *App) Apply(c ApplyConfigProvider) error {
|
||||||
return a.ForEachState(func(run *Run) (bool, []error) {
|
var any bool
|
||||||
return a.apply(run, c)
|
|
||||||
|
mut := &sync.Mutex{}
|
||||||
|
|
||||||
|
err := a.ForEachState(func(run *Run) (bool, []error) {
|
||||||
|
matched, updated, errs := a.apply(run, c)
|
||||||
|
|
||||||
|
mut.Lock()
|
||||||
|
any = any || updated
|
||||||
|
mut.Unlock()
|
||||||
|
|
||||||
|
return matched, errs
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.DetailedExitcode() && any {
|
||||||
|
code := 2
|
||||||
|
|
||||||
|
return &Error{msg: "", Errors: nil, code: &code}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Status(c StatusesConfigProvider) error {
|
func (a *App) Status(c StatusesConfigProvider) error {
|
||||||
|
|
@ -410,10 +431,6 @@ func (a *App) ForEachStateFiltered(do func(*Run) []error) error {
|
||||||
return do(run)
|
return do(run)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil && a.ErrorHandler != nil {
|
|
||||||
return a.ErrorHandler(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -424,10 +441,6 @@ func (a *App) ForEachState(do func(*Run) (bool, []error)) error {
|
||||||
return do(run)
|
return do(run)
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil && a.ErrorHandler != nil {
|
|
||||||
return a.ErrorHandler(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -661,7 +674,7 @@ func (a *App) findDesiredStateFiles(specifiedPath string) ([]string, error) {
|
||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, []error) {
|
func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, bool, []error) {
|
||||||
st := r.state
|
st := r.state
|
||||||
helm := r.helm
|
helm := r.helm
|
||||||
ctx := r.ctx
|
ctx := r.ctx
|
||||||
|
|
@ -670,10 +683,10 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, []error) {
|
||||||
|
|
||||||
toApply, err := st.GetSelectedReleasesWithOverrides()
|
toApply, err := st.GetSelectedReleasesWithOverrides()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, []error{err}
|
return false, false, []error{err}
|
||||||
}
|
}
|
||||||
if len(toApply) == 0 {
|
if len(toApply) == 0 {
|
||||||
return false, nil
|
return false, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do build deps and prepare only on selected releases so that we won't waste time
|
// Do build deps and prepare only on selected releases so that we won't waste time
|
||||||
|
|
@ -682,14 +695,14 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, []error) {
|
||||||
|
|
||||||
if !c.SkipDeps() {
|
if !c.SkipDeps() {
|
||||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||||
return false, errs
|
return false, false, errs
|
||||||
}
|
}
|
||||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||||
return false, errs
|
return false, false, errs
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
||||||
return false, errs
|
return false, false, errs
|
||||||
}
|
}
|
||||||
|
|
||||||
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
|
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
|
||||||
|
|
@ -730,7 +743,7 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, []error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(fatalErrs) > 0 {
|
if len(fatalErrs) > 0 {
|
||||||
return false, fatalErrs
|
return false, false, fatalErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
releasesToBeDeleted := map[string]state.ReleaseSpec{}
|
releasesToBeDeleted := map[string]state.ReleaseSpec{}
|
||||||
|
|
@ -755,7 +768,7 @@ func (a *App) apply(r *Run, c ApplyConfigProvider) (bool, []error) {
|
||||||
logger := c.Logger()
|
logger := c.Logger()
|
||||||
logger.Infof("")
|
logger.Infof("")
|
||||||
logger.Infof("No affected releases")
|
logger.Infof("No affected releases")
|
||||||
return true, nil
|
return true, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
names := []string{}
|
names := []string{}
|
||||||
|
|
@ -838,7 +851,7 @@ Do you really want to apply?
|
||||||
}
|
}
|
||||||
|
|
||||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||||
return true, syncErrs
|
return true, true, syncErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) delete(r *Run, purge bool, c DestroyConfigProvider) (bool, []error) {
|
func (a *App) delete(r *Run, purge bool, c DestroyConfigProvider) (bool, []error) {
|
||||||
|
|
@ -1133,6 +1146,8 @@ type Error struct {
|
||||||
msg string
|
msg string
|
||||||
|
|
||||||
Errors []error
|
Errors []error
|
||||||
|
|
||||||
|
code *int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) Error() string {
|
func (e *Error) Error() string {
|
||||||
|
|
@ -1165,6 +1180,10 @@ func (e *Error) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) Code() int {
|
func (e *Error) Code() int {
|
||||||
|
if e.code != nil {
|
||||||
|
return *e.code
|
||||||
|
}
|
||||||
|
|
||||||
allDiff := false
|
allDiff := false
|
||||||
anyNonZero := false
|
anyNonZero := false
|
||||||
for _, err := range e.Errors {
|
for _, err := range e.Errors {
|
||||||
|
|
@ -1195,7 +1214,7 @@ func (e *Error) Code() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func appError(msg string, err error) error {
|
func appError(msg string, err error) error {
|
||||||
return &Error{msg, []error{err}}
|
return &Error{msg: msg, Errors: []error{err}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c context) clean(errs []error) error {
|
func (c context) clean(errs []error) error {
|
||||||
|
|
|
||||||
|
|
@ -1890,17 +1890,18 @@ func (c configImpl) Concurrency() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
type applyConfig struct {
|
type applyConfig struct {
|
||||||
args string
|
args string
|
||||||
values []string
|
values []string
|
||||||
set []string
|
set []string
|
||||||
skipDeps bool
|
skipDeps bool
|
||||||
suppressSecrets bool
|
suppressSecrets bool
|
||||||
suppressDiff bool
|
suppressDiff bool
|
||||||
noColor bool
|
noColor bool
|
||||||
context int
|
context int
|
||||||
concurrency int
|
concurrency int
|
||||||
interactive bool
|
detailedExitcode bool
|
||||||
logger *zap.SugaredLogger
|
interactive bool
|
||||||
|
logger *zap.SugaredLogger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a applyConfig) Args() string {
|
func (a applyConfig) Args() string {
|
||||||
|
|
@ -1939,6 +1940,10 @@ func (a applyConfig) Concurrency() int {
|
||||||
return a.concurrency
|
return a.concurrency
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a applyConfig) DetailedExitcode() bool {
|
||||||
|
return a.detailedExitcode
|
||||||
|
}
|
||||||
|
|
||||||
func (a applyConfig) Interactive() bool {
|
func (a applyConfig) Interactive() bool {
|
||||||
return a.interactive
|
return a.interactive
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ type ApplyConfigProvider interface {
|
||||||
SuppressSecrets() bool
|
SuppressSecrets() bool
|
||||||
SuppressDiff() bool
|
SuppressDiff() bool
|
||||||
|
|
||||||
|
DetailedExitcode() bool
|
||||||
|
|
||||||
NoColor() bool
|
NoColor() bool
|
||||||
Context() int
|
Context() int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,9 @@ ${helmfile} -f ${dir}/happypath.yaml template
|
||||||
code=$?
|
code=$?
|
||||||
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile template: ${code}"
|
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile template: ${code}"
|
||||||
|
|
||||||
|
info "Applying ${dir}/happypath.yaml"
|
||||||
|
bash -c "${helmfile} -f ${dir}/happypath.yaml apply --detailed-exitcode; code="'$?'"; echo Code: "'$code'"; [ "'${code}'" -eq 2 ]" || fail "unexpected exit code returned by helmfile apply"
|
||||||
|
|
||||||
info "Syncing ${dir}/happypath.yaml"
|
info "Syncing ${dir}/happypath.yaml"
|
||||||
${helmfile} -f ${dir}/happypath.yaml sync
|
${helmfile} -f ${dir}/happypath.yaml sync
|
||||||
wait_deploy_ready httpbin-httpbin
|
wait_deploy_ready httpbin-httpbin
|
||||||
|
|
@ -84,9 +87,9 @@ retry 5 "curl --fail $(minikube service --url --namespace=${test_ns} httpbin-htt
|
||||||
[ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK"
|
[ ${retry_result} -eq 0 ] || fail "httpbin failed to return 200 OK"
|
||||||
|
|
||||||
info "Applying ${dir}/happypath.yaml"
|
info "Applying ${dir}/happypath.yaml"
|
||||||
${helmfile} -f ${dir}/happypath.yaml apply
|
${helmfile} -f ${dir}/happypath.yaml apply --detailed-exitcode
|
||||||
code=$?
|
code=$?
|
||||||
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: ${code}"
|
[ ${code} -eq 0 ] || fail "unexpected exit code returned by helmfile apply: want 0, got ${code}"
|
||||||
|
|
||||||
info "Locking dependencies"
|
info "Locking dependencies"
|
||||||
${helmfile} -f ${dir}/happypath.yaml deps
|
${helmfile} -f ${dir}/happypath.yaml deps
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue