Skip to content

Commit

Permalink
chore(cli): make the dashes under column headings consistent (#1705)
Browse files Browse the repository at this point in the history
Wherever command output is in tabular format, this brings consistency to our formatting-- dashes (same length as heading, not longest element) below the headings.

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.
  • Loading branch information
huanjani authored Nov 24, 2020
1 parent 6128e9c commit ce836bd
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 40 deletions.
3 changes: 3 additions & 0 deletions internal/pkg/cli/app_show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,17 +246,20 @@ func TestShowAppOpts_Execute(t *testing.T) {
Environments
Name AccountID Region
---- --------- ------
test 123456789 us-west-2
prod 123456789 us-west-1
Services
Name Type
---- ----
my-svc lb-web-svc
Pipelines
Name
----
pipeline1
pipeline2
`,
Expand Down
30 changes: 29 additions & 1 deletion internal/pkg/cli/env_show_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,35 @@ func TestEnvShow_Execute(t *testing.T) {
)
},

wantedContent: "About\n\n Name testEnv\n Production false\n Region us-west-2\n Account ID 123456789012\n\nServices\n\n Name Type\n -------- -------------\n testSvc1 load-balanced\n testSvc2 load-balanced\n testSvc3 load-balanced\n\nTags\n\n Key Value\n ------------------- -------\n copilot-application testApp\n copilot-environment testEnv\n key1 value1\n key2 value2\n\nResources\n\n AWS::IAM::Role testApp-testEnv-CFNExecutionRole\n testApp-testEnv-Cluster AWS::ECS::Cluster-jI63pYBWU6BZ\n",
wantedContent: `About
Name testEnv
Production false
Region us-west-2
Account ID 123456789012
Services
Name Type
---- ----
testSvc1 load-balanced
testSvc2 load-balanced
testSvc3 load-balanced
Tags
Key Value
--- -----
copilot-application testApp
copilot-environment testEnv
key1 value1
key2 value2
Resources
AWS::IAM::Role testApp-testEnv-CFNExecutionRole
testApp-testEnv-Cluster AWS::ECS::Cluster-jI63pYBWU6BZ
`,
},
"success in JSON format": {
inputEnv: "testEnv",
Expand Down
13 changes: 10 additions & 3 deletions internal/pkg/describe/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"bytes"
"encoding/json"
"fmt"
"strings"
"text/tabwriter"

"github.com/aws/copilot-cli/internal/pkg/aws/codepipeline"
Expand Down Expand Up @@ -42,19 +43,25 @@ func (a *App) HumanString() string {
fmt.Fprintf(writer, " %s\t%s\n", "URI", a.URI)
fmt.Fprint(writer, color.Bold.Sprint("\nEnvironments\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\t%s\t%s\n", "Name", "AccountID", "Region")
headers := []string{"Name", "AccountID", "Region"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, env := range a.Envs {
fmt.Fprintf(writer, " %s\t%s\t%s\n", env.Name, env.AccountID, env.Region)
}
fmt.Fprint(writer, color.Bold.Sprint("\nServices\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\t%s\n", "Name", "Type")
headers = []string{"Name", "Type"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, svc := range a.Services {
fmt.Fprintf(writer, " %s\t%s\n", svc.Name, svc.Type)
}
fmt.Fprint(writer, color.Bold.Sprint("\nPipelines\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\n", "Name")
headers = []string{"Name"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, pipeline := range a.Pipelines {
fmt.Fprintf(writer, " %s\n", pipeline.Name)
}
Expand Down
25 changes: 6 additions & 19 deletions internal/pkg/describe/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"math"
"sort"
"strings"
"text/tabwriter"
Expand Down Expand Up @@ -189,31 +188,19 @@ func (e *EnvDescription) HumanString() string {
fmt.Fprintf(writer, " %s\t%s\n", "Account ID", e.Environment.AccountID)
fmt.Fprint(writer, color.Bold.Sprint("\nServices\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\t%s\n", "Name", "Type")
nameLengthMax := len("Name")
typeLengthMax := len("Type")
for _, svc := range e.Services {
nameLengthMax = int(math.Max(float64(nameLengthMax), float64(len(svc.Name))))
typeLengthMax = int(math.Max(float64(typeLengthMax), float64(len(svc.Type))))
}
fmt.Fprintf(writer, " %s\t%s\n", strings.Repeat("-", nameLengthMax), strings.Repeat("-", typeLengthMax))
writer.Flush()
headers := []string{"Name", "Type"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, svc := range e.Services {
fmt.Fprintf(writer, " %s\t%s\n", svc.Name, svc.Type)
}
writer.Flush()
if len(e.Tags) != 0 {
fmt.Fprint(writer, color.Bold.Sprint("\nTags\n\n"))
writer.Flush()
KeyLengthMax := len("Key")
ValueLengthMax := len("Value")
for k, v := range e.Tags {
KeyLengthMax = int(math.Max(float64(KeyLengthMax), float64(len(k))))
ValueLengthMax = int(math.Max(float64(ValueLengthMax), float64(len(v))))
}
fmt.Fprintf(writer, " %s\t%s\n", "Key", "Value")
fmt.Fprintf(writer, " %s\t%s\n", strings.Repeat("-", KeyLengthMax), strings.Repeat("-", ValueLengthMax))
writer.Flush()
headers := []string{"Key", "Value"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
// sort Tags in alpha order by keys
keys := make([]string, 0, len(e.Tags))
for k := range e.Tags {
Expand Down
4 changes: 2 additions & 2 deletions internal/pkg/describe/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,15 +377,15 @@ func TestEnvDescription_HumanString(t *testing.T) {
Services
Name Type
-------- -------------
---- ----
testSvc1 load-balanced
testSvc2 load-balanced
testSvc3 load-balanced
Tags
Key Value
---- ------
--- -----
key1 value1
key2 value2
Expand Down
8 changes: 6 additions & 2 deletions internal/pkg/describe/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,17 @@ func (s *ServiceStatusDesc) HumanString() string {
fmt.Fprintf(writer, " %s\t%s\n", "Task Definition", s.Service.TaskDefinition)
fmt.Fprint(writer, color.Bold.Sprint("\nTask Status\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\t%s\t%s\t%s\t%s\t%s\n", "ID", "Image Digest", "Last Status", "Started At", "Stopped At", "Health Status")
headers := []string{"ID", "Image Digest", "Last Status", "Started At", "Stopped At", "Health Status"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, task := range s.Tasks {
fmt.Fprint(writer, task.HumanString())
}
fmt.Fprint(writer, color.Bold.Sprint("\nAlarms\n\n"))
writer.Flush()
fmt.Fprintf(writer, " %s\t%s\t%s\t%s\n", "Name", "Condition", "Last Updated", "Health")
headers = []string{"Name", "Condition", "Last Updated", "Health"}
fmt.Fprintf(writer, " %s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, " %s\n", strings.Join(underline(headers), "\t"))
for _, alarm := range s.Alarms {
updatedTimeSince := humanizeTime(alarm.UpdatedTimes)
printWithMaxWidth(writer, " %s\t%s\t%s\t%s\n", maxAlarmStatusColumnWidth, alarm.Name, alarm.Condition, updatedTimeSince, alarmHealthColor(alarm.Status))
Expand Down
4 changes: 4 additions & 0 deletions internal/pkg/describe/status_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,13 @@ Last Deployment
Task Status
ID Image Digest Last Status Started At Stopped At Health Status
-- ------------ ----------- ---------- ---------- -------------
12345678 - PROVISIONING - - HEALTHY
Alarms
Name Condition Last Updated Health
---- --------- ------------ ------
mySupercalifragilisticexpialid RequestCount > 100.00 for 3 da 2 months from now OK
ociousAlarm tapoints within 25 minutes
Expand Down Expand Up @@ -477,11 +479,13 @@ Last Deployment
Task Status
ID Image Digest Last Status Started At Stopped At Health Status
-- ------------ ----------- ---------- ---------- -------------
12345678 69671a96,ca27a44e RUNNING - - HEALTHY
Alarms
Name Condition Last Updated Health
---- --------- ------------ ------
mockAlarm mockCondition 2 months from now OK
`,
Expand Down
21 changes: 12 additions & 9 deletions internal/pkg/list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"encoding/json"
"fmt"
"io"
"math"
"strings"
"text/tabwriter"

Expand Down Expand Up @@ -134,16 +133,20 @@ func filterByName(wklds []*config.Workload, wantedNames []string) []*config.Work
return filtered
}

func underline(headings []string) []string {
var lines []string
for _, heading := range headings {
line := strings.Repeat("-", len(heading))
lines = append(lines, line)
}
return lines
}

func humanOutput(wklds []*config.Workload, w io.Writer) {
writer := tabwriter.NewWriter(w, minCellWidth, tabWidth, cellPaddingWidth, paddingChar, noAdditionalFormatting)
fmt.Fprintf(writer, "%s\t%s\n", "Name", "Type")
nameLengthMax := len("Name")
typeLengthMax := len("Type")
for _, svc := range wklds {
nameLengthMax = int(math.Max(float64(nameLengthMax), float64(len(svc.Name))))
typeLengthMax = int(math.Max(float64(typeLengthMax), float64(len(svc.Type))))
}
fmt.Fprintf(writer, "%s\t%s\n", strings.Repeat("-", nameLengthMax), strings.Repeat("-", typeLengthMax))
headers := []string{"Name", "Type"}
fmt.Fprintf(writer, "%s\n", strings.Join(headers, "\t"))
fmt.Fprintf(writer, "%s\n", strings.Join(underline(headers), "\t"))
for _, wkld := range wklds {
fmt.Fprintf(writer, "%s\t%s\n", wkld.Name, wkld.Type)
}
Expand Down
12 changes: 8 additions & 4 deletions internal/pkg/list/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ func TestList_JobListWriter(t *testing.T) {
inputAppName: mockAppName,
inputWriteJSON: false,

wantedContent: "Name Type\n-------- -------------\nbadgoose Scheduled Job\nfarmer Scheduled Job\n",
wantedContent: `Name Type
---- ----
badgoose Scheduled Job
farmer Scheduled Job
`,
mocking: func() {
mockStore.EXPECT().
GetApplication(gomock.Eq("barnyard")).
Expand Down Expand Up @@ -88,7 +92,7 @@ func TestList_JobListWriter(t *testing.T) {
inputAppName: mockAppName,
inputListLocal: true,

wantedContent: "Name Type\n-------- -------------\nbadgoose Scheduled Job\n",
wantedContent: "Name Type\n---- ----\nbadgoose Scheduled Job\n",

mocking: func() {
mockStore.EXPECT().GetApplication("barnyard").
Expand Down Expand Up @@ -197,7 +201,7 @@ func TestList_SvcListWriter(t *testing.T) {
inputAppName: mockAppName,
inputWriteJSON: false,

wantedContent: "Name Type\n------ -------------------------\ntrough Backend Service\ngaggle Load Balanced Web Service\n",
wantedContent: "Name Type\n---- ----\ntrough Backend Service\ngaggle Load Balanced Web Service\n",
mocking: func() {
mockStore.EXPECT().
GetApplication(gomock.Eq("barnyard")).
Expand Down Expand Up @@ -249,7 +253,7 @@ func TestList_SvcListWriter(t *testing.T) {
inputAppName: mockAppName,
inputListLocal: true,

wantedContent: "Name Type\n------ ---------------\ntrough Backend Service\n",
wantedContent: "Name Type\n---- ----\ntrough Backend Service\n",

mocking: func() {
mockStore.EXPECT().GetApplication("barnyard").
Expand Down

0 comments on commit ce836bd

Please sign in to comment.