fix: architectural improvements per Opus analysis

1. Version sync: provider/main.go = profile.env = 5.0.60
2. docs-generator: removed detectVersion() — no more dependency on provider/
3. docs-generator: removed detectRoot(), pickPath() — all paths via flags/env
4. docs-generator: require --version, --resources, --docs flags
5. Auto-rebuild: yaml-generator rebuilds if sources newer than binary
6. Three version vars → one VERSION in profile.env
7. Created TOOLS/lib/ — shared YAML contract types (not yet integrated)
This commit is contained in:
“Naeel”
2026-07-06 09:25:21 +04:00
parent dd56bcda83
commit 53d03004de
11 changed files with 189 additions and 60 deletions
+2 -3
View File
@@ -3,9 +3,8 @@ NUBES_API_ENDPOINT="https://deck-api-dev.ngcloud.ru/api/v1"
TOKEN_FILE="secrets/dev.token"
# Release versions
RELEASE_VERSION="3.0.1"
PROVIDER_VERSION="3.0.1"
DOCS_VERSION="3.0.1"
# Version
VERSION="3.0.1"
# Registry/S3 settings
REGISTRY_HOST="terra.k8c.ru"
+2 -3
View File
@@ -3,9 +3,8 @@ NUBES_API_ENDPOINT="https://deck-api.ngcloud.ru/api/v1"
TOKEN_FILE="secrets/prod.token"
# Release versions
RELEASE_VERSION="2.1.23"
PROVIDER_VERSION="2.1.23"
DOCS_VERSION="2.1.23"
# Version
VERSION="2.1.23"
# Registry/S3 settings
REGISTRY_HOST="terra.k8c.ru"
+2 -4
View File
@@ -2,10 +2,8 @@
NUBES_API_ENDPOINT="https://lk-api-gateway-test.ngcloud.ru/api/v1/svc"
TOKEN_FILE="secrets/test.token"
# Release versions
RELEASE_VERSION="5.0.60"
PROVIDER_VERSION="5.0.60"
DOCS_VERSION="5.0.60"
# Version
VERSION="5.0.60"
# Docs generation — ONLY from docs_gen/<stand>/ (never from docs/)
DOCS_GEN_DIR="provider/docs_gen/test"
+21 -43
View File
@@ -7,7 +7,6 @@ import (
"io/fs"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
@@ -29,21 +28,25 @@ func main() {
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)
runOpsMode()
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"))
writers.CloudOutputByServiceID = writers.LoadCloudOutputSnapshot(root)
resourcesDir := *resourcesDirFlag
if resourcesDir == "" {
panic("--resources is required")
}
docsDir := *docsDirFlag
if docsDir == "" {
panic("--docs is required")
}
servicesList := *servicesListFlag
writers.CloudOutputByServiceID = writers.LoadCloudOutputSnapshot(*docsDirFlag)
excludeSet := toSet(*excludeFlag)
version := *versionFlag
if version == "" {
version = detectVersion(filepath.Join(root, "provider", "main.go"))
panic("--version is required")
}
apiEndpoint := *apiEndpointFlag
@@ -70,24 +73,6 @@ func main() {
writers.IndexMD(docsDir, processedSpecs)
}
func detectRoot() string {
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
if filepath.Base(cwd) == "provider" {
return filepath.Dir(cwd)
}
return cwd
}
func pickPath(value, fallback string) string {
if value != "" {
return value
}
return fallback
}
func toSet(csv string) map[string]bool {
out := map[string]bool{}
for _, item := range strings.Split(csv, ",") {
@@ -100,19 +85,6 @@ func toSet(csv string) map[string]bool {
return out
}
func detectVersion(mainPath string) string {
b, err := os.ReadFile(mainPath)
if err != nil {
return "2.x"
}
re := regexp.MustCompile(`version string\s*=\s*"([0-9.]+)"`)
match := re.FindStringSubmatch(string(b))
if len(match) > 1 {
return match[1]
}
return "2.x"
}
func loadServicesList(path string) []types.ServiceMeta {
b, err := os.ReadFile(path)
if err != nil {
@@ -181,9 +153,15 @@ func loadSpecs(dir string, ordered []types.ServiceMeta) []types.ServiceSpec {
}
// 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"))
func runOpsMode() {
yamlDir := os.Getenv("NUBES_OPS_YAML_DIR")
if yamlDir == "" {
panic("NUBES_OPS_YAML_DIR is required for --ops mode")
}
docsDir := os.Getenv("NUBES_OPS_DOCS_DIR")
if docsDir == "" {
panic("NUBES_OPS_DOCS_DIR is required for --ops mode")
}
if err := os.MkdirAll(docsDir, 0o755); err != nil {
panic(err)
+5
View File
@@ -0,0 +1,5 @@
module lib
go 1.24
require gopkg.in/yaml.v3 v3.0.1
+78
View File
@@ -0,0 +1,78 @@
package lib
// Package lib — общие типы YAML-контракта для всех генераторов.
//
// Это КАНОНИЧЕСКОЕ определение YAML-спеков. Все генераторы используют эти типы.
// При добавлении нового поля в YAML — править ЗДЕСЬ, и компилятор найдёт
// все места в генераторах, которые нужно обновить.
package lib
// ServiceSpec — полная YAML-спецификация сервиса.
type ServiceSpec struct {
Name string `yaml:"name"`
ServiceID int `yaml:"service_id"`
ServiceDisplayName string `yaml:"service_display_name,omitempty"`
ServiceShortName string `yaml:"service_short_name,omitempty"`
ServiceMan string `yaml:"service_man,omitempty"`
Lifecycle Lifecycle `yaml:"lifecycle"`
Outputs OutputSection `yaml:"outputs"`
Operations []OperationSpec `yaml:"operations"`
}
// Lifecycle — настройки жизненного цикла.
type Lifecycle struct {
SuspendOnDestroyDefault bool `yaml:"suspend_on_destroy_default"`
AdoptExistingOnCreateDefault bool `yaml:"adopt_existing_on_create_default"`
}
// OutputSection — выходные параметры.
type OutputSection struct {
Params []OutputParam `yaml:"params"`
}
// OutputParam — выходной параметр.
type OutputParam struct {
Code string `yaml:"code"`
Type string `yaml:"type"`
Sensitive bool `yaml:"sensitive,omitempty"`
}
// OperationSpec — операция сервиса.
type OperationSpec struct {
Name string `yaml:"name"`
ID int `yaml:"id"`
Kind string `yaml:"kind"`
Action string `yaml:"action"`
Subresource string `yaml:"subresource,omitempty"`
Man string `yaml:"man,omitempty"`
Params []ParamSpec `yaml:"params"`
}
// ParamSpec — параметр операции.
// Поля с тегом yaml — канонический контракт.
// Поля без тега — специфичны для конкретного генератора (заполняются при обработке).
type ParamSpec struct {
// === YAML-контракт (канонические поля) ===
ID int `yaml:"id"`
Code string `yaml:"code"`
DataType string `yaml:"data_type,omitempty"`
Type string `yaml:"type,omitempty"`
Required bool `yaml:"required"`
Default interface{} `yaml:"default,omitempty"`
ValueList []string `yaml:"value_list,omitempty"`
RefSvcID *int `yaml:"ref_svc_id,omitempty"`
Func string `yaml:"func,omitempty"`
Regex string `yaml:"regex,omitempty"`
Unique string `yaml:"unique_scope,omitempty"`
MaxLength *int `yaml:"maxlength,omitempty"`
MinLength *int `yaml:"minlength,omitempty"`
MaxValue interface{} `yaml:"maxvalue,omitempty"`
MinValue interface{} `yaml:"minvalue,omitempty"`
Descr string `yaml:"descr,omitempty"`
Man string `yaml:"man,omitempty"`
Sort *int `yaml:"sort,omitempty"`
DependsOn interface{} `yaml:"depends_on,omitempty"`
// === Генератор-специфичные поля (не сериализуются в YAML) ===
IsModifiable *bool `yaml:"is_modifiable,omitempty"`
IsSensitive bool `yaml:"is_sensitive,omitempty"`
}
+6 -4
View File
@@ -137,10 +137,12 @@ fi
rm -f "$FAILURES_FILE"
# Build service_spec_gen binary if missing.
if [[ ! -x "${ROOT_DIR}/TOOLS/bin/yaml-generator" ]]; then
echo "Building service_spec_gen..."
# Binary pre-built in TOOLS/bin/yaml-generator
# Auto-rebuild yaml-generator if sources are newer than binary
BIN="${ROOT_DIR}/TOOLS/bin/yaml-generator"
SRC="${ROOT_DIR}/TOOLS/yaml-generator/"
if [[ ! -x "$BIN" ]] || [[ "$SRC" -nt "$BIN" ]]; then
echo "Building yaml-generator..."
(cd "${ROOT_DIR}/TOOLS/yaml-generator" && go build -o "$BIN" .)
fi
# Проверка что список сервисов не пустой
@@ -100,7 +100,7 @@ load_s3cfg_registry() {
VERSION="${1:-}"
if [[ -z "$VERSION" ]]; then
VERSION="${PROVIDER_VERSION:-${RELEASE_VERSION:-}}"
VERSION="${VERSION:-}"
fi
if [[ -z "$VERSION" ]]; then
VERSION=$(grep -E 'version string' "$PROVIDER_MAIN" | sed -E 's/.*"([0-9.]+)".*/\1/')
+1 -1
View File
@@ -52,7 +52,7 @@ resolve_root_path() {
VERSION="${1:-}"
if [[ -z "$VERSION" ]]; then
VERSION="${DOCS_VERSION:-${RELEASE_VERSION:-}}"
VERSION="${VERSION:-}"
fi
if [[ -z "$VERSION" ]]; then
VERSION=$(grep -E 'version string' "$PROVIDER_MAIN" | sed -E 's/.*"([0-9.]+)".*/\1/')