Skip to content

Commit

Permalink
refactor(api): use structs (BREAKING) (#376)
Browse files Browse the repository at this point in the history
* refactor(api): Struct API (BREAKING)

This converts all of the public API to no longer take a wild variety of
modifier functions, but instead clearly defined structs that only allow
setting those properties, that are actually relevant to that specific
struct.

This not only reduces the amount of boilerplate required, but also makes
the API more discoverable and defines it more clearly.

THIS IS A BREAKING CHANGE

* feat(cli): use new API

Adapts all commands to the new struct based API style
  • Loading branch information
sh0rez authored Sep 11, 2020
1 parent 4164b77 commit 6584a37
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 199 deletions.
14 changes: 7 additions & 7 deletions cmd/tk/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ func exportCmd() *cli.Command {
Args: args,
}

vars := workflowFlags(cmd.Flags())
getExtCode, getTLACode := cliCodeParser(cmd.Flags())
format := cmd.Flags().String("format", "{{.apiVersion}}.{{.kind}}-{{.metadata.name}}", "https://tanka.dev/exporting#filenames")
extension := cmd.Flags().String("extension", "yaml", "File extension")
merge := cmd.Flags().Bool("merge", false, "Allow merging with existing directory")

vars := workflowFlags(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

templateFuncMap := template.FuncMap{
"lower": func(s string) string {
return strings.ToLower(s)
Expand Down Expand Up @@ -66,11 +67,10 @@ func exportCmd() *cli.Command {
}

// get the manifests
res, err := tanka.Show(args[0],
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithTargets(stringsToRegexps(vars.targets)),
)
res, err := tanka.Show(args[0], tanka.Opts{
JsonnetOpts: getJsonnetOpts(),
Filters: stringsToRegexps(vars.targets),
})
if err != nil {
return err
}
Expand Down
20 changes: 15 additions & 5 deletions cmd/tk/jsonnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@ func evalCmd() *cli.Command {
Args: workflowArgs,
}

getExtCode, getTLACode := cliCodeParser(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
raw, err := tanka.Eval(args[0],
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
)
raw, err := tanka.Eval(args[0], tanka.Opts{
JsonnetOpts: getJsonnetOpts(),
})

if err != nil {
return err
Expand All @@ -46,6 +45,17 @@ func evalCmd() *cli.Command {
return cmd
}

func jsonnetFlags(fs *pflag.FlagSet) func() tanka.JsonnetOpts {
getExtCode, getTLACode := cliCodeParser(fs)

return func() tanka.JsonnetOpts {
return tanka.JsonnetOpts{
ExtCode: getExtCode(),
TLACode: getTLACode(),
}
}
}

func cliCodeParser(fs *pflag.FlagSet) (func() map[string]string, func() map[string]string) {
// need to use StringArray instead of StringSlice, because pflag attempts to
// parse StringSlice using the csv parser, which breaks when passing objects
Expand Down
7 changes: 6 additions & 1 deletion cmd/tk/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ func statusCmd() *cli.Command {
Short: "display an overview of the environment, including contents and metadata.",
Args: workflowArgs,
}

getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
status, err := tanka.Status(args[0])
status, err := tanka.Status(args[0], tanka.Opts{
JsonnetOpts: getJsonnetOpts(),
})
if err != nil {
return err
}
Expand Down
109 changes: 46 additions & 63 deletions cmd/tk/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,26 +40,19 @@ func applyCmd() *cli.Command {
Args: workflowArgs,
}

vars := workflowFlags(cmd.Flags())
force := cmd.Flags().Bool("force", false, "force applying (kubectl apply --force)")
validate := cmd.Flags().Bool("validate", true, "validation of resources (kubectl --validate=false)")
autoApprove := cmd.Flags().Bool("dangerous-auto-approve", false, "skip interactive approval. Only for automation!")
var opts tanka.ApplyOpts
cmd.Flags().BoolVar(&opts.Force, "force", false, "force applying (kubectl apply --force)")
cmd.Flags().BoolVar(&opts.Validate, "validate", true, "validation of resources (kubectl --validate=false)")
cmd.Flags().BoolVar(&opts.AutoApprove, "dangerous-auto-approve", false, "skip interactive approval. Only for automation!")

getExtCode, getTLACode := cliCodeParser(cmd.Flags())
vars := workflowFlags(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
err := tanka.Apply(args[0],
tanka.WithTargets(stringsToRegexps(vars.targets)),
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithApplyForce(*force),
tanka.WithApplyValidate(*validate),
tanka.WithApplyAutoApprove(*autoApprove),
)
if err != nil {
return err
}
return nil
opts.Filters = stringsToRegexps(vars.targets)
opts.JsonnetOpts = getJsonnetOpts()

return tanka.Apply(args[0], opts)
}
return cmd
}
Expand All @@ -71,17 +64,15 @@ func pruneCmd() *cli.Command {
Args: workflowArgs,
}

getExtCode, getTLACode := cliCodeParser(cmd.Flags())
autoApprove := cmd.Flags().Bool("dangerous-auto-approve", false, "skip interactive approval. Only for automation!")
force := cmd.Flags().Bool("force", false, "force deleting (kubectl delete --force)")
var opts tanka.PruneOpts
cmd.Flags().BoolVar(&opts.Force, "force", false, "force deleting (kubectl delete --force)")
cmd.Flags().BoolVar(&opts.AutoApprove, "dangerous-auto-approve", false, "skip interactive approval. Only for automation!")
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
return tanka.Prune(args[0],
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithApplyAutoApprove(*autoApprove),
tanka.WithApplyForce(*force),
)
opts.JsonnetOpts = getJsonnetOpts()

return tanka.Prune(args[0], opts)
}

return cmd
Expand All @@ -94,25 +85,19 @@ func deleteCmd() *cli.Command {
Args: workflowArgs,
}

var opts tanka.DeleteOpts
cmd.Flags().BoolVar(&opts.Force, "force", false, "force deleting (kubectl delete --force)")
cmd.Flags().BoolVar(&opts.Validate, "validate", true, "validation of resources (kubectl --validate=false)")
cmd.Flags().BoolVar(&opts.AutoApprove, "dangerous-auto-approve", false, "skip interactive approval. Only for automation!")

vars := workflowFlags(cmd.Flags())
force := cmd.Flags().Bool("force", false, "force deleting (kubectl delete --force)")
validate := cmd.Flags().Bool("validate", true, "validation of resources (kubectl --validate=false)")
autoApprove := cmd.Flags().Bool("dangerous-auto-approve", false, "skip interactive approval. Only for automation!")
getExtCode, getTLACode := cliCodeParser(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
err := tanka.Delete(args[0],
tanka.WithTargets(stringsToRegexps(vars.targets)),
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithApplyForce(*force),
tanka.WithApplyValidate(*validate),
tanka.WithApplyAutoApprove(*autoApprove),
)
if err != nil {
return err
}
return nil
opts.Filters = stringsToRegexps(vars.targets)
opts.JsonnetOpts = getJsonnetOpts()

return tanka.Delete(args[0], opts)
}
return cmd
}
Expand All @@ -127,23 +112,18 @@ func diffCmd() *cli.Command {
},
}

// flags
var (
vars = workflowFlags(cmd.Flags())
diffStrategy = cmd.Flags().String("diff-strategy", "", "force the diff-strategy to use. Automatically chosen if not set.")
summarize = cmd.Flags().BoolP("summarize", "s", false, "quick summary of the differences, hides file contents")
)
var opts tanka.DiffOpts
cmd.Flags().StringVar(&opts.Strategy, "diff-strategy", "", "force the diff-strategy to use. Automatically chosen if not set.")
cmd.Flags().BoolVarP(&opts.Summarize, "summarize", "s", false, "print summary of the differences, not the actual contents")

getExtCode, getTLACode := cliCodeParser(cmd.Flags())
vars := workflowFlags(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
changes, err := tanka.Diff(args[0],
tanka.WithTargets(stringsToRegexps(vars.targets)),
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithDiffStrategy(*diffStrategy),
tanka.WithDiffSummarize(*summarize),
)
opts.Filters = stringsToRegexps(vars.targets)
opts.JsonnetOpts = getJsonnetOpts()

changes, err := tanka.Diff(args[0], opts)
if err != nil {
return err
}
Expand Down Expand Up @@ -171,9 +151,12 @@ func showCmd() *cli.Command {
Short: "jsonnet as yaml",
Args: workflowArgs,
}
vars := workflowFlags(cmd.Flags())

allowRedirect := cmd.Flags().Bool("dangerous-allow-redirect", false, "allow redirecting output to a file or a pipe.")
getExtCode, getTLACode := cliCodeParser(cmd.Flags())

vars := workflowFlags(cmd.Flags())
getJsonnetOpts := jsonnetFlags(cmd.Flags())

cmd.Run = func(cmd *cli.Command, args []string) error {
if !interactive && !*allowRedirect {
fmt.Fprintln(os.Stderr, `Redirection of the output of tk show is discouraged and disabled by default.
Expand All @@ -182,11 +165,11 @@ Otherwise run tk show --dangerous-allow-redirect to bypass this check.`)
return nil
}

pretty, err := tanka.Show(args[0],
tanka.WithExtCode(getExtCode()),
tanka.WithTLACode(getTLACode()),
tanka.WithTargets(stringsToRegexps(vars.targets)),
)
pretty, err := tanka.Show(args[0], tanka.Opts{
JsonnetOpts: getJsonnetOpts(),
Filters: stringsToRegexps(vars.targets),
})

if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/kubernetes/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

type DeleteOpts client.DeleteOpts

func (k *Kubernetes) Delete(state manifest.List, opts ApplyOpts) error {
func (k *Kubernetes) Delete(state manifest.List, opts DeleteOpts) error {
// Sort and reverse the manifests to avoid cascading deletions
process.Sort(state)
for i := 0; i < len(state)/2; i++ {
Expand Down
6 changes: 3 additions & 3 deletions pkg/tanka/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ func (p *loaded) connect() (*kubernetes.Kubernetes, error) {
}

// load runs all processing stages described at the Processed type
func load(dir string, opts *options) (*loaded, error) {
raw, env, err := eval(dir, opts.jsonnet)
func load(dir string, opts Opts) (*loaded, error) {
raw, env, err := eval(dir, opts.JsonnetOpts)
if err != nil {
return nil, err
}

rec, err := process.Process(raw, *env, opts.targets)
rec, err := process.Process(raw, *env, opts.Filters)
if err != nil {
return nil, err
}
Expand Down
22 changes: 16 additions & 6 deletions pkg/tanka/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,21 @@ import (
"github.com/grafana/tanka/pkg/term"
)

// PruneOpts specify additional properties for the Prune action
type PruneOpts struct {
Opts

// AutoApprove skips the interactive approval
AutoApprove bool
// Force ignores any warnings kubectl might have
Force bool
}

// Prune deletes all resources from the cluster, that are no longer present in
// Jsonnet. It uses the `tanka.dev/environment` label to identify those.
func Prune(baseDir string, mods ...Modifier) error {
opts := parseModifiers(mods)

func Prune(baseDir string, opts PruneOpts) error {
// parse jsonnet, init k8s client
p, err := load(baseDir, opts)
p, err := load(baseDir, opts.Opts)
if err != nil {
return err
}
Expand Down Expand Up @@ -44,11 +52,13 @@ func Prune(baseDir string, mods ...Modifier) error {
fmt.Print(term.Colordiff(*diff).String())

// prompt for confirm
if opts.apply.AutoApprove {
if opts.AutoApprove {
} else if err := confirmPrompt("Pruning from", p.Env.Spec.Namespace, kube.Info()); err != nil {
return err
}

// delete resources
return kube.Delete(orphaned, opts.apply)
return kube.Delete(orphaned, kubernetes.DeleteOpts{
Force: opts.Force,
})
}
4 changes: 1 addition & 3 deletions pkg/tanka/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ type Info struct {
}

// Status returns information about the particular environment
func Status(baseDir string, mods ...Modifier) (*Info, error) {
opts := parseModifiers(mods)

func Status(baseDir string, opts Opts) (*Info, error) {
r, err := load(baseDir, opts)
if err != nil {
return nil, err
Expand Down
Loading

0 comments on commit 6584a37

Please sign in to comment.