v5.0.59: redeploy as git_revision, no separate action resources, gen_v2 follows ARCHITECTURE.md

This commit is contained in:
“Naeel”
2026-07-05 08:51:45 +04:00
parent a5df6dca62
commit e65bc45f5a
6 changed files with 142 additions and 34 deletions
@@ -96,6 +96,12 @@ type GenResource struct {
NeedsStringDefault bool
HasDomainParam bool
DomainServiceIDs []int
// HasRedeploy: сервис поддерживает redeploy (пересборка из git).
// Если true — в основной ресурс добавляется поле git_revision.
// При изменении git_revision вызывается redeploy вместо modify.
// Правило из ARCHITECTURE.md: только redeploy включается как inline action.
// restart, recovery, reconcile — исключены (ручные операции, только UI).
HasRedeploy bool
// NeedsJsonPlanMod: хотя бы один атрибут имеет data_type: json.
// Управляет добавлением импорта planmodifier в сгенерированный файл.
NeedsJsonPlanMod bool
@@ -277,6 +283,37 @@ func loadSpecs(dir string) ([]GenResource, []GenSubresource, []GenAction, error)
// 3) есть строковые CreateOnlyParams — шаблон генерирует EqualFold в create-only validation (ModifyPlan)
// RefSvcId=12 (S3 Object Storage) НЕ генерирует restore-блок — для S3 UUID обязателен точный формат
gr.NeedsStringsImport = hasRestoreCasingParams(gr.SchemaParams) || analyzeNeedsStrings(gr.ModifyParams) || analyzeNeedsStrings(gr.CreateOnlyRequiredParams) || analyzeNeedsStrings(gr.CreateOnlyParams)
// --- Action processing (ДО append, чтобы HasRedeploy попал в слайс) ---
// Правила из ARCHITECTURE.md:
// - redeploy → встроить как git_revision в основной ресурс
// - restart, recovery, reconcile → исключить (ручные операции, только UI)
// - всё остальное → стандартный action-ресурс (на будущее, если появятся новые)
for _, op := range spec.Operations {
if op.Kind != "action" {
continue
}
switch op.Action {
case "redeploy":
gr.HasRedeploy = true
case "restart", "recovery", "reconcile":
// Исключены
default:
act := GenAction{
ServiceName: spec.Name,
ServiceID: spec.ServiceID,
ActionName: op.Action,
OperationName: op.Name,
Params: convertParams(op.Params),
}
act.SchemaParams = act.Params
analyzeParams(&act.UsesBool, &act.UsesInt64, &act.UsesString, &act.HasDefaults, &act.NeedsBoolDefault, &act.NeedsInt64Default, &act.NeedsStringDefault, act.SchemaParams)
act.NeedsJsonPlanMod = analyzeJsonPlanMod(act.SchemaParams)
act.NeedsStringsImport = analyzeNeedsStrings(act.SchemaParams)
actions = append(actions, act)
}
}
services = append(services, gr)
srByName := map[string]*GenSubresource{}
@@ -326,24 +363,6 @@ func loadSpecs(dir string) ([]GenResource, []GenSubresource, []GenAction, error)
subs = append(subs, *sr)
}
for _, op := range spec.Operations {
if op.Kind != "action" {
continue
}
act := GenAction{
ServiceName: spec.Name,
ServiceID: spec.ServiceID,
ActionName: op.Action,
OperationName: op.Name,
Params: convertParams(op.Params),
}
act.SchemaParams = act.Params
analyzeParams(&act.UsesBool, &act.UsesInt64, &act.UsesString, &act.HasDefaults, &act.NeedsBoolDefault, &act.NeedsInt64Default, &act.NeedsStringDefault, act.SchemaParams)
act.NeedsJsonPlanMod = analyzeJsonPlanMod(act.SchemaParams)
act.NeedsStringsImport = analyzeNeedsStrings(act.SchemaParams)
actions = append(actions, act)
}
return nil
})
@@ -887,6 +906,12 @@ type {{ToCamel .Name}}Model struct {
ResourceName types.String ` + "`" + `tfsdk:"resource_name"` + "`" + `
OperationTimeout types.String ` + "`" + `tfsdk:"operation_timeout"` + "`" + `
LogLevel types.String ` + "`" + `tfsdk:"log_level"` + "`" + `
{{- if .HasRedeploy }}
// --- Redeploy support (ARCHITECTURE.md) ---
// git_revision: при изменении вызывает redeploy вместо modify.
// Опциональное поле — если не задано, modify работает как обычно.
GitRevision types.String ` + "`" + `tfsdk:"git_revision"` + "`" + `
{{- end }}
{{- range .SchemaParams }}
{{ToCamel .Code}} {{ParamType .}} ` + "`" + `tfsdk:"{{ToSnake .Code}}"` + "`" + `
{{- end }}
@@ -920,6 +945,12 @@ func (r *{{ToCamel .Name}}Resource) Schema(ctx context.Context, req resource.Sch
{{- if .IsJson }}PlanModifiers: []planmodifier.String{resources_core.JsonNormalize()},{{- end }}
},
{{- end }}
{{- if .HasRedeploy }}
// --- Redeploy support (ARCHITECTURE.md) ---
// При изменении git_revision вызывается redeploy вместо modify.
// Если не задано — modify работает без изменений.
"git_revision": schema.StringAttribute{Optional: true, MarkdownDescription: "Git revision (commit hash/tag). Changing this triggers redeploy instead of modify."},
{{- end }}
"suspend_on_destroy": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.SuspendOnDestroy}})},
"adopt_existing_on_create": schema.BoolAttribute{Optional: true, Computed: true, Default: booldefault.StaticBool({{.AdoptExistingOnCreate}})},
{{- range .OutputParams }}
@@ -1291,7 +1322,20 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd
}
{{- end }}
if !hasServiceParamChanges {
{{- if .HasRedeploy }}
// --- Redeploy support (ARCHITECTURE.md) ---
// Проверяем изменился ли git_revision.
// Если да — вызываем redeploy вместо modify.
// git_revision = "" (не задано) → обычный modify.
redeployRequested := false
if !plan.GitRevision.IsNull() && !plan.GitRevision.IsUnknown() {
if state.GitRevision.IsNull() || state.GitRevision.IsUnknown() || plan.GitRevision.ValueString() != state.GitRevision.ValueString() {
redeployRequested = true
}
}
{{- end }}
if !hasServiceParamChanges{{if .HasRedeploy}} && !redeployRequested{{end}} {
plan.ID = instanceID
{{- range .OutputParams }}
plan.{{ToCamel .Code}} = state.{{ToCamel .Code}}
@@ -1300,12 +1344,6 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd
return
}
params := map[int]string{
{{- range .ModifyParams }}
{{.ID}}: {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}},
{{- end }}
}
operationTimeout := ""
if !plan.OperationTimeout.IsNull() && !plan.OperationTimeout.IsUnknown() {
operationTimeout = plan.OperationTimeout.ValueString()
@@ -1313,10 +1351,29 @@ func (r *{{ToCamel .Name}}Resource) Update(ctx context.Context, req resource.Upd
if !plan.LogLevel.IsNull() && !plan.LogLevel.IsUnknown() {
ctx = core.CtxWithLogLevel(ctx, plan.LogLevel.ValueString())
}
if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
resp.Diagnostics.AddError("Ошибка клиента", err.Error())
return
{{- if .HasRedeploy }}
// --- Redeploy support (ARCHITECTURE.md) ---
if redeployRequested {
// Вызываем redeploy — пустой params (операция не требует CFS-параметров)
if err := r.client.RunRedeployOperation(ctx, instanceID.ValueString(), operationTimeout); err != nil {
resp.Diagnostics.AddError("Ошибка клиента", err.Error())
return
}
} else {
{{- end }}
params := map[int]string{
{{- range .ModifyParams }}
{{.ID}}: {{ParamFormat . (printf "plan.%s" (ToCamel .Code))}},
{{- end }}
}
if err := resources_core.UpdateResourceWithTimeout(ctx, r.client, instanceID.ValueString(), params, operationTimeout); err != nil {
resp.Diagnostics.AddError("Ошибка клиента", err.Error())
return
}
{{- if .HasRedeploy }}
}
{{- end }}
plan.ID = instanceID
state, diags := resources_core.RefreshResourceState(ctx, r.client, instanceID.ValueString(), {{.ServiceID}}, plan, []resources_core.StateField{