Replicate most of drone-helm's config

This commit is contained in:
Erin Call
2019-12-09 09:56:02 -08:00
parent 238ede6f9e
commit e3051ec72e
12 changed files with 277 additions and 62 deletions

58
internal/helm/config.go Normal file
View File

@@ -0,0 +1,58 @@
package helm
import (
"fmt"
"strings"
)
type Config struct {
// Configuration for drone-helm itself
Command HelmCommand `envconfig:"HELM_COMMAND"` // Helm command to run
DroneEvent string `envconfig:"DRONE_BUILD_EVENT"` // Drone event that invoked this plugin.
UpdateDependencies bool `split_words:"true"` // call `helm dependency update` before the main command
Repos []string `envconfig:"HELM_REPOS"` // call `helm repo add` before the main command
Prefix string `` // Prefix to use when looking up secret env vars
// Global helm config
Debug bool `` // global helm flag (also applies to drone-helm itself)
KubeConfig string `split_words:"true" default:"/root/.kube/config"` // path to the kube config file
Values string ``
StringValues string `split_words:"true"`
ValuesFiles []string `split_words:"true"`
Namespace string ``
Token string `envconfig:"KUBERNETES_TOKEN"`
SkipTLSVerify bool `envconfig:"SKIP_TLS_VERIFY"`
Certificate string `envconfig:"KUBERNETES_CERTIFICATE"`
APIServer string `envconfig:"API_SERVER"`
ServiceAccount string `envconfig:"SERVICE_ACCOUNT"` // Can't just use split_words; need envconfig to find the non-prefixed form
// Config specifically for `helm upgrade`
ChartVersion string `split_words:"true"` //
DryRun bool `split_words:"true"` // also available for `delete`
Wait bool `` //
ReuseValues bool `split_words:"true"` //
Timeout string `` //
Chart string `` // Also available for `lint`, in which case it must be a path to a chart directory
Release string ``
Force bool `` //
}
type HelmCommand string
// HelmCommand.Decode checks the given value against the list of known commands and generates a helpful error if the command is unknown.
func (cmd *HelmCommand) Decode(value string) error {
known := []string{"upgrade", "delete", "lint", "help"}
for _, c := range known {
if value == c {
*cmd = HelmCommand(value)
return nil
}
}
if value == "" {
return nil
}
known[len(known)-1] = fmt.Sprintf("or %s", known[len(known)-1])
return fmt.Errorf("Unknown command '%s'. If specified, command must be %s.",
value, strings.Join(known, ", "))
}

View File

@@ -0,0 +1,28 @@
package helm
import (
"github.com/stretchr/testify/suite"
"testing"
)
type ConfigTestSuite struct {
suite.Suite
}
func TestConfigTestSuite(t *testing.T) {
suite.Run(t, new(ConfigTestSuite))
}
func (suite *ConfigTestSuite) TestHelmCommandDecodeSuccess() {
cmd := HelmCommand("")
err := cmd.Decode("upgrade")
suite.Require().Nil(err)
suite.EqualValues(cmd, "upgrade")
}
func (suite *ConfigTestSuite) TestHelmCommandDecodeFailure() {
cmd := HelmCommand("")
err := cmd.Decode("execute order 66")
suite.EqualError(err, "Unknown command 'execute order 66'. If specified, command must be upgrade, delete, lint, or help.")
}

62
internal/helm/plan.go Normal file
View File

@@ -0,0 +1,62 @@
package helm
import (
"errors"
"github.com/pelotech/drone-helm3/internal/run"
)
type Step interface {
Run() error
}
type Plan struct {
steps []Step
}
func NewPlan(cfg Config) (*Plan, error) {
p := Plan{}
switch cfg.Command {
case "upgrade":
steps, err := upgrade(cfg)
if err != nil {
return nil, err
}
p.steps = steps
case "delete":
return nil, errors.New("not implemented")
case "lint":
return nil, errors.New("not implemented")
case "help":
return nil, errors.New("not implemented")
default:
switch cfg.DroneEvent {
case "push", "tag", "deployment", "pull_request", "promote", "rollback":
steps, err := upgrade(cfg)
if err != nil {
return nil, err
}
p.steps = steps
default:
return nil, errors.New("not implemented")
}
}
return &p, nil
}
func (p *Plan) Execute() error {
for _, step := range p.steps {
if err := step.Run(); err != nil {
return err
}
}
return nil
}
func upgrade(cfg Config) ([]Step, error) {
steps := make([]Step, 0)
steps = append(steps, run.NewUpgrade(cfg.Release, cfg.Chart))
return steps, nil
}

View File

@@ -0,0 +1,53 @@
package helm
import (
"fmt"
"github.com/stretchr/testify/suite"
"testing"
"github.com/pelotech/drone-helm3/internal/run"
)
type PlanTestSuite struct {
suite.Suite
}
func TestPlanTestSuite(t *testing.T) {
suite.Run(t, new(PlanTestSuite))
}
func (suite *PlanTestSuite) TestNewPlanUpgradeCommand() {
cfg := Config{
Command: "upgrade",
Chart: "billboard_top_100",
Release: "post_malone_circles",
}
plan, err := NewPlan(cfg)
suite.Require().Nil(err)
suite.Equal(1, len(plan.steps))
switch step := plan.steps[0].(type) {
case *run.Upgrade:
suite.Equal("billboard_top_100", step.Chart)
suite.Equal("post_malone_circles", step.Release)
default:
suite.Failf("Wrong type for step 1", "Expected Upgrade, got %T", step)
}
}
func (suite *PlanTestSuite) TestNewPlanUpgradeFromDroneEvent() {
cfg := Config{
Chart: "billboard_top_100",
Release: "lizzo_good_as_hell",
}
upgradeEvents := []string{"push", "tag", "deployment", "pull_request", "promote", "rollback"}
for _, event := range upgradeEvents {
cfg.DroneEvent = event
plan, err := NewPlan(cfg)
suite.Require().Nil(err)
suite.Require().Equal(1, len(plan.steps), fmt.Sprintf("for event type '%s'", event))
suite.IsType(&run.Upgrade{}, plan.steps[0], fmt.Sprintf("for event type '%s'", event))
}
}

View File

@@ -4,12 +4,20 @@ import (
"os"
)
func Help(args ...string) error {
args = append([]string{"help"}, args...)
cmd := Command(HELM_BIN, args...)
cmd.Stdout(os.Stdout)
cmd.Stderr(os.Stderr)
return cmd.Run()
type Help struct {
cmd cmd
}
func (h *Help) Run() error {
return h.cmd.Run()
}
func NewHelp() *Help {
h := Help{}
h.cmd = Command(HELM_BIN, "help")
h.cmd.Stdout(os.Stdout)
h.cmd.Stderr(os.Stderr)
return &h
}

View File

@@ -15,7 +15,7 @@ func TestHelp(t *testing.T) {
Command = func(path string, args ...string) cmd {
assert.Equal(t, HELM_BIN, path)
assert.Equal(t, []string{"help", "arg1", "arg2"}, args)
assert.Equal(t, []string{"help"}, args)
return mCmd
}
defer func() { Command = originalCommand }()
@@ -28,5 +28,6 @@ func TestHelp(t *testing.T) {
Run().
Times(1)
Help("arg1", "arg2")
h := NewHelp()
h.Run()
}

View File

@@ -4,12 +4,25 @@ import (
"os"
)
func Upgrade(args ...string) error {
args = append([]string{"upgrade"}, args...)
cmd := Command(HELM_BIN, args...)
cmd.Stdout(os.Stdout)
cmd.Stderr(os.Stderr)
return cmd.Run()
type Upgrade struct {
Chart string
Release string
cmd cmd
}
func (u *Upgrade) Run() error {
return u.cmd.Run()
}
func NewUpgrade(release, chart string) *Upgrade {
u := Upgrade{
Chart: chart,
Release: release,
cmd: Command(HELM_BIN, "upgrade", "--install", release, chart),
}
u.cmd.Stdout(os.Stdout)
u.cmd.Stderr(os.Stderr)
return &u
}

View File

@@ -6,7 +6,7 @@ import (
"testing"
)
func TestUpgrade(t *testing.T) {
func TestNewUpgrade(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
@@ -15,7 +15,7 @@ func TestUpgrade(t *testing.T) {
Command = func(path string, args ...string) cmd {
assert.Equal(t, HELM_BIN, path)
assert.Equal(t, []string{"upgrade", "arg1", "arg2"}, args)
assert.Equal(t, []string{"upgrade", "--install", "jonas_brothers_only_human", "at40"}, args)
return mCmd
}
@@ -29,5 +29,6 @@ func TestUpgrade(t *testing.T) {
Run().
Times(1)
Upgrade("arg1", "arg2")
u := NewUpgrade("jonas_brothers_only_human", "at40")
u.Run()
}