diff --git a/examples/configuration.yaml b/examples/configuration.yaml index 9950586c5..063237c23 100644 --- a/examples/configuration.yaml +++ b/examples/configuration.yaml @@ -69,7 +69,7 @@ spec: variables: # -- The name of the bucket. If omitted, Terraform will assign a random, # unique name - bucket: terranetes-controller-ci-bucket + bucket: terranetes-ctl-ci-bucket-rohith # -- The canned ACL to apply acl: private # -- Manage S3 Bucket Ownership Controls on this bucket. diff --git a/pkg/cmd/factory.go b/pkg/cmd/factory.go index ce42079b1..e754e4763 100644 --- a/pkg/cmd/factory.go +++ b/pkg/cmd/factory.go @@ -19,7 +19,6 @@ package cmd import ( "errors" - "fmt" "io" "k8s.io/cli-runtime/pkg/genericclioptions" @@ -51,6 +50,8 @@ type Factory interface { SaveConfig(config Config) error // Stdout returns the stdout io writer Stdout() io.Writer + // SetFormatter sets the formatter for the cli + SetFormatter(Formatter) } type factory struct { @@ -62,6 +63,8 @@ type factory struct { cfg ConfigInterface // streams is the input and output streams for the command streams genericclioptions.IOStreams + // formatter is the formatter for printing to the screen + formatter Formatter } // OptionFunc is the function type for the option function @@ -78,9 +81,18 @@ func NewFactory(options ...OptionFunc) (Factory, error) { f.cfg = NewFileConfiguration(ConfigPath()) } + if f.formatter == nil { + f.formatter = &defaultFormatter{} + } + return f, nil } +// SetFormatter sets the formatter for the cli +func (f *factory) SetFormatter(formatter Formatter) { + f.formatter = formatter +} + // GetConfig returns the config for the cli if available func (f *factory) GetConfig() (Config, bool, error) { if f.cfg == nil { @@ -112,14 +124,12 @@ func (f *factory) SaveConfig(config Config) error { // Printf prints a message to the output stream func (f *factory) Printf(format string, a ...interface{}) { - //nolint - f.streams.Out.Write([]byte(fmt.Sprintf(format, a...))) + f.formatter.Printf(f.streams.Out, format, a...) } // Println prints a message to the output stream func (f *factory) Println(format string, a ...interface{}) { - //nolint - f.streams.Out.Write([]byte(fmt.Sprintf(format+"\n", a...))) + f.formatter.Println(f.streams.Out, format, a...) } // Stdout returns the stdout io writer diff --git a/pkg/cmd/formatter.go b/pkg/cmd/formatter.go new file mode 100644 index 000000000..97451c96a --- /dev/null +++ b/pkg/cmd/formatter.go @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2022 Appvia Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package cmd + +import ( + "fmt" + "io" +) + +// defaultFormatter is the default formatter for the cli +type defaultFormatter struct{} + +// defaultJSONFormatter is the default json formatter for the cli +type defaultJSONFormatter struct{} + +// NewTextFormatter returns a new text formatter +func NewTextFormatter() Formatter { + return &defaultFormatter{} +} + +// NewJSONFormatter returns a new json formatter +func NewJSONFormatter() Formatter { + return &defaultJSONFormatter{} +} + +// Printf prints a message to the output stream +func (f *defaultJSONFormatter) Printf(out io.Writer, format string, a ...interface{}) { + fmt.Fprintf(out, "{ \"message\": \"" + format + "\" }", a...) +} + +// Println prints a message to the output stream +func (f *defaultJSONFormatter) Println(out io.Writer, format string, a ...interface{}) { + fmt.Fprintf(out, "{ \"message\": \"" + format + "\" }", a...) +} + +// Printf prints a message to the output stream +func (f *defaultFormatter) Printf(out io.Writer, format string, a ...interface{}) { + fmt.Fprintf(out, format, a...) +} + +// Println prints a message to the output stream +func (f *defaultFormatter) Println(out io.Writer, format string, a ...interface{}) { + fmt.Fprintf(out, format+"\n", a...) +} diff --git a/pkg/cmd/formatter_test.go b/pkg/cmd/formatter_test.go new file mode 100644 index 000000000..17df36e6a --- /dev/null +++ b/pkg/cmd/formatter_test.go @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2022 Appvia Ltd + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package cmd + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewTextFormatter(t *testing.T) { + assert.NotNil(t, NewTextFormatter()) +} + +func TestNewJSONFormatter(t *testing.T) { + assert.NotNil(t, NewJSONFormatter()) +} + +func TestDefaultTextFormatterPrintf(t *testing.T) { + buffer := &bytes.Buffer{} + formatter := NewTextFormatter() + + formatter.Printf(buffer, "Hello, %s", "world") + assert.Equal(t, "Hello, world", buffer.String()) +} + +func TestDefaultTextFormatterPrintln(t *testing.T) { + buffer := &bytes.Buffer{} + formatter := NewTextFormatter() + + formatter.Println(buffer, "Hello, world") + assert.Equal(t, "Hello, world\n", buffer.String()) +} + +func TestDefaultJSONFormatterPrintf(t *testing.T) { + buffer := &bytes.Buffer{} + formatter := NewJSONFormatter() + + formatter.Printf(buffer, "Hello, %s", "world") + assert.Equal(t, `{ "message": "Hello, world" }`, buffer.String()) +} + +func TestDefaultJSONFormatterPrintln(t *testing.T) { + buffer := &bytes.Buffer{} + formatter := NewJSONFormatter() + + formatter.Println(buffer, "Hello, world") + assert.Equal(t, `{ "message": "Hello, world" }`, buffer.String()) +} diff --git a/pkg/cmd/option.go b/pkg/cmd/option.go index cf6bd0d9f..e20eabd91 100644 --- a/pkg/cmd/option.go +++ b/pkg/cmd/option.go @@ -50,3 +50,11 @@ func WithStreams(stream genericclioptions.IOStreams) OptionFunc { f.streams = stream } } + +// WithFormatter sets the formatter +func WithFormatter(formatter Formatter) OptionFunc { + return func(f *factory) { + f.formatter = formatter + } +} + diff --git a/pkg/cmd/tnctl/describe/describe.go b/pkg/cmd/tnctl/describe/describe.go index b2d82de55..f9d75a84b 100644 --- a/pkg/cmd/tnctl/describe/describe.go +++ b/pkg/cmd/tnctl/describe/describe.go @@ -97,7 +97,7 @@ func (o *Command) Run(ctx context.Context) error { if found, err := kubernetes.GetIfExists(ctx, cc, configuration); err != nil { return err } else if !found { - return fmt.Errorf("noo configurations found in namespace %q", o.Namespace) + return fmt.Errorf("no configurations found in namespace %q", o.Namespace) } // @step: retrieve a list of all secrets related to the builds diff --git a/pkg/cmd/tnctl/tnctl.go b/pkg/cmd/tnctl/tnctl.go index 51b35cc8f..c6ccca057 100644 --- a/pkg/cmd/tnctl/tnctl.go +++ b/pkg/cmd/tnctl/tnctl.go @@ -61,17 +61,20 @@ func New(factory cmd.Factory) *cobra.Command { Long: strings.TrimPrefix(longDescription, "\n"), SilenceErrors: true, Version: version.Version, - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(fcmd *cobra.Command, args []string) error { log.SetOutput(factory.GetStreams().Out) - if v, _ := cmd.Flags().GetBool("verbose"); v { + if v, _ := fcmd.Flags().GetBool("verbose"); v { log.SetLevel(log.DebugLevel) } - if v, _ := cmd.Flags().GetBool("no-color"); v { + if v, _ := fcmd.Flags().GetBool("no-color"); v { color.NoColor = true } + if v, _ := fcmd.Flags().GetString("output"); v == "json" { + factory.SetFormatter(cmd.NewJSONFormatter()) + } - return cmd.Help() + return fcmd.Help() }, } @@ -95,6 +98,7 @@ func New(factory cmd.Factory) *cobra.Command { flags := command.PersistentFlags() flags.Bool("verbose", false, "Enable verbose logging") + flags.String("output", "text", "Output format for CLI command (text, json)") flags.String("config", filepath.Join(os.ExpandEnv("HOME"), ".tnctl.yaml"), "Path to the configuration file") flag.Bool("no-color", false, "Disable color output") diff --git a/pkg/cmd/types.go b/pkg/cmd/types.go index f749a6949..0e4a245cb 100644 --- a/pkg/cmd/types.go +++ b/pkg/cmd/types.go @@ -17,6 +17,8 @@ RR along with this program. If not, see . package cmd +import "io" + // Config is the configuration for the tnctl command type Config struct { // Workflow is the location of the workflow templates. This should point @@ -33,6 +35,14 @@ type Config struct { Sources []string `json:"sources,omitempty" yaml:"sources,omitempty"` } +// Formatter is the interface that must be implemented by the formatter +type Formatter interface { + // Printf prints a message to the output stream + Printf(out io.Writer, format string, a ...interface{}) + // Println prints a message to the output stream + Println(out io.Writer, format string, a ...interface{}) +} + // ConfigInterface is the interface that must be implemented by the config struct type ConfigInterface interface { // GetConfig returns the config for the cli if available