fix(cli/cliui): handle typed nil and null time in tables (#15984)

This commit is contained in:
Mathias Fredriksson
2024-12-31 14:36:46 +00:00
committed by GitHub
parent ca96e670ed
commit 23b1c2d6b2
2 changed files with 52 additions and 28 deletions
+14 -1
View File
@@ -9,6 +9,8 @@ import (
"github.com/fatih/structtag"
"github.com/jedib0t/go-pretty/v6/table"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/codersdk"
)
// Table creates a new table with standardized styles.
@@ -195,6 +197,12 @@ func renderTable(out any, sort string, headers table.Row, filterColumns []string
if val != nil {
v = val.Format(time.RFC3339)
}
case codersdk.NullTime:
if val.Valid {
v = val.Time.Format(time.RFC3339)
} else {
v = nil
}
case *int64:
if val != nil {
v = *val
@@ -204,8 +212,13 @@ func renderTable(out any, sort string, headers table.Row, filterColumns []string
v = val.String()
}
case fmt.Stringer:
if val != nil {
// Protect against typed nils since fmt.Stringer is an interface.
vv := reflect.ValueOf(v)
nilPtr := vv.Kind() == reflect.Ptr && vv.IsNil()
if val != nil && !nilPtr {
v = val.String()
} else if nilPtr {
v = nil
}
}
+38 -27
View File
@@ -1,6 +1,7 @@
package cliui_test
import (
"database/sql"
"fmt"
"log"
"strings"
@@ -11,6 +12,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk"
)
type stringWrapper struct {
@@ -24,18 +26,20 @@ func (s stringWrapper) String() string {
}
type tableTest1 struct {
Name string `table:"name,default_sort"`
NotIncluded string // no table tag
Age int `table:"age"`
Roles []string `table:"roles"`
Sub1 tableTest2 `table:"sub_1,recursive"`
Sub2 *tableTest2 `table:"sub_2,recursive"`
Sub3 tableTest3 `table:"sub 3,recursive"`
Sub4 tableTest2 `table:"sub 4"` // not recursive
Name string `table:"name,default_sort"`
AltName *stringWrapper `table:"alt_name"`
NotIncluded string // no table tag
Age int `table:"age"`
Roles []string `table:"roles"`
Sub1 tableTest2 `table:"sub_1,recursive"`
Sub2 *tableTest2 `table:"sub_2,recursive"`
Sub3 tableTest3 `table:"sub 3,recursive"`
Sub4 tableTest2 `table:"sub 4"` // not recursive
// Types with special formatting.
Time time.Time `table:"time"`
TimePtr *time.Time `table:"time_ptr"`
Time time.Time `table:"time"`
TimePtr *time.Time `table:"time_ptr"`
NullTime codersdk.NullTime `table:"null_time"`
}
type tableTest2 struct {
@@ -62,9 +66,10 @@ func Test_DisplayTable(t *testing.T) {
// Not sorted by name or age to test sorting.
in := []tableTest1{
{
Name: "bar",
Age: 20,
Roles: []string{"a"},
Name: "bar",
AltName: &stringWrapper{str: "bar alt"},
Age: 20,
Roles: []string{"a"},
Sub1: tableTest2{
Name: stringWrapper{str: "bar1"},
Age: 21,
@@ -82,6 +87,12 @@ func Test_DisplayTable(t *testing.T) {
},
Time: someTime,
TimePtr: nil,
NullTime: codersdk.NullTime{
NullTime: sql.NullTime{
Time: someTime,
Valid: true,
},
},
},
{
Name: "foo",
@@ -138,10 +149,10 @@ func Test_DisplayTable(t *testing.T) {
t.Parallel()
expected := `
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil>
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil>
foo 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z
NAME ALT NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR NULL TIME
bar bar alt 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil> 2022-08-02T15:49:10Z
baz <nil> 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil> <nil>
foo <nil> 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z <nil>
`
// Test with non-pointer values.
@@ -165,10 +176,10 @@ foo 10 [a, b, c] foo1 11 foo2 12 foo3
t.Parallel()
expected := `
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR
foo 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil>
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil>
NAME ALT NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR NULL TIME
foo <nil> 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z <nil>
bar bar alt 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil> 2022-08-02T15:49:10Z
baz <nil> 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil> <nil>
`
out, err := cliui.DisplayTable(in, "age", nil)
@@ -235,12 +246,12 @@ Alice 25
t.Run("WithSeparator", func(t *testing.T) {
t.Parallel()
expected := `
NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR
bar 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil>
---------------------------------------------------------------------------------------------------------------------------------------------------------------
baz 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil>
---------------------------------------------------------------------------------------------------------------------------------------------------------------
foo 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z
NAME ALT NAME AGE ROLES SUB 1 NAME SUB 1 AGE SUB 2 NAME SUB 2 AGE SUB 3 INNER NAME SUB 3 INNER AGE SUB 4 TIME TIME PTR NULL TIME
bar bar alt 20 [a] bar1 21 <nil> <nil> bar3 23 {bar4 24 } 2022-08-02T15:49:10Z <nil> 2022-08-02T15:49:10Z
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
baz <nil> 30 [] baz1 31 <nil> <nil> baz3 33 {baz4 34 } 2022-08-02T15:49:10Z <nil> <nil>
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
foo <nil> 10 [a, b, c] foo1 11 foo2 12 foo3 13 {foo4 14 } 2022-08-02T15:49:10Z 2022-08-02T15:49:10Z <nil>
`
var inlineIn []any