diff --git a/.changes/unreleased/FEATURES-20260227-144449.yaml b/.changes/unreleased/FEATURES-20260227-144449.yaml new file mode 100644 index 00000000..84e229e8 --- /dev/null +++ b/.changes/unreleased/FEATURES-20260227-144449.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'generate: Add support for state stores' +time: 2026-02-27T14:44:49.221116-05:00 +custom: + Issue: "570" diff --git a/.changes/unreleased/FEATURES-20260227-144513.yaml b/.changes/unreleased/FEATURES-20260227-144513.yaml new file mode 100644 index 00000000..49b4ce99 --- /dev/null +++ b/.changes/unreleased/FEATURES-20260227-144513.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'migrate: Add support for state stores' +time: 2026-02-27T14:45:13.780708-05:00 +custom: + Issue: "570" diff --git a/.changes/unreleased/FEATURES-20260227-144523.yaml b/.changes/unreleased/FEATURES-20260227-144523.yaml new file mode 100644 index 00000000..f45ce265 --- /dev/null +++ b/.changes/unreleased/FEATURES-20260227-144523.yaml @@ -0,0 +1,5 @@ +kind: FEATURES +body: 'validate: Add support for state stores' +time: 2026-02-27T14:45:23.218741-05:00 +custom: + Issue: "570" diff --git a/README.md b/README.md index 6f243629..637f36aa 100644 --- a/README.md +++ b/README.md @@ -119,6 +119,7 @@ When you run `tfplugindocs`, by default from the root directory of a provider co * Generate ephemeral resource template files, if missing (Requires Terraform v1.10.0+) * Generate action template files, if missing (Requires Terraform v1.14.0+) * Generate list resource templeate files, if missing (Requires Terraform v1.14.0+) +* Generate state store template files, if missing (Requires Terraform v1.16.0+) * Copy all non-template files to the output website directory > [!NOTE] @@ -219,6 +220,8 @@ For templates: | `templates/functions/.md[.tmpl]` | Function page (or template) | | `templates/list-resources.md[.tmpl]` | Generic list resource page (or template) | | `templates/list-resources/.md[.tmpl]` | List resource page (or template) | +| `templates/state-stores.md[.tmpl]` | Generic state store page (or template) | +| `templates/state-stores/.md[.tmpl]` | State store page (or template) | | `templates/resources.md[.tmpl]` | Generic resource page (or template) | | `templates/resources/.md[.tmpl]` | Resource page (or template) | @@ -238,6 +241,7 @@ For examples: | `examples/ephemeral-resources//ephemeral-resource<*>.tf` | Ephemeral resource example config(s) | | `examples/functions//function<*>.tf` | Function example config(s) | | `examples/list-resources//list-resource<*>.tfquery.hcl` | List resource example config(s) | +| `examples/state-stores//state-store<*>.tf` | State store example config(s) | | `examples/resources//resource<*>.tf` | Resource example config(s) | | `examples/resources//import.sh` | Resource example import command | | `examples/resources//import-by-string-id.tf` | Resource example import by id config | @@ -262,6 +266,7 @@ Legacy website directory structure: | `website/docs/ephemeral-resources/.html.markdown` | Ephemeral resource page | | `website/docs/functons/.html.markdown` | Functions page | | `website/docs/list-resources/.html.markdown` | List resource page | +| `website/docs/state-stores/.html.markdown` | State store page | | `website/docs/r/.html.markdown` | Resource page | Docs website directory structure: @@ -276,6 +281,7 @@ Docs website directory structure: | `docs/ephemeral-resources/.html.markdown` | Ephemeral resource page | | `docs/functions/.html.markdown` | Function page | | `docs/list-resources/.html.markdown` | List resource page | +| `docs/state-stores/.html.markdown` | State store page | | `docs/resources/.html.markdown` | Resource page | Files named `index` (before the first `.`) in the website docs root directory and files in the `website/docs/d/`, `website/docs/r/`, `docs/data-sources/`, @@ -381,6 +387,22 @@ using the following data fields and functions: | `.RenderedProviderName` | string | Value provided via argument `--rendered-provider-name`, otherwise same as `.ProviderName` | | `.SchemaMarkdown` | string | a Markdown formatted list resource Schema definition | +##### State Store Fields + +| Field | Type | Description | +|-------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------| +| `.Name` | string | Name of the state store (ex. `examplecloud_thing`) | +| `.Type` | string | `State Store` | +| `.Description` | string | State store description | +| `.HasExample` | bool | (Legacy) Is there an example file? | +| `.HasExamples` | bool | Are there example files? Always true if HasExample is true. | +| `.ExampleFile` | string | (Legacy) Path to the file with the terraform configuration example | +| `.ExampleFiles` | string | Paths to the files with terraform configuration examples. Includes ExampleFile. | +| `.ProviderName` | string | Canonical provider name (ex. `terraform-provider-http`) | +| `.ProviderShortName` | string | Short version of the rendered provider name (ex. `http`) | +| `.RenderedProviderName` | string | Value provided via argument `--rendered-provider-name`, otherwise same as `.ProviderName` | +| `.SchemaMarkdown` | string | a Markdown formatted state store Schema definition | + #### Template Functions | Function | Description | diff --git a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_generic_templates.txtar b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_generic_templates.txtar index 5099d975..3119c8d0 100644 --- a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_generic_templates.txtar +++ b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_generic_templates.txtar @@ -29,6 +29,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content provider "terraform-provider-scaffolding" template exists, skipping rendering static website diff --git a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_named_templates.txtar b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_named_templates.txtar index 1b2c9652..6f833761 100644 --- a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_named_templates.txtar +++ b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_named_templates.txtar @@ -29,6 +29,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content provider "terraform-provider-scaffolding" template exists, skipping rendering static website diff --git a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_no_templates.txtar b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_no_templates.txtar index 936da55b..382fd001 100644 --- a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_no_templates.txtar +++ b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/framework_provider_success_no_templates.txtar @@ -27,6 +27,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website diff --git a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/null_provider_success.txtar b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/null_provider_success.txtar index 967f435b..e7bf28a1 100644 --- a/cmd/tfplugindocs/testdata/scripts/provider-build/generate/null_provider_success.txtar +++ b/cmd/tfplugindocs/testdata/scripts/provider-build/generate/null_provider_success.txtar @@ -26,6 +26,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content provider "terraform-provider-null" template exists, skipping rendering static website @@ -2404,4 +2405,4 @@ func main() { if err != nil { log.Fatal(err) } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types.txtar index eb46f79b..370a64a5 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_all_framework_types.txtar @@ -22,6 +22,7 @@ generating new template for function "scaffolding" generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_generic_templates.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_generic_templates.txtar index 1c534281..a695740e 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_generic_templates.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_generic_templates.txtar @@ -13,6 +13,7 @@ cmpenv docs/functions/example.md expected-function.md cmpenv docs/ephemeral-resources/example.md expected-ephemeral-resource.md cmpenv docs/actions/example.md expected-action.md cmpenv docs/list-resources/example.md expected-list-resource.md +cmpenv docs/state-stores/example.md expected-state-store.md -- expected-output.txt -- @@ -33,6 +34,8 @@ generating missing action content action "scaffolding_example" fallback template exists, creating template generating missing list resource content list resource "scaffolding_example" fallback template exists, creating template +generating missing state store content +state store "scaffolding_example" fallback template exists, creating template generating missing provider content provider "terraform-provider-scaffolding" template exists, skipping rendering static website @@ -45,6 +48,7 @@ rendering "functions/example.md.tmpl" rendering "index.md.tmpl" rendering "list-resources/example.md.tmpl" rendering "resources/example.md.tmpl" +rendering "state-stores/example.md.tmpl" -- expected-action.md -- # Data Fields @@ -149,6 +153,60 @@ list "scaffolding_example" "example" { } } ``` +-- expected-state-store.md -- +# Data Fields + +Name: scaffolding_example +Type: State Store +Description: Example state store +HasExample: true +ExampleFile: $WORK/examples/state-stores/scaffolding_example/state-store.tf +ProviderName: terraform-provider-scaffolding +ProviderShortName: scaffolding +RenderedProviderName: terraform-provider-scaffolding +SchemaMarkdown: +## Schema + +### Optional + +- `configurable_attribute` (String) Example configurable attribute +- `defaulted` (String) Example configurable attribute with default value + + + +# Functions + +lower: state store +plainmarkdown: State Store +prefixlines: Prefix: State Store +split: [scaffolding example] +title: State Store +trimspace: State Store +upper: STATE STORE + +# Conditionals and File Functions + +printf tffile: +## Example Usage + +{{tffile "$WORK/examples/state-stores/scaffolding_example/state-store.tf"}} + +tffile: +## Example Usage + +```terraform +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} +``` -- expected-datasource.md -- # Data Fields @@ -458,6 +516,44 @@ tffile: {{ if .HasExample -}} ## Example Usage +{{tffile .ExampleFile }} +{{- end }} +-- templates/state-stores.md.tmpl -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +Description: {{.Description}} +HasExample: {{.HasExample}} +ExampleFile: {{.ExampleFile}} +ProviderName: {{.ProviderName}} +ProviderShortName: {{.ProviderShortName}} +RenderedProviderName: {{.RenderedProviderName}} +SchemaMarkdown: {{.SchemaMarkdown}} + +# Functions + +lower: {{ .Type | lower }} +plainmarkdown: {{ .Type | plainmarkdown }} +prefixlines: {{ .Type | prefixlines "Prefix: " }} +split: {{ split .Name "_" }} +title: {{ .Type | title }} +trimspace: {{ .Type | trimspace }} +upper: {{ .Type | upper }} + +# Conditionals and File Functions + +printf tffile: +{{ if .HasExample -}} +## Example Usage + +{{ printf "{{tffile %q}}" .ExampleFile }} +{{- end }} + +tffile: +{{ if .HasExample -}} +## Example Usage + {{tffile .ExampleFile }} {{- end }} -- templates/actions.md.tmpl -- @@ -774,6 +870,18 @@ list "scaffolding_example" "example" { required_attr = "some-value" } } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} -- examples/data-sources/scaffolding_example/data-source.tf -- data "scaffolding_example" "example" { configurable_attribute = "some-value" @@ -848,6 +956,30 @@ resource "scaffolding_example" "example" { } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, @@ -975,4 +1107,4 @@ resource "scaffolding_example" "example" { } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_legacy_docs.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_legacy_docs.txtar index 6dcaf93f..538f2b6c 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_legacy_docs.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_legacy_docs.txtar @@ -37,6 +37,11 @@ cmp templates/list-resources/example.markdown docs/list-resources/example.markdo cmp templates/list-resources/example.html.markdown docs/list-resources/example.html.markdown cmp templates/list-resources/example.html.md docs/list-resources/example.html.md +cmp templates/state-stores/example.md docs/state-stores/example.md +cmp templates/state-stores/example.markdown docs/state-stores/example.markdown +cmp templates/state-stores/example.html.markdown docs/state-stores/example.html.markdown +cmp templates/state-stores/example.html.md docs/state-stores/example.html.md + cmp templates/index.md docs/index.md cmp templates/index.markdown docs/index.markdown cmp templates/index.html.markdown docs/index.html.markdown @@ -59,6 +64,8 @@ generating missing action content action "scaffolding_example" static file exists, skipping generating missing list resource content list resource "scaffolding_example" static file exists, skipping +generating missing state store content +state store "scaffolding_example" static file exists, skipping generating missing provider content provider "terraform-provider-scaffolding" static file exists, skipping rendering static website @@ -92,6 +99,10 @@ copying non-template file: "r/example.html.markdown" copying non-template file: "r/example.html.md" copying non-template file: "r/example.markdown" copying non-template file: "r/example.md" +copying non-template file: "state-stores/example.html.markdown" +copying non-template file: "state-stores/example.html.md" +copying non-template file: "state-stores/example.markdown" +copying non-template file: "state-stores/example.md" -- templates/actions/example.md -- # Data Fields @@ -130,6 +141,26 @@ Type: {{.Type}} -- templates/list-resources/example.html.md -- # Data Fields +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.md -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.markdown -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.html.markdown -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.html.md -- +# Data Fields + Name: {{.Name}} Type: {{.Type}} -- templates/r/example.md -- @@ -256,6 +287,18 @@ list "scaffolding_example" "example" { required_attr = "some-value" } } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} -- examples/data-sources/scaffolding_example/data-source.tf -- data "scaffolding_example" "example" { configurable_attribute = "some-value" @@ -326,6 +369,30 @@ terraform import scaffolding_example.example "id-123" } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, @@ -453,4 +520,4 @@ terraform import scaffolding_example.example "id-123" } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_named_templates.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_named_templates.txtar index 48187073..984c5011 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_named_templates.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_named_templates.txtar @@ -13,6 +13,7 @@ cmpenv docs/functions/example.md expected-function.md cmpenv docs/ephemeral-resources/example.md expected-ephemeral-resource.md cmpenv docs/actions/example.md expected-action.md cmpenv docs/list-resources/example.md expected-list-resource.md +cmpenv docs/state-stores/example.md expected-state-store.md -- expected-output.txt -- rendering website for provider "terraform-provider-scaffolding" (as "Scaffolding") @@ -32,6 +33,8 @@ generating missing action content action "scaffolding_example" template exists, skipping generating missing list resource content list resource "scaffolding_example" template exists, skipping +generating missing state store content +state store "scaffolding_example" template exists, skipping generating missing provider content provider "terraform-provider-scaffolding" template exists, skipping rendering static website @@ -44,6 +47,7 @@ rendering "functions/example.md.tmpl" rendering "index.md.tmpl" rendering "list-resources/example.md.tmpl" rendering "resources/example.md.tmpl" +rendering "state-stores/example.md.tmpl" -- expected-action.md -- # Data Fields @@ -148,6 +152,60 @@ list "scaffolding_example" "example" { } } ``` +-- expected-state-store.md -- +# Data Fields + +Name: scaffolding_example +Type: State Store +Description: Example state store +HasExample: true +ExampleFile: $WORK/examples/state-stores/scaffolding_example/state-store.tf +ProviderName: terraform-provider-scaffolding +ProviderShortName: Scaffolding +RenderedProviderName: Scaffolding +SchemaMarkdown: +## Schema + +### Optional + +- `configurable_attribute` (String) Example configurable attribute +- `defaulted` (String) Example configurable attribute with default value + + + +# Functions + +lower: state store +plainmarkdown: State Store +prefixlines: Prefix: State Store +split: [scaffolding example] +title: State Store +trimspace: State Store +upper: STATE STORE + +# Conditionals and File Functions + +printf tffile: +## Example Usage + +{{tffile "$WORK/examples/state-stores/scaffolding_example/state-store.tf"}} + +tffile: +## Example Usage + +```terraform +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} +``` -- expected-datasource.md -- # Data Fields @@ -509,6 +567,44 @@ tffile: {{ if .HasExample -}} ## Example Usage +{{tffile .ExampleFile }} +{{- end }} +-- templates/state-stores/example.md.tmpl -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +Description: {{.Description}} +HasExample: {{.HasExample}} +ExampleFile: {{.ExampleFile}} +ProviderName: {{.ProviderName}} +ProviderShortName: {{.ProviderShortName}} +RenderedProviderName: {{.RenderedProviderName}} +SchemaMarkdown: {{.SchemaMarkdown}} + +# Functions + +lower: {{ .Type | lower }} +plainmarkdown: {{ .Type | plainmarkdown }} +prefixlines: {{ .Type | prefixlines "Prefix: " }} +split: {{ split .Name "_" }} +title: {{ .Type | title }} +trimspace: {{ .Type | trimspace }} +upper: {{ .Type | upper }} + +# Conditionals and File Functions + +printf tffile: +{{ if .HasExample -}} +## Example Usage + +{{ printf "{{tffile %q}}" .ExampleFile }} +{{- end }} + +tffile: +{{ if .HasExample -}} +## Example Usage + {{tffile .ExampleFile }} {{- end }} -- templates/data-sources/example.md.tmpl -- @@ -790,6 +886,18 @@ list "scaffolding_example" "example" { required_attr = "some-value" } } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} -- examples/data-sources/scaffolding_example/data-source.tf -- data "scaffolding_example" "example" { configurable_attribute = "some-value" @@ -877,6 +985,30 @@ terraform import scaffolding_example.example "id-123" } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, @@ -1026,4 +1158,4 @@ terraform import scaffolding_example.example "id-123" } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_multiple_examples.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_multiple_examples.txtar index ee878854..5612eac5 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_multiple_examples.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_multiple_examples.txtar @@ -12,6 +12,7 @@ cmp docs/resources/example.md expected-resource.md cmp docs/functions/example.md expected-function.md cmp docs/functions/no-variadic.md expected-no-variadic-function.md cmp docs/ephemeral-resources/example.md expected-ephemeral-resource.md +cmp docs/state-stores/example.md expected-state-store.md -- expected-output.txt -- rendering website for provider "terraform-provider-scaffolding" (as "Scaffolding") @@ -30,6 +31,8 @@ generating new template for "scaffolding_example" generating missing action content generating new template for "scaffolding_example" generating missing list resource content +generating missing state store content +generating new template for "scaffolding_example" generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website @@ -42,6 +45,7 @@ rendering "functions/example.md.tmpl" rendering "functions/no-variadic.md.tmpl" rendering "index.md.tmpl" rendering "resources/example.md.tmpl" +rendering "state-stores/example.md.tmpl" -- expected-action.md -- --- # generated by https://github.com/hashicorp/terraform-plugin-docs @@ -352,6 +356,56 @@ resource "scaffolding_example" "example" { ### Read-Only - `id` (String) Example identifier +-- expected-state-store.md -- +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "scaffolding_example State Store - Scaffolding" +subcategory: "" +description: |- + Example state store +--- + +# scaffolding_example (State Store) + +Example state store + +## Example Usage + +```terraform +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value1" + provider "scaffolding" {} + } +} +``` + +```terraform +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value2" + provider "scaffolding" {} + } +} +``` + + +## Schema + +### Optional + +- `configurable_attribute` (String) Example configurable attribute +- `defaulted` (String) Example configurable attribute with default value -- examples/README.md -- # Examples @@ -444,6 +498,30 @@ resource "scaffolding_example" "example" { resource "scaffolding_example" "example" { configurable_attribute = "some-value2" } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value1" + provider "scaffolding" {} + } +} +-- examples/state-stores/scaffolding_example/state-store2.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value2" + provider "scaffolding" {} + } +} -- schema.json -- { "format_version": "1.0", @@ -569,6 +647,30 @@ resource "scaffolding_example" "example" { } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "data_source_schemas": { "scaffolding_example": { "version": 0, @@ -625,4 +727,4 @@ resource "scaffolding_example" "example" { } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_single_example.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_single_example.txtar index f8ae1134..faf116d2 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_single_example.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_no_templates_single_example.txtar @@ -13,6 +13,7 @@ cmp docs/functions/no-variadic.md expected-no-variadic-function.md cmp docs/ephemeral-resources/example.md expected-ephemeral-resource.md cmp docs/actions/example.md expected-action.md cmp docs/list-resources/example.md expected-list-resource.md +cmp docs/state-stores/example.md expected-state-store.md -- expected-output.txt -- rendering website for provider "terraform-provider-scaffolding" (as "Scaffolding") @@ -32,6 +33,8 @@ generating missing action content generating new template for "scaffolding_example" generating missing list resource content generating new template for "scaffolding_example" +generating missing state store content +generating new template for "scaffolding_example" generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website @@ -45,6 +48,7 @@ rendering "functions/no-variadic.md.tmpl" rendering "index.md.tmpl" rendering "list-resources/example.md.tmpl" rendering "resources/example.md.tmpl" +rendering "state-stores/example.md.tmpl" -- expected-action.md -- --- # generated by https://github.com/hashicorp/terraform-plugin-docs @@ -113,6 +117,42 @@ list "scaffolding_example" "example" { ### Optional - `optional_attr` (String) Example optional attribute +-- expected-state-store.md -- +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "scaffolding_example State Store - Scaffolding" +subcategory: "" +description: |- + Example state store +--- + +# scaffolding_example (State Store) + +Example state store + +## Example Usage + +```terraform +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} +``` + + +## Schema + +### Optional + +- `configurable_attribute` (String) Example configurable attribute +- `defaulted` (String) Example configurable attribute with default value -- expected-datasource.md -- --- # generated by https://github.com/hashicorp/terraform-plugin-docs @@ -370,6 +410,18 @@ list "scaffolding_example" "example" { required_attr = "some-value" } } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} -- examples/data-sources/scaffolding_example/data-source.tf -- data "scaffolding_example" "example" { configurable_attribute = "some-value" @@ -460,6 +512,30 @@ resource "scaffolding_example" "example" { } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, @@ -621,4 +697,4 @@ resource "scaffolding_example" "example" { } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_static_files.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_static_files.txtar index 4dcabc1f..ef1a6399 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_static_files.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/framework_provider_success_static_files.txtar @@ -37,6 +37,11 @@ cmp templates/list-resources/example.markdown docs/list-resources/example.markdo cmp templates/list-resources/example.html.markdown docs/list-resources/example.html.markdown cmp templates/list-resources/example.html.md docs/list-resources/example.html.md +cmp templates/state-stores/example.md docs/state-stores/example.md +cmp templates/state-stores/example.markdown docs/state-stores/example.markdown +cmp templates/state-stores/example.html.markdown docs/state-stores/example.html.markdown +cmp templates/state-stores/example.html.md docs/state-stores/example.html.md + cmp templates/index.md docs/index.md cmp templates/index.markdown docs/index.markdown cmp templates/index.html.markdown docs/index.html.markdown @@ -59,6 +64,8 @@ generating missing action content action "scaffolding_example" static file exists, skipping generating missing list resource content list resource "scaffolding_example" static file exists, skipping +generating missing state store content +state store "scaffolding_example" static file exists, skipping generating missing provider content provider "terraform-provider-scaffolding" static file exists, skipping rendering static website @@ -92,6 +99,10 @@ copying non-template file: "resources/example.html.markdown" copying non-template file: "resources/example.html.md" copying non-template file: "resources/example.markdown" copying non-template file: "resources/example.md" +copying non-template file: "state-stores/example.html.markdown" +copying non-template file: "state-stores/example.html.md" +copying non-template file: "state-stores/example.markdown" +copying non-template file: "state-stores/example.md" -- templates/actions/example.md -- # Data Fields @@ -130,6 +141,26 @@ Type: {{.Type}} -- templates/list-resources/example.html.md -- # Data Fields +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.md -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.markdown -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.html.markdown -- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} +-- templates/state-stores/example.html.md -- +# Data Fields + Name: {{.Name}} Type: {{.Type}} -- templates/resources/example.md -- @@ -256,6 +287,18 @@ list "scaffolding_example" "example" { required_attr = "some-value" } } +-- examples/state-stores/scaffolding_example/state-store.tf -- +terraform { + required_providers { + scaffolding = { + source = "registry.terraform.io/hashicorp/scaffolding" + } + } + state_store "scaffolding_example" { + configurable_attribute = "some-value" + provider "scaffolding" {} + } +} -- examples/data-sources/scaffolding_example/data-source.tf -- data "scaffolding_example" "example" { configurable_attribute = "some-value" @@ -326,6 +369,30 @@ terraform import scaffolding_example.example "id-123" } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, @@ -453,4 +520,4 @@ terraform import scaffolding_example.example "id-123" } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/nested_id_attribute.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/nested_id_attribute.txtar index a6be8e81..2ab41c10 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/nested_id_attribute.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/nested_id_attribute.txtar @@ -20,6 +20,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content generating new template for "terraform-provider-scaffolding" rendering static website diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/null_provider_success.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/null_provider_success.txtar index ad6a3ca1..9a9b0db6 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/generate/null_provider_success.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/generate/null_provider_success.txtar @@ -21,6 +21,7 @@ generating missing function content generating missing ephemeral resource content generating missing action content generating missing list resource content +generating missing state store content generating missing provider content provider "terraform-provider-null" template exists, skipping rendering static website @@ -920,4 +921,4 @@ resource "null_resource" "cluster" { } } } -} \ No newline at end of file +} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website.txtar index 1c246f6b..620318ce 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website.txtar @@ -18,6 +18,7 @@ cmpenv templates/resources/static.md.tmpl exp-templates/resources/static.md.tmpl cmpenv templates/ephemeral-resources/ephemeral_static.md.tmpl exp-templates/ephemeral-resources/ephemeral_static.md.tmpl cmpenv templates/actions/example.md.tmpl exp-templates/actions/example.md.tmpl cmpenv templates/list-resources/example.md.tmpl exp-templates/list-resources/example.md.tmpl +cmpenv templates/state-stores/example.md.tmpl exp-templates/state-stores/example.md.tmpl # Check generated example files cmpenv examples/example_1.tf examples/example_1.tf @@ -51,6 +52,8 @@ cmpenv examples/actions/example/example_2.tf exp-examples/actions/example/exampl cmpenv examples/list-resources/example/example_1.tfquery.hcl exp-examples/list-resources/example/example_1.tfquery.hcl +cmpenv examples/state-stores/example/example_1.tf exp-examples/state-stores/example/example_1.tf + -- expected-output.txt -- migrating website from "$WORK/docs" to "$WORK/templates" migrating actions directory: actions @@ -118,6 +121,12 @@ creating example file "$WORK/examples/resources/static/example_1.tf" creating example file "$WORK/examples/resources/static/example_2.tf" creating import file "$WORK/examples/resources/static/import_1.sh" finished creating template "$WORK/templates/resources/static.md.tmpl" +migrating state stores directory: state-stores +migrating file "example.html.markdown" +extracting YAML frontmatter to "$WORK/templates/state-stores/example.md.tmpl" +extracting code examples from "example.html.markdown" +creating example file "$WORK/examples/state-stores/example/example_1.tf" +finished creating template "$WORK/templates/state-stores/example.md.tmpl" -- docs/index.html.markdown -- --- layout: "time" @@ -671,6 +680,29 @@ list "scaffolding_example" "example" { } } ``` +-- docs/state-stores/example.html.markdown -- +--- +layout: "time" +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +Just a fake state store example. + +```terraform +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} +``` -- exp-examples/example_1.tf -- resource "time_static" "ami_update" { triggers = { @@ -864,6 +896,18 @@ list "scaffolding_example" "example" { required_attr = "value-1" } } +-- exp-examples/state-stores/example/example_1.tf -- +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} -- exp-templates/index.md.tmpl -- --- page_title: "Provider: Time" @@ -1250,3 +1294,17 @@ For example, the {{ .SchemaMarkdown }} template can be used to replace manual sc Just a fake example. {{tffile "examples/list-resources/example/example_1.tfquery.hcl"}} +-- exp-templates/state-stores/example.md.tmpl -- +--- +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +Just a fake state store example. + +{{tffile "examples/state-stores/example/example_1.tf"}} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website_with_prefix.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website_with_prefix.txtar index 9e059e0f..7a93920a 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website_with_prefix.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_docs_website_with_prefix.txtar @@ -18,6 +18,7 @@ cmpenv templates/resources/static.md.tmpl exp-templates/resources/static.md.tmpl cmpenv templates/ephemeral-resources/ephemeral_static.md.tmpl exp-templates/ephemeral-resources/ephemeral_static.md.tmpl cmpenv templates/actions/example.md.tmpl exp-templates/actions/example.md.tmpl cmpenv templates/list-resources/example.md.tmpl exp-templates/list-resources/example.md.tmpl +cmpenv templates/state-stores/example.md.tmpl exp-templates/state-stores/example.md.tmpl # Check generated example files cmpenv examples/example_1.tf examples/example_1.tf @@ -51,6 +52,8 @@ cmpenv examples/actions/example/example_2.tf exp-examples/actions/example/exampl cmpenv examples/list-resources/example/example_1.tfquery.hcl exp-examples/list-resources/example/example_1.tfquery.hcl +cmpenv examples/state-stores/example/example_1.tf exp-examples/state-stores/example/example_1.tf + -- expected-output.txt -- migrating website from "$WORK/docs" to "$WORK/templates" migrating actions directory: actions @@ -118,6 +121,12 @@ creating example file "$WORK/examples/resources/static/example_1.tf" creating example file "$WORK/examples/resources/static/example_2.tf" creating import file "$WORK/examples/resources/static/import_1.sh" finished creating template "$WORK/templates/resources/static.md.tmpl" +migrating state stores directory: state-stores +migrating file "example.html.markdown" +extracting YAML frontmatter to "$WORK/templates/state-stores/example.md.tmpl" +extracting code examples from "example.html.markdown" +creating example file "$WORK/examples/state-stores/example/example_1.tf" +finished creating template "$WORK/templates/state-stores/example.md.tmpl" -- docs/index.html.markdown -- --- layout: "time" @@ -671,6 +680,29 @@ list "scaffolding_example" "example" { } } ``` +-- docs/state-stores/example.html.markdown -- +--- +layout: "time" +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +Just a fake state store example. + +```terraform +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} +``` -- exp-examples/example_1.tf -- resource "time_static" "ami_update" { triggers = { @@ -837,6 +869,18 @@ list "scaffolding_example" "example" { required_attr = "value-1" } } +-- exp-examples/state-stores/example/example_1.tf -- +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} -- exp-examples/ephemeral-resources/ephemeral_static/example_1.tf -- resource "time_static" "example" {} @@ -1250,3 +1294,17 @@ For example, the {{ .SchemaMarkdown }} template can be used to replace manual sc Just a fake example. {{tffile "examples/list-resources/example/example_1.tfquery.hcl"}} +-- exp-templates/state-stores/example.md.tmpl -- +--- +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +Just a fake state store example. + +{{tffile "examples/state-stores/example/example_1.tf"}} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website.txtar index 2838c843..e867c4e2 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website.txtar @@ -18,6 +18,7 @@ cmpenv templates/resources/static.md.tmpl exp-templates/resources/static.md.tmpl cmpenv templates/ephemeral-resources/ephemeral_static.md.tmpl exp-templates/ephemeral-resources/ephemeral_static.md.tmpl cmpenv templates/actions/example.md.tmpl exp-templates/actions/example.md.tmpl cmpenv templates/list-resources/example.md.tmpl exp-templates/list-resources/example.md.tmpl +cmpenv templates/state-stores/example.md.tmpl exp-templates/state-stores/example.md.tmpl # Check generated example files cmpenv examples/example_1.tf examples/example_1.tf @@ -51,6 +52,8 @@ cmpenv examples/actions/example/example_2.tf exp-examples/actions/example/exampl cmpenv examples/list-resources/example/example_1.tfquery.hcl exp-examples/list-resources/example/example_1.tfquery.hcl +cmpenv examples/state-stores/example/example_1.tf exp-examples/state-stores/example/example_1.tf + # Verify legacy website directory is removed ! exists website/ @@ -121,6 +124,12 @@ creating example file "$WORK/examples/resources/static/example_1.tf" creating example file "$WORK/examples/resources/static/example_2.tf" creating import file "$WORK/examples/resources/static/import_1.sh" finished creating template "$WORK/templates/resources/static.md.tmpl" +migrating state stores directory: state-stores +migrating file "example.html.markdown" +extracting YAML frontmatter to "$WORK/templates/state-stores/example.md.tmpl" +extracting code examples from "example.html.markdown" +creating example file "$WORK/examples/state-stores/example/example_1.tf" +finished creating template "$WORK/templates/state-stores/example.md.tmpl" -- website/docs/index.html.markdown -- --- layout: "time" @@ -674,6 +683,29 @@ list "scaffolding_example" "example" { } } ``` +-- website/docs/state-stores/example.html.markdown -- +--- +layout: "time" +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +Just a fake state store example. + +```terraform +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} +``` -- exp-examples/example_1.tf -- resource "time_static" "ami_update" { triggers = { @@ -867,6 +899,18 @@ list "scaffolding_example" "example" { required_attr = "value-1" } } +-- exp-examples/state-stores/example/example_1.tf -- +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} -- exp-templates/index.md.tmpl -- --- page_title: "Provider: Time" @@ -1253,3 +1297,17 @@ For example, the {{ .SchemaMarkdown }} template can be used to replace manual sc Just a fake example. {{tffile "examples/list-resources/example/example_1.tfquery.hcl"}} +-- exp-templates/state-stores/example.md.tmpl -- +--- +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +Just a fake state store example. + +{{tffile "examples/state-stores/example/example_1.tf"}} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website_with_prefix.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website_with_prefix.txtar index 1ae50391..922f065f 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website_with_prefix.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/migrate/time_provider_success_legacy_website_with_prefix.txtar @@ -18,6 +18,7 @@ cmpenv templates/resources/static.md.tmpl exp-templates/resources/static.md.tmpl cmpenv templates/ephemeral-resources/ephemeral_static.md.tmpl exp-templates/ephemeral-resources/ephemeral_static.md.tmpl cmpenv templates/actions/example.md.tmpl exp-templates/actions/example.md.tmpl cmpenv templates/list-resources/example.md.tmpl exp-templates/list-resources/example.md.tmpl +cmpenv templates/state-stores/example.md.tmpl exp-templates/state-stores/example.md.tmpl # Check generated example files cmpenv examples/example_1.tf examples/example_1.tf @@ -51,6 +52,8 @@ cmpenv examples/actions/example/example_2.tf exp-examples/actions/example/exampl cmpenv examples/list-resources/example/example_1.tfquery.hcl exp-examples/list-resources/example/example_1.tfquery.hcl +cmpenv examples/state-stores/example/example_1.tf exp-examples/state-stores/example/example_1.tf + # Verify legacy website directory is removed ! exists website/ @@ -121,6 +124,12 @@ creating example file "$WORK/examples/resources/static/example_1.tf" creating example file "$WORK/examples/resources/static/example_2.tf" creating import file "$WORK/examples/resources/static/import_1.sh" finished creating template "$WORK/templates/resources/static.md.tmpl" +migrating state stores directory: state-stores +migrating file "example.html.markdown" +extracting YAML frontmatter to "$WORK/templates/state-stores/example.md.tmpl" +extracting code examples from "example.html.markdown" +creating example file "$WORK/examples/state-stores/example/example_1.tf" +finished creating template "$WORK/templates/state-stores/example.md.tmpl" -- website/docs/index.html.markdown -- --- layout: "time" @@ -674,6 +683,29 @@ list "scaffolding_example" "example" { } } ``` +-- website/docs/state-stores/example.html.markdown -- +--- +layout: "time" +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +Just a fake state store example. + +```terraform +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} +``` -- exp-examples/example_1.tf -- resource "time_static" "ami_update" { triggers = { @@ -840,6 +872,18 @@ list "scaffolding_example" "example" { required_attr = "value-1" } } +-- exp-examples/state-stores/example/example_1.tf -- +terraform { + required_providers { + time = { + source = "registry.terraform.io/hashicorp/time" + } + } + state_store "time_example" { + configurable_attribute = "value-1" + provider "time" {} + } +} -- exp-examples/ephemeral-resources/ephemeral_static/example_1.tf -- resource "time_static" "example" {} @@ -1253,3 +1297,17 @@ For example, the {{ .SchemaMarkdown }} template can be used to replace manual sc Just a fake example. {{tffile "examples/list-resources/example/example_1.tfquery.hcl"}} +-- exp-templates/state-stores/example.md.tmpl -- +--- +page_title: "Time: time_example" +description: |- + Just a fake state store example. +--- + +{{/* This template serves as a starting point for documentation generation, and can be customized with hardcoded values and/or doc gen templates. + +For example, the {{ .SchemaMarkdown }} template can be used to replace manual schema documentation if descriptions of schema attributes are added in the provider source code. */ -}} + +Just a fake state store example. + +{{tffile "examples/state-stores/example/example_1.tf"}} diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_error_file_mismatch.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_error_file_mismatch.txtar index b888bb35..91d1e78a 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_error_file_mismatch.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_error_file_mismatch.txtar @@ -17,7 +17,20 @@ stderr 'matching action for documentation file \(example2.md\) not found, file i stderr 'missing documentation file for action: scaffolding_example' stderr 'matching list resource for documentation file \(example2.md\) not found, file is extraneous or incorrectly named' stderr 'missing documentation file for list resource: scaffolding_example_list' +stderr 'matching state store for documentation file \(example2.md\) not found, file is extraneous or incorrectly named' +stderr 'missing documentation file for state store: scaffolding_example' +-- docs/state-stores/example2.md -- +--- +subcategory: "Example" +page_title: "Example: example_thing" +description: |- + Example description. +--- +# Data Fields + +Name: {{.Name}} +Type: {{.Type}} -- docs/list-resources/example2.md -- --- subcategory: "Example" @@ -127,6 +140,30 @@ Type: {{.Type}} } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_legacy_docs.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_legacy_docs.txtar index 7bb663cd..dba111d0 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_legacy_docs.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_legacy_docs.txtar @@ -26,6 +26,8 @@ running invalid directories check on website/docs/list-resources running file checks on website/docs/list-resources/example.html.md running invalid directories check on website/docs/r running file checks on website/docs/r/example.html.md +running invalid directories check on website/docs/state-stores +running file checks on website/docs/state-stores/example.html.md running file mismatch check -- website/docs/guides/example.html.md -- --- @@ -121,6 +123,18 @@ description: |- --- # Data Fields +Name: {{.Name}} +Type: {{.Type}} +-- website/docs/state-stores/example.html.md -- +--- +subcategory: "Example" +layout: "example" +page_title: "Example: example_thing" +description: |- + Example description. +--- +# Data Fields + Name: {{.Name}} Type: {{.Type}} -- schema.json -- @@ -166,6 +180,30 @@ Type: {{.Type}} } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, diff --git a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_registry_docs.txtar b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_registry_docs.txtar index 2f3f09a5..1242992d 100644 --- a/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_registry_docs.txtar +++ b/cmd/tfplugindocs/testdata/scripts/schema-json/validate/framework_provider_success_registry_docs.txtar @@ -26,6 +26,8 @@ running invalid directories check on docs/list-resources running file checks on docs/list-resources/example.md running invalid directories check on docs/resources running file checks on docs/resources/example.md +running invalid directories check on docs/state-stores +running file checks on docs/state-stores/example.md running file mismatch check -- docs/guides/example.md -- --- @@ -113,6 +115,17 @@ description: |- --- # Data Fields +Name: {{.Name}} +Type: {{.Type}} +-- docs/state-stores/example.md -- +--- +subcategory: "Example" +page_title: "Example: example_thing" +description: |- + Example description. +--- +# Data Fields + Name: {{.Name}} Type: {{.Type}} -- schema.json -- @@ -158,6 +171,30 @@ Type: {{.Type}} } } }, + "state_store_schemas": { + "scaffolding_example": { + "version": 0, + "block": { + "attributes": { + "configurable_attribute": { + "type": "string", + "description": "Example configurable attribute", + "description_kind": "markdown", + "optional": true + }, + "defaulted": { + "type": "string", + "description": "Example configurable attribute with default value", + "description_kind": "markdown", + "optional": true, + "computed": true + } + }, + "description": "Example state store", + "description_kind": "markdown" + } + } + }, "action_schemas": { "scaffolding_example": { "version": 0, diff --git a/go.mod b/go.mod index 3de31a77..23d2029f 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/hashicorp/go-version v1.8.0 github.com/hashicorp/hc-install v0.9.3 github.com/hashicorp/terraform-exec v0.25.0 - github.com/hashicorp/terraform-json v0.27.2 + github.com/hashicorp/terraform-json v0.27.3-0.20260213134036-298b8f6b673a github.com/mattn/go-colorable v0.1.14 github.com/rogpeppe/go-internal v1.14.1 github.com/yuin/goldmark v1.7.7 diff --git a/go.sum b/go.sum index 60b9e6f8..1ce6df97 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ github.com/hashicorp/hc-install v0.9.3 h1:1H4dgmgzxEVwT6E/d/vIL5ORGVKz9twRwDw+qA github.com/hashicorp/hc-install v0.9.3/go.mod h1:FQlQ5I3I/X409N/J1U4pPeQQz1R3BoV0IysB7aiaQE0= github.com/hashicorp/terraform-exec v0.25.0 h1:Bkt6m3VkJqYh+laFMrWIpy9KHYFITpOyzRMNI35rNaY= github.com/hashicorp/terraform-exec v0.25.0/go.mod h1:dl9IwsCfklDU6I4wq9/StFDp7dNbH/h5AnfS1RmiUl8= -github.com/hashicorp/terraform-json v0.27.2 h1:BwGuzM6iUPqf9JYM/Z4AF1OJ5VVJEEzoKST/tRDBJKU= -github.com/hashicorp/terraform-json v0.27.2/go.mod h1:GzPLJ1PLdUG5xL6xn1OXWIjteQRT2CNT9o/6A9mi9hE= +github.com/hashicorp/terraform-json v0.27.3-0.20260213134036-298b8f6b673a h1:T7AMR21kjrbeEpN+KhGlyd31XXHsSZF5zg+ivfeYte4= +github.com/hashicorp/terraform-json v0.27.3-0.20260213134036-298b8f6b673a/go.mod h1:yjb5C2W07l8lmAzdyVgOLji0/D2IoHkR3rusBzUO4O0= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= diff --git a/internal/check/directory.go b/internal/check/directory.go index 11583ccd..dc864a6f 100644 --- a/internal/check/directory.go +++ b/internal/check/directory.go @@ -21,6 +21,7 @@ const ( LegacyFunctionsDirectory = `functions` LegacyActionsDirectory = `actions` LegacyListResourcesDirectory = "list-resources" + LegacyStateStoresDirectory = "state-stores" RegistryIndexDirectory = `docs` RegistryDataSourcesDirectory = `data-sources` @@ -30,6 +31,7 @@ const ( RegistryFunctionsDirectory = `functions` RegistryActionsDirectory = `actions` RegistryListResourcesDirectory = "list-resources" + RegistryStateStoresDirectory = "state-stores" // Terraform Registry Storage Limits // https://www.terraform.io/docs/registry/providers/docs.html#storage-limits @@ -47,6 +49,7 @@ var ValidLegacyDirectories = []string{ LegacyIndexDirectory + "/" + LegacyFunctionsDirectory, LegacyIndexDirectory + "/" + LegacyActionsDirectory, LegacyIndexDirectory + "/" + LegacyListResourcesDirectory, + LegacyIndexDirectory + "/" + LegacyStateStoresDirectory, } var ValidRegistryDirectories = []string{ @@ -58,6 +61,7 @@ var ValidRegistryDirectories = []string{ RegistryIndexDirectory + "/" + RegistryFunctionsDirectory, RegistryIndexDirectory + "/" + RegistryActionsDirectory, RegistryIndexDirectory + "/" + RegistryListResourcesDirectory, + RegistryIndexDirectory + "/" + RegistryStateStoresDirectory, } var ValidCdktfLanguages = []string{ @@ -76,6 +80,7 @@ var ValidLegacySubdirectories = []string{ LegacyResourcesDirectory, LegacyActionsDirectory, LegacyListResourcesDirectory, + LegacyStateStoresDirectory, } var ValidRegistrySubdirectories = []string{ @@ -86,6 +91,7 @@ var ValidRegistrySubdirectories = []string{ RegistryResourcesDirectory, RegistryActionsDirectory, RegistryListResourcesDirectory, + RegistryStateStoresDirectory, } func InvalidDirectoriesCheck(dirPath string) error { diff --git a/internal/check/directory_test.go b/internal/check/directory_test.go index c8ae3aae..9532c7f3 100644 --- a/internal/check/directory_test.go +++ b/internal/check/directory_test.go @@ -11,7 +11,7 @@ import ( "github.com/bmatcuk/doublestar/v4" ) -var DocumentationGlobPattern = `{docs/index.*,docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions}/**/*,website/docs/**/*}` +var DocumentationGlobPattern = `{docs/index.*,docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions,state-stores}/**/*,website/docs/**/*}` func TestMixedDirectoriesCheck(t *testing.T) { t.Parallel() @@ -59,6 +59,13 @@ func TestMixedDirectoriesCheck(t *testing.T) { }, ExpectError: true, }, + "invalid mixed directories - registry state store": { + ProviderFS: fstest.MapFS{ + "docs/state-stores/invalid.md": {}, + "website/docs/index.md": {}, + }, + ExpectError: true, + }, "invalid mixed directories - registry resource": { ProviderFS: fstest.MapFS{ "docs/resources/invalid.md": {}, @@ -108,6 +115,13 @@ func TestMixedDirectoriesCheck(t *testing.T) { }, ExpectError: true, }, + "invalid mixed directories - legacy state store": { + ProviderFS: fstest.MapFS{ + "website/docs/state-stores/invalid.html.markdown": {}, + "docs/resources/thing.md": {}, + }, + ExpectError: true, + }, "invalid mixed directories - legacy resource": { ProviderFS: fstest.MapFS{ "website/docs/r/invalid.html.markdown": {}, diff --git a/internal/check/file_mismatch.go b/internal/check/file_mismatch.go index da5e2fb0..37d1dea1 100644 --- a/internal/check/file_mismatch.go +++ b/internal/check/file_mismatch.go @@ -34,6 +34,8 @@ type FileMismatchOptions struct { ListResourceEntries []os.DirEntry + StateStoreEntries []os.DirEntry + Schema *tfjson.ProviderSchema } @@ -95,6 +97,11 @@ func (check *FileMismatchCheck) Run() error { result = errors.Join(result, err) } + if check.Options.StateStoreEntries != nil { + err := check.ResourceFileMismatchCheck(check.Options.StateStoreEntries, "state store", check.Options.Schema.StateStoreSchemas) + result = errors.Join(result, err) + } + return result } diff --git a/internal/provider/generate.go b/internal/provider/generate.go index 10abd589..2cb43d5b 100644 --- a/internal/provider/generate.go +++ b/internal/provider/generate.go @@ -83,6 +83,14 @@ var ( "list-resources/%s.html.markdown", "list-resources/%s.html.md", } + websiteStateStoreFile = "state-stores/%s.md.tmpl" + websiteStateStoreFallbackFile = "state-stores.md.tmpl" + websiteStateStoreFileStaticCandidates = []string{ + "state-stores/%s.md", + "state-stores/%s.markdown", + "state-stores/%s.html.markdown", + "state-stores/%s.html.md", + } websiteProviderFile = "index.md.tmpl" websiteProviderFileStaticCandidates = []string{ "index.markdown", @@ -99,6 +107,7 @@ var ( "ephemeral-resources", "actions", "list-resources", + "state-stores", } managedWebsiteFiles = []string{ @@ -508,6 +517,42 @@ func (g *generator) generateMissingListResourceTemplate(resourceName string) err return nil } +func (g *generator) generateMissingStateStoreTemplate(stateStoreName string) error { + templatePath := fmt.Sprintf(websiteStateStoreFile, resourceShortName(stateStoreName, g.providerName)) + templatePath = filepath.Join(g.TempTemplatesDir(), templatePath) + if fileExists(templatePath) { + g.infof("state store %q template exists, skipping", stateStoreName) + return nil + } + + fallbackTemplatePath := filepath.Join(g.TempTemplatesDir(), websiteStateStoreFallbackFile) + if fileExists(fallbackTemplatePath) { + g.infof("state store %q fallback template exists, creating template", stateStoreName) + err := cp(fallbackTemplatePath, templatePath) + if err != nil { + return fmt.Errorf("unable to copy fallback template for %q: %w", stateStoreName, err) + } + return nil + } + + for _, candidate := range websiteStateStoreFileStaticCandidates { + candidatePath := fmt.Sprintf(candidate, resourceShortName(stateStoreName, g.providerName)) + candidatePath = filepath.Join(g.TempTemplatesDir(), candidatePath) + if fileExists(candidatePath) { + g.infof("state store %q static file exists, skipping", stateStoreName) + return nil + } + } + + g.infof("generating new template for %q", stateStoreName) + err := writeFile(templatePath, string(defaultResourceTemplate)) + if err != nil { + return fmt.Errorf("unable to write template for %q: %w", stateStoreName, err) + } + + return nil +} + func (g *generator) generateMissingProviderTemplate() error { templatePath := filepath.Join(g.TempTemplatesDir(), websiteProviderFile) if fileExists(templatePath) { @@ -659,6 +704,27 @@ func (g *generator) generateMissingTemplates(providerSchema *tfjson.ProviderSche } } + g.infof("generating missing state store content") + + stateStoreKeys := make([]string, 0, len(providerSchema.StateStoreSchemas)) + for key := range providerSchema.StateStoreSchemas { + stateStoreKeys = append(stateStoreKeys, key) + } + sort.Strings(stateStoreKeys) + + for _, name := range stateStoreKeys { + schema := providerSchema.StateStoreSchemas[name] + + if g.ignoreDeprecated && schema.Block.Deprecated { + continue + } + + err := g.generateMissingStateStoreTemplate(name) + if err != nil { + return fmt.Errorf("unable to generate template for state store %q: %w", name, err) + } + } + g.infof("generating missing provider content") err := g.generateMissingProviderTemplate() if err != nil { @@ -720,13 +786,14 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e relDir, relFile := filepath.Split(rel) relDir = filepath.ToSlash(relDir) - // skip special top-level generic resource, data source, function, ephemeral resource, action and list resource templates + // skip special top-level generic resource, data source, function, ephemeral resource, action, list resource, and state store templates if relDir == "" && (relFile == "resources.md.tmpl" || relFile == "data-sources.md.tmpl" || relFile == "functions.md.tmpl" || relFile == "ephemeral-resources.md.tmpl" || relFile == "actions.md.tmpl" || - relFile == "list-resources.md.tmpl") { + relFile == "list-resources.md.tmpl" || + relFile == "state-stores.md.tmpl") { return nil } @@ -917,6 +984,32 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e return nil } g.warnf("list resource entitled %q, or %q does not exist", shortName, resName) + case "state-stores/": + resSchema, resName := resourceSchema(providerSchema.StateStoreSchemas, shortName, relFile) + + if resSchema != nil { + exampleFilePath := filepath.Join(g.ProviderExamplesDir(), "state-stores", resName, "state-store.tf") + exampleFilesPattern := filepath.Join(g.ProviderExamplesDir(), "state-stores", resName, "state-store*.tf") + exampleFiles, err := filepath.Glob(exampleFilesPattern) + + if err != nil { + return fmt.Errorf("unable to glob example files with pattern %q: %w", exampleFilesPattern, err) + } + + slices.Sort(exampleFiles) + + tmpl := resourceTemplate(tmplData) + render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "State Store", exampleFilePath, exampleFiles, "", "", "", resSchema, nil) + if err != nil { + return fmt.Errorf("unable to render state store template %q: %w", rel, err) + } + _, err = out.WriteString(render) + if err != nil { + return fmt.Errorf("unable to write rendered string: %w", err) + } + return nil + } + g.warnf("state store entitled %q, or %q does not exist", shortName, resName) case "": // provider if relFile == "index.md.tmpl" { exampleFilePath := filepath.Join(g.ProviderExamplesDir(), "provider", "provider.tf") diff --git a/internal/provider/migrate.go b/internal/provider/migrate.go index b815dd60..99185a20 100644 --- a/internal/provider/migrate.go +++ b/internal/provider/migrate.go @@ -153,6 +153,13 @@ func (m *migrator) Migrate() error { return err } return filepath.SkipDir + case "state-stores": + m.infof("migrating state stores directory: %s", d.Name()) + err := filepath.WalkDir(path, m.MigrateTemplate("state-stores")) + if err != nil { + return err + } + return filepath.SkipDir } } else { switch { diff --git a/internal/provider/testdata/schema.json b/internal/provider/testdata/schema.json index 01ed3ca7..5912bd6d 100644 --- a/internal/provider/testdata/schema.json +++ b/internal/provider/testdata/schema.json @@ -104,6 +104,19 @@ } } }, + "state_store_schemas": { + "null_state_store": { + "version": 0, + "block": { + "attributes": { + "id": { + "type": "string", + "optional": true + } + } + } + } + }, "data_source_schemas": { "null_data_source": { "version": 0, diff --git a/internal/provider/util_test.go b/internal/provider/util_test.go index a4d03416..482a58eb 100644 --- a/internal/provider/util_test.go +++ b/internal/provider/util_test.go @@ -116,6 +116,9 @@ func Test_extractSchemaFromFile(t *testing.T) { if providerSchema.ListResourceSchemas["null_list_resource"] == nil { t.Fatalf("null_list_resource not found") } + if providerSchema.StateStoreSchemas["null_state_store"] == nil { + t.Fatalf("null_state_store not found") + } if providerSchema.ResourceSchemas["null_resource"].Block.Attributes["id"] == nil { t.Fatalf("null_resoruce id attribute not found") } @@ -131,4 +134,7 @@ func Test_extractSchemaFromFile(t *testing.T) { if providerSchema.ListResourceSchemas["null_list_resource"].Block.Attributes["required_attr"] == nil { t.Fatalf("null_list_resource required_attr attribute not found") } + if providerSchema.StateStoreSchemas["null_state_store"].Block.Attributes["id"] == nil { + t.Fatalf("null_state_store id attribute not found") + } } diff --git a/internal/provider/validate.go b/internal/provider/validate.go index 02a8cd0c..5f50dfa9 100644 --- a/internal/provider/validate.go +++ b/internal/provider/validate.go @@ -26,8 +26,8 @@ const ( FileExtensionMarkdown = `.markdown` FileExtensionMd = `.md` - DocumentationGlobPattern = `{docs/index.*,docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions}/**/*,website/docs/**/*}` - DocumentationDirGlobPattern = `{docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions}{,/*},website/docs/**/*}` + DocumentationGlobPattern = `{docs/index.*,docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions,state-stores}/**/*,website/docs/**/*}` + DocumentationDirGlobPattern = `{docs/{,cdktf/}{actions,data-sources,ephemeral-resources,guides,list-resources,resources,functions,state-stores}{,/*},website/docs/**/*}` ) var ValidLegacyFileExtensions = []string{ @@ -322,6 +322,10 @@ func (v *validator) validateStaticDocs() error { listResourceFiles, _ := fs.ReadDir(v.providerFS, dir+"/list-resources") mismatchOpt.ListResourceEntries = listResourceFiles } + if dirExists(v.providerFS, dir+"/state-stores") { + stateStoreFiles, _ := fs.ReadDir(v.providerFS, dir+"/state-stores") + mismatchOpt.StateStoreEntries = stateStoreFiles + } v.logger.infof("running file mismatch check") if err := check.NewFileMismatchCheck(mismatchOpt).Run(); err != nil { @@ -417,6 +421,10 @@ func (v *validator) validateLegacyWebsite() error { listResourceFiles, _ := fs.ReadDir(v.providerFS, dir+"/list-resources") mismatchOpt.ListResourceEntries = listResourceFiles } + if dirExists(v.providerFS, dir+"/state-stores") { + stateStoreFiles, _ := fs.ReadDir(v.providerFS, dir+"/state-stores") + mismatchOpt.StateStoreEntries = stateStoreFiles + } v.logger.infof("running file mismatch check") if err := check.NewFileMismatchCheck(mismatchOpt).Run(); err != nil { diff --git a/internal/provider/validate_test.go b/internal/provider/validate_test.go index 9e50a75f..6a0d3ca8 100644 --- a/internal/provider/validate_test.go +++ b/internal/provider/validate_test.go @@ -103,6 +103,9 @@ func TestValidateStaticDocs_DirectoryChecks(t *testing.T) { "docs/resources/thing.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/state-stores/thing.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, "docs/CONTRIBUTING.md": { Data: []byte("contribution guidelines"), }, @@ -134,6 +137,9 @@ func TestValidateStaticDocs_DirectoryChecks(t *testing.T) { "docs/cdktf/typescript/resources/thing.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/cdktf/typescript/state-stores/thing.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, "docs/cdktf/typescript/CONTRIBUTING.md": { Data: []byte("contribution guidelines"), }, @@ -186,6 +192,9 @@ func TestValidateStaticDocs_DirectoryChecks(t *testing.T) { "docs/resources/invalid/thing.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/state-stores/invalid/thing.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, "docs/CONTRIBUTING.md": { Data: []byte("contribution guidelines"), }, @@ -199,7 +208,8 @@ func TestValidateStaticDocs_DirectoryChecks(t *testing.T) { "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "functions", "invalid") + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "guides", "invalid") + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "list-resources", "invalid") + - "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "resources", "invalid"), + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "resources", "invalid") + + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("docs", "state-stores", "invalid"), }, } @@ -360,6 +370,38 @@ func TestValidateStaticDocs_FileChecks(t *testing.T) { filepath.Join("docs", "list-resources", "with_layout.md") + ": error checking file frontmatter: YAML frontmatter should not contain layout\n" + filepath.Join("docs", "list-resources", "with_sidebar_current.md") + ": error checking file frontmatter: YAML frontmatter should not contain sidebar_current", }, + "invalid state store files": { + ProviderFS: fstest.MapFS{ + "docs/state-stores/invalid_extension.txt": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, + "docs/state-stores/invalid_frontmatter.md": &InvalidYAMLFrontMatter, + "docs/state-stores/with_layout.md": { + Data: encodeYAML(t, + &FrontMatterData{ + Layout: &exampleLayout, + Subcategory: &exampleSubcategory, + PageTitle: &examplePageTitle, + Description: &exampleDescription, + }, + ), + }, + "docs/state-stores/with_sidebar_current.md": { + Data: encodeYAML(t, + &FrontMatterData{ + SidebarCurrent: &exampleSidebarCurrent, + Subcategory: &exampleSubcategory, + PageTitle: &examplePageTitle, + Description: &exampleDescription, + }, + ), + }, + }, + ExpectedError: filepath.Join("docs", "state-stores", "invalid_extension.txt") + ": error checking file extension: file does not end with a valid extension, valid extensions: [.md]\n" + + filepath.Join("docs", "state-stores", "invalid_frontmatter.md") + ": error checking file frontmatter: error parsing YAML frontmatter: yaml: line 4: could not find expected ':'\n" + + filepath.Join("docs", "state-stores", "with_layout.md") + ": error checking file frontmatter: YAML frontmatter should not contain layout\n" + + filepath.Join("docs", "state-stores", "with_sidebar_current.md") + ": error checking file frontmatter: YAML frontmatter should not contain sidebar_current", + }, "invalid resource files": { ProviderFS: fstest.MapFS{ "docs/resources/invalid_extension.txt": { @@ -541,6 +583,9 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { Functions: map[string]*tfjson.FunctionSignature{ "parse_id": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + }, }, ProviderFS: fstest.MapFS{ "docs/actions/action.md": { @@ -561,6 +606,9 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { "docs/resources/id.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/state-stores/state_store.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, }, }, "invalid - missing files": { @@ -589,6 +637,10 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { "parse_id": {}, "parse_id2": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + "test_state_store2": {}, + }, }, ProviderFS: fstest.MapFS{ "docs/actions/action.md": { @@ -609,13 +661,17 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { "docs/resources/id.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/state-stores/state_store.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, }, ExpectedError: "missing documentation file for resource: test_id2\n" + "missing documentation file for datasource: test_pet2\n" + "missing documentation file for function: parse_id2\n" + "missing documentation file for ephemeral resource: test_ephemeral_id2\n" + "missing documentation file for action: test_action2\n" + - "missing documentation file for list resource: test_list2", + "missing documentation file for list resource: test_list2\n" + + "missing documentation file for state store: test_state_store2", }, "invalid - extra files": { ProviderSchema: &tfjson.ProviderSchema{ @@ -637,6 +693,9 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { Functions: map[string]*tfjson.FunctionSignature{ "parse_id": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + }, }, ProviderFS: fstest.MapFS{ "docs/actions/action.md": { @@ -675,13 +734,20 @@ func TestValidateStaticDocs_FileMismatchCheck(t *testing.T) { "docs/resources/id2.md": { Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), }, + "docs/state-stores/state_store.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, + "docs/state-stores/state_store2.md": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, }, ExpectedError: "matching resource for documentation file (id2.md) not found, file is extraneous or incorrectly named\n" + "matching datasource for documentation file (pet2.md) not found, file is extraneous or incorrectly named\n" + "matching function for documentation file (parse_id2.md) not found, file is extraneous or incorrectly named\n" + "matching ephemeral resource for documentation file (ephemeral_id2.md) not found, file is extraneous or incorrectly named\n" + "matching action for documentation file (action2.md) not found, file is extraneous or incorrectly named\n" + - "matching list resource for documentation file (list2.md) not found, file is extraneous or incorrectly named", + "matching list resource for documentation file (list2.md) not found, file is extraneous or incorrectly named\n" + + "matching state store for documentation file (state_store2.md) not found, file is extraneous or incorrectly named", }, } @@ -738,6 +804,9 @@ func TestValidateLegacyWebsite_DirectoryChecks(t *testing.T) { "website/docs/r/thing.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/state-stores/thing.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, "website/docs/index.html.markdown": { Data: encodeYAML(t, &ValidLegacyIndexFrontMatter), }, @@ -775,6 +844,9 @@ func TestValidateLegacyWebsite_DirectoryChecks(t *testing.T) { "website/docs/r/thing.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/cdktf/typescript/state-stores/thing.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, "website/docs/index.html.markdown": { Data: encodeYAML(t, &ValidLegacyIndexFrontMatter), }, @@ -803,6 +875,9 @@ func TestValidateLegacyWebsite_DirectoryChecks(t *testing.T) { "website/docs/r/invalid/thing.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/state-stores/invalid/thing.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, "website/docs/index.html.markdown": { Data: encodeYAML(t, &ValidLegacyIndexFrontMatter), }, @@ -813,7 +888,8 @@ func TestValidateLegacyWebsite_DirectoryChecks(t *testing.T) { "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "functions", "invalid") + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "guides", "invalid") + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "list-resources", "invalid") + - "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "r", "invalid"), + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "r", "invalid") + + "\ninvalid Terraform Provider documentation directory found: " + filepath.Join("website", "docs", "state-stores", "invalid"), }, } @@ -910,6 +986,38 @@ func TestValidateLegacyWebsite_FileChecks(t *testing.T) { filepath.Join("website", "docs", "ephemeral-resources", "with_sidebar_current.html.markdown") + ": error checking file frontmatter: YAML frontmatter should not contain sidebar_current\n" + filepath.Join("website", "docs", "ephemeral-resources", "without_layout.html.markdown") + ": error checking file frontmatter: YAML frontmatter missing required layout", }, + "invalid state store files": { + ProviderFS: fstest.MapFS{ + "website/docs/state-stores/invalid_extension.txt": { + Data: encodeYAML(t, &ValidRegistryResourceFrontMatter), + }, + "website/docs/state-stores/invalid_frontmatter.html.markdown": &InvalidYAMLFrontMatter, + "website/docs/state-stores/without_layout.html.markdown": { + Data: encodeYAML(t, + &FrontMatterData{ + Subcategory: &exampleSubcategory, + PageTitle: &examplePageTitle, + Description: &exampleDescription, + }, + ), + }, + "website/docs/state-stores/with_sidebar_current.html.markdown": { + Data: encodeYAML(t, + &FrontMatterData{ + SidebarCurrent: &exampleSidebarCurrent, + Subcategory: &exampleSubcategory, + Layout: &exampleLayout, + PageTitle: &examplePageTitle, + Description: &exampleDescription, + }, + ), + }, + }, + ExpectedError: filepath.Join("website", "docs", "state-stores", "invalid_extension.txt") + ": error checking file extension: file does not end with a valid extension, valid extensions: [.html.markdown .html.md .markdown .md]\n" + + filepath.Join("website", "docs", "state-stores", "invalid_frontmatter.html.markdown") + ": error checking file frontmatter: error parsing YAML frontmatter: yaml: line 4: could not find expected ':'\n" + + filepath.Join("website", "docs", "state-stores", "with_sidebar_current.html.markdown") + ": error checking file frontmatter: YAML frontmatter should not contain sidebar_current\n" + + filepath.Join("website", "docs", "state-stores", "without_layout.html.markdown") + ": error checking file frontmatter: YAML frontmatter missing required layout", + }, "invalid list resource files": { ProviderFS: fstest.MapFS{ "website/docs/list-resources/invalid_extension.txt": { @@ -1163,6 +1271,9 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { Functions: map[string]*tfjson.FunctionSignature{ "parse_id": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + }, }, ProviderFS: fstest.MapFS{ "website/docs/actions/action.html.markdown": { @@ -1183,6 +1294,9 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { "website/docs/r/id.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/state-stores/state_store.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, }, }, "invalid - missing files": { @@ -1211,6 +1325,10 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { "parse_id": {}, "parse_id2": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + "test_state_store2": {}, + }, }, ProviderFS: fstest.MapFS{ "website/docs/actions/action.html.markdown": { @@ -1231,13 +1349,17 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { "website/docs/r/id.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/state-stores/state_store.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, }, ExpectedError: "missing documentation file for resource: test_id2\n" + "missing documentation file for datasource: test_pet2\n" + "missing documentation file for function: parse_id2\n" + "missing documentation file for ephemeral resource: test_ephemeral_id2\n" + "missing documentation file for action: test_action2\n" + - "missing documentation file for list resource: test_list2", + "missing documentation file for list resource: test_list2\n" + + "missing documentation file for state store: test_state_store2", }, "invalid - extra files": { ProviderSchema: &tfjson.ProviderSchema{ @@ -1259,6 +1381,9 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { Functions: map[string]*tfjson.FunctionSignature{ "parse_id": {}, }, + StateStoreSchemas: map[string]*tfjson.Schema{ + "test_state_store": {}, + }, }, ProviderFS: fstest.MapFS{ "website/docs/actions/action.html.markdown": { @@ -1297,13 +1422,20 @@ func TestValidateLegacyWebsite_FileMismatchCheck(t *testing.T) { "website/docs/r/id2.html.markdown": { Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), }, + "website/docs/state-stores/state_store.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, + "website/docs/state-stores/state_store2.html.markdown": { + Data: encodeYAML(t, &ValidLegacyResourceFrontMatter), + }, }, ExpectedError: "matching resource for documentation file (id2.html.markdown) not found, file is extraneous or incorrectly named\n" + "matching datasource for documentation file (pet2.html.markdown) not found, file is extraneous or incorrectly named\n" + "matching function for documentation file (parse_id2.html.markdown) not found, file is extraneous or incorrectly named\n" + "matching ephemeral resource for documentation file (ephemeral_id2.html.markdown) not found, file is extraneous or incorrectly named\n" + "matching action for documentation file (action2.html.markdown) not found, file is extraneous or incorrectly named\n" + - "matching list resource for documentation file (list2.html.markdown) not found, file is extraneous or incorrectly named", + "matching list resource for documentation file (list2.html.markdown) not found, file is extraneous or incorrectly named\n" + + "matching state store for documentation file (state_store2.html.markdown) not found, file is extraneous or incorrectly named", }, }