Initialize Steps with a NewSTEPNAME function [#67]

This seems to be be a more natural separation of concerns--the knowledge
of which config fields map to which parts of a Step belong to the Step,
not to the Plan.
This commit is contained in:
Erin Call 2020-01-16 13:50:04 -08:00
parent 16117eea2f
commit 588c7cb9f7
No known key found for this signature in database
GPG key ID: 4071FF6C15B8DAD1
16 changed files with 218 additions and 179 deletions

View file

@ -98,21 +98,7 @@ var upgrade = func(cfg env.Config) []Step {
if cfg.UpdateDependencies {
steps = append(steps, depUpdate(cfg)...)
}
steps = append(steps, &run.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,
})
steps = append(steps, run.NewUpgrade(cfg))
return steps
}
@ -122,11 +108,7 @@ var uninstall = func(cfg env.Config) []Step {
if cfg.UpdateDependencies {
steps = append(steps, depUpdate(cfg)...)
}
steps = append(steps, &run.Uninstall{
Release: cfg.Release,
DryRun: cfg.DryRun,
KeepHistory: cfg.KeepHistory,
})
steps = append(steps, run.NewUninstall(cfg))
return steps
}
@ -136,53 +118,27 @@ var lint = func(cfg env.Config) []Step {
if cfg.UpdateDependencies {
steps = append(steps, depUpdate(cfg)...)
}
steps = append(steps, &run.Lint{
Chart: cfg.Chart,
Values: cfg.Values,
StringValues: cfg.StringValues,
ValuesFiles: cfg.ValuesFiles,
Strict: cfg.LintStrictly,
})
steps = append(steps, run.NewLint(cfg))
return steps
}
var help = func(cfg env.Config) []Step {
help := &run.Help{
HelmCommand: cfg.Command,
}
return []Step{help}
return []Step{run.NewHelp(cfg)}
}
func initKube(cfg env.Config) []Step {
return []Step{
&run.InitKube{
SkipTLSVerify: cfg.SkipTLSVerify,
Certificate: cfg.Certificate,
APIServer: cfg.APIServer,
ServiceAccount: cfg.ServiceAccount,
Token: cfg.KubeToken,
TemplateFile: kubeConfigTemplate,
ConfigFile: kubeConfigFile,
},
}
return []Step{run.NewInitKube(cfg, kubeConfigTemplate, kubeConfigFile)}
}
func addRepos(cfg env.Config) []Step {
steps := make([]Step, 0)
for _, repo := range cfg.AddRepos {
steps = append(steps, &run.AddRepo{
Repo: repo,
})
steps = append(steps, run.NewAddRepo(repo))
}
return steps
}
func depUpdate(cfg env.Config) []Step {
return []Step{
&run.DepUpdate{
Chart: cfg.Chart,
},
}
return []Step{run.NewDepUpdate(cfg)}
}

View file

@ -130,46 +130,10 @@ func (suite *PlanTestSuite) TestExecuteAbortsOnError() {
}
func (suite *PlanTestSuite) TestUpgrade() {
cfg := env.Config{
ChartVersion: "seventeen",
DryRun: true,
Wait: true,
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
ReuseValues: true,
Timeout: "go sit in the corner",
Chart: "billboard_top_100",
Release: "post_malone_circles",
Force: true,
AtomicUpgrade: true,
CleanupOnFail: true,
}
steps := upgrade(cfg)
steps := upgrade(env.Config{})
suite.Require().Equal(2, len(steps), "upgrade should return 2 steps")
suite.Require().IsType(&run.InitKube{}, steps[0])
suite.Require().IsType(&run.Upgrade{}, steps[1])
upgrade, _ := steps[1].(*run.Upgrade)
expected := &run.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,
}
suite.Equal(expected, upgrade)
suite.IsType(&run.InitKube{}, steps[0])
suite.IsType(&run.Upgrade{}, steps[1])
}
func (suite *PlanTestSuite) TestUpgradeWithUpdateDependencies() {
@ -194,43 +158,11 @@ func (suite *PlanTestSuite) TestUpgradeWithAddRepos() {
}
func (suite *PlanTestSuite) TestUninstall() {
cfg := env.Config{
KubeToken: "b2YgbXkgYWZmZWN0aW9u",
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
DryRun: true,
Timeout: "think about what you did",
Release: "jetta_id_love_to_change_the_world",
KeepHistory: true,
}
steps := uninstall(cfg)
steps := uninstall(env.Config{})
suite.Require().Equal(2, len(steps), "uninstall should return 2 steps")
suite.Require().IsType(&run.InitKube{}, steps[0])
init, _ := steps[0].(*run.InitKube)
var expected Step = &run.InitKube{
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
Token: "b2YgbXkgYWZmZWN0aW9u",
TemplateFile: kubeConfigTemplate,
ConfigFile: kubeConfigFile,
}
suite.Equal(expected, init)
suite.Require().IsType(&run.Uninstall{}, steps[1])
actual, _ := steps[1].(*run.Uninstall)
expected = &run.Uninstall{
Release: "jetta_id_love_to_change_the_world",
DryRun: true,
KeepHistory: true,
}
suite.Equal(expected, actual)
suite.IsType(&run.InitKube{}, steps[0])
suite.IsType(&run.Uninstall{}, steps[1])
}
func (suite *PlanTestSuite) TestUninstallWithUpdateDependencies() {
@ -244,46 +176,21 @@ func (suite *PlanTestSuite) TestUninstallWithUpdateDependencies() {
}
func (suite *PlanTestSuite) TestInitKube() {
cfg := env.Config{
KubeToken: "cXVlZXIgY2hhcmFjdGVyCg==",
SkipTLSVerify: true,
Certificate: "b2Ygd29rZW5lc3MK",
APIServer: "123.456.78.9",
ServiceAccount: "helmet",
}
cfg := env.Config{}
steps := initKube(cfg)
suite.Require().Equal(1, len(steps), "initKube should return one step")
suite.Require().IsType(&run.InitKube{}, steps[0])
init, _ := steps[0].(*run.InitKube)
expected := &run.InitKube{
SkipTLSVerify: true,
Certificate: "b2Ygd29rZW5lc3MK",
APIServer: "123.456.78.9",
ServiceAccount: "helmet",
Token: "cXVlZXIgY2hhcmFjdGVyCg==",
TemplateFile: kubeConfigTemplate,
ConfigFile: kubeConfigFile,
}
suite.Equal(expected, init)
suite.IsType(&run.InitKube{}, steps[0])
}
func (suite *PlanTestSuite) TestDepUpdate() {
cfg := env.Config{
UpdateDependencies: true,
Chart: "scatterplot",
}
steps := depUpdate(cfg)
suite.Require().Equal(1, len(steps), "depUpdate should return one step")
suite.Require().IsType(&run.DepUpdate{}, steps[0])
update, _ := steps[0].(*run.DepUpdate)
expected := &run.DepUpdate{
Chart: "scatterplot",
}
suite.Equal(expected, update)
suite.IsType(&run.DepUpdate{}, steps[0])
}
func (suite *PlanTestSuite) TestAddRepos() {
@ -295,35 +202,14 @@ func (suite *PlanTestSuite) TestAddRepos() {
}
steps := addRepos(cfg)
suite.Require().Equal(2, len(steps), "addRepos should add one step per repo")
suite.Require().IsType(&run.AddRepo{}, steps[0])
suite.Require().IsType(&run.AddRepo{}, steps[1])
first := steps[0].(*run.AddRepo)
second := steps[1].(*run.AddRepo)
suite.Equal(first.Repo, "first=https://add.repos/one")
suite.Equal(second.Repo, "second=https://add.repos/two")
suite.IsType(&run.AddRepo{}, steps[0])
suite.IsType(&run.AddRepo{}, steps[1])
}
func (suite *PlanTestSuite) TestLint() {
cfg := env.Config{
Chart: "./flow",
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
LintStrictly: true,
}
steps := lint(cfg)
suite.Equal(1, len(steps))
want := &run.Lint{
Chart: "./flow",
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
Strict: true,
}
suite.Equal(want, steps[0])
steps := lint(env.Config{})
suite.Require().Equal(1, len(steps))
suite.IsType(&run.Lint{}, steps[0])
}
func (suite *PlanTestSuite) TestLintWithUpdateDependencies() {

View file

@ -11,6 +11,13 @@ type AddRepo struct {
cmd cmd
}
// NewAddRepo creates an AddRepo for the given repo-spec. No validation is performed at this time.
func NewAddRepo(repo string) *AddRepo {
return &AddRepo{
Repo: repo,
}
}
// Execute executes the `helm repo add` command.
func (a *AddRepo) Execute(_ Config) error {
return a.cmd.Run()

View file

@ -38,6 +38,12 @@ func TestAddRepoTestSuite(t *testing.T) {
suite.Run(t, new(AddRepoTestSuite))
}
func (suite *AddRepoTestSuite) TestNewAddRepo() {
repo := NewAddRepo("picompress=https://github.com/caleb_phipps/picompress")
suite.Require().NotNil(repo)
suite.Equal("picompress=https://github.com/caleb_phipps/picompress", repo.Repo)
}
func (suite *AddRepoTestSuite) TestPrepareAndExecute() {
stdout := strings.Builder{}
stderr := strings.Builder{}

View file

@ -2,6 +2,7 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
)
// DepUpdate is an execution step that calls `helm dependency update` when executed.
@ -10,6 +11,13 @@ type DepUpdate struct {
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,
}
}
// Execute executes the `helm upgrade` command.
func (d *DepUpdate) Execute(_ Config) error {
return d.cmd.Run()

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"
@ -31,6 +32,14 @@ func TestDepUpdateTestSuite(t *testing.T) {
suite.Run(t, new(DepUpdateTestSuite))
}
func (suite *DepUpdateTestSuite) TestNewDepUpdate() {
cfg := env.Config{
Chart: "scatterplot",
}
d := NewDepUpdate(cfg)
suite.Equal("scatterplot", d.Chart)
}
func (suite *DepUpdateTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()

View file

@ -2,6 +2,7 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
)
// Help is a step in a helm Plan that calls `helm help`.
@ -10,6 +11,13 @@ type Help struct {
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,
}
}
// Execute executes the `helm help` command.
func (h *Help) Execute(cfg Config) error {
if err := h.cmd.Run(); err != 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/assert"
"github.com/stretchr/testify/suite"
"strings"
@ -17,6 +18,15 @@ func TestHelpTestSuite(t *testing.T) {
suite.Run(t, new(HelpTestSuite))
}
func (suite *HelpTestSuite) TestNewHelp() {
cfg := env.Config{
Command: "everybody dance NOW!!",
}
help := NewHelp(cfg)
suite.Require().NotNil(help)
suite.Equal("everybody dance NOW!!", help.HelmCommand)
}
func (suite *HelpTestSuite) TestPrepare() {
ctrl := gomock.NewController(suite.T())
defer ctrl.Finish()

View file

@ -3,6 +3,7 @@ package run
import (
"errors"
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
"io"
"os"
"text/template"
@ -32,6 +33,19 @@ type kubeValues struct {
Token string
}
// 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{
SkipTLSVerify: cfg.SkipTLSVerify,
Certificate: cfg.Certificate,
APIServer: cfg.APIServer,
ServiceAccount: cfg.ServiceAccount,
Token: cfg.KubeToken,
TemplateFile: templateFile,
ConfigFile: configFile,
}
}
// Execute generates a kubernetes config file from drone-helm3's template.
func (i *InitKube) Execute(cfg Config) error {
if cfg.Debug {

View file

@ -1,6 +1,7 @@
package run
import (
"github.com/pelotech/drone-helm3/internal/env"
"github.com/stretchr/testify/suite"
yaml "gopkg.in/yaml.v2"
"io/ioutil"
@ -17,6 +18,27 @@ func TestInitKubeTestSuite(t *testing.T) {
suite.Run(t, new(InitKubeTestSuite))
}
func (suite *InitKubeTestSuite) TestNewInitKube() {
cfg := env.Config{
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
KubeToken: "b2YgbXkgYWZmZWN0aW9u",
}
init := NewInitKube(cfg, "conf.tpl", "conf.yml")
suite.Equal(&InitKube{
SkipTLSVerify: true,
Certificate: "cHJvY2xhaW1zIHdvbmRlcmZ1bCBmcmllbmRzaGlw",
APIServer: "98.765.43.21",
ServiceAccount: "greathelm",
Token: "b2YgbXkgYWZmZWN0aW9u",
TemplateFile: "conf.tpl",
ConfigFile: "conf.yml",
}, init)
}
func (suite *InitKubeTestSuite) TestPrepareExecute() {
templateFile, err := tempfile("kubeconfig********.yml.tpl", `
certificate: {{ .Certificate }}

View file

@ -2,6 +2,7 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
)
// Lint is an execution step that calls `helm lint` when executed.
@ -14,6 +15,17 @@ type Lint struct {
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,
}
}
// Execute executes the `helm lint` command.
func (l *Lint) Execute(_ Config) error {
return l.cmd.Run()

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"
@ -31,6 +32,25 @@ func TestLintTestSuite(t *testing.T) {
suite.Run(t, new(LintTestSuite))
}
func (suite *LintTestSuite) TestNewLint() {
cfg := env.Config{
Chart: "./flow",
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
LintStrictly: true,
}
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)
}
func (suite *LintTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()

View file

@ -2,6 +2,7 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
)
// Uninstall is an execution step that calls `helm uninstall` when executed.
@ -12,6 +13,15 @@ type Uninstall struct {
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,
}
}
// Execute executes the `helm uninstall` command.
func (u *Uninstall) Execute(_ Config) error {
return u.cmd.Run()

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"
@ -35,6 +36,20 @@ func TestUninstallTestSuite(t *testing.T) {
suite.Run(t, new(UninstallTestSuite))
}
func (suite *UninstallTestSuite) TestNewUninstall() {
cfg := env.Config{
DryRun: true,
Release: "jetta_id_love_to_change_the_world",
KeepHistory: true,
}
u := NewUninstall(cfg)
suite.Equal(&Uninstall{
Release: "jetta_id_love_to_change_the_world",
DryRun: true,
KeepHistory: true,
}, u)
}
func (suite *UninstallTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()

View file

@ -2,6 +2,7 @@ package run
import (
"fmt"
"github.com/pelotech/drone-helm3/internal/env"
)
// Upgrade is an execution step that calls `helm upgrade` when executed.
@ -24,6 +25,25 @@ type Upgrade struct {
cmd cmd
}
// 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,
}
}
// Execute executes the `helm upgrade` command.
func (u *Upgrade) Execute(_ Config) error {
return u.cmd.Run()

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"
@ -31,6 +32,41 @@ func TestUpgradeTestSuite(t *testing.T) {
suite.Run(t, new(UpgradeTestSuite))
}
func (suite *UpgradeTestSuite) TestNewUpgrade() {
cfg := env.Config{
ChartVersion: "seventeen",
DryRun: true,
Wait: true,
Values: "steadfastness,forthrightness",
StringValues: "tensile_strength,flexibility",
ValuesFiles: []string{"/root/price_inventory.yml"},
ReuseValues: true,
Timeout: "go sit in the corner",
Chart: "billboard_top_100",
Release: "post_malone_circles",
Force: true,
AtomicUpgrade: true,
CleanupOnFail: true,
}
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)
}
func (suite *UpgradeTestSuite) TestPrepareAndExecute() {
defer suite.ctrl.Finish()