Generate type fake clients that may opt in to the use of managed fields

This commit is contained in:
Joe Betz
2024-06-24 15:56:42 -04:00
parent 75d6f02432
commit c447c38150
9 changed files with 171 additions and 98 deletions

View File

@@ -23,6 +23,8 @@ import (
"strings" "strings"
openapiv2 "github.com/google/gnostic-models/openapiv2" openapiv2 "github.com/google/gnostic-models/openapiv2"
clientgentypes "k8s.io/code-generator/cmd/client-gen/types"
"k8s.io/gengo/v2/types" "k8s.io/gengo/v2/types"
utilproto "k8s.io/kube-openapi/pkg/util/proto" utilproto "k8s.io/kube-openapi/pkg/util/proto"
"k8s.io/kube-openapi/pkg/validation/spec" "k8s.io/kube-openapi/pkg/validation/spec"
@@ -30,11 +32,7 @@ import (
type typeModels struct { type typeModels struct {
models utilproto.Models models utilproto.Models
gvkToOpenAPIType map[gvk]string gvkToOpenAPIType map[clientgentypes.GroupVersionKind]string
}
type gvk struct {
group, version, kind string
} }
func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Package) (*typeModels, error) { func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Package) (*typeModels, error) {
@@ -56,7 +54,7 @@ func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Pack
// Build a mapping from openAPI type name to GVK. // Build a mapping from openAPI type name to GVK.
// Find the root types needed by by client-go for apply. // Find the root types needed by by client-go for apply.
gvkToOpenAPIType := map[gvk]string{} gvkToOpenAPIType := map[clientgentypes.GroupVersionKind]string{}
rootDefs := map[string]spec.Schema{} rootDefs := map[string]spec.Schema{}
for _, p := range pkgTypes { for _, p := range pkgTypes {
gv := groupVersion(p) gv := groupVersion(p)
@@ -65,11 +63,7 @@ func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Pack
hasApply := tags.HasVerb("apply") || tags.HasVerb("applyStatus") hasApply := tags.HasVerb("apply") || tags.HasVerb("applyStatus")
if tags.GenerateClient && hasApply { if tags.GenerateClient && hasApply {
openAPIType := friendlyName(typeName(t)) openAPIType := friendlyName(typeName(t))
gvk := gvk{ gvk := gv.WithKind(clientgentypes.Kind(t.Name.Name))
group: gv.Group.String(),
version: gv.Version.String(),
kind: t.Name.Name,
}
rootDefs[openAPIType] = openAPISchema.Definitions[openAPIType] rootDefs[openAPIType] = openAPISchema.Definitions[openAPIType]
gvkToOpenAPIType[gvk] = openAPIType gvkToOpenAPIType[gvk] = openAPIType
} }
@@ -94,7 +88,7 @@ func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Pack
var emptyModels = &typeModels{ var emptyModels = &typeModels{
models: &utilproto.Definitions{}, models: &utilproto.Definitions{},
gvkToOpenAPIType: map[gvk]string{}, gvkToOpenAPIType: map[clientgentypes.GroupVersionKind]string{},
} }
func toValidatedModels(openAPISchema *spec.Swagger) (utilproto.Models, error) { func toValidatedModels(openAPISchema *spec.Swagger) (utilproto.Models, error) {

View File

@@ -86,10 +86,14 @@ func GetTargets(context *generator.Context, args *args.Args) []generator.Target
klog.V(5).Infof("skipping type %v because does not have ObjectMeta", t) klog.V(5).Infof("skipping type %v because does not have ObjectMeta", t)
continue continue
} }
gvk := gv.WithKind(clientgentypes.Kind(t.Name.Name))
openAPIName := typeModels.gvkToOpenAPIType[gvk]
if typePkg, ok := refs[t.Name]; ok { if typePkg, ok := refs[t.Name]; ok {
toGenerate = append(toGenerate, applyConfig{ toGenerate = append(toGenerate, applyConfig{
Type: t, Type: t,
ApplyConfiguration: types.Ref(typePkg, t.Name.Name+ApplyConfigurationTypeSuffix), ApplyConfiguration: types.Ref(typePkg, t.Name.Name+ApplyConfigurationTypeSuffix),
OpenAPIName: openAPIName,
}) })
} }
} }
@@ -132,7 +136,7 @@ func GetTargets(context *generator.Context, args *args.Args) []generator.Target
// generate ForKind() utility function // generate ForKind() utility function
targetList = append(targetList, targetList = append(targetList,
targetForUtils(args.OutputDir, args.OutputPkg, targetForUtils(args.OutputDir, args.OutputPkg,
boilerplate, groupVersions, applyConfigsForGroupVersion, groupGoNames)) boilerplate, groupVersions, applyConfigsForGroupVersion, groupGoNames, typeModels))
// generate internal embedded schema, required for generated Extract functions // generate internal embedded schema, required for generated Extract functions
targetList = append(targetList, targetList = append(targetList,
targetForInternal(args.OutputDir, args.OutputPkg, targetForInternal(args.OutputDir, args.OutputPkg,
@@ -171,11 +175,7 @@ func targetForApplyConfigurationsPackage(outputDirBase, outputPkgBase, pkgSubdir
GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) {
for _, toGenerate := range typesToGenerate { for _, toGenerate := range typesToGenerate {
var openAPIType *string var openAPIType *string
gvk := gvk{ gvk := gv.WithKind(clientgentypes.Kind(toGenerate.Type.Name.Name))
group: gv.Group.String(),
version: gv.Version.String(),
kind: toGenerate.Type.Name.Name,
}
if v, ok := models.gvkToOpenAPIType[gvk]; ok { if v, ok := models.gvkToOpenAPIType[gvk]; ok {
openAPIType = &v openAPIType = &v
} }
@@ -198,7 +198,8 @@ func targetForApplyConfigurationsPackage(outputDirBase, outputPkgBase, pkgSubdir
} }
} }
func targetForUtils(outputDirBase, outputPkgBase string, boilerplate []byte, groupVersions map[string]clientgentypes.GroupVersions, applyConfigsForGroupVersion map[clientgentypes.GroupVersion][]applyConfig, groupGoNames map[string]string) generator.Target { func targetForUtils(outputDirBase, outputPkgBase string, boilerplate []byte, groupVersions map[string]clientgentypes.GroupVersions,
applyConfigsForGroupVersion map[clientgentypes.GroupVersion][]applyConfig, groupGoNames map[string]string, models *typeModels) generator.Target {
return &generator.SimpleTarget{ return &generator.SimpleTarget{
PkgName: path.Base(outputPkgBase), PkgName: path.Base(outputPkgBase),
PkgPath: outputPkgBase, PkgPath: outputPkgBase,
@@ -214,6 +215,7 @@ func targetForUtils(outputDirBase, outputPkgBase string, boilerplate []byte, gro
groupVersions: groupVersions, groupVersions: groupVersions,
typesForGroupVersion: applyConfigsForGroupVersion, typesForGroupVersion: applyConfigsForGroupVersion,
groupGoNames: groupGoNames, groupGoNames: groupGoNames,
typeModels: models,
}) })
return generators return generators
}, },

View File

@@ -19,15 +19,17 @@ package generators
import "k8s.io/gengo/v2/types" import "k8s.io/gengo/v2/types"
var ( var (
applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration") applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration")
groupVersionKind = types.Ref("k8s.io/apimachinery/pkg/runtime/schema", "GroupVersionKind") groupVersionKind = types.Ref("k8s.io/apimachinery/pkg/runtime/schema", "GroupVersionKind")
typeMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "TypeMeta") typeMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "TypeMeta")
objectMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "ObjectMeta") objectMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "ObjectMeta")
rawExtension = types.Ref("k8s.io/apimachinery/pkg/runtime", "RawExtension") rawExtension = types.Ref("k8s.io/apimachinery/pkg/runtime", "RawExtension")
unknown = types.Ref("k8s.io/apimachinery/pkg/runtime", "Unknown") unknown = types.Ref("k8s.io/apimachinery/pkg/runtime", "Unknown")
extractInto = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "ExtractInto") extractInto = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "ExtractInto")
smdNewParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "NewParser") runtimeScheme = types.Ref("k8s.io/apimachinery/pkg/runtime", "Scheme")
smdParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "Parser") smdNewParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "NewParser")
yamlObject = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "YAMLObject") smdParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "Parser")
yamlUnmarshal = types.Ref("gopkg.in/yaml.v2", "Unmarshal") testingTypeConverter = types.Ref("k8s.io/client-go/testing", "TypeConverter")
yamlObject = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "YAMLObject")
yamlUnmarshal = types.Ref("gopkg.in/yaml.v2", "Unmarshal")
) )

View File

@@ -18,6 +18,7 @@ package generators
import ( import (
"io" "io"
"path"
"sort" "sort"
"strings" "strings"
@@ -37,6 +38,7 @@ type utilGenerator struct {
groupGoNames map[string]string groupGoNames map[string]string
typesForGroupVersion map[clientgentypes.GroupVersion][]applyConfig typesForGroupVersion map[clientgentypes.GroupVersion][]applyConfig
filtered bool filtered bool
typeModels *typeModels
} }
var _ generator.Generator = &utilGenerator{} var _ generator.Generator = &utilGenerator{}
@@ -92,6 +94,7 @@ func (v versionSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] }
type applyConfig struct { type applyConfig struct {
Type *types.Type Type *types.Type
ApplyConfiguration *types.Type ApplyConfiguration *types.Type
OpenAPIName string
} }
type applyConfigSort []applyConfig type applyConfigSort []applyConfig
@@ -133,16 +136,26 @@ func (g *utilGenerator) GenerateType(c *generator.Context, _ *types.Type, w io.W
sort.Sort(groupSort(groups)) sort.Sort(groupSort(groups))
m := map[string]interface{}{ m := map[string]interface{}{
"applyConfiguration": applyConfiguration,
"groups": groups, "groups": groups,
"internalParser": types.Ref(path.Join(g.outputPackage, "internal"), "Parser"),
"runtimeScheme": runtimeScheme,
"schemeGVs": schemeGVs, "schemeGVs": schemeGVs,
"schemaGroupVersionKind": groupVersionKind, "schemaGroupVersionKind": groupVersionKind,
"applyConfiguration": applyConfiguration, "testingTypeConverter": testingTypeConverter,
} }
sw.Do(forKindFunc, m) sw.Do(forKindFunc, m)
sw.Do(typeConverter, m)
return sw.Error() return sw.Error()
} }
var typeConverter = `
func NewTypeConverter(scheme *{{.runtimeScheme|raw}}) *{{.testingTypeConverter|raw}} {
return &{{.testingTypeConverter|raw}}{Scheme: scheme, TypeResolver: {{.internalParser|raw}}()}
}
`
var forKindFunc = ` var forKindFunc = `
// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no // ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no
// apply configuration type exists for the given GroupVersionKind. // apply configuration type exists for the given GroupVersionKind.

View File

@@ -405,7 +405,7 @@ func GetTargets(context *generator.Context, args *args.Args) []generator.Target
targetForScheme(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate)) targetForScheme(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate))
if args.FakeClient { if args.FakeClient {
targetList = append(targetList, targetList = append(targetList,
fake.TargetForClientset(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate)) fake.TargetForClientset(args, clientsetDir, clientsetPkg, args.ApplyConfigurationPackage, groupGoNames, boilerplate))
} }
// If --clientset-only=true, we don't regenerate the individual typed clients. // If --clientset-only=true, we don't regenerate the individual typed clients.

View File

@@ -88,7 +88,7 @@ func TargetForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clie
} }
} }
func TargetForClientset(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target { func TargetForClientset(args *args.Args, clientsetDir, clientsetPkg string, applyConfigurationPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target {
return &generator.SimpleTarget{ return &generator.SimpleTarget{
// TODO: we'll generate fake clientset for different release in the future. // TODO: we'll generate fake clientset for different release in the future.
// Package name and path are hard coded for now. // Package name and path are hard coded for now.
@@ -108,11 +108,12 @@ func TargetForClientset(args *args.Args, clientsetDir, clientsetPkg string, grou
GoGenerator: generator.GoGenerator{ GoGenerator: generator.GoGenerator{
OutputFilename: "clientset_generated.go", OutputFilename: "clientset_generated.go",
}, },
groups: args.Groups, groups: args.Groups,
groupGoNames: groupGoNames, groupGoNames: groupGoNames,
fakeClientsetPackage: clientsetPkg, fakeClientsetPackage: clientsetPkg,
imports: generator.NewImportTracker(), imports: generator.NewImportTracker(),
realClientsetPackage: clientsetPkg, realClientsetPackage: clientsetPkg,
applyConfigurationPackage: applyConfigurationPkg,
}, },
&scheme.GenScheme{ &scheme.GenScheme{
GoGenerator: generator.GoGenerator{ GoGenerator: generator.GoGenerator{

View File

@@ -37,7 +37,8 @@ type genClientset struct {
imports namer.ImportTracker imports namer.ImportTracker
clientsetGenerated bool clientsetGenerated bool
// the import path of the generated real clientset. // the import path of the generated real clientset.
realClientsetPackage string // must be a Go import-path realClientsetPackage string // must be a Go import-path
applyConfigurationPackage string
} }
var _ generator.Generator = &genClientset{} var _ generator.Generator = &genClientset{}
@@ -76,12 +77,15 @@ func (g *genClientset) Imports(c *generator.Context) (imports []string) {
"fakediscovery \"k8s.io/client-go/discovery/fake\"", "fakediscovery \"k8s.io/client-go/discovery/fake\"",
"k8s.io/apimachinery/pkg/runtime", "k8s.io/apimachinery/pkg/runtime",
"k8s.io/apimachinery/pkg/watch", "k8s.io/apimachinery/pkg/watch",
"k8s.io/apimachinery/pkg/api/meta/testrestmapper",
) )
return return
} }
func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error {
generateApply := len(g.applyConfigurationPackage) > 0
// TODO: We actually don't need any type information to generate the clientset, // TODO: We actually don't need any type information to generate the clientset,
// perhaps we can adapt the go2ild framework to this kind of usage. // perhaps we can adapt the go2ild framework to this kind of usage.
sw := generator.NewSnippetWriter(w, c, "$", "$") sw := generator.NewSnippetWriter(w, c, "$", "$")
@@ -89,6 +93,13 @@ func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Wr
allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames) allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames)
sw.Do(common, nil) sw.Do(common, nil)
if generateApply {
sw.Do(managedFieldsClientset, map[string]any{
"newTypeConverter": types.Ref(g.applyConfigurationPackage, "NewTypeConverter"),
})
}
sw.Do(checkImpl, nil) sw.Do(checkImpl, nil)
for _, group := range allGroups { for _, group := range allGroups {
@@ -107,11 +118,50 @@ func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Wr
} }
// This part of code is version-independent, unchanging. // This part of code is version-independent, unchanging.
var common = `
// NewSimpleClientset returns a clientset that will respond with the provided objects. var managedFieldsClientset = `
// NewClientset returns a clientset that will respond with the provided objects.
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, // It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any validations and/or defaults. It shouldn't be considered a replacement // without applying any validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests. // for a real clientset and is mostly useful in simple unit tests.
func NewClientset(objects ...runtime.Object) *Clientset {
o := testing.NewFieldManagedObjectTracker(
scheme,
codecs.UniversalDecoder(),
$.newTypeConverter|raw$(scheme),
)
for _, obj := range objects {
if err := o.Add(obj); err != nil {
panic(err)
}
}
cs := &Clientset{tracker: o}
cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake}
cs.AddReactor("*", "*", testing.ObjectReaction(o))
cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) {
gvr := action.GetResource()
ns := action.GetNamespace()
watch, err := o.Watch(gvr, ns)
if err != nil {
return false, nil, err
}
return true, watch, nil
})
return cs
}
`
var common = `
// NewSimpleClientset returns a clientset that will respond with the provided objects.
// It's backed by a very simple object tracker that processes creates, updates and deletions as-is,
// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement
// for a real clientset and is mostly useful in simple unit tests.
//
// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves
// server side apply testing. NewClientset is only available when apply configurations are generated (e.g.
// via --with-applyconfig).
func NewSimpleClientset(objects ...runtime.Object) *Clientset { func NewSimpleClientset(objects ...runtime.Object) *Clientset {
o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder())
for _, obj := range objects { for _, obj := range objects {

View File

@@ -23,6 +23,7 @@ import (
"golang.org/x/text/cases" "golang.org/x/text/cases"
"golang.org/x/text/language" "golang.org/x/text/language"
"k8s.io/gengo/v2/generator" "k8s.io/gengo/v2/generator"
"k8s.io/gengo/v2/namer" "k8s.io/gengo/v2/namer"
"k8s.io/gengo/v2/types" "k8s.io/gengo/v2/types"
@@ -123,33 +124,31 @@ func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.
"watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}),
"jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}), "jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}),
"NewRootListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListAction"}), "NewRootListActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListActionWithOptions"}),
"NewListAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListAction"}), "NewListActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListActionWithOptions"}),
"NewRootGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetAction"}), "NewRootGetActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetActionWithOptions"}),
"NewGetAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetAction"}), "NewGetActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetActionWithOptions"}),
"NewRootDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteAction"}), "NewRootDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteActionWithOptions"}),
"NewRootDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteActionWithOptions"}), "NewDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteActionWithOptions"}),
"NewDeleteAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteAction"}), "NewRootDeleteCollectionActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteCollectionActionWithOptions"}),
"NewDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteActionWithOptions"}), "NewDeleteCollectionActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteCollectionActionWithOptions"}),
"NewRootDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteCollectionAction"}), "NewRootUpdateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateActionWithOptions"}),
"NewDeleteCollectionAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteCollectionAction"}), "NewUpdateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateActionWithOptions"}),
"NewRootUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateAction"}), "NewRootCreateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateActionWithOptions"}),
"NewUpdateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateAction"}), "NewCreateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateActionWithOptions"}),
"NewRootCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateAction"}), "NewRootWatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchActionWithOptions"}),
"NewCreateAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateAction"}), "NewWatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchActionWithOptions"}),
"NewRootWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchAction"}), "NewCreateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceActionWithOptions"}),
"NewWatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchAction"}), "NewRootCreateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateSubresourceActionWithOptions"}),
"NewCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceAction"}), "NewUpdateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceActionWithOptions"}),
"NewRootCreateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateSubresourceAction"}), "NewGetSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceActionWithOptions"}),
"NewUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceAction"}), "NewRootGetSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetSubresourceActionWithOptions"}),
"NewGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceAction"}), "NewRootUpdateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceActionWithOptions"}),
"NewRootGetSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetSubresourceAction"}), "NewRootPatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchActionWithOptions"}),
"NewRootUpdateSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceAction"}), "NewPatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchActionWithOptions"}),
"NewRootPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchAction"}), "NewRootPatchSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchSubresourceActionWithOptions"}),
"NewPatchAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchAction"}), "NewPatchSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchSubresourceActionWithOptions"}),
"NewRootPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchSubresourceAction"}), "ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}),
"NewPatchSubresourceAction": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchSubresourceAction"}),
"ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}),
} }
generateApply := len(g.applyConfigurationPackage) > 0 generateApply := len(g.applyConfigurationPackage) > 0
@@ -336,8 +335,8 @@ var listTemplate = `
func (c *Fake$.type|publicPlural$) List(ctx context.Context, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *Fake$.type|publicPlural$) List(ctx context.Context, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
emptyResult := &$.type|raw$List{} emptyResult := &$.type|raw$List{}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult) $if .namespaced$Invokes($.NewListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult)
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$ $else$Invokes($.NewRootListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -350,8 +349,8 @@ var listUsingOptionsTemplate = `
func (c *Fake$.type|publicPlural$) List(ctx context.Context, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { func (c *Fake$.type|publicPlural$) List(ctx context.Context, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) {
emptyResult := &$.type|raw$List{} emptyResult := &$.type|raw$List{}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult) $if .namespaced$Invokes($.NewListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult)
$else$Invokes($.NewRootListAction|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$ $else$Invokes($.NewRootListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -375,8 +374,8 @@ var getTemplate = `
func (c *Fake$.type|publicPlural$) Get(ctx context.Context, name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Get(ctx context.Context, name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetAction|raw$($.type|allLowercasePlural$Resource, c.ns, name), emptyResult) $if .namespaced$Invokes($.NewGetActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, name, options), emptyResult)
$else$Invokes($.NewRootGetAction|raw$($.type|allLowercasePlural$Resource, name), emptyResult)$end$ $else$Invokes($.NewRootGetActionWithOptions|raw$($.type|allLowercasePlural$Resource, name, options), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -389,8 +388,8 @@ var getSubresourceTemplate = `
func (c *Fake$.type|publicPlural$) Get(ctx context.Context, $.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Get(ctx context.Context, $.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name), emptyResult) $if .namespaced$Invokes($.NewGetSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name, options), emptyResult)
$else$Invokes($.NewRootGetSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.type|private$Name), emptyResult)$end$ $else$Invokes($.NewRootGetSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.type|private$Name, options), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -411,8 +410,8 @@ func (c *Fake$.type|publicPlural$) Delete(ctx context.Context, name string, opts
var deleteCollectionTemplate = ` var deleteCollectionTemplate = `
// DeleteCollection deletes a collection of objects. // DeleteCollection deletes a collection of objects.
func (c *Fake$.type|publicPlural$) DeleteCollection(ctx context.Context, opts $.DeleteOptions|raw$, listOpts $.ListOptions|raw$) error { func (c *Fake$.type|publicPlural$) DeleteCollection(ctx context.Context, opts $.DeleteOptions|raw$, listOpts $.ListOptions|raw$) error {
$if .namespaced$action := $.NewDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, c.ns, listOpts) $if .namespaced$action := $.NewDeleteCollectionActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, opts, listOpts)
$else$action := $.NewRootDeleteCollectionAction|raw$($.type|allLowercasePlural$Resource, listOpts) $else$action := $.NewRootDeleteCollectionActionWithOptions|raw$($.type|allLowercasePlural$Resource, opts, listOpts)
$end$ $end$
_, err := c.Fake.Invokes(action, &$.type|raw$List{}) _, err := c.Fake.Invokes(action, &$.type|raw$List{})
return err return err
@@ -423,8 +422,8 @@ var createTemplate = `
func (c *Fake$.type|publicPlural$) Create(ctx context.Context, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Create(ctx context.Context, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), emptyResult) $if .namespaced$Invokes($.NewCreateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$, opts), emptyResult)
$else$Invokes($.NewRootCreateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), emptyResult)$end$ $else$Invokes($.NewRootCreateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -437,8 +436,8 @@ var createSubresourceTemplate = `
func (c *Fake$.type|publicPlural$) Create(ctx context.Context, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Create(ctx context.Context, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$), emptyResult) $if .namespaced$Invokes($.NewCreateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$, opts), emptyResult)
$else$Invokes($.NewRootCreateSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.inputType|private$), emptyResult)$end$ $else$Invokes($.NewRootCreateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.inputType|private$, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -451,8 +450,8 @@ var updateTemplate = `
func (c *Fake$.type|publicPlural$) Update(ctx context.Context, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Update(ctx context.Context, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateAction|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$), emptyResult) $if .namespaced$Invokes($.NewUpdateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$, opts), emptyResult)
$else$Invokes($.NewRootUpdateAction|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$), emptyResult)$end$ $else$Invokes($.NewRootUpdateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -465,8 +464,8 @@ var updateSubresourceTemplate = `
func (c *Fake$.type|publicPlural$) Update(ctx context.Context, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Update(ctx context.Context, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$), &$.inputType|raw${}) $if .namespaced$Invokes($.NewUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$, opts), &$.inputType|raw${})
$else$Invokes($.NewRootUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.inputType|private$), emptyResult)$end$ $else$Invokes($.NewRootUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.inputType|private$, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -480,8 +479,8 @@ var updateStatusTemplate = `
func (c *Fake$.type|publicPlural$) UpdateStatus(ctx context.Context, $.type|private$ *$.type|raw$, opts $.UpdateOptions|raw$) (result *$.type|raw$, err error) { func (c *Fake$.type|publicPlural$) UpdateStatus(ctx context.Context, $.type|private$ *$.type|raw$, opts $.UpdateOptions|raw$) (result *$.type|raw$, err error) {
emptyResult := &$.type|raw${} emptyResult := &$.type|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$), emptyResult) $if .namespaced$Invokes($.NewUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$, opts), emptyResult)
$else$Invokes($.NewRootUpdateSubresourceAction|raw$($.type|allLowercasePlural$Resource, "status", $.type|private$), emptyResult)$end$ $else$Invokes($.NewRootUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "status", $.type|private$, opts), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -493,8 +492,8 @@ var watchTemplate = `
// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$. // Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$.
func (c *Fake$.type|publicPlural$) Watch(ctx context.Context, opts $.ListOptions|raw$) ($.watchInterface|raw$, error) { func (c *Fake$.type|publicPlural$) Watch(ctx context.Context, opts $.ListOptions|raw$) ($.watchInterface|raw$, error) {
return c.Fake. return c.Fake.
$if .namespaced$InvokesWatch($.NewWatchAction|raw$($.type|allLowercasePlural$Resource, c.ns, opts)) $if .namespaced$InvokesWatch($.NewWatchActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, opts))
$else$InvokesWatch($.NewRootWatchAction|raw$($.type|allLowercasePlural$Resource, opts))$end$ $else$InvokesWatch($.NewRootWatchActionWithOptions|raw$($.type|allLowercasePlural$Resource, opts))$end$
} }
` `
@@ -503,8 +502,8 @@ var patchTemplate = `
func (c *Fake$.type|publicPlural$) Patch(ctx context.Context, name string, pt $.PatchType|raw$, data []byte, opts $.PatchOptions|raw$, subresources ...string) (result *$.resultType|raw$, err error) { func (c *Fake$.type|publicPlural$) Patch(ctx context.Context, name string, pt $.PatchType|raw$, data []byte, opts $.PatchOptions|raw$, subresources ...string) (result *$.resultType|raw$, err error) {
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, name, pt, data, subresources... ), emptyResult) $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, name, pt, data, opts, subresources... ), emptyResult)
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, name, pt, data, subresources...), emptyResult)$end$ $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, name, pt, data, opts, subresources...), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -528,8 +527,8 @@ func (c *Fake$.type|publicPlural$) Apply(ctx context.Context, $.inputType|privat
} }
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data), emptyResult) $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions()), emptyResult)
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data), emptyResult)$end$ $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions()), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -554,8 +553,8 @@ func (c *Fake$.type|publicPlural$) ApplyStatus(ctx context.Context, $.inputType|
} }
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, "status"), emptyResult) $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult)
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, "status"), emptyResult)$end$ $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }
@@ -576,8 +575,8 @@ func (c *Fake$.type|publicPlural$) Apply(ctx context.Context, $.type|private$Nam
} }
emptyResult := &$.resultType|raw${} emptyResult := &$.resultType|raw${}
obj, err := c.Fake. obj, err := c.Fake.
$if .namespaced$Invokes($.NewPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$Name, $.ApplyPatchType|raw$, data, "status"), emptyResult) $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$Name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult)
$else$Invokes($.NewRootPatchSubresourceAction|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, $.ApplyPatchType|raw$, data, "status"), emptyResult)$end$ $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult)$end$
if obj == nil { if obj == nil {
return emptyResult, err return emptyResult, err
} }

View File

@@ -56,6 +56,8 @@ func (g Group) PackageName() string {
return strings.ToLower(parts[0]) return strings.ToLower(parts[0])
} }
type Kind string
type PackageVersion struct { type PackageVersion struct {
Version Version
// The fully qualified package, e.g. k8s.io/kubernetes/pkg/apis/apps, where the types.go is found. // The fully qualified package, e.g. k8s.io/kubernetes/pkg/apis/apps, where the types.go is found.
@@ -67,6 +69,12 @@ type GroupVersion struct {
Version Version Version Version
} }
type GroupVersionKind struct {
Group Group
Version Version
Kind Kind
}
func (gv GroupVersion) ToAPIVersion() string { func (gv GroupVersion) ToAPIVersion() string {
if len(gv.Group) > 0 && gv.Group.NonEmpty() != "core" { if len(gv.Group) > 0 && gv.Group.NonEmpty() != "core" {
return gv.Group.String() + "/" + gv.Version.String() return gv.Group.String() + "/" + gv.Version.String()
@@ -75,6 +83,10 @@ func (gv GroupVersion) ToAPIVersion() string {
} }
} }
func (gv GroupVersion) WithKind(kind Kind) GroupVersionKind {
return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind}
}
type GroupVersions struct { type GroupVersions struct {
// The name of the package for this group, e.g. apps. // The name of the package for this group, e.g. apps.
PackageName string PackageName string