Skip to content

Commit ecb5684

Browse files
authored
feat(table): mark columns as deprecated and show warning (#1300)
Closes #1295
1 parent e90a3f2 commit ecb5684

File tree

4 files changed

+37
-7
lines changed

4 files changed

+37
-7
lines changed

internal/cmd/base/list.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,13 @@ func (lc *ListCmd[T, S]) Run(s state.State, cmd *cobra.Command, args []string) e
163163

164164
t := output.NewTable[T](out)
165165
lc.OutputTable(t, s.Client())
166+
167+
warnings, _ := t.ValidateColumns(cols)
168+
// invalid columns are already checked in output.validateOutputFlag(), we only need the warnings here
169+
for _, warning := range warnings {
170+
cmd.PrintErrln("Warning:", warning)
171+
}
172+
166173
if !outOpts.IsSet("noheader") {
167174
t.WriteHeader(cols)
168175
}

internal/cmd/context/list.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,13 @@ func runList(s state.State, cmd *cobra.Command, _ []string) error {
4343
}
4444

4545
tw := newListOutputTable(cmd.OutOrStdout())
46-
if err := tw.ValidateColumns(cols); err != nil {
46+
warnings, err := tw.ValidateColumns(cols)
47+
if err != nil {
4748
return err
4849
}
50+
for _, warning := range warnings {
51+
cmd.PrintErrln("Warning:", warning)
52+
}
4953

5054
if !outOpts.IsSet("noheader") {
5155
tw.WriteHeader(cols)

internal/cmd/output/output.go

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ func NewTable[T any](out io.Writer) *Table[T] {
174174
fieldMapping: map[string]FieldFn[T]{},
175175
fieldAlias: map[string]string{},
176176
allowedFields: map[string]bool{},
177+
deprecations: map[string]string{},
177178
}
178179
}
179180

@@ -187,6 +188,7 @@ type Table[T any] struct {
187188
fieldMapping map[string]FieldFn[T]
188189
fieldAlias map[string]string
189190
allowedFields map[string]bool
191+
deprecations map[string]string
190192
}
191193

192194
// Columns returns a list of known output columns.
@@ -212,6 +214,13 @@ func (o *Table[T]) AddFieldFn(field string, fn FieldFn[T]) *Table[T] {
212214
return o
213215
}
214216

217+
// MarkFieldAsDeprecated marks the specified field as deprecated. The message will be printed
218+
// to stderr if the column is used.
219+
func (o *Table[T]) MarkFieldAsDeprecated(field string, message string) *Table[T] {
220+
o.deprecations[field] = message
221+
return o
222+
}
223+
215224
// AddAllowedFields reads all first level fieldnames of the struct and allows them to be used.
216225
func (o *Table[T]) AddAllowedFields(obj T) *Table[T] {
217226
v := reflect.ValueOf(obj)
@@ -250,18 +259,21 @@ func (o *Table[T]) RemoveAllowedField(fields ...string) *Table[T] {
250259
return o
251260
}
252261

253-
// ValidateColumns returns an error if invalid columns are specified.
254-
func (o *Table[T]) ValidateColumns(cols []string) error {
255-
var invalidCols []string
262+
// ValidateColumns returns a list of warnings for the used columns and an error if invalid columns are specified.
263+
func (o *Table[T]) ValidateColumns(cols []string) ([]string, error) {
264+
var warnings, invalidCols []string
256265
for _, col := range cols {
266+
if warning, isDeprecated := o.deprecations[strings.ToLower(col)]; isDeprecated {
267+
warnings = append(warnings, warning)
268+
}
257269
if _, ok := o.allowedFields[strings.ToLower(col)]; !ok {
258270
invalidCols = append(invalidCols, col)
259271
}
260272
}
261273
if len(invalidCols) > 0 {
262-
return fmt.Errorf("invalid table columns: %s", strings.Join(invalidCols, ","))
274+
return warnings, fmt.Errorf("invalid table columns: %s", strings.Join(invalidCols, ","))
263275
}
264-
return nil
276+
return warnings, nil
265277
}
266278

267279
// WriteHeader writes the table header.

internal/cmd/output/output_test.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,18 @@ func TestTableOutput(t *testing.T) {
5151
assert.Contains(t, to.fieldMapping, "leeroy jenkins")
5252
})
5353

54+
t.Run("MarkFieldAsDeprecated", func(t *testing.T) {
55+
to.MarkFieldAsDeprecated("name", "This field is deprecated")
56+
57+
assert.Contains(t, to.deprecations, "name")
58+
})
59+
5460
t.Run("ValidateColumns", func(t *testing.T) {
55-
err := to.ValidateColumns([]string{"non-existent", "NAME"})
61+
warnings, err := to.ValidateColumns([]string{"non-existent", "NAME"})
5662

5763
require.ErrorContains(t, err, "non-existent")
5864
assert.NotContains(t, err.Error(), "name")
65+
assert.Contains(t, warnings, "This field is deprecated")
5966
})
6067

6168
t.Run("WriteHeader", func(t *testing.T) {

0 commit comments

Comments
 (0)