Skip to content

Commit 5406ca4

Browse files
Add allowed-(guide|resource)-subcategories and allowed-(guide|resource)-subcategories-file arguments to validate (#456)
* Add flags for subcategory validation * Add ValidatorOptions and function to load allowed subcategories * Add allowed subcategories check to frontmatter check * Remove index subcategories check * Correct guides check bug * Clean up * Update README, additional cleanup * Minor formatting update to README * Fix linting errors * Add flags for subcategory validation * Add ValidatorOptions and function to load allowed subcategories * Add allowed subcategories check to frontmatter check * Remove index subcategories check * Correct guides check bug * Clean up * Update README, additional cleanup * Minor formatting update to README * Fix linting errors * Add changelog entries
1 parent 36a4920 commit 5406ca4

File tree

11 files changed

+245
-42
lines changed

11 files changed

+245
-42
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: 'validate: Fixed a bug that caused all non-index files to be detected as guides'
3+
time: 2025-03-18T15:19:55.463729-05:00
4+
custom:
5+
Issue: "456"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: ENHANCEMENTS
2+
body: 'validate: Add `allowed-guide-subcategories` and `allowed-resource-subcategories` to provide a list of allowed subcategories'
3+
time: 2025-03-18T15:22:38.292714-05:00
4+
custom:
5+
Issue: "456"
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: ENHANCEMENTS
2+
body: 'validate: Add `allowed-guide-subcategories-file` and `allowed-resource-subcategories-file` to provide a file containing a list of allowed subcategories'
3+
time: 2025-03-18T15:23:45.718553-05:00
4+
custom:
5+
Issue: "456"

README.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ Available commands are:
5353
generate generates a plugin website from code, templates, and examples
5454
migrate migrates website files from either the legacy rendered website directory (`website/docs/r`) or the docs rendered website directory (`docs/resources`) to the tfplugindocs supported structure (`templates/`).
5555
validate validates a plugin website
56-
56+
5757
```
5858
5959
`generate` command:
@@ -65,14 +65,14 @@ Usage: tfplugindocs generate [<args>]
6565

6666
--examples-dir <ARG> examples directory based on provider-dir (default: "examples")
6767
--ignore-deprecated <ARG> don't generate documentation for deprecated resources and data-sources (default: "false")
68-
--provider-dir <ARG> relative or absolute path to the root provider code directory when running the command outside the root provider code directory
69-
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
70-
--providers-schema <ARG> path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI
71-
--rendered-provider-name <ARG> provider name, as generated in documentation (ex. page titles, ...)
68+
--provider-dir <ARG> relative or absolute path to the root provider code directory when running the command outside the root provider code directory
69+
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
70+
--providers-schema <ARG> path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI
71+
--rendered-provider-name <ARG> provider name, as generated in documentation (ex. page titles, ...)
7272
--rendered-website-dir <ARG> output directory based on provider-dir (default: "docs")
73-
--tf-version <ARG> terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform
73+
--tf-version <ARG> terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform
7474
--website-source-dir <ARG> templates directory based on provider-dir (default: "templates")
75-
--website-temp-dir <ARG> temporary directory (used during generation)
75+
--website-temp-dir <ARG> temporary directory (used during generation)
7676
```
7777
7878
`validate` command:
@@ -82,10 +82,14 @@ $ tfplugindocs validate --help
8282
8383
Usage: tfplugindocs validate [<args>]
8484
85-
--provider-dir <ARG> relative or absolute path to the root provider code directory; this will default to the current working directory if not set
86-
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
87-
--providers-schema <ARG> path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI
88-
--tf-version <ARG> terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform
85+
--allowed-guide-subcategories <ARG> comma separated list of allowed guide frontmatter subcategories
86+
--allowed-guide-subcategories-file <ARG> path to newline separated file of allowed guide frontmatter subcategories
87+
--allowed-resource-subcategories <ARG> comma separated list of allowed resource frontmatter subcategories
88+
--allowed-resource-subcategories-file <ARG> path to newline separated file of allowed resource frontmatter subcategories
89+
--provider-dir <ARG> relative or absolute path to the root provider code directory; this will default to the current working directory if not set
90+
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
91+
--providers-schema <ARG> path to the providers schema JSON file, which contains the output of the terraform providers schema -json command. Setting this flag will skip building the provider and calling Terraform CLI
92+
--tf-version <ARG> terraform binary version to download. If not provided, will look for a terraform binary in the local environment. If not found in the environment, will download the latest version of Terraform
8993
```
9094
9195
`migrate` command:
@@ -98,7 +102,7 @@ Usage: tfplugindocs migrate [<args>]
98102
--examples-dir <ARG> examples directory based on provider-dir (default: "examples")
99103
--provider-dir <ARG> relative or absolute path to the root provider code directory when running the command outside the root provider code directory
100104
--templates-dir <ARG> new website templates directory based on provider-dir; files will be migrated to this directory (default: "templates")
101-
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
105+
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
102106
```
103107
104108
### How it Works
@@ -161,22 +165,22 @@ Otherwise, the provider developer can set an arbitrary description like this:
161165

162166
The `validate` subcommand can be used to validate the provider website documentation against the [Terraform Registry's provider documentation guidelines](https://developer.hashicorp.com/terraform/registry/providers/docs) and provider documentation best practices. The current checks in the `validate` command are:
163167
164-
| Check | Description |
165-
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
166-
| `InvalidDirectoriesCheck` | Checks for valid subdirectory structure and throws an error if an invalid Terraform Provider documentation subdirectory is found. |
167-
| `MixedDirectoriesCheck` | Throws an error if both legacy documentation (`/website/docs`) and registry documentation (`/docs`) are found. |
168-
| `FileSizeCheck` | Throws an error if the documentation file is above the registry storage limit. |
169-
| `FileExtensionCheck` | Throws an error if the extension of the given file is not a valid registry documentation extension. |
170-
| `FrontMatterCheck` | Checks the YAML frontmatter of documentation for missing required fields or invalid fields. |
171-
| `FileMismatchCheck` | Throws an error if the names/number of resources/datasources/functions in the provider schema does not match the names/number of files in the corresponding documentation directory |
168+
| Check | Description |
169+
|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
170+
| `InvalidDirectoriesCheck` | Checks for valid subdirectory structure and throws an error if an invalid Terraform Provider documentation subdirectory is found. |
171+
| `MixedDirectoriesCheck` | Throws an error if both legacy documentation (`/website/docs`) and registry documentation (`/docs`) are found. |
172+
| `FileSizeCheck` | Throws an error if the documentation file is above the registry storage limit. |
173+
| `FileExtensionCheck` | Throws an error if the extension of the given file is not a valid registry documentation extension. |
174+
| `FrontMatterCheck` | Checks the YAML frontmatter of documentation for missing required fields or invalid fields. Optionally, checks that the `subcategory` is within the specified allow list. |
175+
| `FileMismatchCheck` | Throws an error if the names/number of resources/datasources/functions in the provider schema does not match the names/number of files in the corresponding documentation directory. |
172176
173177
All check errors are wrapped and returned as a single error message to stderr.
174178
175179
#### Migrate subcommand
176180
177-
The `migrate` subcommand can be used to migrate website files from either the legacy rendered website directory (`website/docs/r`) or the docs
178-
rendered website directory (`docs/resources`) to the `tfplugindocs` supported structure (`templates/`). Markdown files in the rendered website
179-
directory will be converted to `tfplugindocs` templates. The legacy `website/` directory will be removed after migration to avoid Terraform Registry
181+
The `migrate` subcommand can be used to migrate website files from either the legacy rendered website directory (`website/docs/r`) or the docs
182+
rendered website directory (`docs/resources`) to the `tfplugindocs` supported structure (`templates/`). Markdown files in the rendered website
183+
directory will be converted to `tfplugindocs` templates. The legacy `website/` directory will be removed after migration to avoid Terraform Registry
180184
ingress issues.
181185
182186
The `migrate` subcommand takes the following actions:
@@ -260,10 +264,10 @@ Docs website directory structure:
260264
| `docs/functions/<function name>.html.markdown` | Function page |
261265
| `docs/resources/<resource name>.html.markdown` | Resource page |
262266
263-
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/`,
264-
and `docs/resources/` subdirectories will be converted to `tfplugindocs` templates.
267+
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/`,
268+
and `docs/resources/` subdirectories will be converted to `tfplugindocs` templates.
265269
266-
The `website/docs/guides/` and `docs/guides/` subdirectories will be copied as-is to the `--templates-dir` folder.
270+
The `website/docs/guides/` and `docs/guides/` subdirectories will be copied as-is to the `--templates-dir` folder.
267271
268272
All other files in the conventional paths will be ignored.
269273
@@ -356,13 +360,13 @@ This repo uses the `testscript` [package](https://pkg.go.dev/github.com/rogpeppe
356360

357361
There are two types of acceptance tests: full provider build tests in `tfplugindocs/testdata/scripts/provider-build` and provider schema json tests in `tfplugindocs/testdata/scripts/schema-json`.
358362

359-
Provider build tests run the default `tfplugindocs` command which builds the provider source code and runs Terraform to retrieve the schema. These tests require the full provider source code to build a valid provider binary.
363+
Provider build tests run the default `tfplugindocs` command which builds the provider source code and runs Terraform to retrieve the schema. These tests require the full provider source code to build a valid provider binary.
360364

361-
Schema json tests run the `tfplugindocs` command with the `--providers-schema=<arg>` flag to specify a provider schemas json file. This allows the test to skip the provider build and Terraform CLI call, instead using the specified file to generate docs.
365+
Schema json tests run the `tfplugindocs` command with the `--providers-schema=<arg>` flag to specify a provider schemas json file. This allows the test to skip the provider build and Terraform CLI call, instead using the specified file to generate docs.
362366

363367
You can run `make testacc` to run the full suite of acceptance tests. By default, the provider build acceptance tests will create a temporary directory in `/tmp/tftmp` for testing, but you can change this location in `cmd/tfplugindocs/main_test.go`. The schema json tests uses the `testscript` package's [default work directory](https://pkg.go.dev/github.com/rogpeppe/go-internal/testscript#Params.WorkdirRoot).
364368
365369
The test scripts are defined in the `tfplugindocs/testdata/scripts` directory. Each script includes the test, golden files, and the provider source code or schema JSON file needed to run the test.
366370
367-
Each script is a [text archive](https://pkg.go.dev/golang.org/x/tools/txtar). You can install the `txtar` CLI locally by running `go install golang.org/x/exp/cmd/txtar@latest` to extract the files in the test script for debugging.
371+
Each script is a [text archive](https://pkg.go.dev/golang.org/x/tools/txtar). You can install the `txtar` CLI locally by running `go install golang.org/x/exp/cmd/txtar@latest` to extract the files in the test script for debugging.
368372
You can also use `txtar` CLI archive files into the `.txtar` format to create new tests or modify existing ones.

internal/check/frontmatter.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package check
66
import (
77
"bytes"
88
"fmt"
9+
"slices"
910

1011
"github.com/yuin/goldmark"
1112
"github.com/yuin/goldmark/parser"
@@ -27,13 +28,14 @@ type FrontMatterData struct {
2728

2829
// FrontMatterOptions represents configuration options for FrontMatter.
2930
type FrontMatterOptions struct {
30-
NoLayout bool
31-
NoPageTitle bool
32-
NoSidebarCurrent bool
33-
NoSubcategory bool
34-
RequireDescription bool
35-
RequireLayout bool
36-
RequirePageTitle bool
31+
AllowedSubcategories []string
32+
NoLayout bool
33+
NoPageTitle bool
34+
NoSidebarCurrent bool
35+
NoSubcategory bool
36+
RequireDescription bool
37+
RequireLayout bool
38+
RequirePageTitle bool
3739
}
3840

3941
func NewFrontMatterCheck(opts *FrontMatterOptions) *FrontMatterCheck {
@@ -100,5 +102,11 @@ func (check *FrontMatterCheck) Run(src []byte) error {
100102
return fmt.Errorf("YAML frontmatter missing required page_title")
101103
}
102104

105+
if allowedSubcategories := check.Options.AllowedSubcategories; len(allowedSubcategories) != 0 && frontMatter.Subcategory != nil {
106+
if !slices.Contains(allowedSubcategories, *frontMatter.Subcategory) {
107+
return fmt.Errorf("YAML frontmatter contains a subcategory (%s) that is not in the allowed list", *frontMatter.Subcategory)
108+
}
109+
}
110+
103111
return nil
104112
}

internal/check/frontmatter_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,28 @@ subcategory: Example Subcategory
138138
},
139139
ExpectError: true,
140140
},
141+
"allowed subcategory option": {
142+
Source: `
143+
---
144+
subcategory: Example Subcategory
145+
---
146+
`,
147+
Options: &FrontMatterOptions{
148+
AllowedSubcategories: []string{"Example Subcategory"},
149+
},
150+
ExpectError: false,
151+
},
152+
"disallowed subcategory option": {
153+
Source: `
154+
---
155+
subcategory: Example Subcategory
156+
---
157+
`,
158+
Options: &FrontMatterOptions{
159+
AllowedSubcategories: []string{"Subcategory"},
160+
},
161+
ExpectError: true,
162+
},
141163
}
142164

143165
for name, testCase := range testCases {

0 commit comments

Comments
 (0)