Show the context name and current context using get-context command

The command "airshipctl config get-context" will display the name of the contexts as well as the current context name.

Relates-To: #475
Change-Id: I8234d74f6b98869e27e4974a54b68230d8be8565
This commit is contained in:
chumkid 2021-03-17 22:24:27 +05:30 committed by Chumki
parent 9ca9106f34
commit 02d2fc7e4a
12 changed files with 255 additions and 34 deletions

View File

@ -59,26 +59,12 @@ func NewGetContextCommand(cfgFactory config.Factory) *cobra.Command {
if len(args) == 1 {
o.Name = args[0]
}
if o.Name == "" && !o.CurrentContext {
contexts := airconfig.GetContexts()
if len(contexts) == 0 {
if len(airconfig.GetContexts()) == 0 {
fmt.Fprintln(cmd.OutOrStdout(), "No Contexts found in the configuration.")
} else {
return o.Print(airconfig, cmd.OutOrStdout())
}
for _, context := range contexts {
fmt.Fprintln(cmd.OutOrStdout(), context.String())
}
return nil
}
if o.CurrentContext {
o.Name = airconfig.CurrentContext
}
context, err := airconfig.GetContext(o.Name)
if err != nil {
return err
}
fmt.Fprintln(cmd.OutOrStdout(), context.String())
return nil
},
}
@ -95,4 +81,10 @@ func addGetContextFlags(o *config.ContextOptions, cmd *cobra.Command) {
"current",
false,
"get the current context")
flags.StringVar(
&o.Format,
"format",
"yaml",
"choose between `yaml` or `table`, default is `yaml`")
}

View File

@ -94,6 +94,5 @@ func getNamedTestContext(contextName string) *config.Context {
newContext := &config.Context{
Manifest: fmt.Sprintf("Manifest_%s", contextName),
}
return newContext
}

View File

@ -1,3 +1,4 @@
contexts:
ContextBar:
managementConfiguration: ""
manifest: Manifest_ContextBar

View File

@ -1,3 +1,4 @@
contexts:
ContextFoo:
managementConfiguration: ""
manifest: Manifest_ContextFoo

View File

@ -1,3 +1,4 @@
contexts:
ContextBaz:
managementConfiguration: ""
manifest: Manifest_ContextBaz

View File

@ -19,5 +19,6 @@ airshipctl config get-context exampleContext
Flags:
--current get the current context
--format yaml choose between yaml or `table`, default is `yaml` (default "yaml")
-h, --help help for get-context

View File

@ -19,5 +19,6 @@ airshipctl config get-context exampleContext
Flags:
--current get the current context
--format yaml choose between yaml or `table`, default is `yaml` (default "yaml")
-h, --help help for get-context

View File

@ -30,6 +30,7 @@ airshipctl config get-context exampleContext
```
--current get the current context
--format yaml choose between yaml or `table`, default is `yaml` (default "yaml")
-h, --help help for get-context
```

View File

@ -11,6 +11,7 @@ By default the airship config file is initialized with the
repository "https://opendev.org/airship/treasuremap" as a source of
manifests and with the manifests target path "$HOME/.airship/default".
```
airshipctl document pull [flags]
```

View File

@ -276,3 +276,13 @@ type ErrConfigFileExists struct {
func (e ErrConfigFileExists) Error() string {
return fmt.Sprintf("could not create default config at %s, file already exists", e.Path)
}
// ErrWrongOutputFormat is returned when unknown output format is defined for printing config
type ErrWrongOutputFormat struct {
Wrong string
Possible []string
}
func (e ErrWrongOutputFormat) Error() string {
return fmt.Sprintf("wrong output format %s, must be one of %s", e.Wrong, strings.Join(e.Possible, " "))
}

View File

@ -15,6 +15,14 @@ limitations under the License.
package config
import (
"fmt"
"io"
"sort"
"strings"
"k8s.io/cli-runtime/pkg/printers"
"sigs.k8s.io/yaml"
"opendev.org/airship/airshipctl/pkg/errors"
)
@ -25,6 +33,7 @@ type ContextOptions struct {
Manifest string
Current bool
ManagementConfiguration string
Format string
}
// ManifestOptions holds all configurable options for manifest configuration
@ -67,6 +76,76 @@ func (o *ContextOptions) Validate() error {
return nil
}
// Print prints the config contexts using one of formats `yaml` or `table` to a given output
func (o *ContextOptions) Print(cfg *Config, w io.Writer) error {
if o.CurrentContext {
o.Name = cfg.CurrentContext
}
switch o.Format {
case "yaml":
type reducedConfig struct {
Contexts map[string]*Context `json:"contexts"`
CurrentContext string `json:"currentContext,omitempty"`
}
contexts := &reducedConfig{
Contexts: cfg.Contexts,
CurrentContext: cfg.CurrentContext,
}
if o.Name != "" {
c, err := cfg.GetContext(o.Name)
if err != nil {
return err
}
contexts = &reducedConfig{
Contexts: map[string]*Context{o.Name: c},
}
}
data, err := yaml.Marshal(contexts)
if err != nil {
return err
}
fmt.Fprintf(w, string(data))
case "table":
out := printers.GetNewTabWriter(w)
defer out.Flush()
toPrint := []string{}
if o.Name != "" {
toPrint = append(toPrint, o.Name)
} else {
for name := range cfg.Contexts {
toPrint = append(toPrint, name)
}
}
columnNames := []string{"CURRENT", "NAME", "MANIFEST", "MANAGEMENTCONFIGURATION"}
_, err := fmt.Fprintf(out, "%s\n", strings.Join(columnNames, "\t"))
if err != nil {
return err
}
sort.Strings(toPrint)
for _, name := range toPrint {
prefix := " "
if cfg.CurrentContext == name {
prefix = "*"
}
context, err := cfg.GetContext(name)
if err != nil {
return err
}
_, err = fmt.Fprintf(out, "%s\t%s\t%s\t%s\n", prefix, name, context.Manifest, context.ManagementConfiguration)
if err != nil {
return err
}
}
default:
return ErrWrongOutputFormat{Wrong: o.Format, Possible: []string{"yaml", "table"}}
}
return nil
}
// Validate checks for the possible manifest option values and returns
// Error when invalid value or incompatible choice of values given
func (o *ManifestOptions) Validate() error {

View File

@ -15,13 +15,22 @@ limitations under the License.
package config_test
import (
"bytes"
"fmt"
"io/ioutil"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"opendev.org/airship/airshipctl/pkg/config"
)
const (
testFormatError = "wrong output format , must be one of yaml table"
defaultCurrentContext = "a-context"
)
func TestContextOptionsValidate(t *testing.T) {
tests := []struct {
name string
@ -64,3 +73,128 @@ func TestContextOptionsValidate(t *testing.T) {
})
}
}
func TestContextOptionsPrint(t *testing.T) {
yamlOutput := `contexts:
a-context:
managementConfiguration: a-manageconf
manifest: a-manifest
currentContext: a-context
`
tests := []struct {
name string
testContextOptions config.ContextOptions
testConfig config.Config
expectedOutput string
expectedErr string
}{
{
name: "Wrong output format",
testContextOptions: config.ContextOptions{
Format: "",
},
testConfig: config.Config{},
expectedOutput: "",
expectedErr: testFormatError,
},
{
name: "List contexts in table format",
testContextOptions: config.ContextOptions{
Name: "",
CurrentContext: false,
Format: "table",
},
testConfig: config.Config{
CurrentContext: defaultCurrentContext,
Contexts: map[string]*config.Context{
"a-context": {Manifest: "a-manifest", ManagementConfiguration: "a-manageconf"},
"b-context": {Manifest: "b-manifest", ManagementConfiguration: "b-manageconf"}},
},
expectedOutput: `CURRENT NAME MANIFEST MANAGEMENTCONFIGURATION
* a-context a-manifest a-manageconf
b-context b-manifest b-manageconf
`,
},
{
name: "List contexts in table format(Context name is given)",
testContextOptions: config.ContextOptions{
Name: defaultCurrentContext,
CurrentContext: false,
Format: "table",
},
testConfig: config.Config{
CurrentContext: defaultCurrentContext,
Contexts: map[string]*config.Context{
"a-context": {Manifest: "a-manifest", ManagementConfiguration: "a-manageconf"},
"b-context": {Manifest: "b-manifest", ManagementConfiguration: "b-manageconf"}},
},
expectedOutput: `CURRENT NAME MANIFEST MANAGEMENTCONFIGURATION
* a-context a-manifest a-manageconf
`,
},
{
name: "List contexts in table format(CurrentContext is true)",
testContextOptions: config.ContextOptions{
Name: "",
CurrentContext: true,
Format: "table",
},
testConfig: config.Config{
CurrentContext: defaultCurrentContext,
Contexts: map[string]*config.Context{
"a-context": {Manifest: "a-manifest", ManagementConfiguration: "a-manageconf"},
"b-context": {Manifest: "b-manifest", ManagementConfiguration: "b-manageconf"}},
},
expectedOutput: `CURRENT NAME MANIFEST MANAGEMENTCONFIGURATION
* a-context a-manifest a-manageconf
`,
},
{
name: "List contexts in table format(Wrong Name is given)",
testContextOptions: config.ContextOptions{
Name: "wrong-context",
CurrentContext: false,
Format: "table",
},
testConfig: config.Config{
CurrentContext: defaultCurrentContext,
Contexts: map[string]*config.Context{
"a-context": {Manifest: "a-manifest", ManagementConfiguration: "a-manageconf"},
"b-context": {Manifest: "b-manifest", ManagementConfiguration: "b-manageconf"}},
},
expectedOutput: `CURRENT NAME MANIFEST MANAGEMENTCONFIGURATION
`,
expectedErr: "context with name 'wrong-context'",
},
{
name: "List contexts in yaml format",
testContextOptions: config.ContextOptions{
Name: "",
CurrentContext: false,
Format: "yaml",
},
testConfig: config.Config{
CurrentContext: defaultCurrentContext,
Contexts: map[string]*config.Context{
"a-context": {Manifest: "a-manifest", ManagementConfiguration: "a-manageconf"}},
},
expectedOutput: yamlOutput,
},
}
for _, tc := range tests {
tt := tc
t.Run(tt.name, func(t *testing.T) {
buf := &bytes.Buffer{}
err := tt.testContextOptions.Print(&tt.testConfig, buf)
if tt.expectedErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.expectedErr)
} else {
assert.NoError(t, err)
}
out, err := ioutil.ReadAll(buf)
fmt.Print(string(out))
require.NoError(t, err)
assert.Equal(t, tt.expectedOutput, string(out))
})
}
}