Skip to content

Commit

Permalink
Add configuration API parameter for overriding the field names
Browse files Browse the repository at this point in the history
Signed-off-by: Sergen Yalçın <yalcinsergen97@gmail.com>
  • Loading branch information
sergenyalcin committed Jan 30, 2024
1 parent 7ba180b commit 6a2b6de
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 7 deletions.
26 changes: 26 additions & 0 deletions pkg/config/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,32 @@ type Resource struct {
// useNoForkClient indicates that a no-fork external client should
// be generated instead of the Terraform CLI-forking client.
useNoForkClient bool

// OverrideFieldNames allows to manually override the relevant field name to
// avoid possible Go struct name conflicts that may occur after Multiversion
// CRDs support. During field generation, there may be fields with the same
// struct name calculated in the same group. For example, let X and Y
// resources in the same API group have a field named Tag. This field is an
// object type and the name calculated for the struct to be generated is
// TagParameters (for spec) for both resources. To avoid this conflict, upjet
// looks at all previously created structs in the package during generation
// and if there is a conflict, it puts the Kind name of the related resource
// in front of the next one: YTagParameters.
// With Multiversion CRDs support, the above conflict scenario cannot be
// solved in the generator when the old API group is preserved and not
// regenerated, because the generator does not know the object names in the
// old version. For example, a new API version is generated for resource X. In
// this case, no generation is done for the old version of X and when Y is
// generated, the generator is not aware of the TagParameters in X and
// generates TagParameters instead of YTagParameters. Thus, two object types
// with the same name are generated in the same package. This can be overcome
// by using this configuration API.
// The key of the map indicates the name of the field that is generated and
// causes the conflict, while the value indicates the name used to avoid the
// conflict. By convention, also used in upjet, the field name is preceded by
// the value of the generated Kind, for example:
// "TagParameters": "ClusterTagParameters"
OverrideFieldNames map[string]string
}

func (r *Resource) ShouldUseNoForkClient() bool {
Expand Down
15 changes: 9 additions & 6 deletions pkg/types/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (g *Builder) buildResource(res *schema.Resource, cfg *config.Resource, tfPa
// we need to process all fields in the same order all the time.
keys := sortedKeys(res.Schema)

typeNames, err := NewTypeNames(names, g.Package)
typeNames, err := NewTypeNames(names, g.Package, cfg.OverrideFieldNames)
if err != nil {
return nil, nil, nil, err
}
Expand Down Expand Up @@ -319,20 +319,20 @@ type TypeNames struct {
}

// NewTypeNames returns a new TypeNames object.
func NewTypeNames(fieldPaths []string, pkg *types.Package) (*TypeNames, error) {
paramTypeName, err := generateTypeName("Parameters", pkg, fieldPaths...)
func NewTypeNames(fieldPaths []string, pkg *types.Package, overrideFieldNames map[string]string) (*TypeNames, error) {
paramTypeName, err := generateTypeName("Parameters", pkg, overrideFieldNames, fieldPaths...)
if err != nil {
return nil, errors.Wrapf(err, "cannot generate parameters type name of %s", fieldPath(fieldPaths))
}
paramName := types.NewTypeName(token.NoPos, pkg, paramTypeName, nil)

initTypeName, err := generateTypeName("InitParameters", pkg, fieldPaths...)
initTypeName, err := generateTypeName("InitParameters", pkg, overrideFieldNames, fieldPaths...)
if err != nil {
return nil, errors.Wrapf(err, "cannot generate init parameters type name of %s", fieldPath(fieldPaths))
}
initName := types.NewTypeName(token.NoPos, pkg, initTypeName, nil)

obsTypeName, err := generateTypeName("Observation", pkg, fieldPaths...)
obsTypeName, err := generateTypeName("Observation", pkg, overrideFieldNames, fieldPaths...)
if err != nil {
return nil, errors.Wrapf(err, "cannot generate observation type name of %s", fieldPath(fieldPaths))
}
Expand Down Expand Up @@ -447,8 +447,11 @@ func (r *resource) addReferenceFields(g *Builder, paramName *types.TypeName, fie
// generateTypeName generates a unique name for the type if its original name
// is used by another one. It adds the former field names recursively until it
// finds a unique name.
func generateTypeName(suffix string, pkg *types.Package, names ...string) (string, error) {
func generateTypeName(suffix string, pkg *types.Package, overrideFieldNames map[string]string, names ...string) (string, error) {
n := names[len(names)-1] + suffix
if v, ok := overrideFieldNames[n]; ok {
return v, nil
}
for i := len(names) - 2; i >= 0; i-- {
if pkg.Scope().Lookup(n) == nil {
return n, nil
Expand Down
2 changes: 1 addition & 1 deletion pkg/types/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ func TestBuilder_generateTypeName(t *testing.T) {
g := &Builder{
Package: p,
}
got, gotErr := generateTypeName(tc.args.suffix, g.Package, tc.args.names...)
got, gotErr := generateTypeName(tc.args.suffix, g.Package, map[string]string{}, tc.args.names...)
if diff := cmp.Diff(tc.want.err, gotErr, test.EquateErrors()); diff != "" {
t.Fatalf("generateTypeName(...): -want error, +got error: %s", diff)
}
Expand Down

0 comments on commit 6a2b6de

Please sign in to comment.