Skip to content

Conversation

jmcarp
Copy link
Contributor

@jmcarp jmcarp commented Aug 22, 2025

Rather than constructing docs manually and running them through a linter, use tfplugindocs to generate them. We move examples into the examples/ directory, and override default templates in the templates/ directory. We also add new make targets to generate docs and check that the generated docs match the code.

Resolves #490.

Note: this is a low priority, but I wanted to fix the paper cut before investing more time in the provider.

Also note: the generated docs aren't identical to the current docs. I haven't gone through and tried to make them as similar as possible, but we can do more to minimize the diff if we want to.

@jmcarp jmcarp requested a review from a team as a code owner August 22, 2025 15:58
@jmcarp jmcarp force-pushed the jmcarp/auto-docs branch 2 times, most recently from 2558e2f to 4863f23 Compare August 22, 2025 16:01
@sudomateo
Copy link
Collaborator

I really like this idea! I haven't used tfplugindocs so I want to better understand how it expects to use templates and spend some time updating our descriptions first so the generated documentation is consistent and useful. Agree it's low priority but I'll try to spend some time looking at this on the plane when I travel next week.

@sudomateo sudomateo self-assigned this Aug 30, 2025
Rather than constructing docs manually and running them through a linter, use
tfplugindocs to generate them. We move examples into the examples/ directory,
and override default templates in the templates/ directory. We also add new
make targets to generate docs and check that the generated docs match the code.

Resolves #490.
@jmcarp
Copy link
Contributor Author

jmcarp commented Oct 7, 2025

Conflicts resolved. @lgfa29, thanks for adding the missing descriptions to the resource definitions. @sudomateo, this is ready for a look when you have time.

@sudomateo
Copy link
Collaborator

Conflicts resolved. @lgfa29, thanks for adding the missing descriptions to the resource definitions. @sudomateo, this is ready for a look when you have time.

Ack! Adding it to my list for the day. Have a few back-to-back meetings but later in the afternoon I'll review.

Copy link
Collaborator

@sudomateo sudomateo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you both for working on this! This is much better than handwriting documentation. I made a quick change to solidify my understanding of how this is meant to work.

I'm not sold on the examples in a separate directory versus have resource specific templates but I understand the generator looks for a certain directory structure to generate resource and data source documentation from a default template. My motivation for this is when removing a resource the generated documentation is removed but the examples remain. This is something we can hone in on in the future though so not blocking at all.

My other curiosity is using Go's embed to hold the resource or data source level MarkdownDescription so it doesn't overwhelm the code. The attributes MarkdownDescription is find since it's usually one line but the top-level MarkdownDescription is often a few lines. Again, a future thing we can hone in on as we use this.

Thanks again!

@jmcarp
Copy link
Contributor Author

jmcarp commented Oct 7, 2025

Agreed that some of the assumptions the docs generator makes are silly, but also agreed that we can fix up the implications later on. Thanks for the review!

@jmcarp jmcarp merged commit a2279ca into main Oct 7, 2025
3 of 4 checks passed
@lgfa29
Copy link
Member

lgfa29 commented Oct 8, 2025

One minor benefit of examples being in a separate folder is that they can become "executable" Terraform files. I usually have tmp folder where I write random main.tf files that are effectively copy-and-paste code from the docs example. Being able to just terraform apply from one of the examples folder could be useful.

As for the MarkdownDescription, yeah it's kind of messy, and I was quite surprised to find out that there's no way to escape backticks in raw strings 🙃

One approach I considered was to store the string in a variable, but since all files are in the same package, the variable would need to be very specific, like:

resourceFloatingIPDescription = `
...
`
// ...
func (f *floatingIPResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
	resp.Schema = schema.Schema{
		MarkdownDescription: resourceFloatingIPDescription,
		Attributes: map[string]schema.Attribute{
			// ...

I didn't feel strongly about either way, so I just added everything to the schema. But for resources or data sources with longer descriptions, it may be worth considering the variable approach.

@sudomateo
Copy link
Collaborator

One minor benefit of examples being in a separate folder is that they can become "executable" Terraform files.

Agreed. That, plus syntax highlighting and formatting makes having external example files attractive.

One approach I considered was to store the string in a variable, but since all files are in the same package, the variable would need to be very specific, like:

This is something that always bothered me about Terraform providers. Having everything in the same package leads to use having to create long, unique names like resourceFooBarModel to prevent conflicts. Not important or even urgent but I would like to explore what alternative repository layouts exist that we can make use of.

@lgfa29
Copy link
Member

lgfa29 commented Oct 8, 2025

It doesn't really have to be all in the same package, it's just easier to start like that 😅

We can have them in different pacakages and import the packages in provider.go

// DataSources defines the data sources implemented in the provider.
func (p *oxideProvider) DataSources(_ context.Context) []func() datasource.DataSource {
return []func() datasource.DataSource{
NewAntiAffinityGroupDataSource,
NewImageDataSource,
NewImagesDataSource,
NewInstanceExternalIPsDataSource,
NewIpPoolDataSource,
NewProjectDataSource,
NewProjectsDataSource,
NewSiloDataSource,
NewSSHKeyDataSource,
NewVPCDataSource,
NewVPCInternetGatewayDataSource,
NewVPCRouterDataSource,
NewVPCRouterRouteDataSource,
NewVPCSubnetDataSource,
NewFloatingIPDataSource,
NewSystemIpPoolsDataSource,
}
}
// Resources defines the resources implemented in the provider.
func (p *oxideProvider) Resources(_ context.Context) []func() resource.Resource {
return []func() resource.Resource{
NewAntiAffinityGroupResource,
NewDiskResource,
NewImageResource,
NewInstanceResource,
NewIPPoolResource,
NewIpPoolSiloLinkResource,
NewProjectResource,
NewSnapshotResource,
NewSSHKeyResource,
NewVPCResource,
NewVPCInternetGatewayResource,
NewVPCFirewallRulesResource,
NewVPCRouterResource,
NewVPCRouterRouteResource,
NewVPCSubnetResource,
NewFloatingIPResource,
NewSiloResource,
NewSiloSamlIdentityProviderResource,
}
}

The AWS provider, for example, groups them by service:
https://github.com/hashicorp/terraform-provider-aws/tree/main/internal/service

@sudomateo
Copy link
Collaborator

Let's explore that! I'll add an agenda item to our next sync to discuss it further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Automate docs generation

3 participants