feat(gen): GenModifier расширение (DeleteStrategy/Idempotency/DeleteParams) + LoadSpecs + ValidateSpec
This commit is contained in:
@@ -22,6 +22,7 @@ import (
|
|||||||
|
|
||||||
"resource-generator/internal/params"
|
"resource-generator/internal/params"
|
||||||
"resource-generator/internal/types"
|
"resource-generator/internal/types"
|
||||||
|
"tf-tools/lib"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LoadSpecs загружает все YAML-спеки из директории и строит модели всех ресурсов.
|
// LoadSpecs загружает все YAML-спеки из директории и строит модели всех ресурсов.
|
||||||
@@ -63,12 +64,15 @@ func LoadSpecs(dir string) ([]types.GenResource, []types.GenSubresource, []types
|
|||||||
name = strings.TrimSpace(op.Action)
|
name = strings.TrimSpace(op.Action)
|
||||||
}
|
}
|
||||||
modifier := types.GenModifier{
|
modifier := types.GenModifier{
|
||||||
ServiceName: spec.Name,
|
ServiceName: spec.Name,
|
||||||
ServiceID: spec.ServiceID,
|
ServiceID: spec.ServiceID,
|
||||||
ModifierName: name,
|
ModifierName: name,
|
||||||
OperationName: op.Action,
|
OperationName: op.Action,
|
||||||
Params: ConvertParams(op.Params),
|
Params: ConvertParams(op.Params),
|
||||||
|
DeleteStrategy: normalizeDeleteStrategy(op.DeleteStrategy),
|
||||||
|
Idempotency: normalizeIdempotency(op.Idempotency),
|
||||||
}
|
}
|
||||||
|
modifier.DeleteParams = convertDeleteParams(op.DeleteParams)
|
||||||
modifier.SchemaParams = modifier.Params
|
modifier.SchemaParams = modifier.Params
|
||||||
for idx := range modifier.SchemaParams {
|
for idx := range modifier.SchemaParams {
|
||||||
if modifier.SchemaParams[idx].HasSubParams {
|
if modifier.SchemaParams[idx].HasSubParams {
|
||||||
@@ -375,6 +379,76 @@ func ValidateSpec(path string, spec *types.ServiceSpec) error {
|
|||||||
if op.Kind == "modifier" && strings.TrimSpace(op.Action) == "" {
|
if op.Kind == "modifier" && strings.TrimSpace(op.Action) == "" {
|
||||||
return fmt.Errorf("operation[%d] %q (kind=modifier): missing required field: action", i, op.Name)
|
return fmt.Errorf("operation[%d] %q (kind=modifier): missing required field: action", i, op.Name)
|
||||||
}
|
}
|
||||||
|
if op.Kind == "modifier" {
|
||||||
|
if err := validateModifierOperation(i, &op); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeDeleteStrategy возвращает каноническое значение delete_strategy.
|
||||||
|
// Пусто → noop_warn; неизвестное — как есть (валидация в ValidateSpec отклонит раньше).
|
||||||
|
func normalizeDeleteStrategy(raw string) string {
|
||||||
|
v := strings.ToLower(strings.TrimSpace(raw))
|
||||||
|
if v == "" {
|
||||||
|
return "noop_warn"
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// normalizeIdempotency возвращает каноническое значение idempotency.
|
||||||
|
// Пусто → none.
|
||||||
|
func normalizeIdempotency(raw string) string {
|
||||||
|
v := strings.ToLower(strings.TrimSpace(raw))
|
||||||
|
if v == "" {
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertDeleteParams переносит lib.DeleteParam → types.DeleteParam (wire-строки).
|
||||||
|
func convertDeleteParams(raw []lib.DeleteParam) []types.DeleteParam {
|
||||||
|
if len(raw) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
out := make([]types.DeleteParam, 0, len(raw))
|
||||||
|
for _, p := range raw {
|
||||||
|
out = append(out, types.DeleteParam{Code: strings.TrimSpace(p.Code), Value: p.Value})
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// validateModifierOperation — fail-fast для полей modifier-операции.
|
||||||
|
func validateModifierOperation(i int, op *lib.OperationSpec) error {
|
||||||
|
ds := normalizeDeleteStrategy(op.DeleteStrategy)
|
||||||
|
switch ds {
|
||||||
|
case "noop_warn", "inverse", "error":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("operation[%d] %q (kind=modifier): unknown delete_strategy %q (valid: noop_warn, inverse, error)", i, op.Name, op.DeleteStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
idem := normalizeIdempotency(op.Idempotency)
|
||||||
|
switch idem {
|
||||||
|
case "none", "check_before_run":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("operation[%d] %q (kind=modifier): unknown idempotency %q (valid: none, check_before_run)", i, op.Name, op.Idempotency)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ds == "inverse" && len(op.DeleteParams) == 0 {
|
||||||
|
return fmt.Errorf("operation[%d] %q (kind=modifier): delete_strategy=inverse требует delete_params", i, op.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// каждый delete_params.code обязан существовать среди params (по lower-code)
|
||||||
|
paramCodes := make(map[string]struct{}, len(op.Params))
|
||||||
|
for _, p := range op.Params {
|
||||||
|
paramCodes[strings.ToLower(strings.TrimSpace(p.Code))] = struct{}{}
|
||||||
|
}
|
||||||
|
for _, dp := range op.DeleteParams {
|
||||||
|
if _, ok := paramCodes[strings.ToLower(strings.TrimSpace(dp.Code))]; !ok {
|
||||||
|
return fmt.Errorf("operation[%d] %q (kind=modifier): delete_params.code %q отсутствует в params", i, op.Name, dp.Code)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,6 +158,12 @@ type GenModifier struct {
|
|||||||
OperationName string
|
OperationName string
|
||||||
Params []Param
|
Params []Param
|
||||||
SchemaParams []Param
|
SchemaParams []Param
|
||||||
|
// DeleteStrategy — noop_warn | inverse | error (нормализовано из YAML, пусто → noop_warn).
|
||||||
|
DeleteStrategy string
|
||||||
|
// Idempotency — none | check_before_run (нормализовано из YAML, пусто → none).
|
||||||
|
Idempotency string
|
||||||
|
// DeleteParams — обратные значения (wire-строки), только при DeleteStrategy==inverse.
|
||||||
|
DeleteParams []DeleteParam
|
||||||
UsesBool bool
|
UsesBool bool
|
||||||
UsesInt64 bool
|
UsesInt64 bool
|
||||||
UsesString bool
|
UsesString bool
|
||||||
@@ -167,3 +173,9 @@ type GenModifier struct {
|
|||||||
NeedsStringDefault bool
|
NeedsStringDefault bool
|
||||||
NeedsJsonPlanMod bool
|
NeedsJsonPlanMod bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DeleteParam — обратное значение параметра inverse-Delete (code → wire-строка).
|
||||||
|
type DeleteParam struct {
|
||||||
|
Code string
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user