refactor: merge ops-generator into docs-generator as --ops mode
Single binary, single go.mod — no divergence risk. Run: docs-generator --ops (or regular docs-generator for resource docs)
This commit is contained in:
+4
-6
@@ -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
|
||||
}
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// Package types — структуры данных для ops-документации.
|
||||
package types
|
||||
// Package ops — структуры данных для ops-документации (операции сервисов).
|
||||
package ops
|
||||
|
||||
// ServiceOpsSpec — YAML-спек операций сервиса.
|
||||
type ServiceOpsSpec struct {
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
module ops-generator
|
||||
|
||||
go 1.24
|
||||
|
||||
require gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -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=
|
||||
@@ -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")
|
||||
}
|
||||
Reference in New Issue
Block a user