From 4a5380587ea73950563fbbd679e527cb77ab2560 Mon Sep 17 00:00:00 2001 From: partcyborg <41255671+partcyborg@users.noreply.github.com> Date: Fri, 27 Jan 2023 04:37:32 -0800 Subject: [PATCH] Support forcing color output on/off (#799) * Support forcing color output on/off Closes #798 Introduce flag `--color` to control the colorization of diff output. Add flag to all commands that can output colorized diff text: - `diff` - `apply` - `prune` `--color` has 3 allowed values: - `auto` (default): colorize if stdout is a tty (current behavior) - `always`: always colorize output - `never`: never colorize output * Remove unused attribute Co-authored-by: Matt Wilder Co-authored-by: Julien Duchesne --- cmd/tk/flags.go | 4 ++++ cmd/tk/workflow.go | 43 +++++++++++++++++++++++++++++++++++++++++++ pkg/tanka/workflow.go | 7 +++++++ 3 files changed, 54 insertions(+) diff --git a/cmd/tk/flags.go b/cmd/tk/flags.go index a9384a741..79c32df88 100644 --- a/cmd/tk/flags.go +++ b/cmd/tk/flags.go @@ -24,6 +24,10 @@ func workflowFlags(fs *pflag.FlagSet) *workflowFlagVars { return &v } +func addDiffFlags(fs *pflag.FlagSet, opts *tanka.DiffBaseOpts) { + fs.StringVar(&opts.Color, "color", "auto", `controls color in diff output, must be "auto", "always", or "never"`) +} + func addApplyFlags(fs *pflag.FlagSet, opts *tanka.ApplyBaseOpts, autoApproveDeprecated *bool, autoApprove *string) { fs.StringVar(&opts.DryRun, "dry-run", "", `--dry-run parameter to pass down to kubectl, must be "none", "server", or "client"`) fs.BoolVar(&opts.Force, "force", false, "force applying (kubectl apply --force)") diff --git a/cmd/tk/workflow.go b/cmd/tk/workflow.go index cf3db63bd..b2553a584 100644 --- a/cmd/tk/workflow.go +++ b/cmd/tk/workflow.go @@ -4,6 +4,7 @@ import ( "fmt" "os" + "github.com/fatih/color" "github.com/go-clix/cli" "github.com/posener/complete" @@ -20,6 +21,24 @@ const ( ExitStatusDiff = 16 ) +var ( + colorValues = cli.PredictSet("auto", "always", "never") +) + +func setForceColor(opts *tanka.DiffBaseOpts) error { + switch opts.Color { + case "": + case "auto": + case "always": + color.NoColor = false + case "never": + color.NoColor = true + default: + return fmt.Errorf(`--color must be either: "auto", "always", or "never"`) + } + return nil +} + func validateDryRun(dryRunStr string) error { switch dryRunStr { case "", "none", "client", "server": @@ -56,6 +75,7 @@ func applyCmd() *cli.Command { Short: "apply the configuration to the cluster", Args: workflowArgs, Predictors: complete.Flags{ + "color": colorValues, "diff-strategy": cli.PredictSet("native", "subset", "validate", "server", "none"), "apply-strategy": cli.PredictSet("client", "server"), }, @@ -71,6 +91,7 @@ func applyCmd() *cli.Command { autoApproveString string ) addApplyFlags(cmd.Flags(), &opts.ApplyBaseOpts, &autoApproveDeprecated, &autoApproveString) + addDiffFlags(cmd.Flags(), &opts.DiffBaseOpts) vars := workflowFlags(cmd.Flags()) getJsonnetOpts := jsonnetFlags(cmd.Flags()) @@ -82,6 +103,9 @@ func applyCmd() *cli.Command { if opts.AutoApprove, err = validateAutoApprove(autoApproveDeprecated, autoApproveString); err != nil { return err } + if err := setForceColor(&opts.DiffBaseOpts); err != nil { + return err + } filters, err := process.StrExps(vars.targets...) if err != nil { @@ -101,6 +125,9 @@ func pruneCmd() *cli.Command { Use: "prune ", Short: "delete resources removed from Jsonnet", Args: workflowArgs, + Predictors: complete.Flags{ + "color": colorValues, + }, } var opts tanka.PruneOpts @@ -110,6 +137,7 @@ func pruneCmd() *cli.Command { autoApproveString string ) addApplyFlags(cmd.Flags(), &opts.ApplyBaseOpts, &autoApproveDeprecated, &autoApproveString) + addDiffFlags(cmd.Flags(), &opts.DiffBaseOpts) getJsonnetOpts := jsonnetFlags(cmd.Flags()) cmd.Run = func(cmd *cli.Command, args []string) error { @@ -120,6 +148,9 @@ func pruneCmd() *cli.Command { if opts.AutoApprove, err = validateAutoApprove(autoApproveDeprecated, autoApproveString); err != nil { return err } + if err := setForceColor(&opts.DiffBaseOpts); err != nil { + return err + } opts.JsonnetOpts = getJsonnetOpts() @@ -134,6 +165,9 @@ func deleteCmd() *cli.Command { Use: "delete ", Short: "delete the environment from cluster", Args: workflowArgs, + Predictors: complete.Flags{ + "color": colorValues, + }, } var opts tanka.DeleteOpts @@ -143,6 +177,7 @@ func deleteCmd() *cli.Command { autoApproveString string ) addApplyFlags(cmd.Flags(), &opts.ApplyBaseOpts, &autoApproveDeprecated, &autoApproveString) + addDiffFlags(cmd.Flags(), &opts.DiffBaseOpts) vars := workflowFlags(cmd.Flags()) getJsonnetOpts := jsonnetFlags(cmd.Flags()) @@ -154,6 +189,9 @@ func deleteCmd() *cli.Command { if opts.AutoApprove, err = validateAutoApprove(autoApproveDeprecated, autoApproveString); err != nil { return err } + if err := setForceColor(&opts.DiffBaseOpts); err != nil { + return err + } filters, err := process.StrExps(vars.targets...) if err != nil { @@ -174,11 +212,13 @@ func diffCmd() *cli.Command { Short: "differences between the configuration and the cluster", Args: workflowArgs, Predictors: complete.Flags{ + "color": colorValues, "diff-strategy": cli.PredictSet("native", "subset", "validate", "server"), }, } var opts tanka.DiffOpts + addDiffFlags(cmd.Flags(), &opts.DiffBaseOpts) 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") cmd.Flags().BoolVarP(&opts.WithPrune, "with-prune", "p", false, "include objects deleted from the configuration in the differences") @@ -188,6 +228,9 @@ func diffCmd() *cli.Command { getJsonnetOpts := jsonnetFlags(cmd.Flags()) cmd.Run = func(cmd *cli.Command, args []string) error { + if err := setForceColor(&opts.DiffBaseOpts); err != nil { + return err + } filters, err := process.StrExps(vars.targets...) if err != nil { return err diff --git a/pkg/tanka/workflow.go b/pkg/tanka/workflow.go index 953d1678b..adbc8c330 100644 --- a/pkg/tanka/workflow.go +++ b/pkg/tanka/workflow.go @@ -29,6 +29,7 @@ const ( type ApplyBaseOpts struct { Opts + DiffBaseOpts // AutoApprove skips the interactive approval AutoApprove AutoApproveSetting @@ -38,6 +39,11 @@ type ApplyBaseOpts struct { Force bool } +type DiffBaseOpts struct { + // Color controls color output + Color string +} + // ApplyOpts specify additional properties for the Apply action type ApplyOpts struct { ApplyBaseOpts @@ -152,6 +158,7 @@ func confirmPrompt(action, namespace string, info client.Info) error { // DiffOpts specify additional properties for the Diff action type DiffOpts struct { + DiffBaseOpts Opts // Strategy must be one of "native", "validate", "subset" or "server"