Initialize run.Configs in the NewSTEP functions [#67]

This fixes the run package's leaky abstraction; other packages no longer
need to know or care that run.Config even exists.

Note that since the various Steps now depend on having a non-nil pointer
to a run.Config, it's unsafe (or at least risky) to initialize them
directly. They should be created with their NewSTEPNAME functions. All
their fields are now private, to reflect this.
This commit is contained in:
Erin Call 2020-01-17 10:13:53 -08:00
parent d8ddb79ef4
commit a21848484b
No known key found for this signature in database
GPG key ID: 4071FF6C15B8DAD1
19 changed files with 408 additions and 447 deletions

View file

@ -6,7 +6,6 @@ package helm
import (
gomock "github.com/golang/mock/gomock"
run "github.com/pelotech/drone-helm3/internal/run"
reflect "reflect"
)
@ -34,17 +33,17 @@ func (m *MockStep) EXPECT() *MockStepMockRecorder {
}
// Prepare mocks base method
func (m *MockStep) Prepare(arg0 run.Config) error {
func (m *MockStep) Prepare() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Prepare", arg0)
ret := m.ctrl.Call(m, "Prepare")
ret0, _ := ret[0].(error)
return ret0
}
// Prepare indicates an expected call of Prepare
func (mr *MockStepMockRecorder) Prepare(arg0 interface{}) *gomock.Call {
func (mr *MockStepMockRecorder) Prepare() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockStep)(nil).Prepare), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Prepare", reflect.TypeOf((*MockStep)(nil).Prepare))
}
// Execute mocks base method

View file

@ -14,27 +14,20 @@ const (
// A Step is one step in the plan.
type Step interface {
Prepare(run.Config) error
Prepare() error
Execute() error
}
// A Plan is a series of steps to perform.
type Plan struct {
steps []Step
cfg env.Config
runCfg run.Config
steps []Step
cfg env.Config
}
// NewPlan makes a plan for running a helm operation.
func NewPlan(cfg env.Config) (*Plan, error) {
p := Plan{
cfg: cfg,
runCfg: run.Config{
Debug: cfg.Debug,
Namespace: cfg.Namespace,
Stdout: cfg.Stdout,
Stderr: cfg.Stderr,
},
}
p.steps = (*determineSteps(cfg))(cfg)
@ -44,7 +37,7 @@ func NewPlan(cfg env.Config) (*Plan, error) {
fmt.Fprintf(os.Stderr, "calling %T.Prepare (step %d)\n", step, i)
}
if err := step.Prepare(p.runCfg); err != nil {
if err := step.Prepare(); err != nil {
err = fmt.Errorf("while preparing %T step: %w", step, err)
return nil, err
}
@ -96,7 +89,7 @@ var upgrade = func(cfg env.Config) []Step {
var steps []Step
steps = append(steps, run.NewInitKube(cfg, kubeConfigTemplate, kubeConfigFile))
for _, repo := range cfg.AddRepos {
steps = append(steps, run.NewAddRepo(repo))
steps = append(steps, run.NewAddRepo(cfg, repo))
}
if cfg.UpdateDependencies {
steps = append(steps, run.NewDepUpdate(cfg))
@ -120,7 +113,7 @@ var uninstall = func(cfg env.Config) []Step {
var lint = func(cfg env.Config) []Step {
var steps []Step
for _, repo := range cfg.AddRepos {
steps = append(steps, run.NewAddRepo(repo))
steps = append(steps, run.NewAddRepo(cfg, repo))
}
if cfg.UpdateDependencies {
steps = append(steps, run.NewDepUpdate(cfg))

View file

@ -41,22 +41,14 @@ func (suite *PlanTestSuite) TestNewPlan() {
Stderr: &stderr,
}
runCfg := run.Config{
Debug: false,
Namespace: "outer",
Stdout: &stdout,
Stderr: &stderr,
}
stepOne.EXPECT().
Prepare(runCfg)
Prepare()
stepTwo.EXPECT().
Prepare(runCfg)
Prepare()
plan, err := NewPlan(cfg)
suite.Require().Nil(err)
suite.Equal(cfg, plan.cfg)
suite.Equal(runCfg, plan.runCfg)
}
func (suite *PlanTestSuite) TestNewPlanAbortsOnError() {
@ -76,7 +68,7 @@ func (suite *PlanTestSuite) TestNewPlanAbortsOnError() {
}
stepOne.EXPECT().
Prepare(gomock.Any()).
Prepare().
Return(fmt.Errorf("I'm starry Dave, aye, cat blew that"))
_, err := NewPlan(cfg)
@ -90,11 +82,8 @@ func (suite *PlanTestSuite) TestExecute() {
stepOne := NewMockStep(ctrl)
stepTwo := NewMockStep(ctrl)
runCfg := run.Config{}
plan := Plan{
steps: []Step{stepOne, stepTwo},
runCfg: runCfg,
steps: []Step{stepOne, stepTwo},
}
stepOne.EXPECT().
@ -113,11 +102,8 @@ func (suite *PlanTestSuite) TestExecuteAbortsOnError() {
stepOne := NewMockStep(ctrl)
stepTwo := NewMockStep(ctrl)
runCfg := run.Config{}
plan := Plan{
steps: []Step{stepOne, stepTwo},
runCfg: runCfg,
steps: []Step{stepOne, stepTwo},
}
stepOne.EXPECT().

View file

@ -2,19 +2,22 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
"strings"
)
// AddRepo is an execution step that calls `helm repo add` when executed.
type AddRepo struct {
Repo string
*config
repo string
cmd cmd
}
// NewAddRepo creates an AddRepo for the given repo-spec. No validation is performed at this time.
func NewAddRepo(repo string) *AddRepo {
func NewAddRepo(cfg env.Config, repo string) *AddRepo {
return &AddRepo{
Repo: repo,
config: newConfig(cfg),
repo: repo,
}
}
@ -24,13 +27,13 @@ func (a *AddRepo) Execute() error {
}
// Prepare gets the AddRepo ready to execute.
func (a *AddRepo) Prepare(cfg Config) error {
if a.Repo == "" {
func (a *AddRepo) Prepare() error {
if a.repo == "" {
return fmt.Errorf("repo is required")
}
split := strings.SplitN(a.Repo, "=", 2)
split := strings.SplitN(a.repo, "=", 2)
if len(split) != 2 {
return fmt.Errorf("bad repo spec '%s'", a.Repo)
return fmt.Errorf("bad repo spec '%s'", a.repo)
}
name := split[0]
@ -38,21 +41,21 @@ func (a *AddRepo) Prepare(cfg Config) error {
args := make([]string, 0)
if cfg.Namespace != "" {
args = append(args, "--namespace", cfg.Namespace)
if a.namespace != "" {
args = append(args, "--namespace", a.namespace)
}
if cfg.Debug {
if a.debug {
args = append(args, "--debug")
}
args = append(args, "repo", "add", name, url)
a.cmd = command(helmBin, args...)
a.cmd.Stdout(cfg.Stdout)
a.cmd.Stderr(cfg.Stderr)
a.cmd.Stdout(a.stdout)
a.cmd.Stderr(a.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", a.cmd.String())
if a.debug {
fmt.Fprintf(a.stderr, "Generated command: '%s'\n", a.cmd.String())
}
return nil

View file

@ -3,6 +3,7 @@ package run
import (
"fmt"
"github.com/golang/mock/gomock"
"github.com/pelotech/drone-helm3/internal/env"
"github.com/stretchr/testify/suite"
"strings"
"testing"
@ -39,21 +40,20 @@ func TestAddRepoTestSuite(t *testing.T) {
}
func (suite *AddRepoTestSuite) TestNewAddRepo() {
repo := NewAddRepo("picompress=https://github.com/caleb_phipps/picompress")
repo := NewAddRepo(env.Config{}, "picompress=https://github.com/caleb_phipps/picompress")
suite.Require().NotNil(repo)
suite.Equal("picompress=https://github.com/caleb_phipps/picompress", repo.Repo)
suite.Equal("picompress=https://github.com/caleb_phipps/picompress", repo.repo)
suite.NotNil(repo.config)
}
func (suite *AddRepoTestSuite) TestPrepareAndExecute() {
stdout := strings.Builder{}
stderr := strings.Builder{}
cfg := Config{
cfg := env.Config{
Stdout: &stdout,
Stderr: &stderr,
}
a := AddRepo{
Repo: "edeath=https://github.com/n_marks/e-death",
}
a := NewAddRepo(cfg, "edeath=https://github.com/n_marks/e-death")
suite.mockCmd.EXPECT().
Stdout(&stdout).
@ -62,7 +62,7 @@ func (suite *AddRepoTestSuite) TestPrepareAndExecute() {
Stderr(&stderr).
Times(1)
suite.Require().NoError(a.Prepare(cfg))
suite.Require().NoError(a.Prepare())
suite.Equal(helmBin, suite.commandPath)
suite.Equal([]string{"repo", "add", "edeath", "https://github.com/n_marks/e-death"}, suite.commandArgs)
@ -78,42 +78,35 @@ func (suite *AddRepoTestSuite) TestPrepareRepoIsRequired() {
// These aren't really expected, but allowing them gives clearer test-failure messages
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
cfg := Config{}
a := AddRepo{}
a := NewAddRepo(env.Config{}, "")
err := a.Prepare(cfg)
err := a.Prepare()
suite.EqualError(err, "repo is required")
}
func (suite *AddRepoTestSuite) TestPrepareMalformedRepo() {
a := AddRepo{
Repo: "dwim",
}
err := a.Prepare(Config{})
a := NewAddRepo(env.Config{}, "dwim")
err := a.Prepare()
suite.EqualError(err, "bad repo spec 'dwim'")
}
func (suite *AddRepoTestSuite) TestPrepareWithEqualSignInURL() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
a := AddRepo{
Repo: "samaritan=https://github.com/arthur_claypool/samaritan?version=2.1",
}
suite.NoError(a.Prepare(Config{}))
a := NewAddRepo(env.Config{}, "samaritan=https://github.com/arthur_claypool/samaritan?version=2.1")
suite.NoError(a.Prepare())
suite.Contains(suite.commandArgs, "https://github.com/arthur_claypool/samaritan?version=2.1")
}
func (suite *AddRepoTestSuite) TestNamespaceFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
cfg := Config{
cfg := env.Config{
Namespace: "alliteration",
}
a := AddRepo{
Repo: "edeath=https://github.com/theater_guy/e-death",
}
a := NewAddRepo(cfg, "edeath=https://github.com/theater_guy/e-death")
suite.NoError(a.Prepare(cfg))
suite.NoError(a.Prepare())
suite.Equal(suite.commandPath, helmBin)
suite.Equal(suite.commandArgs, []string{"--namespace", "alliteration",
"repo", "add", "edeath", "https://github.com/theater_guy/e-death"})
@ -133,15 +126,13 @@ func (suite *AddRepoTestSuite) TestDebugFlag() {
return suite.mockCmd
}
cfg := Config{
cfg := env.Config{
Debug: true,
Stderr: &stderr,
}
a := AddRepo{
Repo: "edeath=https://github.com/the_bug/e-death",
}
a := NewAddRepo(cfg, "edeath=https://github.com/the_bug/e-death")
suite.Require().NoError(a.Prepare(cfg))
suite.Require().NoError(a.Prepare())
suite.Equal(fmt.Sprintf("Generated command: '%s --debug "+
"repo add edeath https://github.com/the_bug/e-death'\n", helmBin), stderr.String())
}

View file

@ -1,13 +1,22 @@
package run
import (
"github.com/pelotech/drone-helm3/internal/env"
"io"
)
// Config contains configuration applicable to all helm commands
type Config struct {
Debug bool
Namespace string
Stdout io.Writer
Stderr io.Writer
type config struct {
debug bool
namespace string
stdout io.Writer
stderr io.Writer
}
func newConfig(cfg env.Config) *config {
return &config{
debug: cfg.Debug,
namespace: cfg.Namespace,
stdout: cfg.Stdout,
stderr: cfg.Stderr,
}
}

View file

@ -0,0 +1,35 @@
package run
import (
"github.com/pelotech/drone-helm3/internal/env"
"github.com/stretchr/testify/suite"
"strings"
"testing"
)
type ConfigTestSuite struct {
suite.Suite
}
func TestConfigTestSuite(t *testing.T) {
suite.Run(t, new(ConfigTestSuite))
}
func (suite *ConfigTestSuite) TestNewConfig() {
stdout := &strings.Builder{}
stderr := &strings.Builder{}
envCfg := env.Config{
Namespace: "private",
Debug: true,
Stdout: stdout,
Stderr: stderr,
}
cfg := newConfig(envCfg)
suite.Require().NotNil(cfg)
suite.Equal(&config{
namespace: "private",
debug: true,
stdout: stdout,
stderr: stderr,
}, cfg)
}

View file

@ -7,14 +7,16 @@ import (
// DepUpdate is an execution step that calls `helm dependency update` when executed.
type DepUpdate struct {
Chart string
*config
chart string
cmd cmd
}
// NewDepUpdate creates a DepUpdate using fields from the given Config. No validation is performed at this time.
func NewDepUpdate(cfg env.Config) *DepUpdate {
return &DepUpdate{
Chart: cfg.Chart,
config: newConfig(cfg),
chart: cfg.Chart,
}
}
@ -24,28 +26,28 @@ func (d *DepUpdate) Execute() error {
}
// Prepare gets the DepUpdate ready to execute.
func (d *DepUpdate) Prepare(cfg Config) error {
if d.Chart == "" {
func (d *DepUpdate) Prepare() error {
if d.chart == "" {
return fmt.Errorf("chart is required")
}
args := make([]string, 0)
if cfg.Namespace != "" {
args = append(args, "--namespace", cfg.Namespace)
if d.namespace != "" {
args = append(args, "--namespace", d.namespace)
}
if cfg.Debug {
if d.debug {
args = append(args, "--debug")
}
args = append(args, "dependency", "update", d.Chart)
args = append(args, "dependency", "update", d.chart)
d.cmd = command(helmBin, args...)
d.cmd.Stdout(cfg.Stdout)
d.cmd.Stderr(cfg.Stderr)
d.cmd.Stdout(d.stdout)
d.cmd.Stderr(d.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", d.cmd.String())
if d.debug {
fmt.Fprintf(d.stderr, "Generated command: '%s'\n", d.cmd.String())
}
return nil

View file

@ -37,7 +37,7 @@ func (suite *DepUpdateTestSuite) TestNewDepUpdate() {
Chart: "scatterplot",
}
d := NewDepUpdate(cfg)
suite.Equal("scatterplot", d.Chart)
suite.Equal("scatterplot", d.chart)
}
func (suite *DepUpdateTestSuite) TestPrepareAndExecute() {
@ -45,7 +45,8 @@ func (suite *DepUpdateTestSuite) TestPrepareAndExecute() {
stdout := strings.Builder{}
stderr := strings.Builder{}
cfg := Config{
cfg := env.Config{
Chart: "your_top_songs_2019",
Stdout: &stdout,
Stderr: &stderr,
}
@ -64,19 +65,18 @@ func (suite *DepUpdateTestSuite) TestPrepareAndExecute() {
Run().
Times(1)
d := DepUpdate{
Chart: "your_top_songs_2019",
}
d := NewDepUpdate(cfg)
suite.Require().NoError(d.Prepare(cfg))
suite.Require().NoError(d.Prepare())
suite.NoError(d.Execute())
}
func (suite *DepUpdateTestSuite) TestPrepareNamespaceFlag() {
defer suite.ctrl.Finish()
cfg := Config{
cfg := env.Config{
Namespace: "spotify",
Chart: "your_top_songs_2019",
}
command = func(path string, args ...string) cmd {
@ -87,11 +87,9 @@ func (suite *DepUpdateTestSuite) TestPrepareNamespaceFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
d := DepUpdate{
Chart: "your_top_songs_2019",
}
d := NewDepUpdate(cfg)
suite.Require().NoError(d.Prepare(cfg))
suite.Require().NoError(d.Prepare())
}
func (suite *DepUpdateTestSuite) TestPrepareDebugFlag() {
@ -99,7 +97,8 @@ func (suite *DepUpdateTestSuite) TestPrepareDebugFlag() {
stdout := strings.Builder{}
stderr := strings.Builder{}
cfg := Config{
cfg := env.Config{
Chart: "your_top_songs_2019",
Debug: true,
Stdout: &stdout,
Stderr: &stderr,
@ -115,11 +114,9 @@ func (suite *DepUpdateTestSuite) TestPrepareDebugFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
d := DepUpdate{
Chart: "your_top_songs_2019",
}
d := NewDepUpdate(cfg)
suite.Require().NoError(d.Prepare(cfg))
suite.Require().NoError(d.Prepare())
want := fmt.Sprintf("Generated command: '%s --debug dependency update your_top_songs_2019'\n", helmBin)
suite.Equal(want, stderr.String())
@ -127,11 +124,11 @@ func (suite *DepUpdateTestSuite) TestPrepareDebugFlag() {
}
func (suite *DepUpdateTestSuite) TestPrepareChartRequired() {
d := DepUpdate{}
d := NewDepUpdate(env.Config{})
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
err := d.Prepare(Config{})
err := d.Prepare()
suite.EqualError(err, "chart is required")
}

View file

@ -7,14 +7,16 @@ import (
// Help is a step in a helm Plan that calls `helm help`.
type Help struct {
HelmCommand string
*config
helmCommand string
cmd cmd
}
// NewHelp creates a Help using fields from the given Config. No validation is performed at this time.
func NewHelp(cfg env.Config) *Help {
return &Help{
HelmCommand: cfg.Command,
config: newConfig(cfg),
helmCommand: cfg.Command,
}
}
@ -24,25 +26,25 @@ func (h *Help) Execute() error {
return fmt.Errorf("while running '%s': %w", h.cmd.String(), err)
}
if h.HelmCommand == "help" {
if h.helmCommand == "help" {
return nil
}
return fmt.Errorf("unknown command '%s'", h.HelmCommand)
return fmt.Errorf("unknown command '%s'", h.helmCommand)
}
// Prepare gets the Help ready to execute.
func (h *Help) Prepare(cfg Config) error {
func (h *Help) Prepare() error {
args := []string{"help"}
if cfg.Debug {
if h.debug {
args = append([]string{"--debug"}, args...)
}
h.cmd = command(helmBin, args...)
h.cmd.Stdout(cfg.Stdout)
h.cmd.Stderr(cfg.Stderr)
h.cmd.Stdout(h.stdout)
h.cmd.Stderr(h.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", h.cmd.String())
if h.debug {
fmt.Fprintf(h.stderr, "Generated command: '%s'\n", h.cmd.String())
}
return nil

View file

@ -24,7 +24,7 @@ func (suite *HelpTestSuite) TestNewHelp() {
}
help := NewHelp(cfg)
suite.Require().NotNil(help)
suite.Equal("everybody dance NOW!!", help.HelmCommand)
suite.Equal("everybody dance NOW!!", help.helmCommand)
}
func (suite *HelpTestSuite) TestPrepare() {
@ -49,13 +49,13 @@ func (suite *HelpTestSuite) TestPrepare() {
mCmd.EXPECT().
Stderr(&stderr)
cfg := Config{
cfg := env.Config{
Stdout: &stdout,
Stderr: &stderr,
}
h := Help{}
err := h.Prepare(cfg)
h := NewHelp(cfg)
err := h.Prepare()
suite.NoError(err)
}
@ -63,38 +63,30 @@ func (suite *HelpTestSuite) TestExecute() {
ctrl := gomock.NewController(suite.T())
defer ctrl.Finish()
mCmd := NewMockcmd(ctrl)
originalCommand := command
command = func(_ string, _ ...string) cmd {
return mCmd
}
defer func() { command = originalCommand }()
mCmd.EXPECT().
Run().
Times(2)
help := Help{
HelmCommand: "help",
cmd: mCmd,
}
help := NewHelp(env.Config{Command: "help"})
help.cmd = mCmd
suite.NoError(help.Execute())
help.HelmCommand = "get down on friday"
help.helmCommand = "get down on friday"
suite.EqualError(help.Execute(), "unknown command 'get down on friday'")
}
func (suite *HelpTestSuite) TestPrepareDebugFlag() {
help := Help{}
stdout := strings.Builder{}
stderr := strings.Builder{}
cfg := Config{
cfg := env.Config{
Debug: true,
Stdout: &stdout,
Stderr: &stderr,
}
help.Prepare(cfg)
help := NewHelp(cfg)
help.Prepare()
want := fmt.Sprintf("Generated command: '%s --debug help'\n", helmBin)
suite.Equal(want, stderr.String())

View file

@ -11,10 +11,9 @@ import (
// InitKube is a step in a helm Plan that initializes the kubernetes config file.
type InitKube struct {
*config
templateFilename string
configFilename string
debug bool
stderr io.Writer
template *template.Template
configFile io.WriteCloser
values kubeValues
@ -32,6 +31,7 @@ type kubeValues struct {
// NewInitKube creates a InitKube using the given Config and filepaths. No validation is performed at this time.
func NewInitKube(cfg env.Config, templateFile, configFile string) *InitKube {
return &InitKube{
config: newConfig(cfg),
values: kubeValues{
SkipTLSVerify: cfg.SkipTLSVerify,
Certificate: cfg.Certificate,
@ -42,8 +42,6 @@ func NewInitKube(cfg env.Config, templateFile, configFile string) *InitKube {
},
templateFilename: templateFile,
configFilename: configFile,
debug: cfg.Debug,
stderr: cfg.Stderr,
}
}
@ -57,7 +55,7 @@ func (i *InitKube) Execute() error {
}
// Prepare ensures all required configuration is present and that the config file is writable.
func (i *InitKube) Prepare(cfg Config) error {
func (i *InitKube) Prepare() error {
var err error
if i.values.APIServer == "" {

View file

@ -32,19 +32,16 @@ func (suite *InitKubeTestSuite) TestNewInitKube() {
}
init := NewInitKube(cfg, "conf.tpl", "conf.yml")
suite.Equal(&InitKube{
values: kubeValues{
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
Token: "b2YgbXkgYWZmZWN0aW9u",
},
templateFilename: "conf.tpl",
configFilename: "conf.yml",
debug: true,
stderr: cfg.Stderr,
}, init)
suite.Equal(kubeValues{
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
Token: "b2YgbXkgYWZmZWN0aW9u",
}, init.values)
suite.Equal("conf.tpl", init.templateFilename)
suite.Equal("conf.yml", init.configFilename)
suite.NotNil(init.config)
}
func (suite *InitKubeTestSuite) TestPrepareExecute() {
@ -59,18 +56,14 @@ namespace: {{ .Namespace }}
defer os.Remove(configFile.Name())
suite.Require().Nil(err)
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
Namespace: "Cisco",
},
templateFilename: templateFile.Name(),
configFilename: configFile.Name(),
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
Namespace: "Cisco",
}
cfg := Config{}
err = init.Prepare(cfg)
init := NewInitKube(cfg, templateFile.Name(), configFile.Name())
err = init.Prepare()
suite.Require().Nil(err)
suite.IsType(&template.Template{}, init.template)
@ -94,19 +87,15 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() {
defer os.Remove(configFile.Name())
suite.Require().NoError(err)
cfg := Config{}
init := InitKube{
configFilename: configFile.Name(),
templateFilename: "../../assets/kubeconfig.tpl", // the actual kubeconfig template
values: kubeValues{
APIServer: "https://kube.cluster/peanut",
ServiceAccount: "chef",
Token: "eWVhaCB3ZSB0b2tpbic=",
Certificate: "d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE",
Namespace: "marshmallow",
},
cfg := env.Config{
APIServer: "https://kube.cluster/peanut",
ServiceAccount: "chef",
KubeToken: "eWVhaCB3ZSB0b2tpbic=",
Certificate: "d293LCB5b3UgYXJlIHNvIGNvb2wgZm9yIHNtb2tpbmcgd2VlZCDwn5mE",
Namespace: "marshmallow",
}
suite.Require().NoError(init.Prepare(cfg))
init := NewInitKube(cfg, "../../assets/kubeconfig.tpl", configFile.Name()) // the actual kubeconfig template
suite.Require().NoError(init.Prepare())
suite.Require().NoError(init.Execute())
contents, err := ioutil.ReadFile(configFile.Name())
@ -133,7 +122,7 @@ func (suite *InitKubeTestSuite) TestExecuteGeneratesConfig() {
init.values.SkipTLSVerify = true
init.values.Certificate = ""
suite.Require().NoError(init.Prepare(cfg))
suite.Require().NoError(init.Prepare())
suite.Require().NoError(init.Execute())
contents, err = ioutil.ReadFile(configFile.Name())
suite.Require().NoError(err)
@ -148,29 +137,25 @@ func (suite *InitKubeTestSuite) TestPrepareParseError() {
defer os.Remove(templateFile.Name())
suite.Require().Nil(err)
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
},
templateFilename: templateFile.Name(),
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
}
err = init.Prepare(Config{})
init := NewInitKube(cfg, templateFile.Name(), "")
err = init.Prepare()
suite.Error(err)
suite.Regexp("could not load kubeconfig .* function .* not defined", err)
}
func (suite *InitKubeTestSuite) TestPrepareNonexistentTemplateFile() {
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
},
templateFilename: "/usr/foreign/exclude/kubeprofig.tpl",
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
}
err := init.Prepare(Config{})
init := NewInitKube(cfg, "/usr/foreign/exclude/kubeprofig.tpl", "")
err := init.Prepare()
suite.Error(err)
suite.Regexp("could not load kubeconfig .* no such file or directory", err)
}
@ -179,18 +164,14 @@ func (suite *InitKubeTestSuite) TestPrepareCannotOpenDestinationFile() {
templateFile, err := tempfile("kubeconfig********.yml.tpl", "hurgity burgity")
defer os.Remove(templateFile.Name())
suite.Require().Nil(err)
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
},
templateFilename: templateFile.Name(),
configFilename: "/usr/foreign/exclude/kubeprofig",
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
}
init := NewInitKube(cfg, templateFile.Name(), "/usr/foreign/exclude/kubeprofig")
cfg := Config{}
err = init.Prepare(cfg)
err = init.Prepare()
suite.Error(err)
suite.Regexp("could not open .* for writing: .* no such file or directory", err)
}
@ -205,26 +186,21 @@ func (suite *InitKubeTestSuite) TestPrepareRequiredConfig() {
suite.Require().Nil(err)
// initial config with all required fields present
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
},
templateFilename: templateFile.Name(),
configFilename: configFile.Name(),
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
}
cfg := Config{}
suite.NoError(init.Prepare(cfg)) // consistency check; we should be starting in a happy state
init := NewInitKube(cfg, templateFile.Name(), configFile.Name())
suite.NoError(init.Prepare()) // consistency check; we should be starting in a happy state
init.values.APIServer = ""
suite.Error(init.Prepare(cfg), "APIServer should be required.")
suite.Error(init.Prepare(), "APIServer should be required.")
init.values.APIServer = "Sysadmin"
init.values.Token = ""
suite.Error(init.Prepare(cfg), "Token should be required.")
suite.Error(init.Prepare(), "Token should be required.")
}
func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() {
@ -236,19 +212,14 @@ func (suite *InitKubeTestSuite) TestPrepareDefaultsServiceAccount() {
defer os.Remove(configFile.Name())
suite.Require().Nil(err)
init := InitKube{
values: kubeValues{
APIServer: "Sysadmin",
Certificate: "CCNA",
Token: "Aspire virtual currency",
},
templateFilename: templateFile.Name(),
configFilename: configFile.Name(),
cfg := env.Config{
APIServer: "Sysadmin",
Certificate: "CCNA",
KubeToken: "Aspire virtual currency",
}
init := NewInitKube(cfg, templateFile.Name(), configFile.Name())
cfg := Config{}
init.Prepare(cfg)
init.Prepare()
suite.Equal("helm", init.values.ServiceAccount)
}
@ -270,14 +241,8 @@ func (suite *InitKubeTestSuite) TestDebugOutput() {
Stdout: stdout,
Stderr: stderr,
}
runCfg := Config{
Debug: true,
Stdout: stdout,
Stderr: stderr,
}
init := NewInitKube(cfg, templateFile.Name(), configFile.Name())
suite.NoError(init.Prepare(runCfg))
suite.NoError(init.Prepare())
suite.Contains(stderr.String(), fmt.Sprintf("loading kubeconfig template from %s\n", templateFile.Name()))
suite.Contains(stderr.String(), fmt.Sprintf("truncating kubeconfig file at %s\n", configFile.Name()))

View file

@ -7,22 +7,24 @@ import (
// Lint is an execution step that calls `helm lint` when executed.
type Lint struct {
Chart string
Values string
StringValues string
ValuesFiles []string
Strict bool
*config
chart string
values string
stringValues string
valuesFiles []string
strict bool
cmd cmd
}
// NewLint creates a Lint using fields from the given Config. No validation is performed at this time.
func NewLint(cfg env.Config) *Lint {
return &Lint{
Chart: cfg.Chart,
Values: cfg.Values,
StringValues: cfg.StringValues,
ValuesFiles: cfg.ValuesFiles,
Strict: cfg.LintStrictly,
config: newConfig(cfg),
chart: cfg.Chart,
values: cfg.Values,
stringValues: cfg.StringValues,
valuesFiles: cfg.ValuesFiles,
strict: cfg.LintStrictly,
}
}
@ -32,43 +34,43 @@ func (l *Lint) Execute() error {
}
// Prepare gets the Lint ready to execute.
func (l *Lint) Prepare(cfg Config) error {
if l.Chart == "" {
func (l *Lint) Prepare() error {
if l.chart == "" {
return fmt.Errorf("chart is required")
}
args := make([]string, 0)
if cfg.Namespace != "" {
args = append(args, "--namespace", cfg.Namespace)
if l.namespace != "" {
args = append(args, "--namespace", l.namespace)
}
if cfg.Debug {
if l.debug {
args = append(args, "--debug")
}
args = append(args, "lint")
if l.Values != "" {
args = append(args, "--set", l.Values)
if l.values != "" {
args = append(args, "--set", l.values)
}
if l.StringValues != "" {
args = append(args, "--set-string", l.StringValues)
if l.stringValues != "" {
args = append(args, "--set-string", l.stringValues)
}
for _, vFile := range l.ValuesFiles {
for _, vFile := range l.valuesFiles {
args = append(args, "--values", vFile)
}
if l.Strict {
if l.strict {
args = append(args, "--strict")
}
args = append(args, l.Chart)
args = append(args, l.chart)
l.cmd = command(helmBin, args...)
l.cmd.Stdout(cfg.Stdout)
l.cmd.Stderr(cfg.Stderr)
l.cmd.Stdout(l.stdout)
l.cmd.Stderr(l.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", l.cmd.String())
if l.debug {
fmt.Fprintf(l.stderr, "Generated command: '%s'\n", l.cmd.String())
}
return nil

View file

@ -42,13 +42,12 @@ func (suite *LintTestSuite) TestNewLint() {
}
lint := NewLint(cfg)
suite.Require().NotNil(lint)
suite.Equal(&Lint{
Chart: "./flow",
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
Strict: true,
}, lint)
suite.Equal("./flow", lint.chart)
suite.Equal("steadfastness,forthrightness", lint.values)
suite.Equal("tensile_strength,flexibility", lint.stringValues)
suite.Equal([]string{"/root/price_inventory.yml"}, lint.valuesFiles)
suite.Equal(true, lint.strict)
suite.NotNil(lint.config)
}
func (suite *LintTestSuite) TestPrepareAndExecute() {
@ -57,13 +56,12 @@ func (suite *LintTestSuite) TestPrepareAndExecute() {
stdout := strings.Builder{}
stderr := strings.Builder{}
l := Lint{
Chart: "./epic/mychart",
}
cfg := Config{
cfg := env.Config{
Chart: "./epic/mychart",
Stdout: &stdout,
Stderr: &stderr,
}
l := NewLint(cfg)
command = func(path string, args ...string) cmd {
suite.Equal(helmBin, path)
@ -72,6 +70,7 @@ func (suite *LintTestSuite) TestPrepareAndExecute() {
return suite.mockCmd
}
suite.mockCmd.EXPECT().String().AnyTimes()
suite.mockCmd.EXPECT().
Stdout(&stdout)
suite.mockCmd.EXPECT().
@ -80,7 +79,7 @@ func (suite *LintTestSuite) TestPrepareAndExecute() {
Run().
Times(1)
err := l.Prepare(cfg)
err := l.Prepare()
suite.Require().Nil(err)
l.Execute()
}
@ -90,25 +89,22 @@ func (suite *LintTestSuite) TestPrepareRequiresChart() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
cfg := Config{}
l := Lint{}
err := l.Prepare(cfg)
l := NewLint(env.Config{})
err := l.Prepare()
suite.EqualError(err, "chart is required", "Chart should be mandatory")
}
func (suite *LintTestSuite) TestPrepareWithLintFlags() {
defer suite.ctrl.Finish()
cfg := Config{}
l := Lint{
cfg := env.Config{
Chart: "./uk/top_40",
Values: "width=5",
StringValues: "version=2.0",
ValuesFiles: []string{"/usr/local/underrides", "/usr/local/overrides"},
Strict: true,
LintStrictly: true,
}
l := NewLint(cfg)
command = func(path string, args ...string) cmd {
suite.Equal(helmBin, path)
@ -125,8 +121,9 @@ func (suite *LintTestSuite) TestPrepareWithLintFlags() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().String().AnyTimes()
err := l.Prepare(cfg)
err := l.Prepare()
suite.Require().Nil(err)
}
@ -135,14 +132,12 @@ func (suite *LintTestSuite) TestPrepareWithDebugFlag() {
stderr := strings.Builder{}
cfg := Config{
cfg := env.Config{
Debug: true,
Stderr: &stderr,
Chart: "./scotland/top_40",
}
l := Lint{
Chart: "./scotland/top_40",
}
l := NewLint(cfg)
command = func(path string, args ...string) cmd {
suite.mockCmd.EXPECT().
@ -155,7 +150,7 @@ func (suite *LintTestSuite) TestPrepareWithDebugFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any())
suite.mockCmd.EXPECT().Stderr(&stderr)
err := l.Prepare(cfg)
err := l.Prepare()
suite.Require().Nil(err)
want := fmt.Sprintf("Generated command: '%s --debug lint ./scotland/top_40'\n", helmBin)
@ -165,13 +160,11 @@ func (suite *LintTestSuite) TestPrepareWithDebugFlag() {
func (suite *LintTestSuite) TestPrepareWithNamespaceFlag() {
defer suite.ctrl.Finish()
cfg := Config{
cfg := env.Config{
Namespace: "table-service",
Chart: "./wales/top_40",
}
l := Lint{
Chart: "./wales/top_40",
}
l := NewLint(cfg)
actual := []string{}
command = func(path string, args ...string) cmd {
@ -182,7 +175,7 @@ func (suite *LintTestSuite) TestPrepareWithNamespaceFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
err := l.Prepare(cfg)
err := l.Prepare()
suite.Require().Nil(err)
expected := []string{"--namespace", "table-service", "lint", "./wales/top_40"}

View file

@ -7,18 +7,20 @@ import (
// Uninstall is an execution step that calls `helm uninstall` when executed.
type Uninstall struct {
Release string
DryRun bool
KeepHistory bool
*config
release string
dryRun bool
keepHistory bool
cmd cmd
}
// NewUninstall creates an Uninstall using fields from the given Config. No validation is performed at this time.
func NewUninstall(cfg env.Config) *Uninstall {
return &Uninstall{
Release: cfg.Release,
DryRun: cfg.DryRun,
KeepHistory: cfg.KeepHistory,
config: newConfig(cfg),
release: cfg.Release,
dryRun: cfg.DryRun,
keepHistory: cfg.KeepHistory,
}
}
@ -28,37 +30,37 @@ func (u *Uninstall) Execute() error {
}
// Prepare gets the Uninstall ready to execute.
func (u *Uninstall) Prepare(cfg Config) error {
if u.Release == "" {
func (u *Uninstall) Prepare() error {
if u.release == "" {
return fmt.Errorf("release is required")
}
args := make([]string, 0)
if cfg.Namespace != "" {
args = append(args, "--namespace", cfg.Namespace)
if u.namespace != "" {
args = append(args, "--namespace", u.namespace)
}
if cfg.Debug {
if u.debug {
args = append(args, "--debug")
}
args = append(args, "uninstall")
if u.DryRun {
if u.dryRun {
args = append(args, "--dry-run")
}
if u.KeepHistory {
if u.keepHistory {
args = append(args, "--keep-history")
}
args = append(args, u.Release)
args = append(args, u.release)
u.cmd = command(helmBin, args...)
u.cmd.Stdout(cfg.Stdout)
u.cmd.Stderr(cfg.Stderr)
u.cmd.Stdout(u.stdout)
u.cmd.Stderr(u.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", u.cmd.String())
if u.debug {
fmt.Fprintf(u.stderr, "Generated command: '%s'\n", u.cmd.String())
}
return nil

View file

@ -43,19 +43,19 @@ func (suite *UninstallTestSuite) TestNewUninstall() {
KeepHistory: true,
}
u := NewUninstall(cfg)
suite.Equal(&Uninstall{
Release: "jetta_id_love_to_change_the_world",
DryRun: true,
KeepHistory: true,
}, u)
suite.Equal("jetta_id_love_to_change_the_world", u.release)
suite.Equal(true, u.dryRun)
suite.Equal(true, u.keepHistory)
suite.NotNil(u.config)
}
func (suite *UninstallTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()
u := Uninstall{
cfg := env.Config{
Release: "zayde_wølf_king",
}
u := NewUninstall(cfg)
actual := []string{}
command = func(path string, args ...string) cmd {
@ -73,8 +73,7 @@ func (suite *UninstallTestSuite) TestPrepareAndExecute() {
Run().
Times(1)
cfg := Config{}
suite.NoError(u.Prepare(cfg))
suite.NoError(u.Prepare())
expected := []string{"uninstall", "zayde_wølf_king"}
suite.Equal(expected, actual)
@ -82,60 +81,58 @@ func (suite *UninstallTestSuite) TestPrepareAndExecute() {
}
func (suite *UninstallTestSuite) TestPrepareDryRunFlag() {
u := Uninstall{
cfg := env.Config{
Release: "firefox_ak_wildfire",
DryRun: true,
}
cfg := Config{}
u := NewUninstall(cfg)
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
suite.NoError(u.Prepare(cfg))
suite.NoError(u.Prepare())
expected := []string{"uninstall", "--dry-run", "firefox_ak_wildfire"}
suite.Equal(expected, suite.actualArgs)
}
func (suite *UninstallTestSuite) TestPrepareKeepHistoryFlag() {
u := Uninstall{
cfg := env.Config{
Release: "perturbator_sentient",
KeepHistory: true,
}
cfg := Config{}
u := NewUninstall(cfg)
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
suite.NoError(u.Prepare(cfg))
suite.NoError(u.Prepare())
expected := []string{"uninstall", "--keep-history", "perturbator_sentient"}
suite.Equal(expected, suite.actualArgs)
}
func (suite *UninstallTestSuite) TestPrepareNamespaceFlag() {
u := Uninstall{
Release: "carly_simon_run_away_with_me",
}
cfg := Config{
cfg := env.Config{
Release: "carly_simon_run_away_with_me",
Namespace: "emotion",
}
u := NewUninstall(cfg)
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
suite.NoError(u.Prepare(cfg))
suite.NoError(u.Prepare())
expected := []string{"--namespace", "emotion", "uninstall", "carly_simon_run_away_with_me"}
suite.Equal(expected, suite.actualArgs)
}
func (suite *UninstallTestSuite) TestPrepareDebugFlag() {
u := Uninstall{
Release: "just_a_band_huff_and_puff",
}
stderr := strings.Builder{}
cfg := Config{
Debug: true,
Stderr: &stderr,
cfg := env.Config{
Release: "just_a_band_huff_and_puff",
Debug: true,
Stderr: &stderr,
}
u := NewUninstall(cfg)
command = func(path string, args ...string) cmd {
suite.mockCmd.EXPECT().
@ -148,7 +145,7 @@ func (suite *UninstallTestSuite) TestPrepareDebugFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(&stderr).AnyTimes()
suite.NoError(u.Prepare(cfg))
suite.NoError(u.Prepare())
suite.Equal(fmt.Sprintf("Generated command: '%s --debug "+
"uninstall just_a_band_huff_and_puff'\n", helmBin), stderr.String())
}
@ -158,7 +155,7 @@ func (suite *UninstallTestSuite) TestPrepareRequiresRelease() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
u := Uninstall{}
err := u.Prepare(Config{})
u := NewUninstall(env.Config{})
err := u.Prepare()
suite.EqualError(err, "release is required", "Uninstall.Release should be mandatory")
}

View file

@ -7,20 +7,21 @@ import (
// Upgrade is an execution step that calls `helm upgrade` when executed.
type Upgrade struct {
Chart string
Release string
*config
chart string
release string
ChartVersion string
DryRun bool
Wait bool
Values string
StringValues string
ValuesFiles []string
ReuseValues bool
Timeout string
Force bool
Atomic bool
CleanupOnFail bool
chartVersion string
dryRun bool
wait bool
values string
stringValues string
valuesFiles []string
reuseValues bool
timeout string
force bool
atomic bool
cleanupOnFail bool
cmd cmd
}
@ -28,19 +29,20 @@ type Upgrade struct {
// NewUpgrade creates an Upgrade using fields from the given Config. No validation is performed at this time.
func NewUpgrade(cfg env.Config) *Upgrade {
return &Upgrade{
Chart: cfg.Chart,
Release: cfg.Release,
ChartVersion: cfg.ChartVersion,
DryRun: cfg.DryRun,
Wait: cfg.Wait,
Values: cfg.Values,
StringValues: cfg.StringValues,
ValuesFiles: cfg.ValuesFiles,
ReuseValues: cfg.ReuseValues,
Timeout: cfg.Timeout,
Force: cfg.Force,
Atomic: cfg.AtomicUpgrade,
CleanupOnFail: cfg.CleanupOnFail,
config: newConfig(cfg),
chart: cfg.Chart,
release: cfg.Release,
chartVersion: cfg.ChartVersion,
dryRun: cfg.DryRun,
wait: cfg.Wait,
values: cfg.Values,
stringValues: cfg.StringValues,
valuesFiles: cfg.ValuesFiles,
reuseValues: cfg.ReuseValues,
timeout: cfg.Timeout,
force: cfg.Force,
atomic: cfg.AtomicUpgrade,
cleanupOnFail: cfg.CleanupOnFail,
}
}
@ -50,66 +52,66 @@ func (u *Upgrade) Execute() error {
}
// Prepare gets the Upgrade ready to execute.
func (u *Upgrade) Prepare(cfg Config) error {
if u.Chart == "" {
func (u *Upgrade) Prepare() error {
if u.chart == "" {
return fmt.Errorf("chart is required")
}
if u.Release == "" {
if u.release == "" {
return fmt.Errorf("release is required")
}
args := make([]string, 0)
if cfg.Namespace != "" {
args = append(args, "--namespace", cfg.Namespace)
if u.namespace != "" {
args = append(args, "--namespace", u.namespace)
}
if cfg.Debug {
if u.debug {
args = append(args, "--debug")
}
args = append(args, "upgrade", "--install")
if u.ChartVersion != "" {
args = append(args, "--version", u.ChartVersion)
if u.chartVersion != "" {
args = append(args, "--version", u.chartVersion)
}
if u.DryRun {
if u.dryRun {
args = append(args, "--dry-run")
}
if u.Wait {
if u.wait {
args = append(args, "--wait")
}
if u.ReuseValues {
if u.reuseValues {
args = append(args, "--reuse-values")
}
if u.Timeout != "" {
args = append(args, "--timeout", u.Timeout)
if u.timeout != "" {
args = append(args, "--timeout", u.timeout)
}
if u.Force {
if u.force {
args = append(args, "--force")
}
if u.Atomic {
if u.atomic {
args = append(args, "--atomic")
}
if u.CleanupOnFail {
if u.cleanupOnFail {
args = append(args, "--cleanup-on-fail")
}
if u.Values != "" {
args = append(args, "--set", u.Values)
if u.values != "" {
args = append(args, "--set", u.values)
}
if u.StringValues != "" {
args = append(args, "--set-string", u.StringValues)
if u.stringValues != "" {
args = append(args, "--set-string", u.stringValues)
}
for _, vFile := range u.ValuesFiles {
for _, vFile := range u.valuesFiles {
args = append(args, "--values", vFile)
}
args = append(args, u.Release, u.Chart)
args = append(args, u.release, u.chart)
u.cmd = command(helmBin, args...)
u.cmd.Stdout(cfg.Stdout)
u.cmd.Stderr(cfg.Stderr)
u.cmd.Stdout(u.stdout)
u.cmd.Stderr(u.stderr)
if cfg.Debug {
fmt.Fprintf(cfg.Stderr, "Generated command: '%s'\n", u.cmd.String())
if u.debug {
fmt.Fprintf(u.stderr, "Generated command: '%s'\n", u.cmd.String())
}
return nil

View file

@ -50,30 +50,30 @@ func (suite *UpgradeTestSuite) TestNewUpgrade() {
}
up := NewUpgrade(cfg)
suite.Equal(&Upgrade{
Chart: cfg.Chart,
Release: cfg.Release,
ChartVersion: cfg.ChartVersion,
DryRun: true,
Wait: cfg.Wait,
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
ReuseValues: cfg.ReuseValues,
Timeout: cfg.Timeout,
Force: cfg.Force,
Atomic: true,
CleanupOnFail: true,
}, up)
suite.Equal(cfg.Chart, up.chart)
suite.Equal(cfg.Release, up.release)
suite.Equal(cfg.ChartVersion, up.chartVersion)
suite.Equal(true, up.dryRun)
suite.Equal(cfg.Wait, up.wait)
suite.Equal("steadfastness,forthrightness", up.values)
suite.Equal("tensile_strength,flexibility", up.stringValues)
suite.Equal([]string{"/root/price_inventory.yml"}, up.valuesFiles)
suite.Equal(cfg.ReuseValues, up.reuseValues)
suite.Equal(cfg.Timeout, up.timeout)
suite.Equal(cfg.Force, up.force)
suite.Equal(true, up.atomic)
suite.Equal(true, up.cleanupOnFail)
suite.NotNil(up.config)
}
func (suite *UpgradeTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()
u := Upgrade{
cfg := env.Config{
Chart: "at40",
Release: "jonas_brothers_only_human",
}
u := NewUpgrade(cfg)
command = func(path string, args ...string) cmd {
suite.Equal(helmBin, path)
@ -90,8 +90,7 @@ func (suite *UpgradeTestSuite) TestPrepareAndExecute() {
Run().
Times(1)
cfg := Config{}
err := u.Prepare(cfg)
err := u.Prepare()
suite.Require().Nil(err)
u.Execute()
}
@ -99,10 +98,12 @@ func (suite *UpgradeTestSuite) TestPrepareAndExecute() {
func (suite *UpgradeTestSuite) TestPrepareNamespaceFlag() {
defer suite.ctrl.Finish()
u := Upgrade{
Chart: "at40",
Release: "shaed_trampoline",
cfg := env.Config{
Namespace: "melt",
Chart: "at40",
Release: "shaed_trampoline",
}
u := NewUpgrade(cfg)
command = func(path string, args ...string) cmd {
suite.Equal(helmBin, path)
@ -114,17 +115,14 @@ func (suite *UpgradeTestSuite) TestPrepareNamespaceFlag() {
suite.mockCmd.EXPECT().Stdout(gomock.Any())
suite.mockCmd.EXPECT().Stderr(gomock.Any())
cfg := Config{
Namespace: "melt",
}
err := u.Prepare(cfg)
err := u.Prepare()
suite.Require().Nil(err)
}
func (suite *UpgradeTestSuite) TestPrepareWithUpgradeFlags() {
defer suite.ctrl.Finish()
u := Upgrade{
cfg := env.Config{
Chart: "hot_ac",
Release: "maroon_5_memories",
ChartVersion: "radio_edit",
@ -136,11 +134,10 @@ func (suite *UpgradeTestSuite) TestPrepareWithUpgradeFlags() {
ReuseValues: true,
Timeout: "sit_in_the_corner",
Force: true,
Atomic: true,
AtomicUpgrade: true,
CleanupOnFail: true,
}
cfg := Config{}
u := NewUpgrade(cfg)
command = func(path string, args ...string) cmd {
suite.Equal(helmBin, path)
@ -165,7 +162,7 @@ func (suite *UpgradeTestSuite) TestPrepareWithUpgradeFlags() {
suite.mockCmd.EXPECT().Stdout(gomock.Any())
suite.mockCmd.EXPECT().Stderr(gomock.Any())
err := u.Prepare(cfg)
err := u.Prepare()
suite.Require().Nil(err)
}
@ -174,34 +171,30 @@ func (suite *UpgradeTestSuite) TestRequiresChartAndRelease() {
suite.mockCmd.EXPECT().Stdout(gomock.Any()).AnyTimes()
suite.mockCmd.EXPECT().Stderr(gomock.Any()).AnyTimes()
u := Upgrade{
Release: "seth_everman_unskippable_cutscene",
}
u := NewUpgrade(env.Config{})
u.release = "seth_everman_unskippable_cutscene"
err := u.Prepare(Config{})
err := u.Prepare()
suite.EqualError(err, "chart is required", "Chart should be mandatory")
u = Upgrade{
Chart: "billboard_top_zero",
}
u.release = ""
u.chart = "billboard_top_zero"
err = u.Prepare(Config{})
err = u.Prepare()
suite.EqualError(err, "release is required", "Release should be mandatory")
}
func (suite *UpgradeTestSuite) TestPrepareDebugFlag() {
u := Upgrade{
Chart: "at40",
Release: "lewis_capaldi_someone_you_loved",
}
stdout := strings.Builder{}
stderr := strings.Builder{}
cfg := Config{
Debug: true,
Stdout: &stdout,
Stderr: &stderr,
cfg := env.Config{
Chart: "at40",
Release: "lewis_capaldi_someone_you_loved",
Debug: true,
Stdout: &stdout,
Stderr: &stderr,
}
u := NewUpgrade(cfg)
command = func(path string, args ...string) cmd {
suite.mockCmd.EXPECT().
@ -216,7 +209,7 @@ func (suite *UpgradeTestSuite) TestPrepareDebugFlag() {
suite.mockCmd.EXPECT().
Stderr(&stderr)
u.Prepare(cfg)
u.Prepare()
want := fmt.Sprintf("Generated command: '%s --debug upgrade "+
"--install lewis_capaldi_someone_you_loved at40'\n", helmBin)