diff --git a/cmd/grafana-app-sdk/generate.go b/cmd/grafana-app-sdk/generate.go index 3962d568a..4e5208144 100644 --- a/cmd/grafana-app-sdk/generate.go +++ b/cmd/grafana-app-sdk/generate.go @@ -49,6 +49,8 @@ Allowed values are 'group' and 'kind'. Dictates the packaging of go kinds, where generateCmd.Flags().Lookup("postprocess").NoOptDefVal = "true" generateCmd.Flags().Bool("nomanifest", false, "Whether to disable generating the app manifest") generateCmd.Flags().Lookup("nomanifest").NoOptDefVal = "true" + generateCmd.Flags().Bool("simplecopy", false, "Governs whether the generated go resource.Object implementations use a generated deep copy method, or the reflection-based resource.CopyObject. Set this to true if you are having problems with the generated deep copy code.") + generateCmd.Flags().Lookup("simplecopy").NoOptDefVal = "true" // Don't show "usage" information when an error is returned form the command, // because our errors are not command-usage-based @@ -112,6 +114,10 @@ func generateCmdFunc(cmd *cobra.Command, _ []string) error { if err != nil { return err } + simpleCopy, err := cmd.Flags().GetBool("simplecopy") + if err != nil { + return err + } var files codejen.Files switch format { @@ -136,6 +142,7 @@ func generateCmdFunc(cmd *cobra.Command, _ []string) error { CRDPath: crdPath, GroupKinds: grouping == kindGroupingGroup, GenerateManifest: !noManifest, + GenericCopy: simpleCopy, }, selectors...) if err != nil { return err @@ -190,6 +197,7 @@ type kindGenConfig struct { CRDPath string GroupKinds bool GenerateManifest bool + GenericCopy bool } //nolint:goconst @@ -317,7 +325,7 @@ func generateKindsCue(modFS fs.FS, cfg kindGenConfig, selectors ...string) (code return nil, err } // Resource - resourceFiles, err := generator.FilteredGenerate(cuekind.ResourceGenerator(true, cfg.GroupKinds), func(kind codegen.Kind) bool { + resourceFiles, err := generator.FilteredGenerate(cuekind.ResourceGenerator(true, cfg.GroupKinds, cfg.GenericCopy), func(kind codegen.Kind) bool { return kind.Properties().APIResource != nil }, selectors...) if err != nil { diff --git a/codegen/cuekind/generators.go b/codegen/cuekind/generators.go index 1ba5845a9..d8306bced 100644 --- a/codegen/cuekind/generators.go +++ b/codegen/cuekind/generators.go @@ -23,7 +23,7 @@ func CRDGenerator(outputEncoder jennies.CRDOutputEncoder, outputExtension string // If `groupKinds` is true, kinds within the same group will exist in the same package. // When combined with `versioned`, each version package will contain all kinds in the group // which have a schema for that version. -func ResourceGenerator(versioned bool, groupKinds bool) *codejen.JennyList[codegen.Kind] { +func ResourceGenerator(versioned bool, groupKinds bool, genericCopy bool) *codejen.JennyList[codegen.Kind] { g := codejen.JennyListWithNamer(namerFunc) g.Append( &jennies.GoTypes{ @@ -36,6 +36,7 @@ func ResourceGenerator(versioned bool, groupKinds bool) *codejen.JennyList[codeg OnlyUseCurrentVersion: !versioned, SubresourceTypesArePrefixed: groupKinds, GroupByKind: !groupKinds, + GenericCopy: genericCopy, }, &jennies.SchemaGenerator{ OnlyUseCurrentVersion: !versioned, diff --git a/codegen/cuekind/generators_test.go b/codegen/cuekind/generators_test.go index 7cee3b20a..8044ee2af 100644 --- a/codegen/cuekind/generators_test.go +++ b/codegen/cuekind/generators_test.go @@ -58,7 +58,7 @@ func TestResourceGenerator(t *testing.T) { require.Nil(t, err) t.Run("unversioned", func(t *testing.T) { - files, err := ResourceGenerator(false, false).Generate(kinds...) + files, err := ResourceGenerator(false, false, true).Generate(kinds...) require.Nil(t, err) // Check number of files generated // 6 -> object, spec, metadata, status, schema, codec @@ -68,7 +68,7 @@ func TestResourceGenerator(t *testing.T) { }) t.Run("group by kind", func(t *testing.T) { - files, err := ResourceGenerator(true, false).Generate(kinds...) + files, err := ResourceGenerator(true, false, false).Generate(kinds...) require.Nil(t, err) // Check number of files generated // 12 (6 -> object, spec, metadata, status, schema, codec) * 2 versions @@ -78,7 +78,7 @@ func TestResourceGenerator(t *testing.T) { }) t.Run("group by group", func(t *testing.T) { - files, err := ResourceGenerator(true, true).Generate(kinds...) + files, err := ResourceGenerator(true, true, false).Generate(kinds...) require.Nil(t, err) // Check number of files generated // 12 (6 -> object, spec, metadata, status, schema, codec) * 2 versions @@ -88,7 +88,7 @@ func TestResourceGenerator(t *testing.T) { }) t.Run("group by group, multiple kinds", func(t *testing.T) { - files, err := ResourceGenerator(true, true).Generate(sameGroupKinds...) + files, err := ResourceGenerator(true, true, false).Generate(sameGroupKinds...) require.Nil(t, err) // Check number of files generated assert.Len(t, files, 18) diff --git a/codegen/jennies/gotypes.go b/codegen/jennies/gotypes.go index a8957f6de..2e2d7fa23 100644 --- a/codegen/jennies/gotypes.go +++ b/codegen/jennies/gotypes.go @@ -192,7 +192,7 @@ func GoTypesFromCUE(v cue.Value, cfg CUEGoConfig, maxNamingDepth int) ([]byte, e if i > 0 { path = cue.MakePath(path.Selectors()[i:]...) } - return cfg.NamePrefix + strings.Trim(path.String(), "?#") + return cfg.NamePrefix + exportField(strings.Trim(path.String(), "?#")) }, } diff --git a/codegen/jennies/resourceobject.go b/codegen/jennies/resourceobject.go index 12a6bbd47..b0fa22f36 100644 --- a/codegen/jennies/resourceobject.go +++ b/codegen/jennies/resourceobject.go @@ -11,6 +11,7 @@ import ( "time" "cuelang.org/go/cue" + "github.com/getkin/kin-openapi/openapi3" "github.com/grafana/codejen" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" @@ -61,6 +62,10 @@ type ResourceObjectGenerator struct { // When GroupByKind is false, subresource types (such as spec and status) are assumed to be prefixed with the // kind name, which can be accomplished by setting GroupByKind=false on the GoTypesGenerator. GroupByKind bool + + // GenericCopy toggles whether the generated code for Copy() calls the generic resource.CopyObject method, + // or generates code to deep-copy the entire struct. + GenericCopy bool } func (*ResourceObjectGenerator) JennyName() string { @@ -158,10 +163,32 @@ func (r *ResourceObjectGenerator) generateObjectFile(kind codegen.Kind, version continue } md.Subresources = append(md.Subresources, templates.SubresourceMetadata{ - TypeName: typePrefix + exportField(it.Label()), - JSONName: it.Label(), + TypeName: typePrefix + exportField(it.Label()), + FieldName: exportField(it.Label()), + JSONName: it.Label(), }) } + if !r.GenericCopy { + // Deep copy code + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("cpy := &%s{}\n\n// Copy metadata\no.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta)\n\n// Copy Spec\n", md.TypeName)) + specCopy, err := generateCopyCodeFor(version, "spec", typePrefix) + if err != nil { + // If the generated copy code fails, fall back on the generic behavior + md.CopyCode = "return resource.CopyObject(o)" + } else { + buf.WriteString(specCopy + "\n") + for _, sr := range md.Subresources { + srCopy, err := generateCopyCodeFor(version, sr.JSONName, sr.TypeName) + if err != nil { + return nil, err + } + buf.WriteString(fmt.Sprintf("\n\n// Copy %s\n%s\n", sr.FieldName, srCopy)) + } + buf.WriteString("return cpy") + md.CopyCode = buf.String() + } + } b := bytes.Buffer{} err = templates.WriteResourceObject(md, &b) if err != nil { @@ -193,3 +220,250 @@ func goTypeFromCUEValue(value cue.Value) templates.CustomMetadataFieldGoType { } return templates.CustomMetadataFieldGoType{} } + +// functions for copy codegen +func generateCopyCodeFor(version *codegen.KindVersion, subresource, namePrefix string) (string, error) { + v := version.Schema.LookupPath(cue.MakePath(cue.Str(subresource))) + openAPIConfig := CUEOpenAPIConfig{ + Name: subresource, + Version: version.Version, + NameFunc: func(value cue.Value, path cue.Path) string { + i := 0 + for ; i < len(path.Selectors()) && i < len(v.Path().Selectors()); i++ { + if !SelEq(path.Selectors()[i], v.Path().Selectors()[i]) { + break + } + } + if i > 0 { + path = cue.MakePath(path.Selectors()[i:]...) + } + return namePrefix + exportField(strings.Trim(path.String(), "?#")) + }, + } + + yml, err := CUEValueToOAPIYAML(v, openAPIConfig) + if err != nil { + return "", err + } + + loader := openapi3.NewLoader() + oT, err := loader.LoadFromData(yml) + if err != nil { + return "", err + } + + return generateSchemaCopyCode(oT.Components, oT.Components.Schemas[subresource].Value, fmt.Sprintf("o.%s", exportField(subresource)), fmt.Sprintf("cpy.%s", exportField(subresource)), "") +} + +func generateSchemaCopyCode(root *openapi3.Components, sch *openapi3.Schema, srcName, dstName, namingPrefix string) (string, error) { + // Sort fields so that the generated code is deterministic + fields := make([]string, 0, len(sch.Properties)) + for k := range sch.Properties { + fields = append(fields, k) + } + slices.Sort(fields) + + // For each field, append the copy code generated for the SchemaRef to the string builder + buf := strings.Builder{} + for _, k := range fields { + isPointer := !slices.Contains(sch.Required, k) + str, err := generateSchemaRefCopyCode(root, k, sch.Properties[k], isPointer, srcName, dstName, namingPrefix) + if err != nil { + return "", err + } + buf.WriteString(str) + } + return buf.String(), nil +} + +func generateSchemaRefCopyCode(root *openapi3.Components, field string, schemaRef *openapi3.SchemaRef, isPointer bool, srcName, dstName, namingPrefix string) (string, error) { + // Exported field name to use for the go field names + ek := exportField(field) + + // If this SchemaRef is a reference to another schema ($ref != ""), we need to look up that schema and + // generate copy code using that schema's definition + if schemaRef.Ref != "" { + return generateRefObjectCopyCode(root, schemaRef, isPointer, fmt.Sprintf("%s.%s", srcName, ek), fmt.Sprintf("%s.%s", dstName, ek), namingPrefix) + } + + // Not a ref, examine the schema + schema := schemaRef.Value + if schema == nil { + // No $ref and no schema, this is a malformed SchemaRef object + return "", fmt.Errorf("encountered openapi3.SchemaRef with no $ref or schema: %s", schemaRef.RefPath()) + } + + // Non-ref object type (this is a map or an inline struct) + if schema.Type.Is("object") { + return generateObjectCopyCode(root, schemaRef.Value, fmt.Sprintf("%s.%s", srcName, ek), fmt.Sprintf("%s.%s", dstName, ek), namingPrefix) + } + + // Array type gets converted into a slice, which we copy the values from with the go builtin copy() function + if schema.Type.Is("array") { + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("if %s.%s != nil {\n", srcName, ek)) + buf.WriteString(fmt.Sprintf("%s.%s = make([]%s, len(%s.%s))\n", dstName, ek, oapiTypeToGoType(schema.Items, namingPrefix), srcName, ek)) + buf.WriteString(fmt.Sprintf("copy(%s.%s, %s.%s)\n", dstName, ek, srcName, ek)) + buf.WriteString("}\n") + return buf.String(), nil + } + + // Pointer to a standard type, we need to indirect it to get the value, then create a pointer to that value + if isPointer { + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("if %s.%s != nil {\n", srcName, ek)) + buf.WriteString(fmt.Sprintf("%sCopy := *%s.%s\n", field, srcName, ek)) + buf.WriteString(fmt.Sprintf("%s.%s = &%sCopy\n}\n", dstName, ek, field)) + return buf.String(), nil + } + + // Just a normal value field which we can copy with an assignment + return fmt.Sprintf("%s.%s = %s.%s\n", dstName, ek, srcName, ek), nil +} + +func generateRefObjectCopyCode(root *openapi3.Components, schemaRef *openapi3.SchemaRef, isPointer bool, srcGoField, dstGoField, namingPrefix string) (string, error) { + ref, err := lookupOpenAPISchemaRef(root, schemaRef.Ref) + if err != nil { + return "", err + } + + // Special cases for oneOf, allOf, etc. as the go codegen turns those into untyped interfaces + if len(ref.AllOf) > 0 || len(ref.AnyOf) > 0 || len(ref.OneOf) > 0 { + return fmt.Sprintf("%s = %s", srcGoField, dstGoField), nil + } + + buf := strings.Builder{} + // Generate the correct go type name from the reference and naming prefix + refTypeName := namingPrefix + strings.Join(strings.Split(schemaRef.Ref, "/")[3:], "") + if schemaRef.Value.Type.Is("object") { + if isPointer { + buf.WriteString(fmt.Sprintf("if %s != nil {\n%s = &%s{}\n", srcGoField, dstGoField, refTypeName)) + } + str, err := generateSchemaCopyCode(root, ref, srcGoField, dstGoField, namingPrefix) + if err != nil { + return "", err + } + buf.WriteString(str) + if isPointer { + buf.WriteString("}\n") + } + } + return buf.String(), nil +} + +func generateObjectCopyCode(root *openapi3.Components, schema *openapi3.Schema, srcGoField, dstGoField, namingPrefix string) (string, error) { + if schema.AdditionalProperties.Schema == nil { + // No AdditionalProperties, either an untyped map or embedded struct + if len(schema.Properties) > 0 { + // Embedded struct + buf := strings.Builder{} + for key, prop := range schema.Properties { + str, err := generateSchemaRefCopyCode(root, key, prop, !slices.Contains(schema.Required, key), srcGoField, dstGoField, namingPrefix) + if err != nil { + return "", err + } + buf.WriteString(str) + } + return buf.String(), nil + } + // map[string]any + // TODO something better? + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("%s = make(map[string]any)\n", dstGoField)) + buf.WriteString(fmt.Sprintf("for key, val := range %s {\n", srcGoField)) + buf.WriteString(fmt.Sprintf("%s[key] = val\n}\n", dstGoField)) + return buf.String(), nil + } + + // Object has AdditionalProperties, making it a typed map + // Look up value type from $ref and have it use copy code for that for each value in the map + buf := strings.Builder{} + buf.WriteString(fmt.Sprintf("%s = make(map[string]%s)\n", dstGoField, oapiTypeToGoType(schema.AdditionalProperties.Schema, namingPrefix))) + buf.WriteString(fmt.Sprintf("for key, val := range %s {\n", srcGoField)) + buf.WriteString(fmt.Sprintf("cpyVal := %s{}\n", oapiTypeToGoType(schema.AdditionalProperties.Schema, namingPrefix))) + ref, err := lookupOpenAPISchemaRef(root, schema.AdditionalProperties.Schema.Ref) + if err != nil { + return "", err + } + copyStr, err := generateSchemaCopyCode(root, ref, "val", "cpyVal", namingPrefix) + if err != nil { + return "", err + } + buf.WriteString(fmt.Sprintf("%s\n%s[key] = cpyVal\n}\n", copyStr, dstGoField)) + return buf.String(), nil +} + +// oapiTypeToGoType returns the go type based on the provided OpenAPI type. +// For object reference types, the go type is assumed to be + +func oapiTypeToGoType(v *openapi3.SchemaRef, refNamePrefix string) string { + if v.Value.Type.Is("integer") { + switch v.Value.Format { + case "int32", "int64": + return v.Value.Format + } + return "int" + } + if v.Value.Type.Is("boolean") { + return "bool" + } + if v.Value.Type.Is("object") { + if v.Ref != "" { + return refNamePrefix + strings.Join(strings.Split(v.Ref, "/")[3:], "") + } + // TODO: inline structs + return "any" + } + if v.Value.Type.Is("array") { + return "[]" + oapiTypeToGoType(v.Value.Items, refNamePrefix) + } + if v.Value.Type.Is("string") { + if v.Value.Format == "date-time" { + return "time.Time" + } + return "string" + } + if v.Value.Type.Is("number") { + if v.Value.Format == "double" { + return "float64" + } + if v.Value.Format == "float" { + return "float32" + } + } + return "any" +} + +// lookupOpenAPISchemaRef looks up and returns a Schema by its $ref path from the root openapi3.Components +// $ref paths that don't begin with '#/components/schemas' are not supported by this lookup method. +// If no schema can be found, an error is returned. +func lookupOpenAPISchemaRef(root *openapi3.Components, ref string) (*openapi3.Schema, error) { + parts := strings.Split(ref, "/") + if len(parts) < 3 || strings.Join(parts[:3], "/") != "#/components/schemas" { + return nil, fmt.Errorf("only references to #/components/schemas are supported") + } + for k, v := range root.Schemas { + if k == parts[3] { + if len(parts) > 4 { + return lookupOpenAPISchemaRefInSchema(v.Value.Properties, strings.Join(parts[3:], "/")) + } + return v.Value, nil + } + } + return nil, fmt.Errorf("reference %s not found", ref) +} + +// lookupOpenAPISchemaRefInSchema looks up and returns a Schema based on the $ref path provided, +// assuming the ref path is local to the provided schema. +// If no schema can be found, an error is returned. +func lookupOpenAPISchemaRefInSchema(sch openapi3.Schemas, ref string) (*openapi3.Schema, error) { + parts := strings.Split(ref, "/") + for k, v := range sch { + if k == parts[0] { + if len(parts) > 1 { + return lookupOpenAPISchemaRefInSchema(v.Value.Properties, strings.Join(parts[1:], "/")) + } + return v.Value, nil + } + } + return nil, fmt.Errorf("reference %s not found", ref) +} diff --git a/codegen/templates/resourceobject.tmpl b/codegen/templates/resourceobject.tmpl index 194d78653..4f01eee62 100644 --- a/codegen/templates/resourceobject.tmpl +++ b/codegen/templates/resourceobject.tmpl @@ -20,7 +20,7 @@ type {{.TypeName}} struct { metav1.ObjectMeta `json:"metadata"` Spec {{.SpecTypeName}} `json:"spec"`{{ range .Subresources }}{{ if ne .Comment "" }} // {{.Comment }}{{end}} - {{ .TypeName }} {{.TypeName}} `json:"{{.JSONName}}"`{{ end }} + {{ .FieldName }} {{.TypeName}} `json:"{{.JSONName}}"`{{ end }} } func ({{.ObjectShortName}} *{{.TypeName}}) GetSpec() any { @@ -38,14 +38,14 @@ func ({{.ObjectShortName}} *{{.TypeName}}) SetSpec(spec any) error { func ({{.ObjectShortName}} *{{.TypeName}}) GetSubresources() map[string]any { return map[string]any{ {{ range .Subresources }} - "{{.JSONName}}": {{$root.ObjectShortName}}.{{.TypeName}}, + "{{.JSONName}}": {{$root.ObjectShortName}}.{{.FieldName}}, {{ end }} } } func ({{.ObjectShortName}} *{{.TypeName}}) GetSubresource(name string) (any,bool) { switch name { {{ range .Subresources }} case"{{ .JSONName }}": - return {{$root.ObjectShortName}}.{{.TypeName}}, true + return {{$root.ObjectShortName}}.{{.FieldName}}, true {{ end }}default: return nil, false } @@ -58,7 +58,7 @@ func ({{.ObjectShortName}} *{{.TypeName}}) SetSubresource(name string, value any if !ok { return fmt.Errorf("cannot set {{.JSONName}} type %#v, not of type {{.TypeName}}", value) } - {{$root.ObjectShortName}}.{{.TypeName}} = cast + {{$root.ObjectShortName}}.{{.FieldName}} = cast return nil {{ end }}default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -184,7 +184,7 @@ func ({{$root.ObjectShortName}} *{{$root.TypeName}}) Set{{.FieldName}}({{.JSONNa {{end}} func ({{.ObjectShortName}} *{{.TypeName}}) Copy() resource.Object { - return resource.CopyObject({{.ObjectShortName}}) + {{ if eq .CopyCode "" }}return resource.CopyObject({{.ObjectShortName}}){{ else }}{{ .CopyCode }}{{ end }} } func ({{.ObjectShortName}} *{{.TypeName}}) DeepCopyObject() runtime.Object { diff --git a/codegen/templates/templates.go b/codegen/templates/templates.go index a9f3bbb57..33e3d885f 100644 --- a/codegen/templates/templates.go +++ b/codegen/templates/templates.go @@ -81,15 +81,17 @@ type ResourceObjectTemplateMetadata struct { SpecTypeName string ObjectTypeName string ObjectShortName string + CopyCode string Subresources []SubresourceMetadata CustomMetadataFields []ObjectMetadataField } // SubresourceMetadata is subresource information used in templates type SubresourceMetadata struct { - TypeName string - JSONName string - Comment string + TypeName string + FieldName string + JSONName string + Comment string } // WriteResourceObject executes the Resource Object template, and writes out the generated go code to out diff --git a/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_object_gen.go.txt index db30307da..ac2307176 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_object_gen.go.txt @@ -19,7 +19,7 @@ type CustomKind struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` Spec CustomKindSpec `json:"spec"` - CustomKindStatus CustomKindStatus `json:"status"` + Status CustomKindStatus `json:"status"` } func (o *CustomKind) GetSpec() any { @@ -37,14 +37,14 @@ func (o *CustomKind) SetSpec(spec any) error { func (o *CustomKind) GetSubresources() map[string]any { return map[string]any{ - "status": o.CustomKindStatus, + "status": o.Status, } } func (o *CustomKind) GetSubresource(name string) (any, bool) { switch name { case "status": - return o.CustomKindStatus, true + return o.Status, true default: return nil, false } @@ -57,7 +57,7 @@ func (o *CustomKind) SetSubresource(name string, value any) error { if !ok { return fmt.Errorf("cannot set status type %#v, not of type CustomKindStatus", value) } - o.CustomKindStatus = cast + o.Status = cast return nil default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -212,7 +212,38 @@ func (o *CustomKind) SetUpdatedBy(updatedBy string) { } func (o *CustomKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &CustomKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.DeprecatedField = o.Spec.DeprecatedField + cpy.Spec.Field1 = o.Spec.Field1 + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]CustomKindStatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := CustomKindStatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + + return cpy } func (o *CustomKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_status_gen.go.txt index 34deb3493..0961f2ebf 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/custom/v0_0/customkind_status_gen.go.txt @@ -7,11 +7,11 @@ const ( CustomKindOperatorStateStateSuccess CustomKindOperatorStateState = "success" ) -// Defines values for CustomKindstatusOperatorStateState. +// Defines values for CustomKindStatusOperatorStateState. const ( - CustomKindstatusOperatorStateStateFailed CustomKindstatusOperatorStateState = "failed" - CustomKindstatusOperatorStateStateInProgress CustomKindstatusOperatorStateState = "in_progress" - CustomKindstatusOperatorStateStateSuccess CustomKindstatusOperatorStateState = "success" + CustomKindStatusOperatorStateStateFailed CustomKindStatusOperatorStateState = "failed" + CustomKindStatusOperatorStateStateInProgress CustomKindStatusOperatorStateState = "in_progress" + CustomKindStatusOperatorStateStateSuccess CustomKindStatusOperatorStateState = "success" ) // CustomKindOperatorState defines model for CustomKindOperatorState. @@ -44,12 +44,12 @@ type CustomKindStatus struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]CustomKindstatusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]CustomKindStatusOperatorState `json:"operatorStates,omitempty"` } -// CustomKindstatusOperatorState defines model for CustomKindstatus.#OperatorState. +// CustomKindStatusOperatorState defines model for CustomKindStatus.#OperatorState. // +k8s:openapi-gen=true -type CustomKindstatusOperatorState struct { +type CustomKindStatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` @@ -61,10 +61,10 @@ type CustomKindstatusOperatorState struct { // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State CustomKindstatusOperatorStateState `json:"state"` + State CustomKindStatusOperatorStateState `json:"state"` } -// CustomKindstatusOperatorStateState state describes the state of the lastEvaluation. +// CustomKindStatusOperatorStateState state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. // +k8s:openapi-gen=true -type CustomKindstatusOperatorStateState string +type CustomKindStatusOperatorStateState string diff --git a/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_object_gen.go.txt index 853e58719..c7c625ad1 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_object_gen.go.txt @@ -19,7 +19,7 @@ type CustomKind struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` Spec CustomKindSpec `json:"spec"` - CustomKindStatus CustomKindStatus `json:"status"` + Status CustomKindStatus `json:"status"` } func (o *CustomKind) GetSpec() any { @@ -37,14 +37,14 @@ func (o *CustomKind) SetSpec(spec any) error { func (o *CustomKind) GetSubresources() map[string]any { return map[string]any{ - "status": o.CustomKindStatus, + "status": o.Status, } } func (o *CustomKind) GetSubresource(name string) (any, bool) { switch name { case "status": - return o.CustomKindStatus, true + return o.Status, true default: return nil, false } @@ -57,7 +57,7 @@ func (o *CustomKind) SetSubresource(name string, value any) error { if !ok { return fmt.Errorf("cannot set status type %#v, not of type CustomKindStatus", value) } - o.CustomKindStatus = cast + o.Status = cast return nil default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -244,7 +244,65 @@ func (o *CustomKind) SetUpdatedBy(updatedBy string) { } func (o *CustomKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &CustomKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.BoolField = o.Spec.BoolField + cpy.Spec.Enum = o.Spec.Enum + cpy.Spec.Field1 = o.Spec.Field1 + cpy.Spec.FloatField = o.Spec.FloatField + cpy.Spec.I32 = o.Spec.I32 + cpy.Spec.I64 = o.Spec.I64 + cpy.Spec.Inner.InnerField1 = o.Spec.Inner.InnerField1 + if o.Spec.Inner.InnerField2 != nil { + cpy.Spec.Inner.InnerField2 = make([]string, len(o.Spec.Inner.InnerField2)) + copy(cpy.Spec.Inner.InnerField2, o.Spec.Inner.InnerField2) + } + if o.Spec.Inner.InnerField3 != nil { + cpy.Spec.Inner.InnerField3 = make([]CustomKindInnerObject2, len(o.Spec.Inner.InnerField3)) + copy(cpy.Spec.Inner.InnerField3, o.Spec.Inner.InnerField3) + } + cpy.Spec.Map = make(map[string]CustomKindType2) + for key, val := range o.Spec.Map { + cpyVal := CustomKindType2{} + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.Group = val.Group + + cpy.Spec.Map[key] = cpyVal + } + cpy.Spec.Timestamp = o.Spec.Timestamp + o.Spec.Union = cpy.Spec.Union + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]CustomKindStatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := CustomKindStatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + cpy.Status.StatusField1 = o.Status.StatusField1 + + return cpy } func (o *CustomKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_status_gen.go.txt index 0d4bec6ab..0d42dd6fa 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/custom/v1_0/customkind_status_gen.go.txt @@ -7,11 +7,11 @@ const ( CustomKindOperatorStateStateSuccess CustomKindOperatorStateState = "success" ) -// Defines values for CustomKindstatusOperatorStateState. +// Defines values for CustomKindStatusOperatorStateState. const ( - CustomKindstatusOperatorStateStateFailed CustomKindstatusOperatorStateState = "failed" - CustomKindstatusOperatorStateStateInProgress CustomKindstatusOperatorStateState = "in_progress" - CustomKindstatusOperatorStateStateSuccess CustomKindstatusOperatorStateState = "success" + CustomKindStatusOperatorStateStateFailed CustomKindStatusOperatorStateState = "failed" + CustomKindStatusOperatorStateStateInProgress CustomKindStatusOperatorStateState = "in_progress" + CustomKindStatusOperatorStateStateSuccess CustomKindStatusOperatorStateState = "success" ) // CustomKindOperatorState defines model for CustomKindOperatorState. @@ -44,13 +44,13 @@ type CustomKindStatus struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]CustomKindstatusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]CustomKindStatusOperatorState `json:"operatorStates,omitempty"` StatusField1 string `json:"statusField1"` } -// CustomKindstatusOperatorState defines model for CustomKindstatus.#OperatorState. +// CustomKindStatusOperatorState defines model for CustomKindStatus.#OperatorState. // +k8s:openapi-gen=true -type CustomKindstatusOperatorState struct { +type CustomKindStatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` @@ -62,10 +62,10 @@ type CustomKindstatusOperatorState struct { // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State CustomKindstatusOperatorStateState `json:"state"` + State CustomKindStatusOperatorStateState `json:"state"` } -// CustomKindstatusOperatorStateState state describes the state of the lastEvaluation. +// CustomKindStatusOperatorStateState state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. // +k8s:openapi-gen=true -type CustomKindstatusOperatorStateState string +type CustomKindStatusOperatorStateState string diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_object_gen.go.txt index c060230eb..c94e6f5bc 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_object_gen.go.txt @@ -19,7 +19,7 @@ type TestKind2 struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` Spec TestKind2Spec `json:"spec"` - TestKind2Status TestKind2Status `json:"status"` + Status TestKind2Status `json:"status"` } func (o *TestKind2) GetSpec() any { @@ -37,14 +37,14 @@ func (o *TestKind2) SetSpec(spec any) error { func (o *TestKind2) GetSubresources() map[string]any { return map[string]any{ - "status": o.TestKind2Status, + "status": o.Status, } } func (o *TestKind2) GetSubresource(name string) (any, bool) { switch name { case "status": - return o.TestKind2Status, true + return o.Status, true default: return nil, false } @@ -57,7 +57,7 @@ func (o *TestKind2) SetSubresource(name string, value any) error { if !ok { return fmt.Errorf("cannot set status type %#v, not of type TestKind2Status", value) } - o.TestKind2Status = cast + o.Status = cast return nil default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -212,7 +212,37 @@ func (o *TestKind2) SetUpdatedBy(updatedBy string) { } func (o *TestKind2) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &TestKind2{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.TestField = o.Spec.TestField + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]TestKind2StatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := TestKind2StatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + + return cpy } func (o *TestKind2) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_status_gen.go.txt index b46b4285d..06a8172f7 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind2_status_gen.go.txt @@ -7,11 +7,11 @@ const ( TestKind2OperatorStateStateSuccess TestKind2OperatorStateState = "success" ) -// Defines values for TestKind2statusOperatorStateState. +// Defines values for TestKind2StatusOperatorStateState. const ( - TestKind2statusOperatorStateStateFailed TestKind2statusOperatorStateState = "failed" - TestKind2statusOperatorStateStateInProgress TestKind2statusOperatorStateState = "in_progress" - TestKind2statusOperatorStateStateSuccess TestKind2statusOperatorStateState = "success" + TestKind2StatusOperatorStateStateFailed TestKind2StatusOperatorStateState = "failed" + TestKind2StatusOperatorStateStateInProgress TestKind2StatusOperatorStateState = "in_progress" + TestKind2StatusOperatorStateStateSuccess TestKind2StatusOperatorStateState = "success" ) // TestKind2OperatorState defines model for TestKind2OperatorState. @@ -44,12 +44,12 @@ type TestKind2Status struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]TestKind2statusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]TestKind2StatusOperatorState `json:"operatorStates,omitempty"` } -// TestKind2statusOperatorState defines model for TestKind2status.#OperatorState. +// TestKind2StatusOperatorState defines model for TestKind2Status.#OperatorState. // +k8s:openapi-gen=true -type TestKind2statusOperatorState struct { +type TestKind2StatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` @@ -61,10 +61,10 @@ type TestKind2statusOperatorState struct { // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State TestKind2statusOperatorStateState `json:"state"` + State TestKind2StatusOperatorStateState `json:"state"` } -// TestKind2statusOperatorStateState state describes the state of the lastEvaluation. +// TestKind2StatusOperatorStateState state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. // +k8s:openapi-gen=true -type TestKind2statusOperatorStateState string +type TestKind2StatusOperatorStateState string diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_object_gen.go.txt index e01a8c659..49703fa6c 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_object_gen.go.txt @@ -19,7 +19,7 @@ type TestKind struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` Spec TestKindSpec `json:"spec"` - TestKindStatus TestKindStatus `json:"status"` + Status TestKindStatus `json:"status"` } func (o *TestKind) GetSpec() any { @@ -37,14 +37,14 @@ func (o *TestKind) SetSpec(spec any) error { func (o *TestKind) GetSubresources() map[string]any { return map[string]any{ - "status": o.TestKindStatus, + "status": o.Status, } } func (o *TestKind) GetSubresource(name string) (any, bool) { switch name { case "status": - return o.TestKindStatus, true + return o.Status, true default: return nil, false } @@ -57,7 +57,7 @@ func (o *TestKind) SetSubresource(name string, value any) error { if !ok { return fmt.Errorf("cannot set status type %#v, not of type TestKindStatus", value) } - o.TestKindStatus = cast + o.Status = cast return nil default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -212,7 +212,37 @@ func (o *TestKind) SetUpdatedBy(updatedBy string) { } func (o *TestKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &TestKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.StringField = o.Spec.StringField + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]TestKindStatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := TestKindStatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + + return cpy } func (o *TestKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_status_gen.go.txt index 05d157e43..83d3fc56a 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v1/testkind_status_gen.go.txt @@ -7,11 +7,11 @@ const ( TestKindOperatorStateStateSuccess TestKindOperatorStateState = "success" ) -// Defines values for TestKindstatusOperatorStateState. +// Defines values for TestKindStatusOperatorStateState. const ( - TestKindstatusOperatorStateStateFailed TestKindstatusOperatorStateState = "failed" - TestKindstatusOperatorStateStateInProgress TestKindstatusOperatorStateState = "in_progress" - TestKindstatusOperatorStateStateSuccess TestKindstatusOperatorStateState = "success" + TestKindStatusOperatorStateStateFailed TestKindStatusOperatorStateState = "failed" + TestKindStatusOperatorStateStateInProgress TestKindStatusOperatorStateState = "in_progress" + TestKindStatusOperatorStateStateSuccess TestKindStatusOperatorStateState = "success" ) // TestKindOperatorState defines model for TestKindOperatorState. @@ -44,12 +44,12 @@ type TestKindStatus struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]TestKindstatusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]TestKindStatusOperatorState `json:"operatorStates,omitempty"` } -// TestKindstatusOperatorState defines model for TestKindstatus.#OperatorState. +// TestKindStatusOperatorState defines model for TestKindStatus.#OperatorState. // +k8s:openapi-gen=true -type TestKindstatusOperatorState struct { +type TestKindStatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` @@ -61,10 +61,10 @@ type TestKindstatusOperatorState struct { // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State TestKindstatusOperatorStateState `json:"state"` + State TestKindStatusOperatorStateState `json:"state"` } -// TestKindstatusOperatorStateState state describes the state of the lastEvaluation. +// TestKindStatusOperatorStateState state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. // +k8s:openapi-gen=true -type TestKindstatusOperatorStateState string +type TestKindStatusOperatorStateState string diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_object_gen.go.txt index 4cce10e2f..a716901b4 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_object_gen.go.txt @@ -19,7 +19,7 @@ type TestKind struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata"` Spec TestKindSpec `json:"spec"` - TestKindStatus TestKindStatus `json:"status"` + Status TestKindStatus `json:"status"` } func (o *TestKind) GetSpec() any { @@ -37,14 +37,14 @@ func (o *TestKind) SetSpec(spec any) error { func (o *TestKind) GetSubresources() map[string]any { return map[string]any{ - "status": o.TestKindStatus, + "status": o.Status, } } func (o *TestKind) GetSubresource(name string) (any, bool) { switch name { case "status": - return o.TestKindStatus, true + return o.Status, true default: return nil, false } @@ -57,7 +57,7 @@ func (o *TestKind) SetSubresource(name string, value any) error { if !ok { return fmt.Errorf("cannot set status type %#v, not of type TestKindStatus", value) } - o.TestKindStatus = cast + o.Status = cast return nil default: return fmt.Errorf("subresource '%s' does not exist", name) @@ -212,7 +212,39 @@ func (o *TestKind) SetUpdatedBy(updatedBy string) { } func (o *TestKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &TestKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.IntField = o.Spec.IntField + cpy.Spec.StringField = o.Spec.StringField + cpy.Spec.TimeField = o.Spec.TimeField + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]TestKindStatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := TestKindStatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + + return cpy } func (o *TestKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_status_gen.go.txt index 72ffbfe5e..b992fba09 100644 --- a/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbygroup/test/v2/testkind_status_gen.go.txt @@ -7,11 +7,11 @@ const ( TestKindOperatorStateStateSuccess TestKindOperatorStateState = "success" ) -// Defines values for TestKindstatusOperatorStateState. +// Defines values for TestKindStatusOperatorStateState. const ( - TestKindstatusOperatorStateStateFailed TestKindstatusOperatorStateState = "failed" - TestKindstatusOperatorStateStateInProgress TestKindstatusOperatorStateState = "in_progress" - TestKindstatusOperatorStateStateSuccess TestKindstatusOperatorStateState = "success" + TestKindStatusOperatorStateStateFailed TestKindStatusOperatorStateState = "failed" + TestKindStatusOperatorStateStateInProgress TestKindStatusOperatorStateState = "in_progress" + TestKindStatusOperatorStateStateSuccess TestKindStatusOperatorStateState = "success" ) // TestKindOperatorState defines model for TestKindOperatorState. @@ -44,12 +44,12 @@ type TestKindStatus struct { // operatorStates is a map of operator ID to operator state evaluations. // Any operator which consumes this kind SHOULD add its state evaluation information to this field. - OperatorStates map[string]TestKindstatusOperatorState `json:"operatorStates,omitempty"` + OperatorStates map[string]TestKindStatusOperatorState `json:"operatorStates,omitempty"` } -// TestKindstatusOperatorState defines model for TestKindstatus.#OperatorState. +// TestKindStatusOperatorState defines model for TestKindStatus.#OperatorState. // +k8s:openapi-gen=true -type TestKindstatusOperatorState struct { +type TestKindStatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format DescriptiveState *string `json:"descriptiveState,omitempty"` @@ -61,10 +61,10 @@ type TestKindstatusOperatorState struct { // state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. - State TestKindstatusOperatorStateState `json:"state"` + State TestKindStatusOperatorStateState `json:"state"` } -// TestKindstatusOperatorStateState state describes the state of the lastEvaluation. +// TestKindStatusOperatorStateState state describes the state of the lastEvaluation. // It is limited to three possible states for machine evaluation. // +k8s:openapi-gen=true -type TestKindstatusOperatorStateState string +type TestKindStatusOperatorStateState string diff --git a/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_object_gen.go.txt index 20cd97215..d6859f468 100644 --- a/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_object_gen.go.txt @@ -212,7 +212,38 @@ func (o *CustomKind) SetUpdatedBy(updatedBy string) { } func (o *CustomKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &CustomKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.DeprecatedField = o.Spec.DeprecatedField + cpy.Spec.Field1 = o.Spec.Field1 + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]StatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := StatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + + return cpy } func (o *CustomKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_status_gen.go.txt index 54ca37c2d..2b9039401 100644 --- a/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbykind/customkind/v0_0/customkind_status_gen.go.txt @@ -47,7 +47,7 @@ type Status struct { OperatorStates map[string]StatusOperatorState `json:"operatorStates,omitempty"` } -// StatusOperatorState defines model for status.#OperatorState. +// StatusOperatorState defines model for Status.#OperatorState. // +k8s:openapi-gen=true type StatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format diff --git a/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_object_gen.go.txt b/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_object_gen.go.txt index aa692257b..075f59179 100644 --- a/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_object_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_object_gen.go.txt @@ -244,7 +244,65 @@ func (o *CustomKind) SetUpdatedBy(updatedBy string) { } func (o *CustomKind) Copy() resource.Object { - return resource.CopyObject(o) + cpy := &CustomKind{} + + // Copy metadata + o.ObjectMeta.DeepCopyInto(&cpy.ObjectMeta) + + // Copy Spec + cpy.Spec.BoolField = o.Spec.BoolField + cpy.Spec.Enum = o.Spec.Enum + cpy.Spec.Field1 = o.Spec.Field1 + cpy.Spec.FloatField = o.Spec.FloatField + cpy.Spec.I32 = o.Spec.I32 + cpy.Spec.I64 = o.Spec.I64 + cpy.Spec.Inner.InnerField1 = o.Spec.Inner.InnerField1 + if o.Spec.Inner.InnerField2 != nil { + cpy.Spec.Inner.InnerField2 = make([]string, len(o.Spec.Inner.InnerField2)) + copy(cpy.Spec.Inner.InnerField2, o.Spec.Inner.InnerField2) + } + if o.Spec.Inner.InnerField3 != nil { + cpy.Spec.Inner.InnerField3 = make([]InnerObject2, len(o.Spec.Inner.InnerField3)) + copy(cpy.Spec.Inner.InnerField3, o.Spec.Inner.InnerField3) + } + cpy.Spec.Map = make(map[string]Type2) + for key, val := range o.Spec.Map { + cpyVal := Type2{} + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.Group = val.Group + + cpy.Spec.Map[key] = cpyVal + } + cpy.Spec.Timestamp = o.Spec.Timestamp + o.Spec.Union = cpy.Spec.Union + + // Copy Status + cpy.Status.AdditionalFields = make(map[string]any) + for key, val := range o.Status.AdditionalFields { + cpy.Status.AdditionalFields[key] = val + } + cpy.Status.OperatorStates = make(map[string]StatusOperatorState) + for key, val := range o.Status.OperatorStates { + cpyVal := StatusOperatorState{} + if val.DescriptiveState != nil { + descriptiveStateCopy := *val.DescriptiveState + cpyVal.DescriptiveState = &descriptiveStateCopy + } + cpyVal.Details = make(map[string]any) + for key, val := range val.Details { + cpyVal.Details[key] = val + } + cpyVal.LastEvaluation = val.LastEvaluation + cpyVal.State = val.State + + cpy.Status.OperatorStates[key] = cpyVal + } + cpy.Status.StatusField1 = o.Status.StatusField1 + + return cpy } func (o *CustomKind) DeepCopyObject() runtime.Object { diff --git a/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_status_gen.go.txt b/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_status_gen.go.txt index 39c90cf7b..658a1fc7a 100644 --- a/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/groupbykind/customkind/v1_0/customkind_status_gen.go.txt @@ -48,7 +48,7 @@ type Status struct { StatusField1 string `json:"statusField1"` } -// StatusOperatorState defines model for status.#OperatorState. +// StatusOperatorState defines model for Status.#OperatorState. // +k8s:openapi-gen=true type StatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format diff --git a/codegen/testing/golden_generated/go/unversioned/customkind/customkind_status_gen.go.txt b/codegen/testing/golden_generated/go/unversioned/customkind/customkind_status_gen.go.txt index 4b88db094..4437d75b1 100644 --- a/codegen/testing/golden_generated/go/unversioned/customkind/customkind_status_gen.go.txt +++ b/codegen/testing/golden_generated/go/unversioned/customkind/customkind_status_gen.go.txt @@ -48,7 +48,7 @@ type Status struct { StatusField1 string `json:"statusField1"` } -// StatusOperatorState defines model for status.#OperatorState. +// StatusOperatorState defines model for Status.#OperatorState. // +k8s:openapi-gen=true type StatusOperatorState struct { // descriptiveState is an optional more descriptive state field which has no requirements on format diff --git a/codegen/thema/generators.go b/codegen/thema/generators.go index 5dc9ef1a0..61394c721 100644 --- a/codegen/thema/generators.go +++ b/codegen/thema/generators.go @@ -71,6 +71,7 @@ func ResourceGenerator() *codejen.JennyList[kindsys.Custom] { OnlyUseCurrentVersion: true, GroupByKind: true, SubresourceTypesArePrefixed: false, + GenericCopy: true, }, kindsysCustomToKind), codejen.AdaptOneToMany[codegen.Kind, kindsys.Custom](&jennies.SchemaGenerator{ OnlyUseCurrentVersion: true,