feat(generator): generate nav file #83
8 changed files with 312 additions and 12 deletions
7
.github/workflows/publish.yaml
vendored
7
.github/workflows/publish.yaml
vendored
|
|
@ -119,6 +119,12 @@ jobs:
|
||||||
--gpgPubKeyFile=public_key.pem \
|
--gpgPubKeyFile=public_key.pem \
|
||||||
--version=${VERSION}
|
--version=${VERSION}
|
||||||
|
|
||||||
|
- name: Prepare documentation nav file
|
||||||
|
run: |
|
||||||
|
go run generator/main.go \
|
||||||
|
docs \
|
||||||
|
--outFile nav.md
|
||||||
|
|
||||||
- name: Publish provider to S3
|
- name: Publish provider to S3
|
||||||
run: |
|
run: |
|
||||||
set -e
|
set -e
|
||||||
|
|
@ -138,3 +144,4 @@ jobs:
|
||||||
ssh -o StrictHostKeyChecking=no ubuntu@${{ vars.DOCS_SERVER_IP }} 'rm -rf /srv/www/docs'
|
ssh -o StrictHostKeyChecking=no ubuntu@${{ vars.DOCS_SERVER_IP }} 'rm -rf /srv/www/docs'
|
||||||
echo "${{ github.ref_name }}" >docs/_version.txt
|
echo "${{ github.ref_name }}" >docs/_version.txt
|
||||||
scp -o StrictHostKeyChecking=no -r docs ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
|
scp -o StrictHostKeyChecking=no -r docs ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
|
||||||
|
scp -o StrictHostKeyChecking=no nav.md ubuntu@${{ vars.DOCS_SERVER_IP }}:/srv/www/
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@ import (
|
||||||
"go/token"
|
"go/token"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path"
|
"path"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/tools"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Builder struct {
|
type Builder struct {
|
||||||
|
|
@ -276,20 +277,14 @@ func handleLine(line string) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) determineRoot() error {
|
func (b *Builder) determineRoot() error {
|
||||||
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
root, err := tools.GetGitRoot()
|
||||||
out, err := cmd.Output()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
lines := strings.Split(string(out), "\n")
|
b.rootDir = root
|
||||||
if lines[0] == "" {
|
|
||||||
return fmt.Errorf("unable to determine root directory from git")
|
|
||||||
}
|
|
||||||
b.rootDir = lines[0]
|
|
||||||
if b.Verbose {
|
if b.Verbose {
|
||||||
slog.Info(" ... using root", "dir", b.rootDir)
|
slog.Info(" ... using root", "dir", b.rootDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
247
generator/cmd/docCmd.go
Normal file
247
generator/cmd/docCmd.go
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/tools"
|
||||||
|
)
|
||||||
|
|
||||||
|
var outFile string
|
||||||
|
|
||||||
|
var docsCmd = &cobra.Command{
|
||||||
|
Use: "docs",
|
||||||
|
Short: "handle documentation",
|
||||||
|
Long: `...`,
|
||||||
|
RunE: func(_ *cobra.Command, _ []string) error {
|
||||||
|
// filePathStr := "stackit/internal/services/postgresflexalpha/database/datasources_gen/database_data_source_gen.go"
|
||||||
|
//
|
||||||
|
// src, err := os.ReadFile(filePathStr)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// i := interp.New(
|
||||||
|
// interp.Options{
|
||||||
|
// GoPath: "/home/henselinm/.asdf/installs/golang/1.25.6/packages",
|
||||||
|
// BuildTags: nil,
|
||||||
|
// Stdin: nil,
|
||||||
|
// Stdout: nil,
|
||||||
|
// Stderr: nil,
|
||||||
|
// Args: nil,
|
||||||
|
// Env: nil,
|
||||||
|
// SourcecodeFilesystem: nil,
|
||||||
|
// Unrestricted: false,
|
||||||
|
// },
|
||||||
|
//)
|
||||||
|
// err = i.Use(i.Symbols("github.com/hashicorp/terraform-plugin-framework-validators"))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
// err = i.Use(stdlib.Symbols)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
// _, err = i.Eval(string(src))
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// v, err := i.Eval("DatabaseDataSourceSchema")
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// bar := v.Interface().(func(string) string)
|
||||||
|
//
|
||||||
|
// r := bar("Kung")
|
||||||
|
// println(r)
|
||||||
|
//
|
||||||
|
// evalPath, err := i.EvalPath(filePathStr)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
// fmt.Printf("%+v\n", evalPath)
|
||||||
|
|
||||||
|
// _, err = i.Eval(`import "fmt"`)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
// _, err = i.Eval(`func Hallo() { fmt.Println("Hi!") }`)
|
||||||
|
// if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
|
||||||
|
// v = i.Symbols("Hallo")
|
||||||
|
|
||||||
|
// fmt.Println(v)
|
||||||
|
return workDocs()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type NavDocs struct {
|
||||||
|
PageTitle string
|
||||||
|
Description string
|
||||||
|
NavigationTitle string
|
||||||
|
ProviderTitle string
|
||||||
|
IndexFound bool
|
||||||
|
Services []Service
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
ServiceTitle string
|
||||||
|
DataSources []ResItem
|
||||||
|
Resources []ResItem
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResItem struct {
|
||||||
|
ItemName string
|
||||||
|
ItemLink string
|
||||||
|
}
|
||||||
|
|
||||||
|
func workDocs() error {
|
||||||
|
slog.Info("creating docs navigation")
|
||||||
|
root, err := tools.GetGitRoot()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("ERROR", "err", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
nav := NavDocs{
|
||||||
|
PageTitle: "STACKIT terraform provider PRIVATE-PREVIEW",
|
||||||
|
Description: "",
|
||||||
|
NavigationTitle: "Navigation",
|
||||||
|
ProviderTitle: "Provider",
|
||||||
|
IndexFound: false,
|
||||||
|
}
|
||||||
|
startPath := path.Join(root, "docs")
|
||||||
|
|
||||||
|
docs, err := os.ReadDir(startPath)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
services := make(map[string]Service)
|
||||||
|
dataSources := make(map[string][]ResItem)
|
||||||
|
resources := make(map[string][]ResItem)
|
||||||
|
|
||||||
|
for _, entry := range docs {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
if entry.Name() == "index.md" {
|
||||||
|
slog.Debug(" found provider index file")
|
||||||
|
nav.IndexFound = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slog.Debug(" found am ignored file", "fileName", entry.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if entry.Name() != "data-sources" && entry.Name() != "resources" {
|
||||||
|
slog.Error("unable to handle entry, skipping", "entry", entry.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
elements, err := os.ReadDir(path.Join(startPath, entry.Name()))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for _, res := range elements {
|
||||||
|
if res.IsDir() {
|
||||||
|
slog.Warn("found unexpected directory", "dir", res.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
re := regexp.MustCompile(`([a-z]+)_([a-z]+).md`)
|
||||||
|
matches := re.FindAllStringSubmatch(res.Name(), -1)
|
||||||
|
if matches == nil {
|
||||||
|
slog.Error("unable to identify resource", "item", res.Name())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
services[matches[0][1]] = Service{
|
||||||
|
ServiceTitle: matches[0][1],
|
||||||
|
}
|
||||||
|
switch entry.Name() {
|
||||||
|
case "data-sources":
|
||||||
|
dataSources[matches[0][1]] = append(dataSources[matches[0][1]], ResItem{
|
||||||
|
ItemName: matches[0][2],
|
||||||
|
ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
|
||||||
|
})
|
||||||
|
case "resources":
|
||||||
|
resources[matches[0][1]] = append(resources[matches[0][1]], ResItem{
|
||||||
|
ItemName: matches[0][2],
|
||||||
|
ItemLink: fmt.Sprintf("docs/%s/%s", entry.Name(), matches[0][0]),
|
||||||
|
})
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("this should never have happened")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
keys := make([]string, 0, len(services))
|
||||||
|
for k := range services {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
|
||||||
|
for _, name := range keys {
|
||||||
|
item := services[name]
|
||||||
|
item.DataSources = dataSources[name]
|
||||||
|
item.Resources = resources[name]
|
||||||
|
nav.Services = append(nav.Services, item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn := template.FuncMap{
|
||||||
|
"ucfirst": ucfirst,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.
|
||||||
|
New("nav.md.gompl").
|
||||||
|
Funcs(fn).
|
||||||
|
ParseFiles(path.Join(root, "generator", "cmd", "docs", "templates", "nav.md.gompl"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var f *os.File
|
||||||
|
f, err = os.Create(outFile)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = tmpl.Execute(f, nav)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = f.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
slog.Info("finished")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDocsCmd() *cobra.Command {
|
||||||
|
return docsCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func ucfirst(s string) string {
|
||||||
|
if s == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return strings.ToUpper(s[:1]) + s[1:]
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { // nolint: gochecknoinits
|
||||||
|
docsCmd.Flags().StringVarP(&outFile, "outFile", "o", "nav.md", "nav.md")
|
||||||
|
}
|
||||||
27
generator/cmd/docs/templates/nav.md.gompl
vendored
Normal file
27
generator/cmd/docs/templates/nav.md.gompl
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
---
|
||||||
|
page_title: {{ .PageTitle }}
|
||||||
|
description: {{ .Description }}
|
||||||
|
---
|
||||||
|
## {{ .NavigationTitle }}
|
||||||
|
### {{ .ProviderTitle }}
|
||||||
|
{{ if .IndexFound }}
|
||||||
|
[Provider](/docs/docs/index.md)
|
||||||
|
{{ end }}
|
||||||
|
{{- range $index, $service := .Services }}
|
||||||
|
### {{ $service.ServiceTitle }}
|
||||||
|
<details>
|
||||||
|
|
||||||
|
#### data sources
|
||||||
|
|
||||||
|
{{- range $service.DataSources }}
|
||||||
|
- [{{ .ItemName }}]({{ .ItemLink }})
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
#### resources
|
||||||
|
|
||||||
|
{{- range $service.Resources }}
|
||||||
|
- [{{ .ItemName }}]({{ .ItemLink }})
|
||||||
|
{{- end }}
|
||||||
|
</details>
|
||||||
|
|
||||||
|
{{ end }}
|
||||||
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
func NewRootCmd() *cobra.Command {
|
func NewRootCmd() *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "build-tools",
|
Use: "generator",
|
||||||
Short: "...",
|
Short: "...",
|
||||||
Long: "...",
|
Long: "...",
|
||||||
SilenceErrors: true, // Error is beautified in a custom way before being printed
|
SilenceErrors: true, // Error is beautified in a custom way before being printed
|
||||||
|
|
|
||||||
20
generator/cmd/tools/tools.go
Normal file
20
generator/cmd/tools/tools.go
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
package tools
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetGitRoot() (string, error) {
|
||||||
|
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
lines := strings.Split(string(out), "\n")
|
||||||
|
if lines[0] == "" {
|
||||||
|
return "", fmt.Errorf("unable to determine root directory from git")
|
||||||
|
}
|
||||||
|
return lines[0], nil
|
||||||
|
}
|
||||||
|
|
@ -31,6 +31,7 @@ func main() {
|
||||||
cmd.NewPublishCmd(),
|
cmd.NewPublishCmd(),
|
||||||
cmd.NewGetFieldsCmd(),
|
cmd.NewGetFieldsCmd(),
|
||||||
cmd.NewExamplesCmd(),
|
cmd.NewExamplesCmd(),
|
||||||
|
cmd.NewDocsCmd(),
|
||||||
)
|
)
|
||||||
|
|
||||||
err := rootCmd.Execute()
|
err := rootCmd.Execute()
|
||||||
|
|
|
||||||
|
|
@ -314,11 +314,14 @@ func TestAccInstanceEncryption(t *testing.T) {
|
||||||
data.KekKeyID = os.Getenv("TF_ACC_KEK_KEY_ID")
|
data.KekKeyID = os.Getenv("TF_ACC_KEK_KEY_ID")
|
||||||
data.KekKeyRingID = os.Getenv("TF_ACC_KEK_KEY_RING_ID")
|
data.KekKeyRingID = os.Getenv("TF_ACC_KEK_KEY_RING_ID")
|
||||||
verString := os.Getenv("TF_ACC_KEK_KEY_VERSION")
|
verString := os.Getenv("TF_ACC_KEK_KEY_VERSION")
|
||||||
|
if verString == "" {
|
||||||
|
verString = "1"
|
||||||
|
}
|
||||||
version, err := strconv.ParseInt(verString, 0, 32)
|
version, err := strconv.ParseInt(verString, 0, 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("error coverting value to uint8: %+v", verString)
|
t.Errorf("error coverting value to uint8: '%+v'", verString)
|
||||||
}
|
}
|
||||||
data.KekKeyVersion = uint8(version) //nolint:gosec // not important its a test
|
data.KekKeyVersion = uint8(version) //nolint:gosec // not important it's a test
|
||||||
data.KekServiceAccount = os.Getenv("TF_ACC_KEK_SERVICE_ACCOUNT")
|
data.KekServiceAccount = os.Getenv("TF_ACC_KEK_SERVICE_ACCOUNT")
|
||||||
|
|
||||||
resource.ParallelTest(t, resource.TestCase{
|
resource.ParallelTest(t, resource.TestCase{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue