Skip to content

Commit 8661cf8

Browse files
Handle additionalProperties in resource type display (#11764)
# Description `rad resource-type show` now displays nested fields for object schemas defined with `additionalProperties`, so map-style resource properties no longer render as empty object-property sections. ## Type of change - This pull request fixes a bug in Radius and has an approved issue (issue link required). Fixes: #10257 ## Validation - `go test ./pkg/cli/cmd/resourcetype/show -run Test_GetResourceTypeSchema_AdditionalProperties -count=1` - `go test ./pkg/cli/cmd/resourcetype/... -count=1` - `go vet ./pkg/cli/cmd/resourcetype/...` - `git diff --check` ## Contributor checklist - An overview of proposed schema changes is included in a linked GitHub issue. - [ ] Yes <!-- TaskRadio schema --> - [x] Not applicable <!-- TaskRadio schema --> - A design document PR is created in the [design-notes repository](https://github.com/radius-project/design-notes/), if new APIs are being introduced. - [ ] Yes <!-- TaskRadio design-pr --> - [x] Not applicable <!-- TaskRadio design-pr --> - The design document has been reviewed and approved by Radius maintainers/approvers. - [ ] Yes <!-- TaskRadio design-review --> - [x] Not applicable <!-- TaskRadio design-review --> - A PR for the [samples repository](https://github.com/radius-project/samples) is created, if existing samples are affected by the changes in this PR. - [ ] Yes <!-- TaskRadio samples-pr --> - [x] Not applicable <!-- TaskRadio samples-pr --> - A PR for the [documentation repository](https://github.com/radius-project/docs) is created, if the changes in this PR affect the documentation or any user facing updates are made. - [ ] Yes <!-- TaskRadio docs-pr --> - [x] Not applicable <!-- TaskRadio docs-pr --> - A PR for the [recipes repository](https://github.com/radius-project/recipes) is created, if existing recipes are affected by the changes in this PR. - [ ] Yes <!-- TaskRadio recipes-pr --> - [x] Not applicable <!-- TaskRadio recipes-pr --> --------- Signed-off-by: Akash Kumar <meakash7902@gmail.com> Co-authored-by: Nithya Subramanian <98416062+nithyatsu@users.noreply.github.com>
1 parent 7064761 commit 8661cf8

2 files changed

Lines changed: 172 additions & 1 deletion

File tree

‎pkg/cli/cmd/resourcetype/show/display.go‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,22 @@ func GetResourceTypeSchema(schema map[string]any) map[string]FieldSchema {
211211
Description: description,
212212
IsRequired: isRequired,
213213
IsReadOnly: isReadOnly,
214-
Properties: GetResourceTypeSchema(prop),
214+
Properties: GetResourceTypeSchema(getNestedSchema(prop)),
215215
}
216216
}
217217
}
218218

219219
return fieldSchema
220220
}
221+
222+
func getNestedSchema(schema map[string]any) map[string]any {
223+
if _, ok := schema["properties"].(map[string]any); ok {
224+
return schema
225+
}
226+
227+
if additionalProperties, ok := schema["additionalProperties"].(map[string]any); ok {
228+
return additionalProperties
229+
}
230+
231+
return schema
232+
}

‎pkg/cli/cmd/resourcetype/show/show_test.go‎

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,162 @@ func Test_Run(t *testing.T) {
245245
require.Empty(t, outputSink.Writes)
246246
})
247247
}
248+
249+
func Test_GetResourceTypeSchema_Properties(t *testing.T) {
250+
schema := map[string]any{
251+
"properties": map[string]any{
252+
"name": map[string]any{
253+
"type": "string",
254+
"description": "The resource name.",
255+
},
256+
"settings": map[string]any{
257+
"type": "object",
258+
"properties": map[string]any{
259+
"replicas": map[string]any{
260+
"type": "integer",
261+
"description": "Number of replicas.",
262+
},
263+
},
264+
"required": []any{"replicas"},
265+
},
266+
},
267+
"required": []any{"name"},
268+
}
269+
270+
result := GetResourceTypeSchema(schema)
271+
272+
require.Equal(t, map[string]FieldSchema{
273+
"name": {
274+
Name: "name",
275+
Type: "string",
276+
Description: "The resource name.",
277+
IsRequired: true,
278+
IsReadOnly: false,
279+
Properties: map[string]FieldSchema{},
280+
},
281+
"settings": {
282+
Name: "settings",
283+
Type: "object",
284+
Description: "",
285+
IsRequired: false,
286+
IsReadOnly: false,
287+
Properties: map[string]FieldSchema{
288+
"replicas": {
289+
Name: "replicas",
290+
Type: "integer",
291+
Description: "Number of replicas.",
292+
IsRequired: true,
293+
IsReadOnly: false,
294+
Properties: map[string]FieldSchema{},
295+
},
296+
},
297+
},
298+
}, result)
299+
}
300+
301+
func Test_getNestedSchema(t *testing.T) {
302+
t.Run("returns input when schema has properties", func(t *testing.T) {
303+
schema := map[string]any{
304+
"properties": map[string]any{
305+
"foo": map[string]any{"type": "string"},
306+
},
307+
}
308+
309+
got := getNestedSchema(schema)
310+
require.Same(t, &schema, &schema)
311+
require.Equal(t, schema, got)
312+
})
313+
314+
t.Run("descends into additionalProperties when no properties key", func(t *testing.T) {
315+
nested := map[string]any{
316+
"properties": map[string]any{
317+
"value": map[string]any{"type": "string"},
318+
},
319+
}
320+
schema := map[string]any{
321+
"type": "object",
322+
"additionalProperties": nested,
323+
}
324+
325+
got := getNestedSchema(schema)
326+
require.Equal(t, nested, got)
327+
})
328+
329+
t.Run("returns input when neither properties nor additionalProperties match", func(t *testing.T) {
330+
schema := map[string]any{
331+
"type": "string",
332+
}
333+
334+
got := getNestedSchema(schema)
335+
require.Equal(t, schema, got)
336+
})
337+
338+
t.Run("prefers properties over additionalProperties when both exist", func(t *testing.T) {
339+
schema := map[string]any{
340+
"properties": map[string]any{
341+
"a": map[string]any{"type": "string"},
342+
},
343+
"additionalProperties": map[string]any{
344+
"properties": map[string]any{
345+
"b": map[string]any{"type": "string"},
346+
},
347+
},
348+
}
349+
350+
got := getNestedSchema(schema)
351+
require.Equal(t, schema, got)
352+
})
353+
}
354+
355+
func Test_GetResourceTypeSchema_AdditionalProperties(t *testing.T) {
356+
schema := map[string]any{
357+
"properties": map[string]any{
358+
"data": map[string]any{
359+
"type": "object",
360+
"additionalProperties": map[string]any{
361+
"type": "object",
362+
"properties": map[string]any{
363+
"encoding": map[string]any{
364+
"type": "string",
365+
"description": "Content encoding of the value.",
366+
},
367+
"value": map[string]any{
368+
"type": "string",
369+
"description": "The secret value.",
370+
},
371+
},
372+
},
373+
},
374+
},
375+
}
376+
377+
result := GetResourceTypeSchema(schema)
378+
379+
require.Equal(t, map[string]FieldSchema{
380+
"data": {
381+
Name: "data",
382+
Type: "object",
383+
Description: "",
384+
IsRequired: false,
385+
IsReadOnly: false,
386+
Properties: map[string]FieldSchema{
387+
"encoding": {
388+
Name: "encoding",
389+
Type: "string",
390+
Description: "Content encoding of the value.",
391+
IsRequired: false,
392+
IsReadOnly: false,
393+
Properties: map[string]FieldSchema{},
394+
},
395+
"value": {
396+
Name: "value",
397+
Type: "string",
398+
Description: "The secret value.",
399+
IsRequired: false,
400+
IsReadOnly: false,
401+
Properties: map[string]FieldSchema{},
402+
},
403+
},
404+
},
405+
}, result)
406+
}

0 commit comments

Comments
 (0)