Skip to content

Commit 4a9ffe7

Browse files
committed
Move plugin-sdk to in-tree in core repository
Moving terraform-docs/plugin-sdk standalone module to in-tree, because maintaining both of them, specifically if anything needs to be added to Config, or terraform will required dual effort on both repository. As such now everything is consolidated under one repository. Example usage for plugin developer after this move is as follow: ```go package main import ( _ "embed" //nolint "github.com/terraform-docs/terraform-docs/plugin" "github.com/terraform-docs/terraform-docs/print" "github.com/terraform-docs/terraform-docs/template" "github.com/terraform-docs/terraform-docs/terraform" ) func main() { plugin.Serve(&plugin.ServeOpts{ Name: "template", Version: "0.1.0", Printer: printer, }) } //go:embed sections.tmpl var tplCustom []byte // Print the custom format template. You have all the flexibility to generate // the output however you choose to. func printer(config *print.Config, module *terraform.Module) (string, error) { tpl := template.New(config, &template.Item{Name: "custom", Text: string(tplCustom)}, ) rendered, err := tpl.Render("custom", module) if err != nil { return "", err } return rendered, nil } ``` Signed-off-by: Khosrow Moossavi <khos2ow@gmail.com>
1 parent 40f20c5 commit 4a9ffe7

File tree

21 files changed

+450
-168
lines changed

21 files changed

+450
-168
lines changed

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,14 @@ when formatter is set to `markdown table`.
253253
Note that sections visibility (i.e. `sections.show` and `sections.hide`) takes
254254
precedence over the `content`.
255255

256+
Additionally there's also one extra special variable avaialble to the `content`:
257+
258+
- `{{ .Module }}`
259+
260+
As opposed to the other variables mentioned above, which are generated sections
261+
based on a selected formatter, the `{{ .Module }}` variable is just a `struct`
262+
representing a [Terraform module].
263+
256264
````yaml
257265
content: |-
258266
Any arbitrary text can be placed anywhere in the content
@@ -278,6 +286,12 @@ content: |-
278286
```hcl
279287
{{ include "examples/foo/main.tf" }}
280288
```
289+
290+
## Resources
291+
292+
{{ range .Module.Resources }}
293+
- {{ .GetMode }}.{{ .Spec }} ({{ .Position.Filename }}#{{ .Position.Line }})
294+
{{- end }}
281295
````
282296

283297
## Build on top of terraform-docs
@@ -320,6 +334,68 @@ func buildTerraformDocs(path string, tmpl string) (string, error) {
320334
}
321335
```
322336

337+
## Plugin
338+
339+
Generated output can be heavily customized with [`content`], but if using that
340+
is not enough for your use-case, you can write your own plugin.
341+
342+
In order to install a plugin the following steps are needed:
343+
344+
- download the plugin and place it in `~/.tfdocs.d/plugins` (or `./.tfdocs.d/plugins`)
345+
- make sure the plugin file name is `tfdocs-format-<NAME>`
346+
- modify [`formatter`] of `.terraform-docs.yml` file to be `<NAME>`
347+
348+
**Important notes:**
349+
350+
- if the plugin file name is different than the example above, terraform-docs won't
351+
be able to to pick it up nor register it properly
352+
- you can only use plugin thorough `.terraform-docs.yml` file and it cannot be used
353+
with CLI arguments
354+
355+
To create a new plugin create a new repository called `tfdocs-format-<NAME>` with
356+
following `main.go`:
357+
358+
```go
359+
package main
360+
361+
import (
362+
_ "embed" //nolint
363+
364+
"github.com/terraform-docs/terraform-docs/plugin"
365+
"github.com/terraform-docs/terraform-docs/print"
366+
"github.com/terraform-docs/terraform-docs/template"
367+
"github.com/terraform-docs/terraform-docs/terraform"
368+
)
369+
370+
func main() {
371+
plugin.Serve(&plugin.ServeOpts{
372+
Name: "<NAME>",
373+
Version: "0.1.0",
374+
Printer: printerFunc,
375+
})
376+
}
377+
378+
//go:embed sections.tmpl
379+
var tplCustom []byte
380+
381+
// printerFunc the function being executed by the plugin client.
382+
func printerFunc(config *print.Config, module *terraform.Module) (string, error) {
383+
tpl := template.New(config,
384+
&template.Item{Name: "custom", Text: string(tplCustom)},
385+
)
386+
387+
rendered, err := tpl.Render("custom", module)
388+
if err != nil {
389+
return "", err
390+
}
391+
392+
return rendered, nil
393+
}
394+
```
395+
396+
Please refer to [tfdocs-format-template] for more details. You can create a new
397+
repository from it by clicking on `Use this template` button.
398+
323399
## Documentation
324400

325401
- **Users**
@@ -341,8 +417,10 @@ MIT License - Copyright (c) 2021 The terraform-docs Authors.
341417

342418
[Chocolatey]: https://www.chocolatey.org
343419
[Config File Reference]: https://terraform-docs.io/user-guide/configuration/
420+
[`content`]: https://terraform-docs.io/user-guide/configuration/content/
344421
[Contributing Guide]: CONTRIBUTING.md
345422
[Formats Guide]: https://terraform-docs.io/reference/terraform-docs/
423+
[`formatter`]: https://terraform-docs.io/user-guide/configuration/formatter/
346424
[here]: https://golang.org/doc/code.html#GOPATH
347425
[Homebrew]: https://brew.sh
348426
[install pre-commit]: https://pre-commit.com/#install
@@ -351,5 +429,7 @@ MIT License - Copyright (c) 2021 The terraform-docs Authors.
351429
[Scoop]: https://scoop.sh/
352430
[Slack]: https://slack.terraform-docs.io/
353431
[terraform-docs GitHub Action]: https://github.com/terraform-docs/gh-actions
432+
[Terraform module]: https://pkg.go.dev/github.com/terraform-docs/terraform-docs/terraform#Module
433+
[tfdocs-format-template]: https://github.com/terraform-docs/tfdocs-format-template
354434
[our website]: https://terraform-docs.io/
355435
[User Guide]: https://terraform-docs.io/user-guide/introduction/

docs/developer-guide/plugins.md

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,66 @@ weight: 310
88
toc: false
99
---
1010

11-
If you want to add or change formatter, you need to write plugins. When changing
12-
plugins, refer to the repository of each plugin and refer to how to build and
13-
install.
11+
Generated output can be heavily customized with [`content`], but if using that
12+
is not enough for your use-case, you can write your own plugin.
1413

15-
If you want to create a new plugin, please refer to [tfdocs-format-template]. The
16-
plugin can use [plugin-sdk] to communicate with the host process. You can create a
17-
new repository from `Use this template`.
14+
In order to install a plugin the following steps are needed:
1815

19-
[plugin-sdk]: https://github.com/terraform-docs/plugin-sdk
16+
- download the plugin and place it in `~/.tfdocs.d/plugins` (or `./.tfdocs.d/plugins`)
17+
- make sure the plugin file name is `tfdocs-format-<NAME>`
18+
- modify [`formatter`] of `.terraform-docs.yml` file to be `<NAME>`
19+
20+
**Important notes:**
21+
22+
- if the plugin file name is different than the example above, terraform-docs won't
23+
be able to to pick it up nor register it properly
24+
- you can only use plugin thorough `.terraform-docs.yml` file and it cannot be used
25+
with CLI arguments
26+
27+
To create a new plugin create a new repository called `tfdocs-format-<NAME>` with
28+
following `main.go`:
29+
30+
```go
31+
package main
32+
33+
import (
34+
_ "embed" //nolint
35+
36+
"github.com/terraform-docs/terraform-docs/plugin"
37+
"github.com/terraform-docs/terraform-docs/print"
38+
"github.com/terraform-docs/terraform-docs/template"
39+
"github.com/terraform-docs/terraform-docs/terraform"
40+
)
41+
42+
func main() {
43+
plugin.Serve(&plugin.ServeOpts{
44+
Name: "<NAME>",
45+
Version: "0.1.0",
46+
Printer: printerFunc,
47+
})
48+
}
49+
50+
//go:embed sections.tmpl
51+
var tplCustom []byte
52+
53+
// printerFunc the function being executed by the plugin client.
54+
func printerFunc(config *print.Config, module *terraform.Module) (string, error) {
55+
tpl := template.New(config,
56+
&template.Item{Name: "custom", Text: string(tplCustom)},
57+
)
58+
59+
rendered, err := tpl.Render("custom", module)
60+
if err != nil {
61+
return "", err
62+
}
63+
64+
return rendered, nil
65+
}
66+
```
67+
68+
Please refer to [tfdocs-format-template] for more details. You can create a new
69+
repository from it by clicking on `Use this template` button.
70+
71+
[`content`]: {{< ref "content" >}}
72+
[`formatter`]: {{< ref "formatter" >}}
2073
[tfdocs-format-template]: https://github.com/terraform-docs/tfdocs-format-template

examples/.terraform-docs.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
# version: ">= 0.10, < 0.12"
33

44
# see: https://terraform-docs.io/user-guide/configuration/formatter
5-
formatter: markdown table
5+
# formatter: markdown table
6+
formatter: template
67

78
# see: https://terraform-docs.io/user-guide/configuration/header-from
89
header-from: doc.txt

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.16
55
require (
66
github.com/BurntSushi/toml v0.3.1
77
github.com/Masterminds/sprig/v3 v3.2.2
8+
github.com/hashicorp/go-hclog v0.15.0
89
github.com/hashicorp/go-plugin v1.4.2
910
github.com/hashicorp/go-version v1.3.0
1011
github.com/hashicorp/hcl/v2 v2.10.1
@@ -15,7 +16,6 @@ require (
1516
github.com/spf13/pflag v1.0.5
1617
github.com/spf13/viper v1.8.1
1718
github.com/stretchr/testify v1.7.0
18-
github.com/terraform-docs/plugin-sdk v0.3.1-0.20210825180722-c52e9860f575
1919
github.com/terraform-docs/terraform-config-inspect v0.0.0-20210728164355-9c1f178932fa
2020
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
2121
honnef.co/go/tools v0.2.0

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,6 @@ github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
172172
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
173173
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
174174
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
175-
github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
176175
github.com/hashicorp/go-plugin v1.4.2 h1:yFvG3ufXXpqiMiZx9HLcaK3XbIqQ1WJFR/F1a2CuVw0=
177176
github.com/hashicorp/go-plugin v1.4.2/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
178177
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
@@ -310,8 +309,6 @@ github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5Cc
310309
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
311310
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
312311
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
313-
github.com/terraform-docs/plugin-sdk v0.3.1-0.20210825180722-c52e9860f575 h1:pwOvvonyymFBE2YE5Yx1M236lH4WT9i8sgVYC4KMsgE=
314-
github.com/terraform-docs/plugin-sdk v0.3.1-0.20210825180722-c52e9860f575/go.mod h1:3G+0nZTeaMF1c5CZh8cOEYeNq0kUL6+DlQOVcxK7eCQ=
315312
github.com/terraform-docs/terraform-config-inspect v0.0.0-20210728164355-9c1f178932fa h1:wdyf3TobwYFwsqnUGJcjdNHxKfwHPFbaOknBJehnF1M=
316313
github.com/terraform-docs/terraform-config-inspect v0.0.0-20210728164355-9c1f178932fa/go.mod h1:GtanFwTsRRXScYHOMb5h4K18XQBFeS2tXat9/LrPtPc=
317314
github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
@@ -691,7 +688,6 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
691688
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
692689
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
693690
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
694-
honnef.co/go/tools v0.1.2/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
695691
honnef.co/go/tools v0.2.0 h1:ws8AfbgTX3oIczLPNPCu5166oBg9ST2vNs0rcht+mDE=
696692
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
697693
mvdan.cc/xurls/v2 v2.3.0 h1:59Olnbt67UKpxF1EwVBopJvkSUBmgtb468E4GVWIZ1I=

internal/cli/run.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ import (
2222
"github.com/spf13/pflag"
2323
"github.com/spf13/viper"
2424

25-
pluginsdk "github.com/terraform-docs/plugin-sdk/plugin"
2625
"github.com/terraform-docs/terraform-docs/format"
2726
"github.com/terraform-docs/terraform-docs/internal/plugin"
2827
"github.com/terraform-docs/terraform-docs/internal/version"
28+
pluginsdk "github.com/terraform-docs/terraform-docs/plugin"
2929
"github.com/terraform-docs/terraform-docs/print"
3030
"github.com/terraform-docs/terraform-docs/terraform"
3131
)
@@ -344,9 +344,9 @@ func generateContent(config *print.Config) error {
344344
return fmt.Errorf("formatter '%s' not found", config.Formatter)
345345
}
346346

347-
content, cerr := client.Execute(pluginsdk.ExecuteArgs{
348-
Module: module.Convert(),
349-
Settings: nil, // TODO settings.Convert(),
347+
content, cerr := client.Execute(&pluginsdk.ExecuteArgs{
348+
Module: module,
349+
Config: config,
350350
})
351351
if cerr != nil {
352352
return cerr

internal/plugin/discovery.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
goplugin "github.com/hashicorp/go-plugin"
2323
"github.com/mitchellh/go-homedir"
2424

25-
pluginsdk "github.com/terraform-docs/plugin-sdk/plugin"
25+
pluginsdk "github.com/terraform-docs/terraform-docs/plugin"
2626
)
2727

2828
// Discover plugins and registers them. The lookup priority of plugins is as

internal/plugin/plugin.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ package plugin
1313
import (
1414
goplugin "github.com/hashicorp/go-plugin"
1515

16-
pluginsdk "github.com/terraform-docs/plugin-sdk/plugin"
16+
pluginsdk "github.com/terraform-docs/terraform-docs/plugin"
1717
)
1818

1919
// namePrefix is the mandatory prefix for name of the plugin file. What

internal/types/types.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"bytes"
1515
"encoding/json"
1616
"encoding/xml"
17-
"go/types"
1817
"reflect"
1918
"sort"
2019
)
@@ -94,7 +93,7 @@ func TypeOf(t string, v interface{}) String {
9493
}
9594

9695
// Nil represents a 'nil' value which is marshaled to `null` when empty for JSON and YAML
97-
type Nil types.Nil
96+
type Nil struct{}
9897

9998
// HasDefault return false for Nil, because there's no value set for the variable
10099
func (n Nil) HasDefault() bool {

plugin/client.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright 2021 The terraform-docs Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package plugin
18+
19+
import (
20+
"net/rpc"
21+
"os"
22+
"os/exec"
23+
24+
"github.com/hashicorp/go-hclog"
25+
goplugin "github.com/hashicorp/go-plugin"
26+
27+
"github.com/terraform-docs/terraform-docs/print"
28+
"github.com/terraform-docs/terraform-docs/terraform"
29+
)
30+
31+
// Client is an RPC Client for the host.
32+
type Client struct {
33+
rpcClient *rpc.Client
34+
broker *goplugin.MuxBroker
35+
}
36+
37+
// ClientOpts is an option for initializing a Client.
38+
type ClientOpts struct {
39+
Cmd *exec.Cmd
40+
}
41+
42+
// ExecuteArgs is the collection of arguments being sent by terraform-docs
43+
// core while executing the plugin command.
44+
type ExecuteArgs struct {
45+
Module *terraform.Module
46+
Config *print.Config
47+
}
48+
49+
// NewClient is a wrapper of plugin.NewClient.
50+
func NewClient(opts *ClientOpts) *goplugin.Client {
51+
return goplugin.NewClient(&goplugin.ClientConfig{
52+
HandshakeConfig: handshakeConfig,
53+
Plugins: map[string]goplugin.Plugin{
54+
"formatter": &formatter{},
55+
},
56+
Cmd: opts.Cmd,
57+
Logger: hclog.New(&hclog.LoggerOptions{
58+
Name: "plugin",
59+
Output: os.Stderr,
60+
Level: hclog.LevelFromString(os.Getenv("TFDOCS_LOG")),
61+
}),
62+
})
63+
}
64+
65+
// Name calls the server-side Name method and returns its version.
66+
func (c *Client) Name() (string, error) {
67+
var resp string
68+
err := c.rpcClient.Call("Plugin.Name", new(interface{}), &resp)
69+
return resp, err
70+
}
71+
72+
// Version calls the server-side Version method and returns its version.
73+
func (c *Client) Version() (string, error) {
74+
var resp string
75+
err := c.rpcClient.Call("Plugin.Version", new(interface{}), &resp)
76+
return resp, err
77+
}
78+
79+
// Execute calls the server-side Execute method and returns generated output.
80+
func (c *Client) Execute(args *ExecuteArgs) (string, error) {
81+
var resp string
82+
err := c.rpcClient.Call("Plugin.Execute", args, &resp)
83+
return resp, err
84+
}

0 commit comments

Comments
 (0)