From 6a1b243366b1681add1789b2297971399c6f0b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9CNaeel=E2=80=9D?= Date: Sun, 5 Jul 2026 10:28:59 +0400 Subject: [PATCH] refactor: merge ops-generator into docs-generator as --ops mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single binary, single go.mod — no divergence risk. Run: docs-generator --ops (or regular docs-generator for resource docs) --- .../internal/ops/ops.go} | 10 +- .../internal/ops}/types.go | 4 +- TOOLS/docs-generator/main.go | 65 +++++++++++ TOOLS/ops-generator/go.mod | 5 - TOOLS/ops-generator/go.sum | 4 - TOOLS/ops-generator/main.go | 106 ------------------ 6 files changed, 71 insertions(+), 123 deletions(-) rename TOOLS/{ops-generator/internal/docs/docs.go => docs-generator/internal/ops/ops.go} (95%) rename TOOLS/{ops-generator/internal/types => docs-generator/internal/ops}/types.go (93%) delete mode 100644 TOOLS/ops-generator/go.mod delete mode 100644 TOOLS/ops-generator/go.sum delete mode 100644 TOOLS/ops-generator/main.go diff --git a/TOOLS/ops-generator/internal/docs/docs.go b/TOOLS/docs-generator/internal/ops/ops.go similarity index 95% rename from TOOLS/ops-generator/internal/docs/docs.go rename to TOOLS/docs-generator/internal/ops/ops.go index 63b8fd8..a839916 100644 --- a/TOOLS/ops-generator/internal/docs/docs.go +++ b/TOOLS/docs-generator/internal/ops/ops.go @@ -1,13 +1,11 @@ -// Package docs — генерация ops-документации. -package docs +// Package ops — генерация per-service operations документации. +package ops import ( "encoding/json" "fmt" "os" "strings" - - "ops-generator/internal/types" ) // Entry — запись в индексе документации. @@ -20,7 +18,7 @@ type Entry struct { } // ServiceDoc генерирует Markdown-документацию операций сервиса. -func ServiceDoc(path string, spec types.ServiceOpsSpec) error { +func ServiceDoc(path string, spec ServiceOpsSpec) error { var b strings.Builder b.WriteString(fmt.Sprintf("# Operations for nubes_%s\n\n", spec.Name)) b.WriteString(fmt.Sprintf("Service ID: `%d`\n\n", spec.ServiceID)) @@ -110,7 +108,7 @@ func Name(name string) string { } // Title возвращает отображаемое имя сервиса. -func Title(spec types.ServiceOpsSpec) string { +func Title(spec ServiceOpsSpec) string { if strings.TrimSpace(spec.ServiceDisplayName) != "" { return spec.ServiceDisplayName } diff --git a/TOOLS/ops-generator/internal/types/types.go b/TOOLS/docs-generator/internal/ops/types.go similarity index 93% rename from TOOLS/ops-generator/internal/types/types.go rename to TOOLS/docs-generator/internal/ops/types.go index 33803a4..8399297 100644 --- a/TOOLS/ops-generator/internal/types/types.go +++ b/TOOLS/docs-generator/internal/ops/types.go @@ -1,5 +1,5 @@ -// Package types — структуры данных для ops-документации. -package types +// Package ops — структуры данных для ops-документации (операции сервисов). +package ops // ServiceOpsSpec — YAML-спек операций сервиса. type ServiceOpsSpec struct { diff --git a/TOOLS/docs-generator/main.go b/TOOLS/docs-generator/main.go index c419712..a36589f 100644 --- a/TOOLS/docs-generator/main.go +++ b/TOOLS/docs-generator/main.go @@ -14,6 +14,7 @@ import ( "gopkg.in/yaml.v3" + "docs-generator/internal/ops" "docs-generator/internal/types" "docs-generator/internal/writers" ) @@ -25,9 +26,16 @@ func main() { excludeFlag := flag.String("exclude", "", "Comma-separated resource names to skip") versionFlag := flag.String("version", "", "Provider version for example block") apiEndpointFlag := flag.String("api-endpoint", "https://deck-api.ngcloud.ru/api/v1/index.cfm", "API endpoint for example block") + opsFlag := flag.Bool("ops", false, "Generate per-service operations docs (resources_ops_yaml → docs/.../operations)") flag.Parse() root := detectRoot() + + // --ops mode: generate per-service operations documentation + if *opsFlag { + runOpsMode(root) + return + } resourcesDir := pickPath(*resourcesDirFlag, filepath.Join(root, "provider", "resources_yaml")) docsDir := pickPath(*docsDirFlag, filepath.Join(root, "docs", "30_registry", "resources")) servicesList := pickPath(*servicesListFlag, filepath.Join(root, "devops", "config", "services_list.txt")) @@ -171,3 +179,60 @@ func loadSpecs(dir string, ordered []types.ServiceMeta) []types.ServiceSpec { } return specs } + +// runOpsMode генерирует per-service operations документацию. +func runOpsMode(root string) { + yamlDir := pickPath(os.Getenv("NUBES_OPS_YAML_DIR"), filepath.Join(root, "provider", "resources_ops_yaml")) + docsDir := pickPath(os.Getenv("NUBES_OPS_DOCS_DIR"), filepath.Join(root, "docs", "30_registry", "resources", "operations")) + + if err := os.MkdirAll(docsDir, 0o755); err != nil { + panic(err) + } + + entries := []ops.Entry{} + + err := filepath.WalkDir(yamlDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { + return nil + } + b, err := os.ReadFile(path) + if err != nil { + return err + } + var spec ops.ServiceOpsSpec + if err := yaml.Unmarshal(b, &spec); err != nil { + return err + } + if spec.ServiceID == 0 || spec.Name == "" { + return nil + } + + fileName := fmt.Sprintf("%d_%s.md", spec.ServiceID, ops.Name(spec.Name)) + outPath := filepath.Join(docsDir, fileName) + if err := ops.ServiceDoc(outPath, spec); err != nil { + return err + } + + entries = append(entries, ops.Entry{ + ServiceID: spec.ServiceID, + Name: spec.Name, + File: fileName, + Title: ops.Title(spec), + OpCount: len(spec.Operations), + }) + return nil + }) + if err != nil { + panic(err) + } + + sort.Slice(entries, func(i, j int) bool { return entries[i].ServiceID < entries[j].ServiceID }) + if err := ops.Index(filepath.Join(docsDir, "index.md"), entries); err != nil { + panic(err) + } + + fmt.Printf("Generated %d operations docs in %s\n", len(entries), docsDir) +} diff --git a/TOOLS/ops-generator/go.mod b/TOOLS/ops-generator/go.mod deleted file mode 100644 index 2fa9b63..0000000 --- a/TOOLS/ops-generator/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module ops-generator - -go 1.24 - -require gopkg.in/yaml.v3 v3.0.1 diff --git a/TOOLS/ops-generator/go.sum b/TOOLS/ops-generator/go.sum deleted file mode 100644 index a62c313..0000000 --- a/TOOLS/ops-generator/go.sum +++ /dev/null @@ -1,4 +0,0 @@ -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/TOOLS/ops-generator/main.go b/TOOLS/ops-generator/main.go deleted file mode 100644 index afce4d4..0000000 --- a/TOOLS/ops-generator/main.go +++ /dev/null @@ -1,106 +0,0 @@ -// ops-generator — генератор per-service operations документации. -package main - -import ( - "fmt" - "io/fs" - "os" - "path/filepath" - "sort" - "strings" - - "gopkg.in/yaml.v3" - - "ops-generator/internal/docs" - "ops-generator/internal/types" -) - -func main() { - repoRoot, err := findRepoRoot() - if err != nil { - panic(err) - } - - yamlDir := strings.TrimSpace(os.Getenv("NUBES_OPS_YAML_DIR")) - if yamlDir == "" { - yamlDir = filepath.Join(repoRoot, "resources_ops_yaml") - } - - docsDir := strings.TrimSpace(os.Getenv("NUBES_OPS_DOCS_DIR")) - if docsDir == "" { - root := filepath.Dir(repoRoot) - docsDir = filepath.Join(root, "docs", "30_registry", "resources", "operations") - } - - if err := os.MkdirAll(docsDir, 0o755); err != nil { - panic(err) - } - - entries := []docs.Entry{} - - err = filepath.WalkDir(yamlDir, func(path string, d fs.DirEntry, err error) error { - if err != nil { - return err - } - if d.IsDir() || !strings.HasSuffix(d.Name(), ".yaml") { - return nil - } - b, err := os.ReadFile(path) - if err != nil { - return err - } - var spec types.ServiceOpsSpec - if err := yaml.Unmarshal(b, &spec); err != nil { - return err - } - if spec.ServiceID == 0 || spec.Name == "" { - return nil - } - - fileName := fmt.Sprintf("%d_%s.md", spec.ServiceID, docs.Name(spec.Name)) - outPath := filepath.Join(docsDir, fileName) - if err := docs.ServiceDoc(outPath, spec); err != nil { - return err - } - - entries = append(entries, docs.Entry{ - ServiceID: spec.ServiceID, - Name: spec.Name, - File: fileName, - Title: docs.Title(spec), - OpCount: len(spec.Operations), - }) - return nil - }) - if err != nil { - panic(err) - } - - sort.Slice(entries, func(i, j int) bool { return entries[i].ServiceID < entries[j].ServiceID }) - if err := docs.Index(filepath.Join(docsDir, "index.md"), entries); err != nil { - panic(err) - } - - fmt.Printf("Generated %d operations docs in %s\n", len(entries), docsDir) -} - -func findRepoRoot() (string, error) { - wd, err := os.Getwd() - if err != nil { - return "", err - } - current := wd - for i := 0; i < 8; i++ { - candidate := filepath.Join(current, "resources_yaml") - info, err := os.Stat(candidate) - if err == nil && info.IsDir() { - return current, nil - } - parent := filepath.Dir(current) - if parent == current { - break - } - current = parent - } - return "", fmt.Errorf("failed to locate provider repo root") -}