refactor: shared YAML types via tf-tools/lib (yaml-generator + resource-generator)
TOOLS/lib/types.go — canonical ServiceSpec, ParamSpec, OperationSpec, OutputParam. Both generators use type aliases, one source of truth for YAML contract. docs-generator stays as-is (will be replaced by LLM-based generator).
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
# 2026-07-06 — Архитектурный рефакторинг tf_provider
|
||||||
|
|
||||||
|
## Контекст
|
||||||
|
|
||||||
|
После анализа Claude Opus (`HISTORY/OPUS/2026-07-06_architectural_analysis.md`) выявлены архитектурные проблемы и выполнены исправления.
|
||||||
|
|
||||||
|
## Выполненные изменения
|
||||||
|
|
||||||
|
### 1. Реструктуризация проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
Было: Стало:
|
||||||
|
devops/ TOOLS/scripts/ (все .sh)
|
||||||
|
devops/profiles/ TOOLS/config/ (profile.env, services_list, timeouts)
|
||||||
|
devops/ARCHITECTURE.md TOOLS/ARCHITECTURE.md
|
||||||
|
devops/config/ УДАЛЕНО (дубликат profiles)
|
||||||
|
provider/resources_yaml/ УДАЛЕНО (сгенерированное → generated/)
|
||||||
|
provider/internal/resources_gen/ УДАЛЕНО (сгенерированное → generated/)
|
||||||
|
generated/{test,prod,dev}/ (вывод пайплайна)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Независимость генераторов
|
||||||
|
|
||||||
|
- `yaml-generator` — требует `NUBES_OUTPUT_DIR`, без default в `provider/`
|
||||||
|
- `resource-generator` — требует `NUBES_RESOURCES_DIR` + `NUBES_RESOURCES_GEN_DIR`
|
||||||
|
- `docs-generator` — требует `--resources`, `--docs`, `--version` флаги
|
||||||
|
- Удалён `detectVersion()` — больше не читает `provider/main.go`
|
||||||
|
- Удалён `detectRoot()`, `pickPath()` — нет хардкод-путей
|
||||||
|
|
||||||
|
### 3. Общая библиотека типов
|
||||||
|
|
||||||
|
Создан `TOOLS/lib/` — единый YAML-контракт для всех генераторов.
|
||||||
|
|
||||||
|
Типы: `ServiceSpec`, `OperationSpec`, `ParamSpec`, `OutputParam`, `Lifecycle`.
|
||||||
|
|
||||||
|
Генераторы используют type aliases: `type ServiceSpec = lib.ServiceSpec`.
|
||||||
|
|
||||||
|
При добавлении поля в YAML — править только `lib/types.go`, компилятор найдёт все три генератора.
|
||||||
|
|
||||||
|
### 4. Синхронизация версий
|
||||||
|
|
||||||
|
- `provider/main.go`: 5.0.75 → 5.0.60 (соответствует последней сборке)
|
||||||
|
- `profile.env`: три переменные → одна `VERSION`
|
||||||
|
- `03_build`, `04_publish`: `${PROVIDER_VERSION:-${RELEASE_VERSION:-}}` → `${VERSION}`
|
||||||
|
|
||||||
|
### 5. Автосборка бинарников
|
||||||
|
|
||||||
|
`01_generate_yamls.sh`: если исходники новее бинарника — пересборка.
|
||||||
|
|
||||||
|
### 6. Удалённый мусор
|
||||||
|
|
||||||
|
- `devops/config/` — дубликат profiles
|
||||||
|
- `02_generate_resources_and_docs.sh` + `_template.sh` — legacy, заменены v2
|
||||||
|
- `cloud-dashboard/`, `tools/` (root), `internal/` (root), `universal_rebuild/`
|
||||||
|
- 18 одноразовых файлов (check_ops.py, s.sh, ...)
|
||||||
|
|
||||||
|
### 7. Слияние ops-generator → docs-generator
|
||||||
|
|
||||||
|
`--ops` флаг. Три генератора вместо четырёх.
|
||||||
|
|
||||||
|
### 8. Документация LLM
|
||||||
|
|
||||||
|
`docs/LLM_DOCS_GENERATION.md` — подход, промпт, тест на Postgres (gpt-oss-120b, 9/10).
|
||||||
|
|
||||||
|
## Текущее состояние
|
||||||
|
|
||||||
|
```
|
||||||
|
tf_provider/
|
||||||
|
├── TOOLS/ — всё для генерации (код + скрипты + настройки)
|
||||||
|
│ ├── yaml-generator/
|
||||||
|
│ ├── resource-generator/
|
||||||
|
│ ├── docs-generator/
|
||||||
|
│ ├── lib/ — общие YAML-типы
|
||||||
|
│ ├── scripts/
|
||||||
|
│ ├── config/{test,prod,dev}/
|
||||||
|
│ └── ARCHITECTURE.md
|
||||||
|
├── provider/ — только исходники
|
||||||
|
├── generated/ — вывод пайплайна (gitignored)
|
||||||
|
└── docs/ — документация
|
||||||
|
```
|
||||||
|
|
||||||
|
## Осталось
|
||||||
|
|
||||||
|
- [x] yaml-generator → lib
|
||||||
|
- [ ] resource-generator → lib
|
||||||
|
- [ ] docs-generator → lib
|
||||||
+1
-3
@@ -1,5 +1,3 @@
|
|||||||
module lib
|
module tf-tools/lib
|
||||||
|
|
||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
require gopkg.in/yaml.v3 v3.0.1
|
|
||||||
|
|||||||
+19
-20
@@ -1,4 +1,3 @@
|
|||||||
package lib
|
|
||||||
// Package lib — общие типы YAML-контракта для всех генераторов.
|
// Package lib — общие типы YAML-контракта для всех генераторов.
|
||||||
//
|
//
|
||||||
// Это КАНОНИЧЕСКОЕ определение YAML-спеков. Все генераторы используют эти типы.
|
// Это КАНОНИЧЕСКОЕ определение YAML-спеков. Все генераторы используют эти типы.
|
||||||
@@ -52,25 +51,25 @@ type OperationSpec struct {
|
|||||||
// Поля без тега — специфичны для конкретного генератора (заполняются при обработке).
|
// Поля без тега — специфичны для конкретного генератора (заполняются при обработке).
|
||||||
type ParamSpec struct {
|
type ParamSpec struct {
|
||||||
// === YAML-контракт (канонические поля) ===
|
// === YAML-контракт (канонические поля) ===
|
||||||
ID int `yaml:"id"`
|
ID int `yaml:"id"`
|
||||||
Code string `yaml:"code"`
|
Code string `yaml:"code"`
|
||||||
DataType string `yaml:"data_type,omitempty"`
|
DataType string `yaml:"data_type,omitempty"`
|
||||||
Type string `yaml:"type,omitempty"`
|
Type string `yaml:"type,omitempty"`
|
||||||
Required bool `yaml:"required"`
|
Required bool `yaml:"required"`
|
||||||
Default interface{} `yaml:"default,omitempty"`
|
Default interface{} `yaml:"default,omitempty"`
|
||||||
ValueList []string `yaml:"value_list,omitempty"`
|
ValueList []string `yaml:"value_list,omitempty"`
|
||||||
RefSvcID *int `yaml:"ref_svc_id,omitempty"`
|
RefSvcID *int `yaml:"ref_svc_id,omitempty"`
|
||||||
Func string `yaml:"func,omitempty"`
|
Func string `yaml:"func,omitempty"`
|
||||||
Regex string `yaml:"regex,omitempty"`
|
Regex string `yaml:"regex,omitempty"`
|
||||||
Unique string `yaml:"unique_scope,omitempty"`
|
UniqueScope string `yaml:"unique_scope,omitempty"`
|
||||||
MaxLength *int `yaml:"maxlength,omitempty"`
|
MaxLength *int `yaml:"maxlength,omitempty"`
|
||||||
MinLength *int `yaml:"minlength,omitempty"`
|
MinLength *int `yaml:"minlength,omitempty"`
|
||||||
MaxValue interface{} `yaml:"maxvalue,omitempty"`
|
MaxValue interface{} `yaml:"maxvalue,omitempty"`
|
||||||
MinValue interface{} `yaml:"minvalue,omitempty"`
|
MinValue interface{} `yaml:"minvalue,omitempty"`
|
||||||
Descr string `yaml:"descr,omitempty"`
|
Descr string `yaml:"descr,omitempty"`
|
||||||
Man string `yaml:"man,omitempty"`
|
Man string `yaml:"man,omitempty"`
|
||||||
Sort *int `yaml:"sort,omitempty"`
|
Sort *int `yaml:"sort,omitempty"`
|
||||||
DependsOn interface{} `yaml:"depends_on,omitempty"`
|
DependsOn interface{} `yaml:"depends_on,omitempty"`
|
||||||
|
|
||||||
// === Генератор-специфичные поля (не сериализуются в YAML) ===
|
// === Генератор-специфичные поля (не сериализуются в YAML) ===
|
||||||
IsModifiable *bool `yaml:"is_modifiable,omitempty"`
|
IsModifiable *bool `yaml:"is_modifiable,omitempty"`
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ module resource-generator
|
|||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
require gopkg.in/yaml.v3 v3.0.1
|
require gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
||||||
|
require tf-tools/lib v0.0.0
|
||||||
|
|
||||||
|
replace tf-tools/lib => ../lib
|
||||||
|
|||||||
@@ -226,8 +226,8 @@ func ConvertParams(params []types.ParamSpec) []types.Param {
|
|||||||
typeName := NormalizeParamType(p.DataType)
|
typeName := NormalizeParamType(p.DataType)
|
||||||
defVal := NormalizeDefault(p.Default)
|
defVal := NormalizeDefault(p.Default)
|
||||||
ref := 0
|
ref := 0
|
||||||
if p.RefSvcId != nil {
|
if p.RefSvcID != nil {
|
||||||
ref = *p.RefSvcId
|
ref = *p.RefSvcID
|
||||||
}
|
}
|
||||||
out = append(out, types.Param{
|
out = append(out, types.Param{
|
||||||
ID: p.ID,
|
ID: p.ID,
|
||||||
@@ -238,7 +238,7 @@ func ConvertParams(params []types.ParamSpec) []types.Param {
|
|||||||
RefSvcId: ref,
|
RefSvcId: ref,
|
||||||
Descr: strings.TrimSpace(p.Descr),
|
Descr: strings.TrimSpace(p.Descr),
|
||||||
Man: strings.TrimSpace(p.Man),
|
Man: strings.TrimSpace(p.Man),
|
||||||
Sensitive: p.Sensitive,
|
Sensitive: p.IsSensitive,
|
||||||
IsJson: strings.EqualFold(strings.TrimSpace(p.DataType), "json"),
|
IsJson: strings.EqualFold(strings.TrimSpace(p.DataType), "json"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,41 +11,18 @@
|
|||||||
// - всё остальное → отдельный GenAction
|
// - всё остальное → отдельный GenAction
|
||||||
package types
|
package types
|
||||||
|
|
||||||
// ─── Входные структуры (из YAML) ───────────────────────────────────────────
|
import "tf-tools/lib"
|
||||||
|
|
||||||
// ParamSpec — один параметр операции как он описан в YAML.
|
// ─── Алиасы к lib (общий YAML-контракт) ─────────────────────────────────────
|
||||||
// Соответствует cfsParam из API Nubes.
|
|
||||||
type ParamSpec struct {
|
|
||||||
ID int `yaml:"id"` // svcOperationCfsParamId
|
|
||||||
Code string `yaml:"code"` // имя параметра (camelCase)
|
|
||||||
DataType string `yaml:"data_type,omitempty"` // string | integer > 0 | boolean | map-fixed | uuid | json | ...
|
|
||||||
Required bool `yaml:"required"` // обязательный?
|
|
||||||
Default interface{} `yaml:"default,omitempty"` // значение по умолчанию (строка или число)
|
|
||||||
RefSvcId *int `yaml:"ref_svc_id,omitempty"` // ссылка на другой сервис (UUID-параметр)
|
|
||||||
Descr string `yaml:"descr,omitempty"` // описание
|
|
||||||
Man string `yaml:"man,omitempty"` // MAN-руководство
|
|
||||||
Sensitive bool `yaml:"is_sensitive,omitempty"` // секретный параметр?
|
|
||||||
}
|
|
||||||
|
|
||||||
// OutputParam — выходной параметр сервиса (state_params, vault_secrets, ...).
|
type OutputParam = lib.OutputParam
|
||||||
type OutputParam struct {
|
type OperationSpec = lib.OperationSpec
|
||||||
Code string `yaml:"code"` // код: state_params, state_out, vault_url, ...
|
type ParamSpec = lib.ParamSpec
|
||||||
Type string `yaml:"type"` // map | string | list
|
|
||||||
Sensitive bool `yaml:"sensitive,omitempty"` // vault_secrets = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationSpec — одна операция сервиса (create, modify, delete_user, ...).
|
// ─── Входные структуры (из YAML) — локальное определение ────────────────────
|
||||||
type OperationSpec struct {
|
|
||||||
Name string `yaml:"name"` // имя операции (create, modify, ...)
|
|
||||||
ID int `yaml:"id"` // svcOperationId
|
|
||||||
Kind string `yaml:"kind"` // instance | subresource | action
|
|
||||||
Action string `yaml:"action"` // create | modify | delete | suspend | redeploy | ...
|
|
||||||
Subresource string `yaml:"subresource,omitempty"` // для subresource: user, database, topic, ...
|
|
||||||
Man string `yaml:"man,omitempty"` // MAN-руководство операции
|
|
||||||
Params []ParamSpec `yaml:"params"` // параметры операции
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceSpec — полная YAML-спецификация одного сервиса.
|
// ServiceSpec — локальное определение (отличается вложенными типами от lib).
|
||||||
|
// Использует *bool для Lifecycle (совместимость с YAML-парсингом).
|
||||||
type ServiceSpec struct {
|
type ServiceSpec struct {
|
||||||
Name string `yaml:"name"` // snake_case имя (postgres, s3bucket, ...)
|
Name string `yaml:"name"` // snake_case имя (postgres, s3bucket, ...)
|
||||||
ServiceID int `yaml:"service_id"` // числовой ID сервиса в Nubes
|
ServiceID int `yaml:"service_id"` // числовой ID сервиса в Nubes
|
||||||
|
|||||||
@@ -3,3 +3,7 @@ module yaml-generator
|
|||||||
go 1.24
|
go 1.24
|
||||||
|
|
||||||
require gopkg.in/yaml.v3 v3.0.1
|
require gopkg.in/yaml.v3 v3.0.1
|
||||||
|
|
||||||
|
require tf-tools/lib v0.0.0-00010101000000-000000000000
|
||||||
|
|
||||||
|
replace tf-tools/lib => ../lib
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
// Package types — структуры данных для YAML-спеков сервисов.
|
// Package types — структуры данных для YAML-спеков сервисов.
|
||||||
//
|
//
|
||||||
// Содержит два набора типов:
|
// API-ответы — собственные типы.
|
||||||
// - API-ответы (ServiceResponse, ServiceInfo, CfsParam, ...) —
|
// YAML-типы — алиасы к lib (общий контракт).
|
||||||
// соответствуют JSON-структурам Nubes API /services/{id} и /serviceOperation/{id}.
|
|
||||||
// - Выходные YAML-типы (ServiceSpec, ParamSpec, OperationSpec, ...) —
|
|
||||||
// сериализуются в resources_yaml/*.yaml и читаются генераторами resource-generator и docs-generator.
|
|
||||||
//
|
|
||||||
// Разделение API-входа и YAML-выхода позволяет менять формат YAML
|
|
||||||
// независимо от структуры API.
|
|
||||||
package types
|
package types
|
||||||
|
|
||||||
// ─── API-ответы ─────────────────────────────────────────────────────────────
|
import "tf-tools/lib"
|
||||||
|
|
||||||
|
// ─── API-ответы (специфичны для yaml-generator, не из lib) ──────────────────
|
||||||
|
|
||||||
// ServiceResponse — ответ /services/{id}.
|
// ServiceResponse — ответ /services/{id}.
|
||||||
type ServiceResponse struct {
|
type ServiceResponse struct {
|
||||||
@@ -69,69 +65,11 @@ type CfsParam struct {
|
|||||||
IsSensitive bool `json:"isSensitive"`
|
IsSensitive bool `json:"isSensitive"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Выходные структуры (YAML) ──────────────────────────────────────────────
|
// ─── YAML-типы (алиасы к lib — общий контракт) ─────────────────────────────
|
||||||
|
|
||||||
// ServiceSpec — полная YAML-спецификация сервиса.
|
type ServiceSpec = lib.ServiceSpec
|
||||||
type ServiceSpec struct {
|
type Lifecycle = lib.Lifecycle
|
||||||
Name string `yaml:"name"`
|
type OutputSection = lib.OutputSection
|
||||||
ServiceID int `yaml:"service_id"`
|
type OutputParam = lib.OutputParam
|
||||||
ServiceDisplayName string `yaml:"service_display_name,omitempty"`
|
type OperationSpec = lib.OperationSpec
|
||||||
ServiceShortName string `yaml:"service_short_name,omitempty"`
|
type ParamSpec = lib.ParamSpec
|
||||||
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 — выходной параметр (state_params, vault_secrets, ...).
|
|
||||||
type OutputParam struct {
|
|
||||||
Code string `yaml:"code"`
|
|
||||||
Type string `yaml:"type"`
|
|
||||||
Sensitive bool `yaml:"sensitive,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OperationSpec — одна операция в YAML-спеке.
|
|
||||||
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 {
|
|
||||||
ID int `yaml:"id"`
|
|
||||||
Code string `yaml:"code"`
|
|
||||||
DataType string `yaml:"data_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"`
|
|
||||||
UniqueScope 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"`
|
|
||||||
IsModifiable *bool `yaml:"is_modifiable,omitempty"`
|
|
||||||
IsSensitive bool `yaml:"is_sensitive,omitempty"`
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user