Skip to content

Commit e00d970

Browse files
authored
feat: Generate source plugin docs (#47)
* Generate source plugin docs
1 parent 08ac745 commit e00d970

File tree

5 files changed

+187
-109
lines changed

5 files changed

+187
-109
lines changed

docs/source.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// Package docs helps create plugin documentation
2+
package docs
3+
4+
import (
5+
"fmt"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
"text/template"
10+
11+
"github.com/cloudquery/plugin-sdk/plugins"
12+
"github.com/cloudquery/plugin-sdk/schema"
13+
)
14+
15+
const tableTmpl = `
16+
# Table: {{.Name}}
17+
{{ $.Description }}
18+
## Columns
19+
| Name | Type | Description |
20+
| ------------- | ------------- | ----- |
21+
{{- range $column := $.Columns }}
22+
|{{$column.Name}}|{{$column.Type | formatType}}|{{$column.Description|removeLineBreaks}}|
23+
{{- end }}
24+
`
25+
26+
// GenerateSourcePluginDocs creates table documentation for the source plugin based on its list of tables
27+
func GenerateSourcePluginDocs(p *plugins.SourcePlugin, dir string) error {
28+
for _, table := range p.Tables() {
29+
if err := renderAllTables(table, dir); err != nil {
30+
fmt.Printf("render table %s error: %s", table.Name, err)
31+
return err
32+
}
33+
}
34+
return nil
35+
}
36+
37+
func renderAllTables(t *schema.Table, dir string) error {
38+
if err := renderTable(t, dir); err != nil {
39+
return err
40+
}
41+
for _, r := range t.Relations {
42+
if err := renderAllTables(r, dir); err != nil {
43+
return err
44+
}
45+
}
46+
return nil
47+
}
48+
49+
func renderTable(table *schema.Table, dir string) error {
50+
t := template.New("").Funcs(map[string]interface{}{
51+
"formatType": formatType,
52+
"removeLineBreaks": func(text string) string {
53+
return strings.ReplaceAll(text, "\n", " ")
54+
},
55+
})
56+
t, err := t.New("").Parse(tableTmpl)
57+
if err != nil {
58+
return err
59+
}
60+
61+
outputPath := filepath.Join(dir, fmt.Sprintf("%s.md", table.Name))
62+
f, err := os.Create(outputPath)
63+
if err != nil {
64+
return fmt.Errorf("failed to create file %v: %v", outputPath, err)
65+
}
66+
defer f.Close()
67+
return t.Execute(f, table)
68+
}
69+
70+
func formatType(v schema.ValueType) string {
71+
return strings.TrimPrefix(v.String(), "Type")
72+
}

docs/source_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package docs
2+
3+
import (
4+
"context"
5+
"io/ioutil"
6+
"os"
7+
"path"
8+
"testing"
9+
10+
"github.com/cloudquery/plugin-sdk/plugins"
11+
"github.com/cloudquery/plugin-sdk/schema"
12+
"github.com/cloudquery/plugin-sdk/specs"
13+
"github.com/google/go-cmp/cmp"
14+
"github.com/rs/zerolog"
15+
)
16+
17+
type testExecutionClient struct {
18+
logger zerolog.Logger
19+
}
20+
21+
var testTables = []*schema.Table{
22+
{
23+
Name: "test_table",
24+
Description: "Description for test table",
25+
Columns: []schema.Column{
26+
{
27+
Name: "int_col",
28+
Type: schema.TypeInt,
29+
Description: "Int column",
30+
},
31+
},
32+
Relations: []*schema.Table{
33+
{
34+
Name: "relation_table",
35+
Description: "Description for relational table",
36+
Columns: []schema.Column{
37+
{
38+
Name: "string_col",
39+
Type: schema.TypeString,
40+
Description: "String column",
41+
},
42+
},
43+
},
44+
},
45+
},
46+
}
47+
48+
var expectFiles = []struct {
49+
Name string
50+
Content string
51+
}{
52+
{
53+
Name: "test_table.md",
54+
Content: `
55+
# Table: test_table
56+
Description for test table
57+
## Columns
58+
| Name | Type | Description |
59+
| ------------- | ------------- | ----- |
60+
|int_col|Int|Int column|
61+
|_cq_id|UUID|Internal CQ ID of the row|
62+
|_cq_fetch_time|Timestamp|Internal CQ row of when fetch was started (this will be the same for all rows in a single fetch)|
63+
`,
64+
},
65+
{
66+
Name: "relation_table.md",
67+
Content: `
68+
# Table: relation_table
69+
Description for relational table
70+
## Columns
71+
| Name | Type | Description |
72+
| ------------- | ------------- | ----- |
73+
|string_col|String|String column|
74+
|_cq_id|UUID|Internal CQ ID of the row|
75+
|_cq_fetch_time|Timestamp|Internal CQ row of when fetch was started (this will be the same for all rows in a single fetch)|
76+
`,
77+
},
78+
}
79+
80+
func (c *testExecutionClient) Logger() *zerolog.Logger {
81+
return &c.logger
82+
}
83+
84+
func newTestExecutionClient(context.Context, zerolog.Logger, specs.Source) (schema.ClientMeta, error) {
85+
return &testExecutionClient{}, nil
86+
}
87+
88+
func TestGenerateSourcePluginDocs(t *testing.T) {
89+
tmpdir, tmpErr := os.MkdirTemp("", "docs_test_*")
90+
if tmpErr != nil {
91+
t.Fatalf("failed to create temporary directory: %v", tmpErr)
92+
}
93+
defer os.RemoveAll(tmpdir)
94+
95+
p := plugins.NewSourcePlugin("test", "v1.0.0", testTables, newTestExecutionClient)
96+
err := GenerateSourcePluginDocs(p, tmpdir)
97+
if err != nil {
98+
t.Fatalf("unexpected error calling GenerateSourcePluginDocs: %v", err)
99+
}
100+
101+
for _, exp := range expectFiles {
102+
output := path.Join(tmpdir, exp.Name)
103+
got, err := ioutil.ReadFile(output)
104+
if err != nil {
105+
t.Fatalf("error reading %q: %v ", exp.Name, err)
106+
}
107+
108+
if diff := cmp.Diff(string(got), exp.Content); diff != "" {
109+
t.Errorf("Generate docs for %q not as expected (+got, -want): %v", exp.Name, diff)
110+
}
111+
}
112+
}

schema/md_docs.go

Lines changed: 0 additions & 59 deletions
This file was deleted.

schema/md_docs_test.go

Lines changed: 0 additions & 47 deletions
This file was deleted.

serve/doc.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ package serve
33
import (
44
"fmt"
55

6-
"github.com/cloudquery/plugin-sdk/schema"
6+
"github.com/cloudquery/plugin-sdk/docs"
77
"github.com/spf13/cobra"
88
)
99

1010
const (
11-
docShort = "Generate markdown documentation for table"
11+
docShort = "Generate markdown documentation for tables"
1212
)
1313

1414
func newCmdDoc(opts Options) *cobra.Command {
@@ -22,7 +22,7 @@ func newCmdDoc(opts Options) *cobra.Command {
2222
return fmt.Errorf("doc generation is only supported for source plugins")
2323
}
2424

25-
return schema.GenerateMarkdownTree(opts.SourcePlugin.Tables(), args[0])
25+
return docs.GenerateSourcePluginDocs(opts.SourcePlugin, args[0])
2626
},
2727
}
2828
}

0 commit comments

Comments
 (0)