Skip to content

Commit 14eebdd

Browse files
authored
generate: Prevent automatic id attribute behaviors under blocks (#365)
Reference: #335 Previously, the automatic `id` attribute handling intended for root level schema blocks was applied to all blocks, causing the generator to errantly set the grouping to `Read-Only` and the description to `The ID of this resource`. This was captured via a new integration test: ``` --- FAIL: Test_SchemaJson_GenerateAcceptanceTests (0.00s) --- FAIL: Test_SchemaJson_GenerateAcceptanceTests/nested_id_attribute (0.25s) testscript.go:558: # Copyright (c) HashiCorp, Inc. # SPDX-License-Identifier: MPL-2.0 # Ensure only root level id attribute receives automatic description (0.236s) > [!unix] skip > exec tfplugindocs --provider-name=terraform-provider-scaffolding --providers-schema=schema.json [stdout] rendering website for provider "terraform-provider-scaffolding" (as "terraform-provider-scaffolding") exporting schema from JSON file getting provider schema generating missing templates generating missing resource content generating new template for "scaffolding_example" generating missing data source content generating missing function content generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website cleaning rendered website dir rendering templated website to static markdown rendering "index.md.tmpl" rendering "resources/example.md.tmpl" > cmp stdout expected-output.txt > cmp docs/index.md expected-index.md > cmp docs/resources/example.md expected-resource.md diff docs/resources/example.md expected-resource.md --- docs/resources/example.md +++ expected-resource.md @@ -48,17 +48,17 @@ <a id="nestedblock--list_nested_block_optional_id"></a> ### Nested Schema for `list_nested_block_optional_id` -Read-Only: - -- `id` (String) The ID of this resource. +Optional: + +- `id` (String) <a id="nestedblock--list_nested_block_required_id"></a> ### Nested Schema for `list_nested_block_required_id` -Read-Only: - -- `id` (String) The ID of this resource. +Required: + +- `id` (String) <a id="nestedatt--optional_object_attribute"></a> @@ -72,33 +72,33 @@ <a id="nestedblock--set_nested_block_optional_id"></a> ### Nested Schema for `set_nested_block_optional_id` -Read-Only: - -- `id` (String) The ID of this resource. +Optional: + +- `id` (String) <a id="nestedblock--set_nested_block_required_id"></a> ### Nested Schema for `set_nested_block_required_id` -Read-Only: - -- `id` (String) The ID of this resource. +Required: + +- `id` (String) <a id="nestedblock--single_nested_block_optional_id"></a> ### Nested Schema for `single_nested_block_optional_id` -Read-Only: - -- `id` (String) The ID of this resource. +Optional: + +- `id` (String) <a id="nestedblock--single_nested_block_required_id"></a> ### Nested Schema for `single_nested_block_required_id` -Read-Only: - -- `id` (String) The ID of this resource. +Required: + +- `id` (String) <a id="nestedatt--computed_object_attribute"></a> @@ -114,7 +114,7 @@ Read-Only: -- `id` (String) The ID of this resource. +- `id` (String) <a id="nestedblock--set_nested_block_computed_id"></a> @@ -122,7 +122,7 @@ Read-Only: -- `id` (String) The ID of this resource. +- `id` (String) <a id="nestedblock--single_nested_block_computed_id"></a> @@ -130,4 +130,4 @@ Read-Only: -- `id` (String) The ID of this resource. +- `id` (String) FAIL: testdata/scripts/schema-json/generate/nested_id_attribute.txtar:9: docs/resources/example.md and expected-resource.md differ ``` The schema rendering logic could likely use a full refactoring as it has very high code complexity, but this change is only a very targeted fix for the acute and errant `id` attribute handling behavior.
1 parent 8a55c41 commit 14eebdd

File tree

3 files changed

+387
-1
lines changed

3 files changed

+387
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: 'generate: Prevented automatic `id` attribute behaviors under blocks'
3+
time: 2024-04-26T11:13:33.275469-04:00
4+
custom:
5+
Issue: "365"
Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
# Copyright (c) HashiCorp, Inc.
2+
# SPDX-License-Identifier: MPL-2.0
3+
4+
# Ensure only root level id attribute receives automatic description
5+
[!unix] skip
6+
exec tfplugindocs --provider-name=terraform-provider-scaffolding --providers-schema=schema.json
7+
cmp stdout expected-output.txt
8+
cmp docs/index.md expected-index.md
9+
cmp docs/resources/example.md expected-resource.md
10+
11+
-- expected-output.txt --
12+
rendering website for provider "terraform-provider-scaffolding" (as "terraform-provider-scaffolding")
13+
exporting schema from JSON file
14+
getting provider schema
15+
generating missing templates
16+
generating missing resource content
17+
generating new template for "scaffolding_example"
18+
generating missing data source content
19+
generating missing function content
20+
generating missing provider content
21+
generating new template for "terraform-provider-scaffolding"
22+
rendering static website
23+
cleaning rendered website dir
24+
rendering templated website to static markdown
25+
rendering "index.md.tmpl"
26+
rendering "resources/example.md.tmpl"
27+
-- expected-index.md --
28+
---
29+
# generated by https://github.com/hashicorp/terraform-plugin-docs
30+
page_title: "scaffolding Provider"
31+
subcategory: ""
32+
description: |-
33+
Example provider
34+
---
35+
36+
# scaffolding Provider
37+
38+
Example provider
39+
40+
41+
42+
<!-- schema generated by tfplugindocs -->
43+
## Schema
44+
45+
### Optional
46+
47+
- `endpoint` (String) Example provider attribute
48+
-- expected-resource.md --
49+
---
50+
# generated by https://github.com/hashicorp/terraform-plugin-docs
51+
page_title: "scaffolding_example Resource - terraform-provider-scaffolding"
52+
subcategory: ""
53+
description: |-
54+
example resource
55+
---
56+
57+
# scaffolding_example (Resource)
58+
59+
example resource
60+
61+
62+
63+
<!-- schema generated by tfplugindocs -->
64+
## Schema
65+
66+
### Required
67+
68+
- `required_object_attribute` (Object) example required object attribute (see [below for nested schema](#nestedatt--required_object_attribute))
69+
70+
### Optional
71+
72+
- `list_nested_block_optional_id` (Block List) example list nested block with optional id attribute (see [below for nested schema](#nestedblock--list_nested_block_optional_id))
73+
- `list_nested_block_required_id` (Block List) example list nested block with required id attribute (see [below for nested schema](#nestedblock--list_nested_block_required_id))
74+
- `optional_object_attribute` (Object) example optional object attribute (see [below for nested schema](#nestedatt--optional_object_attribute))
75+
- `set_nested_block_optional_id` (Block Set) example set nested block with optional id attribute (see [below for nested schema](#nestedblock--set_nested_block_optional_id))
76+
- `set_nested_block_required_id` (Block Set) example set nested block with required id attribute (see [below for nested schema](#nestedblock--set_nested_block_required_id))
77+
- `single_nested_block_optional_id` (Block, Optional) example single nested block with optional id attribute (see [below for nested schema](#nestedblock--single_nested_block_optional_id))
78+
- `single_nested_block_required_id` (Block, Optional) example single nested block with required id attribute (see [below for nested schema](#nestedblock--single_nested_block_required_id))
79+
80+
### Read-Only
81+
82+
- `computed_object_attribute` (Object) example computed object attribute (see [below for nested schema](#nestedatt--computed_object_attribute))
83+
- `id` (String) The ID of this resource.
84+
- `list_nested_block_computed_id` (Block List) example list nested block with computed id attribute (see [below for nested schema](#nestedblock--list_nested_block_computed_id))
85+
- `set_nested_block_computed_id` (Block Set) example set nested block with computed id attribute (see [below for nested schema](#nestedblock--set_nested_block_computed_id))
86+
- `single_nested_block_computed_id` (Block, Read-only) example single nested block with computed id attribute (see [below for nested schema](#nestedblock--single_nested_block_computed_id))
87+
88+
<a id="nestedatt--required_object_attribute"></a>
89+
### Nested Schema for `required_object_attribute`
90+
91+
Required:
92+
93+
- `id` (String)
94+
95+
96+
<a id="nestedblock--list_nested_block_optional_id"></a>
97+
### Nested Schema for `list_nested_block_optional_id`
98+
99+
Optional:
100+
101+
- `id` (String)
102+
103+
104+
<a id="nestedblock--list_nested_block_required_id"></a>
105+
### Nested Schema for `list_nested_block_required_id`
106+
107+
Required:
108+
109+
- `id` (String)
110+
111+
112+
<a id="nestedatt--optional_object_attribute"></a>
113+
### Nested Schema for `optional_object_attribute`
114+
115+
Optional:
116+
117+
- `id` (String)
118+
119+
120+
<a id="nestedblock--set_nested_block_optional_id"></a>
121+
### Nested Schema for `set_nested_block_optional_id`
122+
123+
Optional:
124+
125+
- `id` (String)
126+
127+
128+
<a id="nestedblock--set_nested_block_required_id"></a>
129+
### Nested Schema for `set_nested_block_required_id`
130+
131+
Required:
132+
133+
- `id` (String)
134+
135+
136+
<a id="nestedblock--single_nested_block_optional_id"></a>
137+
### Nested Schema for `single_nested_block_optional_id`
138+
139+
Optional:
140+
141+
- `id` (String)
142+
143+
144+
<a id="nestedblock--single_nested_block_required_id"></a>
145+
### Nested Schema for `single_nested_block_required_id`
146+
147+
Required:
148+
149+
- `id` (String)
150+
151+
152+
<a id="nestedatt--computed_object_attribute"></a>
153+
### Nested Schema for `computed_object_attribute`
154+
155+
Read-Only:
156+
157+
- `id` (String)
158+
159+
160+
<a id="nestedblock--list_nested_block_computed_id"></a>
161+
### Nested Schema for `list_nested_block_computed_id`
162+
163+
Read-Only:
164+
165+
- `id` (String)
166+
167+
168+
<a id="nestedblock--set_nested_block_computed_id"></a>
169+
### Nested Schema for `set_nested_block_computed_id`
170+
171+
Read-Only:
172+
173+
- `id` (String)
174+
175+
176+
<a id="nestedblock--single_nested_block_computed_id"></a>
177+
### Nested Schema for `single_nested_block_computed_id`
178+
179+
Read-Only:
180+
181+
- `id` (String)
182+
-- schema.json --
183+
{
184+
"format_version": "1.0",
185+
"provider_schemas": {
186+
"registry.terraform.io/hashicorp/scaffolding": {
187+
"provider": {
188+
"version": 0,
189+
"block": {
190+
"attributes": {
191+
"endpoint": {
192+
"type": "string",
193+
"description": "Example provider attribute",
194+
"description_kind": "plain",
195+
"optional": true
196+
}
197+
},
198+
"description": "Example provider",
199+
"description_kind": "plain"
200+
}
201+
},
202+
"resource_schemas": {
203+
"scaffolding_example": {
204+
"version": 0,
205+
"block": {
206+
"attributes": {
207+
"id": {
208+
"type": "string",
209+
"description_kind": "plain",
210+
"computed": true
211+
},
212+
"computed_object_attribute": {
213+
"type": [
214+
"object",
215+
{
216+
"id": "string"
217+
}
218+
],
219+
"description": "example computed object attribute",
220+
"description_kind": "plain",
221+
"computed": true
222+
},
223+
"optional_object_attribute": {
224+
"type": [
225+
"object",
226+
{
227+
"id": "string"
228+
}
229+
],
230+
"description": "example optional object attribute",
231+
"description_kind": "plain",
232+
"optional": true
233+
},
234+
"required_object_attribute": {
235+
"type": [
236+
"object",
237+
{
238+
"id": "string"
239+
}
240+
],
241+
"description": "example required object attribute",
242+
"description_kind": "plain",
243+
"required": true
244+
}
245+
},
246+
"block_types": {
247+
"list_nested_block_computed_id": {
248+
"nesting_mode": "list",
249+
"block": {
250+
"attributes": {
251+
"id": {
252+
"type": "string",
253+
"description_kind": "plain",
254+
"computed": true
255+
}
256+
},
257+
"description": "example list nested block with computed id attribute",
258+
"description_kind": "plain"
259+
}
260+
},
261+
"list_nested_block_optional_id": {
262+
"nesting_mode": "list",
263+
"block": {
264+
"attributes": {
265+
"id": {
266+
"type": "string",
267+
"description_kind": "plain",
268+
"optional": true
269+
}
270+
},
271+
"description": "example list nested block with optional id attribute",
272+
"description_kind": "plain"
273+
}
274+
},
275+
"list_nested_block_required_id": {
276+
"nesting_mode": "list",
277+
"block": {
278+
"attributes": {
279+
"id": {
280+
"type": "string",
281+
"description_kind": "plain",
282+
"required": true
283+
}
284+
},
285+
"description": "example list nested block with required id attribute",
286+
"description_kind": "plain"
287+
}
288+
},
289+
"set_nested_block_computed_id": {
290+
"nesting_mode": "set",
291+
"block": {
292+
"attributes": {
293+
"id": {
294+
"type": "string",
295+
"description_kind": "plain",
296+
"computed": true
297+
}
298+
},
299+
"description": "example set nested block with computed id attribute",
300+
"description_kind": "plain"
301+
}
302+
},
303+
"set_nested_block_optional_id": {
304+
"nesting_mode": "set",
305+
"block": {
306+
"attributes": {
307+
"id": {
308+
"type": "string",
309+
"description_kind": "plain",
310+
"optional": true
311+
}
312+
},
313+
"description": "example set nested block with optional id attribute",
314+
"description_kind": "plain"
315+
}
316+
},
317+
"set_nested_block_required_id": {
318+
"nesting_mode": "set",
319+
"block": {
320+
"attributes": {
321+
"id": {
322+
"type": "string",
323+
"description_kind": "plain",
324+
"required": true
325+
}
326+
},
327+
"description": "example set nested block with required id attribute",
328+
"description_kind": "plain"
329+
}
330+
},
331+
"single_nested_block_computed_id": {
332+
"nesting_mode": "single",
333+
"block": {
334+
"attributes": {
335+
"id": {
336+
"type": "string",
337+
"description_kind": "plain",
338+
"computed": true
339+
}
340+
},
341+
"description": "example single nested block with computed id attribute",
342+
"description_kind": "plain"
343+
}
344+
},
345+
"single_nested_block_optional_id": {
346+
"nesting_mode": "single",
347+
"block": {
348+
"attributes": {
349+
"id": {
350+
"type": "string",
351+
"description_kind": "plain",
352+
"optional": true
353+
}
354+
},
355+
"description": "example single nested block with optional id attribute",
356+
"description_kind": "plain"
357+
}
358+
},
359+
"single_nested_block_required_id": {
360+
"nesting_mode": "single",
361+
"block": {
362+
"attributes": {
363+
"id": {
364+
"type": "string",
365+
"description_kind": "plain",
366+
"required": true
367+
}
368+
},
369+
"description": "example single nested block with required id attribute",
370+
"description_kind": "plain"
371+
}
372+
}
373+
},
374+
"description": "example resource",
375+
"description_kind": "plain"
376+
}
377+
}
378+
}
379+
}
380+
}
381+
}

internal/schemamd/render.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,7 @@ nameLoop:
238238
//
239239
// If a `.Description` is provided instead, the behaviour will be the
240240
// same as for every other attribute.
241-
if strings.ToLower(n) == "id" && childAtt.Description == "" {
241+
if strings.ToLower(n) == "id" && len(parents) == 0 && childAtt.Description == "" {
242242
if strings.Contains(gf.topLevelTitle, "Read-Only") {
243243
childAtt.Description = "The ID of this resource."
244244
groups[i] = append(groups[i], n)

0 commit comments

Comments
 (0)