diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index e6245e52..8a277b91 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -119,6 +119,12 @@ jobs: --gpgPubKeyFile=public_key.pem \ --version=${VERSION} + - name: Prepare documentation nav file + run: | + go run generator/main.go \ + docs \ + --outFile nav.md + - name: Publish provider to S3 run: | set -e @@ -138,3 +144,4 @@ jobs: ssh -o StrictHostKeyChecking=no ubuntu@${{ vars.DOCS_SERVER_IP }} 'rm -rf /srv/www/docs' echo "${{ github.ref_name }}" >docs/_version.txt 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/ diff --git a/generator/cmd/build/build.go b/generator/cmd/build/build.go index f8585bad..38f07daa 100644 --- a/generator/cmd/build/build.go +++ b/generator/cmd/build/build.go @@ -8,10 +8,11 @@ import ( "go/token" "log/slog" "os" - "os/exec" "path" "regexp" "strings" + + "tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/generator/cmd/tools" ) type Builder struct { @@ -276,20 +277,14 @@ func handleLine(line string) (string, error) { } func (b *Builder) determineRoot() error { - cmd := exec.Command("git", "rev-parse", "--show-toplevel") - out, err := cmd.Output() + root, err := tools.GetGitRoot() if err != nil { return err } - lines := strings.Split(string(out), "\n") - if lines[0] == "" { - return fmt.Errorf("unable to determine root directory from git") - } - b.rootDir = lines[0] + b.rootDir = root if b.Verbose { slog.Info(" ... using root", "dir", b.rootDir) } - return nil } diff --git a/generator/cmd/docCmd.go b/generator/cmd/docCmd.go new file mode 100644 index 00000000..77b1dc23 --- /dev/null +++ b/generator/cmd/docCmd.go @@ -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") +} diff --git a/generator/cmd/docs/templates/nav.md.gompl b/generator/cmd/docs/templates/nav.md.gompl new file mode 100644 index 00000000..3800b171 --- /dev/null +++ b/generator/cmd/docs/templates/nav.md.gompl @@ -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 }} +
+ +#### data sources + +{{- range $service.DataSources }} +- [{{ .ItemName }}]({{ .ItemLink }}) +{{- end }} + +#### resources + +{{- range $service.Resources }} +- [{{ .ItemName }}]({{ .ItemLink }}) +{{- end }} +
+ +{{ end }} diff --git a/generator/cmd/rootCmd.go b/generator/cmd/rootCmd.go index 924d8794..8f764b57 100644 --- a/generator/cmd/rootCmd.go +++ b/generator/cmd/rootCmd.go @@ -6,7 +6,7 @@ import ( func NewRootCmd() *cobra.Command { return &cobra.Command{ - Use: "build-tools", + Use: "generator", Short: "...", Long: "...", SilenceErrors: true, // Error is beautified in a custom way before being printed diff --git a/generator/cmd/tools/tools.go b/generator/cmd/tools/tools.go new file mode 100644 index 00000000..334e95ee --- /dev/null +++ b/generator/cmd/tools/tools.go @@ -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 +} diff --git a/generator/main.go b/generator/main.go index 44e11c23..464e57a0 100644 --- a/generator/main.go +++ b/generator/main.go @@ -31,6 +31,7 @@ func main() { cmd.NewPublishCmd(), cmd.NewGetFieldsCmd(), cmd.NewExamplesCmd(), + cmd.NewDocsCmd(), ) err := rootCmd.Execute() diff --git a/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go b/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go index 6d6354ea..f6971fd1 100644 --- a/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go +++ b/stackit/internal/services/sqlserverflexalpha/sqlserverflex_acc_test.go @@ -314,11 +314,14 @@ func TestAccInstanceEncryption(t *testing.T) { data.KekKeyID = os.Getenv("TF_ACC_KEK_KEY_ID") data.KekKeyRingID = os.Getenv("TF_ACC_KEK_KEY_RING_ID") verString := os.Getenv("TF_ACC_KEK_KEY_VERSION") + if verString == "" { + verString = "1" + } version, err := strconv.ParseInt(verString, 0, 32) 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") resource.ParallelTest(t, resource.TestCase{