[#394] plan list -o yaml changes
Added yaml output flag to show plan list in yaml format Relates-To: #394 Co-authored By: Niharika Bhavaraju<niha.twinkle@gmail.com> Change-Id: I8bed077573eb79783cfc77e4ebf82c819f41d125
This commit is contained in:
parent
05b36dd40f
commit
5085f22c56
@ -25,20 +25,35 @@ const (
|
||||
listLong = `
|
||||
List life-cycle plans which were defined in document model.
|
||||
`
|
||||
listExample = `
|
||||
#list plan
|
||||
airshipctl plan list
|
||||
|
||||
#list plan(yaml output format)
|
||||
airshipctl plan list -o yaml
|
||||
|
||||
#list plan(table output format)
|
||||
airshipctl plan list -o table`
|
||||
)
|
||||
|
||||
// NewListCommand creates a command which prints available phase plans
|
||||
func NewListCommand(cfgFactory config.Factory) *cobra.Command {
|
||||
planCmd := &phase.PlanListCommand{Factory: cfgFactory}
|
||||
p := &phase.PlanListCommand{Factory: cfgFactory}
|
||||
|
||||
listCmd := &cobra.Command{
|
||||
Use: "list",
|
||||
Short: "List plans",
|
||||
Long: listLong[1:],
|
||||
Example: listExample,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
planCmd.Writer = cmd.OutOrStdout()
|
||||
return planCmd.RunE()
|
||||
p.Writer = cmd.OutOrStdout()
|
||||
return p.RunE()
|
||||
},
|
||||
}
|
||||
flags := listCmd.Flags()
|
||||
flags.StringVarP(&p.Options.FormatType,
|
||||
"output", "o", "table", "'table' "+
|
||||
"and 'yaml' are available "+
|
||||
"output formats")
|
||||
return listCmd
|
||||
}
|
||||
|
@ -3,5 +3,17 @@ List life-cycle plans which were defined in document model.
|
||||
Usage:
|
||||
list [flags]
|
||||
|
||||
Examples:
|
||||
|
||||
#list plan
|
||||
airshipctl plan list
|
||||
|
||||
#list plan(yaml output format)
|
||||
airshipctl plan list -o yaml
|
||||
|
||||
#list plan(table output format)
|
||||
airshipctl plan list -o table
|
||||
|
||||
Flags:
|
||||
-h, --help help for list
|
||||
-o, --output string 'table' and 'yaml' are available output formats (default "table")
|
||||
|
@ -11,10 +11,25 @@ List life-cycle plans which were defined in document model.
|
||||
airshipctl plan list [flags]
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
|
||||
#list plan
|
||||
airshipctl plan list
|
||||
|
||||
#list plan(yaml output format)
|
||||
airshipctl plan list -o yaml
|
||||
|
||||
#list plan(table output format)
|
||||
airshipctl plan list -o table
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
```
|
||||
-h, --help help for list
|
||||
-o, --output string 'table' and 'yaml' are available output formats (default "table")
|
||||
```
|
||||
|
||||
### Options inherited from parent commands
|
||||
|
@ -15,17 +15,12 @@
|
||||
package phase
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/cli-utils/pkg/print/table"
|
||||
|
||||
"opendev.org/airship/airshipctl/pkg/api/v1alpha1"
|
||||
"opendev.org/airship/airshipctl/pkg/cluster/clustermap"
|
||||
"opendev.org/airship/airshipctl/pkg/config"
|
||||
"opendev.org/airship/airshipctl/pkg/document"
|
||||
@ -35,6 +30,13 @@ import (
|
||||
"opendev.org/airship/airshipctl/pkg/util/yaml"
|
||||
)
|
||||
|
||||
const (
|
||||
// TableOutputFormat table
|
||||
TableOutputFormat = "table"
|
||||
// YamlOutputFormat yaml
|
||||
YamlOutputFormat = "yaml"
|
||||
)
|
||||
|
||||
// GenericRunFlags generic options for run command
|
||||
type GenericRunFlags struct {
|
||||
DryRun bool
|
||||
@ -85,7 +87,7 @@ type ListCommand struct {
|
||||
|
||||
// RunE runs a phase list command
|
||||
func (c *ListCommand) RunE() error {
|
||||
if c.OutputFormat != "table" && c.OutputFormat != "yaml" {
|
||||
if c.OutputFormat != TableOutputFormat && c.OutputFormat != YamlOutputFormat {
|
||||
return phaseerrors.ErrInvalidFormat{RequestedFormat: c.OutputFormat}
|
||||
}
|
||||
cfg, err := c.Factory()
|
||||
@ -103,7 +105,7 @@ func (c *ListCommand) RunE() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.OutputFormat == "table" {
|
||||
if c.OutputFormat == TableOutputFormat {
|
||||
return PrintPhaseListTable(c.Writer, phaseList)
|
||||
}
|
||||
return yaml.WriteOut(c.Writer, phaseList)
|
||||
@ -160,14 +162,23 @@ func (c *TreeCommand) RunE() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PlanListFlags flags given for plan list command
|
||||
type PlanListFlags struct {
|
||||
FormatType string
|
||||
}
|
||||
|
||||
// PlanListCommand phase list command
|
||||
type PlanListCommand struct {
|
||||
Options PlanListFlags
|
||||
Factory config.Factory
|
||||
Writer io.Writer
|
||||
}
|
||||
|
||||
// RunE runs a plan list command
|
||||
func (c *PlanListCommand) RunE() error {
|
||||
if c.Options.FormatType != TableOutputFormat && c.Options.FormatType != YamlOutputFormat {
|
||||
return phaseerrors.ErrInvalidFormat{RequestedFormat: c.Options.FormatType}
|
||||
}
|
||||
cfg, err := c.Factory()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -178,42 +189,18 @@ func (c *PlanListCommand) RunE() error {
|
||||
return err
|
||||
}
|
||||
|
||||
phases, err := helper.ListPlans()
|
||||
phasePlans, err := helper.ListPlans()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rt, err := util.NewResourceTable(phases, util.DefaultStatusFunction())
|
||||
if err != nil {
|
||||
return err
|
||||
switch {
|
||||
case c.Options.FormatType == YamlOutputFormat:
|
||||
return yaml.WriteOut(c.Writer, phasePlans)
|
||||
case c.Options.FormatType == TableOutputFormat:
|
||||
return PrintPlanListTable(c.Writer, phasePlans)
|
||||
default:
|
||||
return PrintPlanListTable(c.Writer, phasePlans)
|
||||
}
|
||||
|
||||
printer := util.DefaultTablePrinter(c.Writer, nil)
|
||||
descriptionCol := table.ColumnDef{
|
||||
ColumnName: "description",
|
||||
ColumnHeader: "DESCRIPTION",
|
||||
ColumnWidth: 200,
|
||||
PrintResourceFunc: func(w io.Writer, width int, r table.Resource) (int, error) {
|
||||
rs := r.ResourceStatus()
|
||||
if rs == nil {
|
||||
return 0, nil
|
||||
}
|
||||
plan := &v1alpha1.PhasePlan{}
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(rs.Resource.Object, plan)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
txt := plan.Description
|
||||
if len(txt) > width {
|
||||
txt = txt[:width]
|
||||
}
|
||||
_, err = fmt.Fprint(w, txt)
|
||||
return len(txt), err
|
||||
},
|
||||
}
|
||||
printer.Columns = append(printer.Columns, descriptionCol)
|
||||
printer.PrintTable(rt, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
// PlanRunFlags options for phase run command
|
||||
@ -258,7 +245,7 @@ type ClusterListCommand struct {
|
||||
|
||||
// RunE executes cluster list command
|
||||
func (c *ClusterListCommand) RunE() error {
|
||||
if c.Format != "table" && c.Format != "name" {
|
||||
if c.Format != TableOutputFormat && c.Format != "name" {
|
||||
return phaseerrors.ErrInvalidOutputFormat{RequestedFormat: c.Format}
|
||||
}
|
||||
cfg, err := c.Factory()
|
||||
|
@ -324,12 +324,25 @@ func TestTreeCommand(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPlanListCommand(t *testing.T) {
|
||||
yamlOutput := `---
|
||||
- apiVersion: airshipit.org/v1alpha1
|
||||
description: Default phase plan
|
||||
kind: PhasePlan
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: phasePlan
|
||||
phases:
|
||||
- name: phase
|
||||
...
|
||||
`
|
||||
testErr := fmt.Errorf(testFactoryErr)
|
||||
testCases := []struct {
|
||||
name string
|
||||
factory config.Factory
|
||||
expectedOut [][]byte
|
||||
expectedErr string
|
||||
Format string
|
||||
expectedYaml string
|
||||
}{
|
||||
{
|
||||
name: "Error config factory",
|
||||
@ -338,13 +351,27 @@ func TestPlanListCommand(t *testing.T) {
|
||||
},
|
||||
expectedErr: testFactoryErr,
|
||||
expectedOut: [][]byte{{}},
|
||||
Format: "table",
|
||||
},
|
||||
{
|
||||
name: "Error new helper",
|
||||
factory: func() (*config.Config, error) {
|
||||
return &config.Config{
|
||||
CurrentContext: "does not exist",
|
||||
Contexts: make(map[string]*config.Context),
|
||||
}, nil
|
||||
},
|
||||
expectedErr: testNewHelperErr,
|
||||
Format: "table",
|
||||
expectedOut: [][]byte{{}},
|
||||
},
|
||||
|
||||
{
|
||||
name: "List phases",
|
||||
factory: func() (*config.Config, error) {
|
||||
conf := config.NewConfig()
|
||||
manifest := conf.Manifests[config.AirshipDefaultManifest]
|
||||
manifest.TargetPath = "testdata"
|
||||
manifest.TargetPath = testTargetPath
|
||||
manifest.MetadataPath = testMetadataPath
|
||||
manifest.Repositories[config.DefaultTestPhaseRepo].URLString = ""
|
||||
return conf, nil
|
||||
@ -359,6 +386,20 @@ func TestPlanListCommand(t *testing.T) {
|
||||
" "),
|
||||
{},
|
||||
},
|
||||
Format: "table",
|
||||
},
|
||||
{
|
||||
name: "Valid yaml input format",
|
||||
factory: func() (*config.Config, error) {
|
||||
conf := config.NewConfig()
|
||||
manifest := conf.Manifests[config.AirshipDefaultManifest]
|
||||
manifest.TargetPath = testTargetPath
|
||||
manifest.MetadataPath = "metadata.yaml"
|
||||
manifest.Repositories[config.DefaultTestPhaseRepo].URLString = ""
|
||||
return conf, nil
|
||||
},
|
||||
Format: "yaml",
|
||||
expectedYaml: yamlOutput,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
@ -368,6 +409,7 @@ func TestPlanListCommand(t *testing.T) {
|
||||
cmd := phase.PlanListCommand{
|
||||
Factory: tt.factory,
|
||||
Writer: buf,
|
||||
Options: phase.PlanListFlags{FormatType: tt.Format},
|
||||
}
|
||||
err := cmd.RunE()
|
||||
if tt.expectedErr != "" {
|
||||
@ -377,8 +419,13 @@ func TestPlanListCommand(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
out, err := ioutil.ReadAll(buf)
|
||||
fmt.Print(string(out))
|
||||
require.NoError(t, err)
|
||||
if tt.Format == "yaml" {
|
||||
assert.Equal(t, tt.expectedYaml, string(out))
|
||||
} else {
|
||||
assert.Equal(t, tt.expectedOut, bytes.Split(out, []byte("\n")))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -415,7 +462,7 @@ func TestPlanRunCommand(t *testing.T) {
|
||||
conf.Manifests = map[string]*config.Manifest{
|
||||
"manifest": {
|
||||
MetadataPath: testMetadataPath,
|
||||
TargetPath: "testdata",
|
||||
TargetPath: testTargetPath,
|
||||
PhaseRepositoryName: config.DefaultTestPhaseRepo,
|
||||
Repositories: map[string]*config.Repository{
|
||||
config.DefaultTestPhaseRepo: {
|
||||
|
@ -101,3 +101,38 @@ func phaseFromResource(r table.Resource) (*v1alpha1.Phase, error) {
|
||||
phase := &v1alpha1.Phase{}
|
||||
return phase, runtime.DefaultUnstructuredConverter.FromUnstructured(rs.Resource.Object, phase)
|
||||
}
|
||||
|
||||
//PrintPlanListTable prints plan list table
|
||||
func PrintPlanListTable(w io.Writer, phasePlans []*v1alpha1.PhasePlan) error {
|
||||
rt, err := util.NewResourceTable(phasePlans, util.DefaultStatusFunction())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
printer := util.DefaultTablePrinter(w, nil)
|
||||
descriptionCol := table.ColumnDef{
|
||||
ColumnName: "description",
|
||||
ColumnHeader: "DESCRIPTION",
|
||||
ColumnWidth: 200,
|
||||
PrintResourceFunc: func(w io.Writer, width int, r table.Resource) (int, error) {
|
||||
rs := r.ResourceStatus()
|
||||
if rs == nil {
|
||||
return 0, nil
|
||||
}
|
||||
plan := &v1alpha1.PhasePlan{}
|
||||
err := runtime.DefaultUnstructuredConverter.FromUnstructured(rs.Resource.Object, plan)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
txt := plan.Description
|
||||
if len(txt) > width {
|
||||
txt = txt[:width]
|
||||
}
|
||||
_, err = fmt.Fprintf(w, txt)
|
||||
return len(txt), err
|
||||
},
|
||||
}
|
||||
printer.Columns = append(printer.Columns, descriptionCol)
|
||||
printer.PrintTable(rt, 0)
|
||||
return nil
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ import (
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
@ -118,3 +119,60 @@ func TestDefaultStatusFunction(t *testing.T) {
|
||||
rs := f(printable)
|
||||
assert.Equal(t, expectedObj, rs.Resource.Object)
|
||||
}
|
||||
|
||||
func TestPrintPlanListTable(t *testing.T) {
|
||||
plans := []*v1alpha1.PhasePlan{
|
||||
{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PhasePlan",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p",
|
||||
},
|
||||
Description: "description",
|
||||
Phases: []v1alpha1.PhaseStep{
|
||||
{
|
||||
Name: "phase",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
plans []*v1alpha1.PhasePlan
|
||||
}{
|
||||
{
|
||||
name: "Success print plan list",
|
||||
plans: plans,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
w := &bytes.Buffer{}
|
||||
err := PrintPlanListTable(w, tt.plans)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultStatusFunctionForPhasePlan(t *testing.T) {
|
||||
f := util.DefaultStatusFunction()
|
||||
expectedObj := map[string]interface{}{
|
||||
"kind": "PhasePlan",
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "p1",
|
||||
"creationTimestamp": nil,
|
||||
},
|
||||
}
|
||||
printable := &v1alpha1.PhasePlan{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PhasePlan",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "p1",
|
||||
},
|
||||
}
|
||||
rs := f(printable)
|
||||
assert.Equal(t, expectedObj, rs.Resource.Object)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user