[#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 = `
|
listLong = `
|
||||||
List life-cycle plans which were defined in document model.
|
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
|
// NewListCommand creates a command which prints available phase plans
|
||||||
func NewListCommand(cfgFactory config.Factory) *cobra.Command {
|
func NewListCommand(cfgFactory config.Factory) *cobra.Command {
|
||||||
planCmd := &phase.PlanListCommand{Factory: cfgFactory}
|
p := &phase.PlanListCommand{Factory: cfgFactory}
|
||||||
|
|
||||||
listCmd := &cobra.Command{
|
listCmd := &cobra.Command{
|
||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List plans",
|
Short: "List plans",
|
||||||
Long: listLong[1:],
|
Long: listLong[1:],
|
||||||
|
Example: listExample,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
planCmd.Writer = cmd.OutOrStdout()
|
p.Writer = cmd.OutOrStdout()
|
||||||
return planCmd.RunE()
|
return p.RunE()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
flags := listCmd.Flags()
|
||||||
|
flags.StringVarP(&p.Options.FormatType,
|
||||||
|
"output", "o", "table", "'table' "+
|
||||||
|
"and 'yaml' are available "+
|
||||||
|
"output formats")
|
||||||
return listCmd
|
return listCmd
|
||||||
}
|
}
|
||||||
|
@ -3,5 +3,17 @@ List life-cycle plans which were defined in document model.
|
|||||||
Usage:
|
Usage:
|
||||||
list [flags]
|
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:
|
Flags:
|
||||||
-h, --help help for list
|
-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]
|
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
|
### Options
|
||||||
|
|
||||||
```
|
```
|
||||||
-h, --help help for list
|
-h, --help help for list
|
||||||
|
-o, --output string 'table' and 'yaml' are available output formats (default "table")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Options inherited from parent commands
|
### Options inherited from parent commands
|
||||||
|
@ -15,17 +15,12 @@
|
|||||||
package phase
|
package phase
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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/cluster/clustermap"
|
||||||
"opendev.org/airship/airshipctl/pkg/config"
|
"opendev.org/airship/airshipctl/pkg/config"
|
||||||
"opendev.org/airship/airshipctl/pkg/document"
|
"opendev.org/airship/airshipctl/pkg/document"
|
||||||
@ -35,6 +30,13 @@ import (
|
|||||||
"opendev.org/airship/airshipctl/pkg/util/yaml"
|
"opendev.org/airship/airshipctl/pkg/util/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// TableOutputFormat table
|
||||||
|
TableOutputFormat = "table"
|
||||||
|
// YamlOutputFormat yaml
|
||||||
|
YamlOutputFormat = "yaml"
|
||||||
|
)
|
||||||
|
|
||||||
// GenericRunFlags generic options for run command
|
// GenericRunFlags generic options for run command
|
||||||
type GenericRunFlags struct {
|
type GenericRunFlags struct {
|
||||||
DryRun bool
|
DryRun bool
|
||||||
@ -85,7 +87,7 @@ type ListCommand struct {
|
|||||||
|
|
||||||
// RunE runs a phase list command
|
// RunE runs a phase list command
|
||||||
func (c *ListCommand) RunE() error {
|
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}
|
return phaseerrors.ErrInvalidFormat{RequestedFormat: c.OutputFormat}
|
||||||
}
|
}
|
||||||
cfg, err := c.Factory()
|
cfg, err := c.Factory()
|
||||||
@ -103,7 +105,7 @@ func (c *ListCommand) RunE() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if c.OutputFormat == "table" {
|
if c.OutputFormat == TableOutputFormat {
|
||||||
return PrintPhaseListTable(c.Writer, phaseList)
|
return PrintPhaseListTable(c.Writer, phaseList)
|
||||||
}
|
}
|
||||||
return yaml.WriteOut(c.Writer, phaseList)
|
return yaml.WriteOut(c.Writer, phaseList)
|
||||||
@ -160,14 +162,23 @@ func (c *TreeCommand) RunE() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PlanListFlags flags given for plan list command
|
||||||
|
type PlanListFlags struct {
|
||||||
|
FormatType string
|
||||||
|
}
|
||||||
|
|
||||||
// PlanListCommand phase list command
|
// PlanListCommand phase list command
|
||||||
type PlanListCommand struct {
|
type PlanListCommand struct {
|
||||||
|
Options PlanListFlags
|
||||||
Factory config.Factory
|
Factory config.Factory
|
||||||
Writer io.Writer
|
Writer io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunE runs a plan list command
|
// RunE runs a plan list command
|
||||||
func (c *PlanListCommand) RunE() error {
|
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()
|
cfg, err := c.Factory()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -178,42 +189,18 @@ func (c *PlanListCommand) RunE() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
phases, err := helper.ListPlans()
|
phasePlans, err := helper.ListPlans()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
switch {
|
||||||
rt, err := util.NewResourceTable(phases, util.DefaultStatusFunction())
|
case c.Options.FormatType == YamlOutputFormat:
|
||||||
if err != nil {
|
return yaml.WriteOut(c.Writer, phasePlans)
|
||||||
return err
|
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
|
// PlanRunFlags options for phase run command
|
||||||
@ -258,7 +245,7 @@ type ClusterListCommand struct {
|
|||||||
|
|
||||||
// RunE executes cluster list command
|
// RunE executes cluster list command
|
||||||
func (c *ClusterListCommand) RunE() error {
|
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}
|
return phaseerrors.ErrInvalidOutputFormat{RequestedFormat: c.Format}
|
||||||
}
|
}
|
||||||
cfg, err := c.Factory()
|
cfg, err := c.Factory()
|
||||||
|
@ -324,12 +324,25 @@ func TestTreeCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPlanListCommand(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)
|
testErr := fmt.Errorf(testFactoryErr)
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
factory config.Factory
|
factory config.Factory
|
||||||
expectedOut [][]byte
|
expectedOut [][]byte
|
||||||
expectedErr string
|
expectedErr string
|
||||||
|
Format string
|
||||||
|
expectedYaml string
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "Error config factory",
|
name: "Error config factory",
|
||||||
@ -338,13 +351,27 @@ func TestPlanListCommand(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedErr: testFactoryErr,
|
expectedErr: testFactoryErr,
|
||||||
expectedOut: [][]byte{{}},
|
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",
|
name: "List phases",
|
||||||
factory: func() (*config.Config, error) {
|
factory: func() (*config.Config, error) {
|
||||||
conf := config.NewConfig()
|
conf := config.NewConfig()
|
||||||
manifest := conf.Manifests[config.AirshipDefaultManifest]
|
manifest := conf.Manifests[config.AirshipDefaultManifest]
|
||||||
manifest.TargetPath = "testdata"
|
manifest.TargetPath = testTargetPath
|
||||||
manifest.MetadataPath = testMetadataPath
|
manifest.MetadataPath = testMetadataPath
|
||||||
manifest.Repositories[config.DefaultTestPhaseRepo].URLString = ""
|
manifest.Repositories[config.DefaultTestPhaseRepo].URLString = ""
|
||||||
return conf, nil
|
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 {
|
for _, tc := range testCases {
|
||||||
@ -368,6 +409,7 @@ func TestPlanListCommand(t *testing.T) {
|
|||||||
cmd := phase.PlanListCommand{
|
cmd := phase.PlanListCommand{
|
||||||
Factory: tt.factory,
|
Factory: tt.factory,
|
||||||
Writer: buf,
|
Writer: buf,
|
||||||
|
Options: phase.PlanListFlags{FormatType: tt.Format},
|
||||||
}
|
}
|
||||||
err := cmd.RunE()
|
err := cmd.RunE()
|
||||||
if tt.expectedErr != "" {
|
if tt.expectedErr != "" {
|
||||||
@ -377,8 +419,13 @@ func TestPlanListCommand(t *testing.T) {
|
|||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
}
|
}
|
||||||
out, err := ioutil.ReadAll(buf)
|
out, err := ioutil.ReadAll(buf)
|
||||||
|
fmt.Print(string(out))
|
||||||
require.NoError(t, err)
|
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")))
|
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{
|
conf.Manifests = map[string]*config.Manifest{
|
||||||
"manifest": {
|
"manifest": {
|
||||||
MetadataPath: testMetadataPath,
|
MetadataPath: testMetadataPath,
|
||||||
TargetPath: "testdata",
|
TargetPath: testTargetPath,
|
||||||
PhaseRepositoryName: config.DefaultTestPhaseRepo,
|
PhaseRepositoryName: config.DefaultTestPhaseRepo,
|
||||||
Repositories: map[string]*config.Repository{
|
Repositories: map[string]*config.Repository{
|
||||||
config.DefaultTestPhaseRepo: {
|
config.DefaultTestPhaseRepo: {
|
||||||
|
@ -101,3 +101,38 @@ func phaseFromResource(r table.Resource) (*v1alpha1.Phase, error) {
|
|||||||
phase := &v1alpha1.Phase{}
|
phase := &v1alpha1.Phase{}
|
||||||
return phase, runtime.DefaultUnstructuredConverter.FromUnstructured(rs.Resource.Object, 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/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
@ -118,3 +119,60 @@ func TestDefaultStatusFunction(t *testing.T) {
|
|||||||
rs := f(printable)
|
rs := f(printable)
|
||||||
assert.Equal(t, expectedObj, rs.Resource.Object)
|
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