diff --git a/.gitignore b/.gitignore index 00676e1..7738e08 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,5 @@ __pycache__/ *.dump *.dmp docs/70_api/api_analysis/*.txt +universal_rebuild/gen_v2 +universal_rebuild/docs_template_gen_v2 diff --git a/universal_rebuild/tools/gen_v2/generate_resources_v2.go b/universal_rebuild/tools/gen_v2/generate_resources_v2.go index 886c5ea..fed2a80 100644 --- a/universal_rebuild/tools/gen_v2/generate_resources_v2.go +++ b/universal_rebuild/tools/gen_v2/generate_resources_v2.go @@ -213,6 +213,11 @@ func loadSpecs(dir string) ([]GenResource, []GenSubresource, []GenAction, error) return err } + // P1.4: fail-fast на неизвестных kind'ах и отсутствующих обязательных полях. + if err := validateSpec(path, &spec); err != nil { + return fmt.Errorf("%s: %w", path, err) + } + createParams := []Param{} modifyParams := []Param{} supportsSuspendDestroy := false @@ -2039,8 +2044,38 @@ func (r *{{ToCamel (printf "%s_%s" .ServiceName .ActionName)}}Resource) Configur } ` -// TODO: Support import by resource_name (non-UUID) by resolving instanceUid via API. -// TODO: Handle non-unique names (error or require service_id/resource_realm filter). +// knownKinds — допустимые значения Kind операций. +var knownKinds = map[string]bool{ + "instance": true, + "subresource": true, + "action": true, +} + +// validateSpec проверяет YAML-спек на обязательные поля и неизвестные kinds. +// P1.4: fail-fast — паника при неизвестном kind вместо тихого игнорирования. +func validateSpec(path string, spec *ServiceSpec) error { + if spec.Name == "" { + return fmt.Errorf("missing required field: name") + } + if spec.ServiceID <= 0 { + return fmt.Errorf("missing required field: service_id") + } + for i, op := range spec.Operations { + if op.Kind == "" { + return fmt.Errorf("operation[%d] %q: missing required field: kind", i, op.Name) + } + if !knownKinds[op.Kind] { + return fmt.Errorf("operation[%d] %q: unknown kind %q (valid: instance, subresource, action)", i, op.Name, op.Kind) + } + if op.Action == "" { + return fmt.Errorf("operation[%d] %q (kind=%s): missing required field: action", i, op.Name, op.Kind) + } + if op.Kind == "subresource" && op.Subresource == "" { + return fmt.Errorf("operation[%d] %q (kind=subresource): missing required field: subresource", i, op.Name) + } + } + return nil +} func buildSubresourceForceNewCodes(sr *GenSubresource, createOnly map[string]struct{}) map[string]struct{} { forceNew := map[string]struct{}{}