Skip to content

Commit

Permalink
generate: Prevent automatic id attribute behaviors under blocks (#365)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bflad committed Apr 26, 2024
1 parent 8a55c41 commit 14eebdd
Show file tree
Hide file tree
Showing 3 changed files with 387 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changes/unreleased/BUG FIXES-20240426-111333.yaml
@@ -0,0 +1,5 @@
kind: BUG FIXES
body: 'generate: Prevented automatic `id` attribute behaviors under blocks'
time: 2024-04-26T11:13:33.275469-04:00
custom:
Issue: "365"
@@ -0,0 +1,381 @@
# Copyright (c) HashiCorp, Inc.
# SPDX-License-Identifier: MPL-2.0

# Ensure only root level id attribute receives automatic description
[!unix] skip
exec tfplugindocs --provider-name=terraform-provider-scaffolding --providers-schema=schema.json
cmp stdout expected-output.txt
cmp docs/index.md expected-index.md
cmp docs/resources/example.md expected-resource.md

-- expected-output.txt --
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"
-- expected-index.md --
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "scaffolding Provider"
subcategory: ""
description: |-
Example provider
---

# scaffolding Provider

Example provider



<!-- schema generated by tfplugindocs -->
## Schema

### Optional

- `endpoint` (String) Example provider attribute
-- expected-resource.md --
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "scaffolding_example Resource - terraform-provider-scaffolding"
subcategory: ""
description: |-
example resource
---

# scaffolding_example (Resource)

example resource



<!-- schema generated by tfplugindocs -->
## Schema

### Required

- `required_object_attribute` (Object) example required object attribute (see [below for nested schema](#nestedatt--required_object_attribute))

### Optional

- `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))
- `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))
- `optional_object_attribute` (Object) example optional object attribute (see [below for nested schema](#nestedatt--optional_object_attribute))
- `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))
- `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))
- `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))
- `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))

### Read-Only

- `computed_object_attribute` (Object) example computed object attribute (see [below for nested schema](#nestedatt--computed_object_attribute))
- `id` (String) The ID of this resource.
- `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))
- `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))
- `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))

<a id="nestedatt--required_object_attribute"></a>
### Nested Schema for `required_object_attribute`

Required:

- `id` (String)


<a id="nestedblock--list_nested_block_optional_id"></a>
### Nested Schema for `list_nested_block_optional_id`

Optional:

- `id` (String)


<a id="nestedblock--list_nested_block_required_id"></a>
### Nested Schema for `list_nested_block_required_id`

Required:

- `id` (String)


<a id="nestedatt--optional_object_attribute"></a>
### Nested Schema for `optional_object_attribute`

Optional:

- `id` (String)


<a id="nestedblock--set_nested_block_optional_id"></a>
### Nested Schema for `set_nested_block_optional_id`

Optional:

- `id` (String)


<a id="nestedblock--set_nested_block_required_id"></a>
### Nested Schema for `set_nested_block_required_id`

Required:

- `id` (String)


<a id="nestedblock--single_nested_block_optional_id"></a>
### Nested Schema for `single_nested_block_optional_id`

Optional:

- `id` (String)


<a id="nestedblock--single_nested_block_required_id"></a>
### Nested Schema for `single_nested_block_required_id`

Required:

- `id` (String)


<a id="nestedatt--computed_object_attribute"></a>
### Nested Schema for `computed_object_attribute`

Read-Only:

- `id` (String)


<a id="nestedblock--list_nested_block_computed_id"></a>
### Nested Schema for `list_nested_block_computed_id`

Read-Only:

- `id` (String)


<a id="nestedblock--set_nested_block_computed_id"></a>
### Nested Schema for `set_nested_block_computed_id`

Read-Only:

- `id` (String)


<a id="nestedblock--single_nested_block_computed_id"></a>
### Nested Schema for `single_nested_block_computed_id`

Read-Only:

- `id` (String)
-- schema.json --
{
"format_version": "1.0",
"provider_schemas": {
"registry.terraform.io/hashicorp/scaffolding": {
"provider": {
"version": 0,
"block": {
"attributes": {
"endpoint": {
"type": "string",
"description": "Example provider attribute",
"description_kind": "plain",
"optional": true
}
},
"description": "Example provider",
"description_kind": "plain"
}
},
"resource_schemas": {
"scaffolding_example": {
"version": 0,
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"computed": true
},
"computed_object_attribute": {
"type": [
"object",
{
"id": "string"
}
],
"description": "example computed object attribute",
"description_kind": "plain",
"computed": true
},
"optional_object_attribute": {
"type": [
"object",
{
"id": "string"
}
],
"description": "example optional object attribute",
"description_kind": "plain",
"optional": true
},
"required_object_attribute": {
"type": [
"object",
{
"id": "string"
}
],
"description": "example required object attribute",
"description_kind": "plain",
"required": true
}
},
"block_types": {
"list_nested_block_computed_id": {
"nesting_mode": "list",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"computed": true
}
},
"description": "example list nested block with computed id attribute",
"description_kind": "plain"
}
},
"list_nested_block_optional_id": {
"nesting_mode": "list",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"optional": true
}
},
"description": "example list nested block with optional id attribute",
"description_kind": "plain"
}
},
"list_nested_block_required_id": {
"nesting_mode": "list",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"required": true
}
},
"description": "example list nested block with required id attribute",
"description_kind": "plain"
}
},
"set_nested_block_computed_id": {
"nesting_mode": "set",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"computed": true
}
},
"description": "example set nested block with computed id attribute",
"description_kind": "plain"
}
},
"set_nested_block_optional_id": {
"nesting_mode": "set",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"optional": true
}
},
"description": "example set nested block with optional id attribute",
"description_kind": "plain"
}
},
"set_nested_block_required_id": {
"nesting_mode": "set",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"required": true
}
},
"description": "example set nested block with required id attribute",
"description_kind": "plain"
}
},
"single_nested_block_computed_id": {
"nesting_mode": "single",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"computed": true
}
},
"description": "example single nested block with computed id attribute",
"description_kind": "plain"
}
},
"single_nested_block_optional_id": {
"nesting_mode": "single",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"optional": true
}
},
"description": "example single nested block with optional id attribute",
"description_kind": "plain"
}
},
"single_nested_block_required_id": {
"nesting_mode": "single",
"block": {
"attributes": {
"id": {
"type": "string",
"description_kind": "plain",
"required": true
}
},
"description": "example single nested block with required id attribute",
"description_kind": "plain"
}
}
},
"description": "example resource",
"description_kind": "plain"
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion internal/schemamd/render.go
Expand Up @@ -238,7 +238,7 @@ nameLoop:
//
// If a `.Description` is provided instead, the behaviour will be the
// same as for every other attribute.
if strings.ToLower(n) == "id" && childAtt.Description == "" {
if strings.ToLower(n) == "id" && len(parents) == 0 && childAtt.Description == "" {
if strings.Contains(gf.topLevelTitle, "Read-Only") {
childAtt.Description = "The ID of this resource."
groups[i] = append(groups[i], n)
Expand Down

0 comments on commit 14eebdd

Please sign in to comment.