Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 75 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ Usage: tfplugindocs generate [<args>]
--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
--rendered-provider-name <ARG> provider name, as generated in documentation (ex. page titles, ...); defaults to the --provider-name
--rendered-website-dir <ARG> output directory based on provider-dir (default: "docs")
--syntax <ARG> default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform")
--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
--website-source-dir <ARG> templates directory based on provider-dir (default: "templates")
--website-temp-dir <ARG> temporary directory (used during generation)
Expand All @@ -89,6 +90,7 @@ Usage: tfplugindocs validate [<args>]
--provider-dir <ARG> relative or absolute path to the root provider code directory; this will default to the current working directory if not set
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
--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
--syntax <ARG> default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform")
--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
```

Expand All @@ -101,8 +103,9 @@ Usage: tfplugindocs migrate [<args>]

--examples-dir <ARG> examples directory based on provider-dir (default: "examples")
--provider-dir <ARG> relative or absolute path to the root provider code directory when running the command outside the root provider code directory
--templates-dir <ARG> new website templates directory based on provider-dir; files will be migrated to this directory (default: "templates")
--provider-name <ARG> provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)
--syntax <ARG> default syntax highlighting format for code blocks (e.g., terraform, hcl) (default: "terraform")
--templates-dir <ARG> new website templates directory based on provider-dir; files will be migrated to this directory (default: "templates")
```

### How it Works
Expand Down Expand Up @@ -383,18 +386,77 @@ using the following data fields and functions:

#### Template Functions

| Function | Description |
|-----------------|---------------------------------------------------------------------------------------------------|
| `codefile` | Create a Markdown code block with the content of a file. Path is relative to the repository root. |
| `lower` | Equivalent to [`strings.ToLower`](https://pkg.go.dev/strings#ToLower). |
| `plainmarkdown` | Render Markdown content as plaintext. |
| `prefixlines` | Add a prefix to all (newline-separated) lines in a string. |
| `printf` | Equivalent to [`fmt.Printf`](https://pkg.go.dev/fmt#Printf). |
| `split` | Split string into sub-strings, by a given separator (ex. `split .Name "_"`). |
| `title` | Equivalent to [`cases.Title`](https://pkg.go.dev/golang.org/x/text/cases#Title). |
| `tffile` | A special case of the `codefile` function, designed for Terraform files (i.e. `.tf`). |
| `trimspace` | Equivalent to [`strings.TrimSpace`](https://pkg.go.dev/strings#TrimSpace). |
| `upper` | Equivalent to [`strings.ToUpper`](https://pkg.go.dev/strings#ToUpper). |
| Function | Description |
|-----------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `codefile` | Create a Markdown code block with the content of a file. Path is relative to the repository root. |
| `lower` | Equivalent to [`strings.ToLower`](https://pkg.go.dev/strings#ToLower). |
| `plainmarkdown` | Render Markdown content as plaintext. |
| `prefixlines` | Add a prefix to all (newline-separated) lines in a string. |
| `printf` | Equivalent to [`fmt.Printf`](https://pkg.go.dev/fmt#Printf). |
| `split` | Split string into sub-strings, by a given separator (ex. `split .Name "_"`). |
| `title` | Equivalent to [`cases.Title`](https://pkg.go.dev/golang.org/x/text/cases#Title). |
| `tffile` | A special case of the `codefile` function, designed for Terraform files (i.e. `.tf`). Supports optional syntax highlighting format parameter. |
| `trimspace` | Equivalent to [`strings.TrimSpace`](https://pkg.go.dev/strings#TrimSpace). |
| `upper` | Equivalent to [`strings.ToUpper`](https://pkg.go.dev/strings#ToUpper). |

##### Code Block Syntax Formatting

The `tffile` function and `codefile` function support syntax highlighting for code blocks. The syntax format can be controlled in several ways:

1. **Command-line flag (default syntax)**: Use the `--syntax` flag when running `generate`, `validate`, or `migrate` commands to set the default syntax highlighting format for all code blocks:

```shell
tfplugindocs generate --syntax hcl
```

The default value is `"terraform"` if not specified.

2. **Template literal override**: Override the default syntax for a specific code block by passing a literal string as the second parameter to `tffile`:

```go
{{ tffile . }}
{{ tffile . "hcl" }}
{{ tffile . "terraform" }}
{{ tffile . "mySyntax" }}
```

3. **Template variable override**: Use a template variable to dynamically set the syntax format:

```go
{{ $format := .Format }}
{{ tffile . $format }}
```

Or more concisely:

```go
{{ tffile . .Format }}
```

**Examples:**

Using the default syntax (from `--syntax` flag):
```markdown
{{ tffile .ExampleFile }}
```

Overriding with a specific syntax:
```markdown
{{ tffile .ExampleFile "hcl" }}
```

Using multiple syntaxes in the same template:
```markdown
Default: {{ tffile .ExampleFile }}
HCL: {{ tffile .ExampleFile "hcl" }}
Custom: {{ tffile .ExampleFile "custom" }}
```

Using a template variable:
```markdown
{{ $format := "hcl" }}
{{ tffile .ExampleFile $format }}
```

## Disclaimer

Expand Down
3 changes: 3 additions & 0 deletions internal/cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type generateCmd struct {
flagWebsiteTmpDir string
flagWebsiteSourceDir string
tfVersion string
flagSyntax string
}

func (cmd *generateCmd) Synopsis() string {
Expand Down Expand Up @@ -82,6 +83,7 @@ func (cmd *generateCmd) Flags() *flag.FlagSet {
fs.StringVar(&cmd.flagWebsiteSourceDir, "website-source-dir", "templates", "templates directory based on provider-dir")
fs.StringVar(&cmd.tfVersion, "tf-version", "", "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")
fs.BoolVar(&cmd.flagIgnoreDeprecated, "ignore-deprecated", false, "don't generate documentation for deprecated resources and data-sources")
fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)")
return fs
}

Expand Down Expand Up @@ -109,6 +111,7 @@ func (cmd *generateCmd) runInternal() error {
cmd.flagWebsiteSourceDir,
cmd.tfVersion,
cmd.flagIgnoreDeprecated,
cmd.flagSyntax,
)
if err != nil {
return fmt.Errorf("unable to generate website: %w", err)
Expand Down
3 changes: 3 additions & 0 deletions internal/cmd/migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type migrateCmd struct {
flagTemplatesDir string
flagExamplesDir string
flagProviderName string
flagSyntax string
}

func (cmd *migrateCmd) Synopsis() string {
Expand Down Expand Up @@ -69,6 +70,7 @@ func (cmd *migrateCmd) Flags() *flag.FlagSet {
fs.StringVar(&cmd.flagTemplatesDir, "templates-dir", "templates", "new website templates directory based on provider-dir; files will be migrated to this directory")
fs.StringVar(&cmd.flagExamplesDir, "examples-dir", "examples", "examples directory based on provider-dir; extracted code examples will be migrated to this directory")
fs.StringVar(&cmd.flagProviderName, "provider-name", "", "provider name, as used in Terraform configurations; defaults to the --provider-dir short name (after removing `terraform-provider-` prefix)")
fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)")

return fs
}
Expand All @@ -91,6 +93,7 @@ func (cmd *migrateCmd) runInternal() error {
cmd.flagTemplatesDir,
cmd.flagExamplesDir,
cmd.flagProviderName,
cmd.flagSyntax,
)
if err != nil {
return fmt.Errorf("unable to migrate website: %w", err)
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type validateCmd struct {
flagProviderDir string
flagProvidersSchema string
tfVersion string
flagSyntax string
}

func (cmd *validateCmd) Synopsis() string {
Expand Down Expand Up @@ -77,6 +78,7 @@ func (cmd *validateCmd) Flags() *flag.FlagSet {
fs.StringVar(&cmd.flagProviderDir, "provider-dir", "", "relative or absolute path to the root provider code directory; this will default to the current working directory if not set")
fs.StringVar(&cmd.flagProvidersSchema, "providers-schema", "", "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")
fs.StringVar(&cmd.tfVersion, "tf-version", "", "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")
fs.StringVar(&cmd.flagSyntax, "syntax", "terraform", "default syntax highlighting format for code blocks (e.g., terraform, hcl)")
return fs
}

Expand Down
4 changes: 2 additions & 2 deletions internal/provider/action_template.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type ActionTemplateType struct {
RenderedProviderName string
}

func (t actionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, schema *tfjson.ActionSchema) (string, error) {
func (t actionTemplate) Render(providerDir, name, providerName, renderedProviderName, typeName, exampleFile string, exampleFiles []string, schema *tfjson.ActionSchema, syntax string) (string, error) {
schemaBuffer := bytes.NewBuffer(nil)
err := schemamd.RenderAction(schema, schemaBuffer)
if err != nil {
Expand Down Expand Up @@ -60,7 +60,7 @@ func (t actionTemplate) Render(providerDir, name, providerName, renderedProvider
SchemaMarkdown: actionSchemaComment + "\n" + schemaBuffer.String(),

RenderedProviderName: renderedProviderName,
})
}, syntax)
}

const defaultActionTemplate actionTemplate = `---
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/action_template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ action "scaffolding_example" "example1" {
},
}

result, err := tpl.Render("testdata/test-action-dir", "testTemplate", "test-action", "test-action", "action", "action.tf", []string{"action.tf"}, &schema)
result, err := tpl.Render("testdata/test-action-dir", "testTemplate", "test-action", "test-action", "action", "action.tf", []string{"action.tf"}, &schema, "terraform")
if err != nil {
t.Error(err)
}
Expand Down
24 changes: 15 additions & 9 deletions internal/provider/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ var (
type generator struct {
ignoreDeprecated bool
tfVersion string
syntax string

// providerDir is the absolute path to the root provider directory
providerDir string
Expand All @@ -132,7 +133,7 @@ func (g *generator) warnf(format string, a ...interface{}) {
g.ui.Warn(fmt.Sprintf(format, a...))
}

func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated bool) error {
func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, renderedProviderName, renderedWebsiteDir, examplesDir, websiteTmpDir, templatesDir, tfVersion string, ignoreDeprecated bool, syntax string) error {
// Ensure provider directory is resolved absolute path
if providerDir == "" {
wd, err := os.Getwd()
Expand Down Expand Up @@ -163,9 +164,14 @@ func Generate(ui cli.Ui, providerDir, providerName, providersSchemaPath, rendere
return fmt.Errorf("expected %q to be a directory", providerDir)
}

if syntax == "" {
syntax = "terraform"
}

g := &generator{
ignoreDeprecated: ignoreDeprecated,
tfVersion: tfVersion,
syntax: syntax,

providerDir: providerDir,
providerName: providerName,
Expand Down Expand Up @@ -772,7 +778,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
slices.Sort(exampleFiles)

tmpl := resourceTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, exampleFiles, "", "", "", resSchema, nil)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Data Source", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax)
if err != nil {
return fmt.Errorf("unable to render data source template %q: %w", rel, err)
}
Expand Down Expand Up @@ -803,7 +809,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
importIdentityConfigFilePath := filepath.Join(g.ProviderExamplesDir(), "resources", resName, "import-by-identity.tf")

tmpl := resourceTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, exampleFiles, importIDConfigFilePath, importIdentityConfigFilePath, importFilePath, resSchema, resIdentitySchema)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Resource", exampleFilePath, exampleFiles, importIDConfigFilePath, importIdentityConfigFilePath, importFilePath, resSchema, resIdentitySchema, g.syntax)
if err != nil {
return fmt.Errorf("unable to render resource template %q: %w", rel, err)
}
Expand All @@ -828,7 +834,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
slices.Sort(exampleFiles)

tmpl := functionTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, funcName, g.providerName, g.renderedProviderName, "function", exampleFilePath, exampleFiles, signature)
render, err := tmpl.Render(g.providerDir, funcName, g.providerName, g.renderedProviderName, "function", exampleFilePath, exampleFiles, signature, g.syntax)
if err != nil {
return fmt.Errorf("unable to render function template %q: %w", rel, err)
}
Expand All @@ -855,7 +861,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
slices.Sort(exampleFiles)

tmpl := resourceTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Ephemeral Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Ephemeral Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax)
if err != nil {
return fmt.Errorf("unable to render ephemeral resource template %q: %w", rel, err)
}
Expand All @@ -881,7 +887,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
slices.Sort(exampleFiles)

tmpl := actionTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Action", exampleFilePath, exampleFiles, actionSchema)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "Action", exampleFilePath, exampleFiles, actionSchema, g.syntax)
if err != nil {
return fmt.Errorf("unable to render action template %q: %w", rel, err)
}
Expand All @@ -906,7 +912,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e

if resSchema != nil {
tmpl := resourceTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "List Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil)
render, err := tmpl.Render(g.providerDir, resName, g.providerName, g.renderedProviderName, "List Resource", exampleFilePath, exampleFiles, "", "", "", resSchema, nil, g.syntax)
if err != nil {
return fmt.Errorf("unable to render list resource template %q: %w", rel, err)
}
Expand All @@ -930,7 +936,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
slices.Sort(exampleFiles)

tmpl := providerTemplate(tmplData)
render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, exampleFiles, providerSchema.ConfigSchema)
render, err := tmpl.Render(g.providerDir, g.providerName, g.renderedProviderName, exampleFilePath, exampleFiles, providerSchema.ConfigSchema, g.syntax)
if err != nil {
return fmt.Errorf("unable to render provider template %q: %w", rel, err)
}
Expand All @@ -943,7 +949,7 @@ func (g *generator) renderStaticWebsite(providerSchema *tfjson.ProviderSchema) e
}

tmpl := docTemplate(tmplData)
err = tmpl.Render(g.providerDir, out)
err = tmpl.Render(g.providerDir, out, g.syntax)
if err != nil {
return fmt.Errorf("unable to render template %q: %w", rel, err)
}
Expand Down
Loading