feat: helmfile as a go library (#639)
* feat: helmfile as a go library This removes almost all the dependencies from the helmfile core logic to urfave/cli. `main.go` is now a thin wrapper around the core logic implemented in `pkg/app`.
This commit is contained in:
parent
f6057a1cca
commit
e2d6dc4afa
98
cmd/cmd.go
98
cmd/cmd.go
|
|
@ -1,98 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/roboll/helmfile/pkg/app"
|
||||
"github.com/roboll/helmfile/pkg/helmexec"
|
||||
"github.com/roboll/helmfile/pkg/state"
|
||||
"github.com/urfave/cli"
|
||||
"go.uber.org/zap"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func VisitAllDesiredStates(c *cli.Context, converge func(*state.HelmState, helmexec.Interface, app.Context) (bool, []error)) error {
|
||||
a, fileOrDir, err := InitAppEntry(c, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := app.NewContext()
|
||||
|
||||
convergeWithHelmBinary := func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
|
||||
if c.GlobalString("helm-binary") != "" {
|
||||
helm.SetHelmBinary(c.GlobalString("helm-binary"))
|
||||
}
|
||||
return converge(st, helm, ctx)
|
||||
}
|
||||
|
||||
err = a.VisitDesiredStates(fileOrDir, app.LoadOpts{Selectors: a.Selectors}, convergeWithHelmBinary)
|
||||
|
||||
return toCliError(c, err)
|
||||
}
|
||||
|
||||
func InitAppEntry(c *cli.Context, reverse bool) (*app.App, string, error) {
|
||||
if c.NArg() > 0 {
|
||||
cli.ShowAppHelp(c)
|
||||
return nil, "", fmt.Errorf("err: extraneous arguments: %s", strings.Join(c.Args(), ", "))
|
||||
}
|
||||
|
||||
fileOrDir := c.GlobalString("file")
|
||||
kubeContext := c.GlobalString("kube-context")
|
||||
namespace := c.GlobalString("namespace")
|
||||
selectors := c.GlobalStringSlice("selector")
|
||||
logger := c.App.Metadata["logger"].(*zap.SugaredLogger)
|
||||
|
||||
env := c.GlobalString("environment")
|
||||
if env == "" {
|
||||
env = state.DefaultEnv
|
||||
}
|
||||
|
||||
app := app.Init(&app.App{
|
||||
KubeContext: kubeContext,
|
||||
Logger: logger,
|
||||
Reverse: reverse,
|
||||
Env: env,
|
||||
Namespace: namespace,
|
||||
Selectors: selectors,
|
||||
})
|
||||
|
||||
return app, fileOrDir, nil
|
||||
}
|
||||
|
||||
func FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c *cli.Context, reverse bool, converge func(*state.HelmState, helmexec.Interface, app.Context) []error) error {
|
||||
a, fileOrDir, err := InitAppEntry(c, reverse)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx := app.NewContext()
|
||||
|
||||
convergeWithHelmBinary := func(st *state.HelmState, helm helmexec.Interface) []error {
|
||||
if c.GlobalString("helm-binary") != "" {
|
||||
helm.SetHelmBinary(c.GlobalString("helm-binary"))
|
||||
}
|
||||
return converge(st, helm, ctx)
|
||||
}
|
||||
|
||||
err = a.VisitDesiredStatesWithReleasesFiltered(fileOrDir, convergeWithHelmBinary)
|
||||
|
||||
return toCliError(c, err)
|
||||
}
|
||||
|
||||
func toCliError(c *cli.Context, err error) error {
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
case *app.NoMatchingHelmfileError:
|
||||
noMatchingExitCode := 3
|
||||
if c.GlobalBool("allow-no-matching-release") {
|
||||
noMatchingExitCode = 0
|
||||
}
|
||||
return cli.NewExitError(e.Error(), noMatchingExitCode)
|
||||
case *app.Error:
|
||||
return cli.NewExitError(e.Error(), e.Code())
|
||||
default:
|
||||
panic(fmt.Errorf("BUG: please file an github issue for this unhandled error: %T: %v", e, e))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
37
cmd/deps.go
37
cmd/deps.go
|
|
@ -1,37 +0,0 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/roboll/helmfile/pkg/app"
|
||||
"github.com/roboll/helmfile/pkg/argparser"
|
||||
"github.com/roboll/helmfile/pkg/helmexec"
|
||||
"github.com/roboll/helmfile/pkg/state"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func Deps() cli.Command {
|
||||
return cli.Command{
|
||||
Name: "deps",
|
||||
Usage: "update charts based on the contents of requirements.yaml",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "args",
|
||||
Value: "",
|
||||
Usage: "pass args to helm exec",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return VisitAllDesiredStates(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) (bool, []error) {
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
errs := state.UpdateDeps(helm)
|
||||
|
||||
ok := len(errs) == 0
|
||||
|
||||
return ok, errs
|
||||
})
|
||||
},
|
||||
}
|
||||
}
|
||||
456
main.go
456
main.go
|
|
@ -2,9 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/roboll/helmfile/cmd"
|
||||
"github.com/roboll/helmfile/pkg/app"
|
||||
"github.com/roboll/helmfile/pkg/argparser"
|
||||
"github.com/roboll/helmfile/pkg/helmexec"
|
||||
"github.com/roboll/helmfile/pkg/state"
|
||||
"github.com/urfave/cli"
|
||||
|
|
@ -94,7 +92,20 @@ func main() {
|
|||
|
||||
cliApp.Before = configureLogging
|
||||
cliApp.Commands = []cli.Command{
|
||||
cmd.Deps(),
|
||||
{
|
||||
Name: "deps",
|
||||
Usage: "update charts based on the contents of requirements.yaml",
|
||||
Flags: []cli.Flag{
|
||||
cli.StringFlag{
|
||||
Name: "args",
|
||||
Value: "",
|
||||
Usage: "pass args to helm exec",
|
||||
},
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Deps(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "repos",
|
||||
Usage: "sync repositories from state file (helm repo add && helm repo update)",
|
||||
|
|
@ -105,20 +116,9 @@ func main() {
|
|||
Usage: "pass args to helm exec",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmd.VisitAllDesiredStates(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) (bool, []error) {
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
errs := ctx.SyncReposOnce(state, helm)
|
||||
|
||||
ok := len(state.Repositories) > 0 && len(errs) == 0
|
||||
|
||||
return ok, errs
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Repos(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "charts",
|
||||
|
|
@ -139,14 +139,9 @@ func main() {
|
|||
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
||||
return executeSyncCommand(c, &affectedReleases, st, helm)
|
||||
})
|
||||
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
||||
return errs
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.DeprecatedSyncCharts(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "diff",
|
||||
|
|
@ -179,24 +174,9 @@ func main() {
|
|||
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
||||
if !c.Bool("skip-deps") {
|
||||
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := state.PrepareReleases(helm, "diff"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
_, errs := ExecuteDiffCommand(NewUrfaveCliConfigImpl(c), state, helm, c.Bool("detailed-exitcode"), c.Bool("suppress-secrets"))
|
||||
return errs
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Diff(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "template",
|
||||
|
|
@ -221,22 +201,9 @@ func main() {
|
|||
Usage: "skip running `helm repo update` and `helm dependency build`",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
||||
if !c.Bool("skip-deps") {
|
||||
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := state.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return executeTemplateCommand(c, state, helm)
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Template(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "lint",
|
||||
|
|
@ -261,25 +228,9 @@ func main() {
|
|||
Usage: "skip running `helm repo update` and `helm dependency build`",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
||||
values := c.StringSlice("values")
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
workers := c.Int("concurrency")
|
||||
if !c.Bool("skip-deps") {
|
||||
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := state.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return state.LintReleases(helm, values, args, workers)
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Lint(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "sync",
|
||||
|
|
@ -304,25 +255,9 @@ func main() {
|
|||
Usage: "skip running `helm repo update` and `helm dependency build`",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
||||
if !c.Bool("skip-deps") {
|
||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return executeSyncCommand(c, &affectedReleases, st, helm)
|
||||
})
|
||||
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
||||
return errs
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Sync(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "apply",
|
||||
|
|
@ -351,88 +286,9 @@ func main() {
|
|||
Usage: "skip running `helm repo update` and `helm dependency build`",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := findAndIterateOverDesiredStatesUsingFlags(c, func(st *state.HelmState, helm helmexec.Interface, ctx app.Context) []error {
|
||||
if !c.Bool("skip-deps") {
|
||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
releases, errs := ExecuteDiffCommand(NewUrfaveCliConfigImpl(c), st, helm, true, c.Bool("suppress-secrets"))
|
||||
|
||||
releasesToBeDeleted, err := st.DetectReleasesToBeDeleted(helm)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
fatalErrs := []error{}
|
||||
|
||||
noError := true
|
||||
for _, e := range errs {
|
||||
switch err := e.(type) {
|
||||
case *state.ReleaseError:
|
||||
if err.Code != 2 {
|
||||
noError = false
|
||||
fatalErrs = append(fatalErrs, e)
|
||||
}
|
||||
default:
|
||||
noError = false
|
||||
fatalErrs = append(fatalErrs, e)
|
||||
}
|
||||
}
|
||||
|
||||
// sync only when there are changes
|
||||
if noError {
|
||||
if len(releases) == 0 && len(releasesToBeDeleted) == 0 {
|
||||
// TODO better way to get the logger
|
||||
logger := c.App.Metadata["logger"].(*zap.SugaredLogger)
|
||||
logger.Infof("")
|
||||
logger.Infof("No affected releases")
|
||||
} else {
|
||||
names := []string{}
|
||||
for _, r := range releases {
|
||||
names = append(names, fmt.Sprintf(" %s (%s) UPDATED", r.Name, r.Chart))
|
||||
}
|
||||
for _, r := range releasesToBeDeleted {
|
||||
names = append(names, fmt.Sprintf(" %s (%s) DELETED", r.Name, r.Chart))
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to apply?
|
||||
Helmfile will apply all your changes, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.GlobalBool("interactive")
|
||||
if !interactive || interactive && askForConfirmation(msg) {
|
||||
rs := []state.ReleaseSpec{}
|
||||
for _, r := range releases {
|
||||
rs = append(rs, *r)
|
||||
}
|
||||
for _, r := range releasesToBeDeleted {
|
||||
rs = append(rs, *r)
|
||||
}
|
||||
|
||||
st.Releases = rs
|
||||
return executeSyncCommand(c, &affectedReleases, st, helm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fatalErrs
|
||||
})
|
||||
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
||||
return errs
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Apply(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "status",
|
||||
|
|
@ -449,18 +305,9 @@ Do you really want to apply?
|
|||
Usage: "pass args to helm exec",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
||||
workers := c.Int("concurrency")
|
||||
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
return state.ReleaseStatuses(helm, workers)
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Status(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "delete",
|
||||
|
|
@ -476,37 +323,9 @@ Do you really want to apply?
|
|||
Usage: "purge releases i.e. free release names and histories",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, true, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
||||
purge := c.Bool("purge")
|
||||
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
names := make([]string, len(state.Releases))
|
||||
for i, r := range state.Releases {
|
||||
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to delete?
|
||||
Helmfile will delete all your releases, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.GlobalBool("interactive")
|
||||
if !interactive || interactive && askForConfirmation(msg) {
|
||||
return state.DeleteReleases(&affectedReleases, helm, purge)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
||||
return errs
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Delete(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "destroy",
|
||||
|
|
@ -518,35 +337,9 @@ Do you really want to delete?
|
|||
Usage: "pass args to helm exec",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, true, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
names := make([]string, len(state.Releases))
|
||||
for i, r := range state.Releases {
|
||||
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to delete?
|
||||
Helmfile will delete all your releases, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.GlobalBool("interactive")
|
||||
if !interactive || interactive && askForConfirmation(msg) {
|
||||
return state.DeleteReleases(&affectedReleases, helm, true)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
affectedReleases.DisplayAffectedReleases(c.App.Metadata["logger"].(*zap.SugaredLogger))
|
||||
return errs
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Destroy(c)
|
||||
}),
|
||||
},
|
||||
{
|
||||
Name: "test",
|
||||
|
|
@ -572,20 +365,9 @@ Do you really want to delete?
|
|||
Usage: "maximum number of concurrent helm processes to run, 0 is unlimited",
|
||||
},
|
||||
},
|
||||
Action: func(c *cli.Context) error {
|
||||
return findAndIterateOverDesiredStatesUsingFlags(c, func(state *state.HelmState, helm helmexec.Interface, _ app.Context) []error {
|
||||
cleanup := c.Bool("cleanup")
|
||||
timeout := c.Int("timeout")
|
||||
concurrency := c.Int("concurrency")
|
||||
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
return state.TestReleases(helm, cleanup, timeout, concurrency)
|
||||
})
|
||||
},
|
||||
Action: action(func(run *app.App, c configImpl) error {
|
||||
return run.Test(c)
|
||||
}),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -596,41 +378,19 @@ Do you really want to delete?
|
|||
}
|
||||
}
|
||||
|
||||
func executeSyncCommand(c *cli.Context, affectedReleases *state.AffectedReleases, state *state.HelmState, helm helmexec.Interface) []error {
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
}
|
||||
|
||||
values := c.StringSlice("values")
|
||||
workers := c.Int("concurrency")
|
||||
|
||||
return state.SyncReleases(affectedReleases, helm, values, workers)
|
||||
}
|
||||
|
||||
func executeTemplateCommand(c *cli.Context, state *state.HelmState, helm helmexec.Interface) []error {
|
||||
args := argparser.GetArgs(c.String("args"), state)
|
||||
values := c.StringSlice("values")
|
||||
workers := c.Int("concurrency")
|
||||
|
||||
return state.TemplateReleases(helm, values, args, workers)
|
||||
}
|
||||
|
||||
type Config interface {
|
||||
HasCommandName(string) bool
|
||||
Values() []string
|
||||
Concurrency() int
|
||||
Args() string
|
||||
}
|
||||
|
||||
type configImpl struct {
|
||||
c *cli.Context
|
||||
}
|
||||
|
||||
func NewUrfaveCliConfigImpl(c *cli.Context) configImpl {
|
||||
func NewUrfaveCliConfigImpl(c *cli.Context) (configImpl, error) {
|
||||
if c.NArg() > 0 {
|
||||
cli.ShowAppHelp(c)
|
||||
return configImpl{}, fmt.Errorf("err: extraneous arguments: %s", strings.Join(c.Args(), ", "))
|
||||
}
|
||||
|
||||
return configImpl{
|
||||
c: c,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (c configImpl) Values() []string {
|
||||
|
|
@ -649,17 +409,105 @@ func (c configImpl) HasCommandName(name string) bool {
|
|||
return c.c.Command.HasName(name)
|
||||
}
|
||||
|
||||
func ExecuteDiffCommand(c Config, st *state.HelmState, helm helmexec.Interface, detailedExitCode, suppressSecrets bool) ([]*state.ReleaseSpec, []error) {
|
||||
args := argparser.GetArgs(c.Args(), st)
|
||||
if len(args) > 0 {
|
||||
helm.SetExtraArgs(args...)
|
||||
// DiffConfig
|
||||
|
||||
func (c configImpl) SkipDeps() bool {
|
||||
return c.c.Bool("skip-deps")
|
||||
}
|
||||
|
||||
func (c configImpl) DetailedExitcode() bool {
|
||||
return c.c.Bool("detailed-exitcode")
|
||||
}
|
||||
|
||||
func (c configImpl) SuppressSecrets() bool {
|
||||
return c.c.Bool("suppress-secrets")
|
||||
}
|
||||
|
||||
// DeleteConfig
|
||||
|
||||
func (c configImpl) Purge() bool {
|
||||
return c.c.Bool("purge")
|
||||
}
|
||||
|
||||
// TestConfig
|
||||
|
||||
func (c configImpl) Cleanup() bool {
|
||||
return c.c.Bool("cleanup")
|
||||
}
|
||||
|
||||
func (c configImpl) Timeout() int {
|
||||
return c.c.Int("timeout")
|
||||
}
|
||||
|
||||
// GlobalConfig
|
||||
|
||||
func (c configImpl) HelmBinary() string {
|
||||
return c.c.GlobalString("helm-binary")
|
||||
}
|
||||
|
||||
func (c configImpl) KubeContext() string {
|
||||
return c.c.GlobalString("kube-context")
|
||||
}
|
||||
|
||||
func (c configImpl) Namespace() string {
|
||||
return c.c.GlobalString("namespace")
|
||||
}
|
||||
|
||||
func (c configImpl) FileOrDir() string {
|
||||
return c.c.GlobalString("file")
|
||||
}
|
||||
|
||||
func (c configImpl) Selectors() []string {
|
||||
return c.c.GlobalStringSlice("selector")
|
||||
}
|
||||
|
||||
func (c configImpl) Interactive() bool {
|
||||
return c.c.GlobalBool("interactive")
|
||||
}
|
||||
|
||||
func (c configImpl) Logger() *zap.SugaredLogger {
|
||||
return c.c.App.Metadata["logger"].(*zap.SugaredLogger)
|
||||
}
|
||||
|
||||
func (c configImpl) Env() string {
|
||||
env := c.c.GlobalString("environment")
|
||||
if env == "" {
|
||||
env = state.DefaultEnv
|
||||
}
|
||||
|
||||
triggerCleanupEvents := c.HasCommandName("diff")
|
||||
|
||||
return st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, suppressSecrets, triggerCleanupEvents)
|
||||
return env
|
||||
}
|
||||
|
||||
func findAndIterateOverDesiredStatesUsingFlags(c *cli.Context, converge func(*state.HelmState, helmexec.Interface, app.Context) []error) error {
|
||||
return cmd.FindAndIterateOverDesiredStatesUsingFlagsWithReverse(c, false, converge)
|
||||
func action(do func(*app.App, configImpl) error) func(*cli.Context) error {
|
||||
return func(implCtx *cli.Context) error {
|
||||
conf, err := NewUrfaveCliConfigImpl(implCtx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a := app.New(conf)
|
||||
|
||||
a.ErrorHandler = func(err error) error {
|
||||
return toCliError(implCtx, err)
|
||||
}
|
||||
|
||||
return do(a, conf)
|
||||
}
|
||||
}
|
||||
|
||||
func toCliError(c *cli.Context, err error) error {
|
||||
if err != nil {
|
||||
switch e := err.(type) {
|
||||
case *app.NoMatchingHelmfileError:
|
||||
noMatchingExitCode := 3
|
||||
if c.GlobalBool("allow-no-matching-release") {
|
||||
noMatchingExitCode = 0
|
||||
}
|
||||
return cli.NewExitError(e.Error(), noMatchingExitCode)
|
||||
case *app.Error:
|
||||
return cli.NewExitError(e.Error(), e.Code())
|
||||
default:
|
||||
panic(fmt.Errorf("BUG: please file an github issue for this unhandled error: %T: %v", e, e))
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
123
pkg/app/app.go
123
pkg/app/app.go
|
|
@ -24,6 +24,12 @@ type App struct {
|
|||
Env string
|
||||
Namespace string
|
||||
Selectors []string
|
||||
HelmBinary string
|
||||
Args string
|
||||
|
||||
FileOrDir string
|
||||
|
||||
ErrorHandler func(error) error
|
||||
|
||||
readFile func(string) ([]byte, error)
|
||||
fileExists func(string) (bool, error)
|
||||
|
|
@ -36,6 +42,19 @@ type App struct {
|
|||
chdir func(string) error
|
||||
}
|
||||
|
||||
func New(conf ConfigProvider) *App {
|
||||
return Init(&App{
|
||||
KubeContext: conf.KubeContext(),
|
||||
Logger: conf.Logger(),
|
||||
Env: conf.Env(),
|
||||
Namespace: conf.Namespace(),
|
||||
Selectors: conf.Selectors(),
|
||||
HelmBinary: conf.HelmBinary(),
|
||||
Args: conf.Args(),
|
||||
FileOrDir: conf.FileOrDir(),
|
||||
})
|
||||
}
|
||||
|
||||
func Init(app *App) *App {
|
||||
app.readFile = ioutil.ReadFile
|
||||
app.glob = filepath.Glob
|
||||
|
|
@ -48,6 +67,84 @@ func Init(app *App) *App {
|
|||
return app
|
||||
}
|
||||
|
||||
func (a *App) Deps(c DepsConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Deps(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Repos(c ReposConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Repos(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) reverse() *App {
|
||||
new := *a
|
||||
new.Reverse = true
|
||||
return &new
|
||||
}
|
||||
|
||||
func (a *App) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.DeprecatedSyncCharts(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Diff(c DiffConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Diff(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Template(c TemplateConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Template(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Lint(c LintConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Lint(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Sync(c SyncConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Sync(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Apply(c ApplyConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Apply(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Status(c StatusesConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Status(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Delete(c DeleteConfigProvider) error {
|
||||
return a.reverse().ForEachState(func(run *Run) []error {
|
||||
return run.Delete(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Destroy(c DestroyConfigProvider) error {
|
||||
return a.reverse().ForEachState(func(run *Run) []error {
|
||||
return run.Destroy(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) Test(c TestConfigProvider) error {
|
||||
return a.ForEachState(func(run *Run) []error {
|
||||
return run.Test(c)
|
||||
})
|
||||
}
|
||||
|
||||
func (a *App) within(dir string, do func() error) error {
|
||||
if dir == "." {
|
||||
return do()
|
||||
|
|
@ -140,7 +237,7 @@ func (a *App) loadDesiredStateFromYaml(file string, opts ...LoadOpts) (*state.He
|
|||
return ld.Load(file, op)
|
||||
}
|
||||
|
||||
func (a *App) VisitDesiredStates(fileOrDir string, opts LoadOpts, converge func(*state.HelmState, helmexec.Interface) (bool, []error)) error {
|
||||
func (a *App) visitStates(fileOrDir string, opts LoadOpts, converge func(*state.HelmState, helmexec.Interface) (bool, []error)) error {
|
||||
noMatchInHelmfiles := true
|
||||
|
||||
err := a.visitStateFiles(fileOrDir, func(f, d string) error {
|
||||
|
|
@ -195,7 +292,7 @@ func (a *App) VisitDesiredStates(fileOrDir string, opts LoadOpts, converge func(
|
|||
} else {
|
||||
optsForNestedState.Selectors = m.Selectors
|
||||
}
|
||||
if err := a.VisitDesiredStates(m.Path, optsForNestedState, converge); err != nil {
|
||||
if err := a.visitStates(m.Path, optsForNestedState, converge); err != nil {
|
||||
switch err.(type) {
|
||||
case *NoMatchingHelmfileError:
|
||||
|
||||
|
|
@ -229,10 +326,26 @@ func (a *App) VisitDesiredStates(fileOrDir string, opts LoadOpts, converge func(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *App) ForEachState(do func(*Run) []error) error {
|
||||
err := a.VisitDesiredStatesWithReleasesFiltered(a.FileOrDir, func(st *state.HelmState, helm helmexec.Interface) []error {
|
||||
ctx := NewContext()
|
||||
|
||||
run := NewRun(st, helm, ctx)
|
||||
|
||||
return do(run)
|
||||
})
|
||||
|
||||
if err != nil && a.ErrorHandler != nil {
|
||||
return a.ErrorHandler(err)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *App) VisitDesiredStatesWithReleasesFiltered(fileOrDir string, converge func(*state.HelmState, helmexec.Interface) []error) error {
|
||||
opts := LoadOpts{Selectors: a.Selectors}
|
||||
|
||||
err := a.VisitDesiredStates(fileOrDir, opts, func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
|
||||
err := a.visitStates(fileOrDir, opts, func(st *state.HelmState, helm helmexec.Interface) (bool, []error) {
|
||||
if len(st.Selectors) > 0 {
|
||||
err := st.FilterReleases()
|
||||
if err != nil {
|
||||
|
|
@ -240,6 +353,10 @@ func (a *App) VisitDesiredStatesWithReleasesFiltered(fileOrDir string, converge
|
|||
}
|
||||
}
|
||||
|
||||
if a.HelmBinary != "" {
|
||||
helm.SetHelmBinary(a.HelmBinary)
|
||||
}
|
||||
|
||||
type Key struct {
|
||||
TillerNamespace, Name string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package app
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
|
|
@ -11,7 +11,7 @@ import (
|
|||
// Copyright (c) 2017 Roland Singer [roland.singer@desertbit.com]
|
||||
//
|
||||
// Shamelessly borrowed from @r0l1's awesome work that is available at https://gist.github.com/r0l1/3dcbb0c8f6cfe9c66ab8008f55f8f28b
|
||||
func askForConfirmation(s string) bool {
|
||||
func AskForConfirmation(s string) bool {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
for {
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package app
|
||||
|
||||
import "go.uber.org/zap"
|
||||
|
||||
type ConfigProvider interface {
|
||||
Args() string
|
||||
HelmBinary() string
|
||||
|
||||
FileOrDir() string
|
||||
KubeContext() string
|
||||
Namespace() string
|
||||
Selectors() []string
|
||||
Env() string
|
||||
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type DeprecatedChartsConfigProvider interface {
|
||||
Values() []string
|
||||
|
||||
concurrencyConfig
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type DepsConfigProvider interface {
|
||||
Args() string
|
||||
}
|
||||
|
||||
type ReposConfigProvider interface {
|
||||
Args() string
|
||||
}
|
||||
|
||||
type ApplyConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Values() []string
|
||||
SkipDeps() bool
|
||||
|
||||
SuppressSecrets() bool
|
||||
|
||||
concurrencyConfig
|
||||
interactive
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type SyncConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Values() []string
|
||||
SkipDeps() bool
|
||||
|
||||
concurrencyConfig
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type DiffConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Values() []string
|
||||
SkipDeps() bool
|
||||
|
||||
SuppressSecrets() bool
|
||||
|
||||
DetailedExitcode() bool
|
||||
|
||||
concurrencyConfig
|
||||
}
|
||||
|
||||
type DeleteConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Purge() bool
|
||||
|
||||
interactive
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type DestroyConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
interactive
|
||||
loggingConfig
|
||||
}
|
||||
|
||||
type TestConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Timeout() int
|
||||
Cleanup() bool
|
||||
|
||||
concurrencyConfig
|
||||
}
|
||||
|
||||
type LintConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Values() []string
|
||||
SkipDeps() bool
|
||||
|
||||
concurrencyConfig
|
||||
}
|
||||
|
||||
type TemplateConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
Values() []string
|
||||
SkipDeps() bool
|
||||
|
||||
concurrencyConfig
|
||||
}
|
||||
|
||||
type StatusesConfigProvider interface {
|
||||
Args() string
|
||||
|
||||
concurrencyConfig
|
||||
}
|
||||
|
||||
type concurrencyConfig interface {
|
||||
Concurrency() int
|
||||
}
|
||||
|
||||
type loggingConfig interface {
|
||||
Logger() *zap.SugaredLogger
|
||||
}
|
||||
|
||||
type interactive interface {
|
||||
Interactive() bool
|
||||
}
|
||||
|
|
@ -0,0 +1,302 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/roboll/helmfile/pkg/argparser"
|
||||
"github.com/roboll/helmfile/pkg/helmexec"
|
||||
"github.com/roboll/helmfile/pkg/state"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Run struct {
|
||||
state *state.HelmState
|
||||
helm helmexec.Interface
|
||||
ctx Context
|
||||
|
||||
Ask func(string) bool
|
||||
}
|
||||
|
||||
func NewRun(st *state.HelmState, helm helmexec.Interface, ctx Context) *Run {
|
||||
return &Run{state: st, helm: helm, ctx: ctx}
|
||||
}
|
||||
|
||||
func (r *Run) askForConfirmation(msg string) bool {
|
||||
if r.Ask != nil {
|
||||
return r.Ask(msg)
|
||||
}
|
||||
return AskForConfirmation(msg)
|
||||
}
|
||||
|
||||
func (r *Run) Deps(c DepsConfigProvider) []error {
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
return r.state.UpdateDeps(r.helm)
|
||||
}
|
||||
|
||||
func (r *Run) Repos(c ReposConfigProvider) []error {
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
return r.ctx.SyncReposOnce(r.state, r.helm)
|
||||
}
|
||||
|
||||
func (r *Run) DeprecatedSyncCharts(c DeprecatedChartsConfigProvider) []error {
|
||||
st := r.state
|
||||
helm := r.helm
|
||||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *Run) Status(c StatusesConfigProvider) []error {
|
||||
workers := c.Concurrency()
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
return r.state.ReleaseStatuses(r.helm, workers)
|
||||
}
|
||||
|
||||
func (r *Run) Delete(c DeleteConfigProvider) []error {
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
purge := c.Purge()
|
||||
|
||||
errs := []error{}
|
||||
|
||||
names := make([]string, len(r.state.Releases))
|
||||
for i, r := range r.state.Releases {
|
||||
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to delete?
|
||||
Helmfile will delete all your releases, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.Interactive()
|
||||
if !interactive || interactive && r.askForConfirmation(msg) {
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
errs = r.state.DeleteReleases(&affectedReleases, r.helm, purge)
|
||||
}
|
||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *Run) Destroy(c DestroyConfigProvider) []error {
|
||||
errs := []error{}
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
|
||||
names := make([]string, len(r.state.Releases))
|
||||
for i, r := range r.state.Releases {
|
||||
names[i] = fmt.Sprintf(" %s (%s)", r.Name, r.Chart)
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to delete?
|
||||
Helmfile will delete all your releases, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.Interactive()
|
||||
if !interactive || interactive && r.askForConfirmation(msg) {
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
errs = r.state.DeleteReleases(&affectedReleases, r.helm, true)
|
||||
}
|
||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *Run) Apply(c ApplyConfigProvider) []error {
|
||||
st := r.state
|
||||
helm := r.helm
|
||||
ctx := r.ctx
|
||||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
if !c.SkipDeps() {
|
||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "apply"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
// helm must be 2.11+ and helm-diff should be provided `--detailed-exitcode` in order for `helmfile apply` to work properly
|
||||
detailedExitCode := true
|
||||
|
||||
releases, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), detailedExitCode, c.SuppressSecrets(), false)
|
||||
|
||||
releasesToBeDeleted, err := st.DetectReleasesToBeDeleted(helm)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
|
||||
fatalErrs := []error{}
|
||||
|
||||
noError := true
|
||||
for _, e := range errs {
|
||||
switch err := e.(type) {
|
||||
case *state.ReleaseError:
|
||||
if err.Code != 2 {
|
||||
noError = false
|
||||
fatalErrs = append(fatalErrs, e)
|
||||
}
|
||||
default:
|
||||
noError = false
|
||||
fatalErrs = append(fatalErrs, e)
|
||||
}
|
||||
}
|
||||
|
||||
// sync only when there are changes
|
||||
if noError {
|
||||
if len(releases) == 0 && len(releasesToBeDeleted) == 0 {
|
||||
// TODO better way to get the logger
|
||||
logger := c.Logger()
|
||||
logger.Infof("")
|
||||
logger.Infof("No affected releases")
|
||||
} else {
|
||||
names := []string{}
|
||||
for _, r := range releases {
|
||||
names = append(names, fmt.Sprintf(" %s (%s) UPDATED", r.Name, r.Chart))
|
||||
}
|
||||
for _, r := range releasesToBeDeleted {
|
||||
names = append(names, fmt.Sprintf(" %s (%s) DELETED", r.Name, r.Chart))
|
||||
}
|
||||
|
||||
msg := fmt.Sprintf(`Affected releases are:
|
||||
%s
|
||||
|
||||
Do you really want to apply?
|
||||
Helmfile will apply all your changes, as shown above.
|
||||
|
||||
`, strings.Join(names, "\n"))
|
||||
interactive := c.Interactive()
|
||||
if !interactive || interactive && r.askForConfirmation(msg) {
|
||||
rs := []state.ReleaseSpec{}
|
||||
for _, r := range releases {
|
||||
rs = append(rs, *r)
|
||||
}
|
||||
for _, r := range releasesToBeDeleted {
|
||||
rs = append(rs, *r)
|
||||
}
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
st.Releases = rs
|
||||
return st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||
return fatalErrs
|
||||
}
|
||||
|
||||
func (r *Run) Diff(c DiffConfigProvider) []error {
|
||||
st := r.state
|
||||
helm := r.helm
|
||||
ctx := r.ctx
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "diff"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
_, errs := st.DiffReleases(helm, c.Values(), c.Concurrency(), c.DetailedExitcode(), c.SuppressSecrets(), true)
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *Run) Sync(c SyncConfigProvider) []error {
|
||||
st := r.state
|
||||
helm := r.helm
|
||||
ctx := r.ctx
|
||||
|
||||
affectedReleases := state.AffectedReleases{}
|
||||
if !c.SkipDeps() {
|
||||
if errs := ctx.SyncReposOnce(st, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := st.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := st.PrepareReleases(helm, "sync"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
errs := st.SyncReleases(&affectedReleases, helm, c.Values(), c.Concurrency())
|
||||
affectedReleases.DisplayAffectedReleases(c.Logger())
|
||||
return errs
|
||||
}
|
||||
|
||||
func (r *Run) Template(c TemplateConfigProvider) []error {
|
||||
state := r.state
|
||||
helm := r.helm
|
||||
ctx := r.ctx
|
||||
|
||||
if !c.SkipDeps() {
|
||||
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := state.PrepareReleases(helm, "template"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
|
||||
args := argparser.GetArgs(c.Args(), state)
|
||||
return state.TemplateReleases(helm, c.Values(), args, c.Concurrency())
|
||||
}
|
||||
|
||||
func (r *Run) Test(c TestConfigProvider) []error {
|
||||
cleanup := c.Cleanup()
|
||||
timeout := c.Timeout()
|
||||
concurrency := c.Concurrency()
|
||||
|
||||
r.helm.SetExtraArgs(argparser.GetArgs(c.Args(), r.state)...)
|
||||
|
||||
return r.state.TestReleases(r.helm, cleanup, timeout, concurrency)
|
||||
}
|
||||
|
||||
func (r *Run) Lint(c LintConfigProvider) []error {
|
||||
state := r.state
|
||||
helm := r.helm
|
||||
ctx := r.ctx
|
||||
|
||||
values := c.Values()
|
||||
args := argparser.GetArgs(c.Args(), state)
|
||||
workers := c.Concurrency()
|
||||
if !c.SkipDeps() {
|
||||
if errs := ctx.SyncReposOnce(state, helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
if errs := state.BuildDeps(helm); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
}
|
||||
if errs := state.PrepareReleases(helm, "lint"); errs != nil && len(errs) > 0 {
|
||||
return errs
|
||||
}
|
||||
return state.LintReleases(helm, values, args, workers)
|
||||
}
|
||||
|
|
@ -514,6 +514,9 @@ func (st *HelmState) downloadCharts(helm helmexec.Interface, dir string, concurr
|
|||
|
||||
// TemplateReleases wrapper for executing helm template on the releases
|
||||
func (st *HelmState) TemplateReleases(helm helmexec.Interface, additionalValues []string, args []string, workerLimit int) []error {
|
||||
// Reset the extra args if already set, not to break `helm fetch` by adding the args intended for `lint`
|
||||
helm.SetExtraArgs()
|
||||
|
||||
errs := []error{}
|
||||
// Create tmp directory and bail immediately if it fails
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
|
|
@ -577,6 +580,9 @@ func (st *HelmState) TemplateReleases(helm helmexec.Interface, additionalValues
|
|||
|
||||
// LintReleases wrapper for executing helm lint on the releases
|
||||
func (st *HelmState) LintReleases(helm helmexec.Interface, additionalValues []string, args []string, workerLimit int) []error {
|
||||
// Reset the extra args if already set, not to break `helm fetch` by adding the args intended for `lint`
|
||||
helm.SetExtraArgs()
|
||||
|
||||
errs := []error{}
|
||||
// Create tmp directory and bail immediately if it fails
|
||||
dir, err := ioutil.TempDir("", "")
|
||||
|
|
|
|||
Loading…
Reference in New Issue