Repository: GoogleContainerTools/kpt
Pull request #3584 (2022-09-27 14:28:30)

Add KptFileGVK to expose typed GVK information for Kptfile
More ergonomic than a set of strings.



Patch:
diff --git a/commands/live/migrate/migratecmd.go b/commands/live/migrate/migratecmd.go
index e22d6202..eb50d13f 100644
--- a/commands/live/migrate/migratecmd.go
+++ b/commands/live/migrate/migratecmd.go
@@ -205,7 +205,7 @@ func (mr *Runner) retrieveConfigMapInv(reader io.Reader, args []string) (invento
 
 	// cli-utils treats any resource that contains the inventory-id label as an inventory object. We should
 	// ignore any inventories that are stored as ResourceGroup resources since they do not need migration.
-	if cmInvObj.GetKind() == rgfilev1alpha1.RGFileKind {
+	if cmInvObj.GetKind() == rgfilev1alpha1.ResourceGroupGVK().Kind {
 		// No ConfigMap inventory means the migration has already run before.
 		fmt.Fprintln(mr.ioStreams.Out, "no ConfigMap inventory...completed")
 		return nil, &inventory.NoInventoryObjError{}
diff --git a/internal/builtins/pkg_context.go b/internal/builtins/pkg_context.go
index 2638ee4f..614497ac 100644
--- a/internal/builtins/pkg_context.go
+++ b/internal/builtins/pkg_context.go
@@ -35,7 +35,7 @@ const (
 
 var (
 	configMapGVK = resid.NewGvk("", "v1", "ConfigMap")
-	kptfileGVK   = resid.NewGvk(kptfilev1.KptFileGroup, kptfilev1.KptFileVersion, kptfilev1.KptFileKind)
+	kptfileGVK   = resid.NewGvk(kptfilev1.KptFileGVK().Group, kptfilev1.KptFileGVK().Version, kptfilev1.KptFileGVK().Kind)
 )
 
 // PackageContextGenerator is a built-in KRM function that generates
diff --git a/internal/errors/resolver/pkg.go b/internal/errors/resolver/pkg.go
index f6338850..63e17a85 100644
--- a/internal/errors/resolver/pkg.go
+++ b/internal/errors/resolver/pkg.go
@@ -99,7 +99,7 @@ func resolveNestedErr(err error, tmplArgs map[string]interface{}) (ResolvedResul
 
 	var deprecatedv1alpha1KptfileError *pkg.DeprecatedKptfileError
 	if errors.As(err, &deprecatedv1alpha1KptfileError) &&
-		deprecatedv1alpha1KptfileError.Version == pkg.DeprecatedKptfileVersions[0] {
+		deprecatedv1alpha1KptfileError.Version == "v1alpha1" {
 		tmplArgs["version"] = deprecatedv1alpha1KptfileError.Version
 		errMsg := deprecatedv1Alpha1KptfileMsg
 		return ResolvedResult{
@@ -109,7 +109,7 @@ func resolveNestedErr(err error, tmplArgs map[string]interface{}) (ResolvedResul
 
 	var deprecatedv1alpha2KptfileError *pkg.DeprecatedKptfileError
 	if errors.As(err, &deprecatedv1alpha2KptfileError) &&
-		deprecatedv1alpha1KptfileError.Version == pkg.DeprecatedKptfileVersions[1] {
+		deprecatedv1alpha1KptfileError.Version == "v1alpha2" {
 		tmplArgs["version"] = deprecatedv1alpha2KptfileError.Version
 		errMsg := deprecatedv1Alpha2KptfileMsg
 		return ResolvedResult{
diff --git a/internal/pkg/pkg.go b/internal/pkg/pkg.go
index e4c55fa7..3e553fa7 100644
--- a/internal/pkg/pkg.go
+++ b/internal/pkg/pkg.go
@@ -30,7 +30,6 @@ import (
 	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
 	rgfilev1alpha1 "github.com/GoogleContainerTools/kpt/pkg/api/resourcegroup/v1alpha1"
 	"k8s.io/apimachinery/pkg/runtime/schema"
-	"k8s.io/kubectl/pkg/util/slice"
 	"sigs.k8s.io/kustomize/kyaml/filesys"
 	"sigs.k8s.io/kustomize/kyaml/kio"
 	"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
@@ -45,17 +44,17 @@ const (
 	pkgPathAnnotation = "internal.config.kubernetes.io/package-path"
 )
 
-var DeprecatedKptfileVersions = []string{
-	"v1alpha1",
-	"v1alpha2",
+var DeprecatedKptfileVersions = []schema.GroupVersionKind{
+	kptfilev1.KptFileGVK().GroupKind().WithVersion("v1alpha1"),
+	kptfilev1.KptFileGVK().GroupKind().WithVersion("v1alpha2"),
 }
 
 // MatchAllKRM represents set of glob pattern to match all KRM
 // resources including Kptfile.
 var MatchAllKRM = append([]string{kptfilev1.KptFileName}, kio.MatchAll...)
 
-var SupportedKptfileVersions = []string{
-	kptfilev1.KptFileVersion,
+var SupportedKptfileVersions = []schema.GroupVersionKind{
+	kptfilev1.KptFileGVK(),
 }
 
 // KptfileError records errors regarding reading or parsing of a Kptfile.
@@ -286,18 +285,15 @@ func CheckKptfileVersion(content []byte) error {
 	if err != nil {
 		return err
 	}
+	gvk := gv.WithKind(kind)
 
 	switch {
 	// If the resource type matches what we are looking for, just return nil.
-	case gv.Group == kptfilev1.KptFileGroup &&
-		kind == kptfilev1.KptFileKind &&
-		isSupportedKptfileVersion(gv.Version):
+	case isSupportedKptfileVersion(gvk):
 		return nil
 	// If the kind and group is correct and the version is a known deprecated
 	// schema for the Kptfile, return DeprecatedKptfileError.
-	case gv.Group == kptfilev1.KptFileGroup &&
-		kind == kptfilev1.KptFileKind &&
-		isDeprecatedKptfileVersion(gv.Version):
+	case isDeprecatedKptfileVersion(gvk):
 		return &DeprecatedKptfileError{
 			Version: gv.Version,
 		}
@@ -310,12 +306,22 @@ func CheckKptfileVersion(content []byte) error {
 	}
 }
 
-func isDeprecatedKptfileVersion(version string) bool {
-	return slice.ContainsString(DeprecatedKptfileVersions, version, nil)
+func isDeprecatedKptfileVersion(gvk schema.GroupVersionKind) bool {
+	for _, v := range DeprecatedKptfileVersions {
+		if v == gvk {
+			return true
+		}
+	}
+	return false
 }
 
-func isSupportedKptfileVersion(version string) bool {
-	return slice.ContainsString(SupportedKptfileVersions, version, nil)
+func isSupportedKptfileVersion(gvk schema.GroupVersionKind) bool {
+	for _, v := range SupportedKptfileVersions {
+		if v == gvk {
+			return true
+		}
+	}
+	return false
 }
 
 // Pipeline returns the Pipeline section of the pkg's Kptfile.
@@ -777,7 +783,7 @@ func filterResourceGroups(input []*yaml.RNode) (output []*yaml.RNode, err error)
 			return nil, fmt.Errorf("failed to read metadata for resource %w", err)
 		}
 		// Filter out any non-ResourceGroup files.
-		if !(meta.APIVersion == rgfilev1alpha1.RGFileAPIVersion && meta.Kind == rgfilev1alpha1.RGFileKind) {
+		if !(meta.APIVersion == rgfilev1alpha1.ResourceGroupGVK().GroupVersion().String() && meta.Kind == rgfilev1alpha1.ResourceGroupGVK().Kind) {
 			continue
 		}
 
diff --git a/pkg/api/fnresult/v1/types.go b/pkg/api/fnresult/v1/types.go
index e6dc7848..29783fee 100644
--- a/pkg/api/fnresult/v1/types.go
+++ b/pkg/api/fnresult/v1/types.go
@@ -15,7 +15,7 @@
 package v1
 
 import (
-	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"sigs.k8s.io/kustomize/kyaml/fn/framework"
 	"sigs.k8s.io/kustomize/kyaml/yaml"
 )
@@ -42,12 +42,25 @@ type Result struct {
 }
 
 const (
-	ResultListKind       = "FunctionResultList"
-	ResultListGroup      = kptfilev1.KptFileGroup
-	ResultListVersion    = kptfilev1.KptFileVersion
+	// Deprecated: prefer ResultListGVK
+	ResultListKind = "FunctionResultList"
+	// Deprecated: prefer ResultListGVK
+	ResultListGroup = "kpt.dev"
+	// Deprecated: prefer ResultListGVK
+	ResultListVersion = "v1"
+	// Deprecated: prefer ResultListGVK
 	ResultListAPIVersion = ResultListGroup + "/" + ResultListVersion
 )
 
+// KptFileGVK is the GroupVersionKind of FunctionResultList objects
+func ResultListGVK() schema.GroupVersionKind {
+	return schema.GroupVersionKind{
+		Group:   "kpt.dev",
+		Version: "v1",
+		Kind:    "FunctionResultList",
+	}
+}
+
 // ResultList contains aggregated results from multiple functions
 type ResultList struct {
 	yaml.ResourceMeta `yaml:",inline"`
diff --git a/pkg/api/kptfile/v1/types.go b/pkg/api/kptfile/v1/types.go
index c5bd8883..c46b01bc 100644
--- a/pkg/api/kptfile/v1/types.go
+++ b/pkg/api/kptfile/v1/types.go
@@ -20,17 +20,35 @@ package v1
 import (
 	"fmt"
 
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"sigs.k8s.io/kustomize/kyaml/yaml"
 )
 
 const (
-	KptFileName       = "Kptfile"
-	KptFileKind       = "Kptfile"
-	KptFileGroup      = "kpt.dev"
-	KptFileVersion    = "v1"
+	KptFileName = "Kptfile"
+
+	// Deprecated: prefer KptFileGVK
+	KptFileKind = "Kptfile"
+
+	// Deprecated: prefer KptFileGVK
+	KptFileGroup = "kpt.dev"
+
+	// Deprecated: prefer KptFileGVK
+	KptFileVersion = "v1"
+
+	// Deprecated: prefer KptFileGVK
 	KptFileAPIVersion = KptFileGroup + "/" + KptFileVersion
 )
 
+// KptFileGVK is the GroupVersionKind of Kptfile objects
+func KptFileGVK() schema.GroupVersionKind {
+	return schema.GroupVersionKind{
+		Group:   "kpt.dev",
+		Version: "v1",
+		Kind:    "Kptfile",
+	}
+}
+
 // TypeMeta is the TypeMeta for KptFile instances.
 var TypeMeta = yaml.ResourceMeta{
 	TypeMeta: yaml.TypeMeta{
diff --git a/pkg/api/resourcegroup/v1alpha1/types.go b/pkg/api/resourcegroup/v1alpha1/types.go
index 0d9741ff..5ad6e458 100644
--- a/pkg/api/resourcegroup/v1alpha1/types.go
+++ b/pkg/api/resourcegroup/v1alpha1/types.go
@@ -18,20 +18,35 @@
 package v1alpha1
 
 import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
 	"sigs.k8s.io/cli-utils/pkg/common"
 	"sigs.k8s.io/kustomize/kyaml/yaml"
 )
 
 const (
-	RGFileName       = "resourcegroup.yaml"
-	RGFileKind       = "ResourceGroup"
-	RGFileGroup      = "kpt.dev"
-	RGFileVersion    = "v1alpha1"
-	RGFileAPIVersion = RGFileGroup + "/" + RGFileVersion
+	RGFileName = "resourcegroup.yaml"
 	// RGInventoryIDLabel is the label name used for storing an inventory ID.
 	RGInventoryIDLabel = common.InventoryLabel
+
+	// Deprecated: prefer ResourceGroupGVK
+	RGFileKind = "ResourceGroup"
+	// Deprecated: prefer ResourceGroupGVK
+	RGFileGroup = "kpt.dev"
+	// Deprecated: prefer ResourceGroupGVK
+	RGFileVersion = "v1alpha1"
+	// Deprecated: prefer ResourceGroupGVK
+	RGFileAPIVersion = RGFileGroup + "/" + RGFileVersion
 )
 
+// ResourceGroupGVK is the GroupVersionKind of ResourceGroup objects
+func ResourceGroupGVK() schema.GroupVersionKind {
+	return schema.GroupVersionKind{
+		Group:   "kpt.dev",
+		Version: "v1alpha1",
+		Kind:    "ResourceGroup",
+	}
+}
+
 // DefaultMeta is the ResourceMeta for ResourceGroup instances.
 var DefaultMeta = yaml.ResourceMeta{
 	TypeMeta: yaml.TypeMeta{
diff --git a/pkg/live/load.go b/pkg/live/load.go
index 424ffab7..b5b9c29c 100644
--- a/pkg/live/load.go
+++ b/pkg/live/load.go
@@ -26,6 +26,8 @@ import (
 	kptfilev1 "github.com/GoogleContainerTools/kpt/pkg/api/kptfile/v1"
 	rgfilev1alpha1 "github.com/GoogleContainerTools/kpt/pkg/api/resourcegroup/v1alpha1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/klog/v2"
 	"k8s.io/kubectl/pkg/cmd/util"
 	"sigs.k8s.io/cli-utils/pkg/common"
 	"sigs.k8s.io/cli-utils/pkg/inventory"
@@ -195,8 +197,7 @@ type InventoryFilter struct {
 }
 
 func (i *InventoryFilter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
-	if object.GetApiVersion() != kptfilev1.KptFileAPIVersion ||
-		object.GetKind() != kptfilev1.KptFileKind {
+	if GroupVersionKindForObject(object) != kptfilev1.KptFileGVK() {
 		return object, nil
 	}
 
@@ -220,9 +221,18 @@ type RGFilter struct {
 	Inventories []*rgfilev1alpha1.ResourceGroup
 }
 
+// GroupVersionKindForObject extracts the group/version/kind from an RNode holding a kubernetes object.
+func GroupVersionKindForObject(object *yaml.RNode) schema.GroupVersionKind {
+	apiVersion := object.GetApiVersion()
+	gv, err := schema.ParseGroupVersion(apiVersion)
+	if err != nil {
+		klog.Warningf("error parsing apiVersion=%q", apiVersion)
+	}
+	return gv.WithKind(object.GetKind())
+}
+
 func (r *RGFilter) Filter(object *yaml.RNode) (*yaml.RNode, error) {
-	if object.GetApiVersion() != rgfilev1alpha1.RGFileAPIVersion ||
-		object.GetKind() != rgfilev1alpha1.RGFileKind {
+	if GroupVersionKindForObject(object) != rgfilev1alpha1.ResourceGroupGVK() {
 		return object, nil
 	}
 
diff --git a/pkg/live/rgpath.go b/pkg/live/rgpath.go
index 556a1736..7c2e712e 100644
--- a/pkg/live/rgpath.go
+++ b/pkg/live/rgpath.go
@@ -66,7 +66,7 @@ func (r *ResourceGroupPathManifestReader) Read() ([]*unstructured.Unstructured,
 		// Skip if current file is a ResourceGroup resource. We do not want to apply/delete any ResourceGroup CRs when we
 		// run any `kpt live` commands on a package. Instead, we have specific logic in place for handling ResourceGroups in
 		// the live cluster.
-		if u.GetKind() == rgfilev1alpha1.RGFileKind && u.GetAPIVersion() == rgfilev1alpha1.DefaultMeta.APIVersion {
+		if u.GroupVersionKind() == rgfilev1alpha1.ResourceGroupGVK() {
 			continue
 		}
 		objs = append(objs, u)
diff --git a/pkg/live/rgstream.go b/pkg/live/rgstream.go
index 855b7568..354e3eb3 100644
--- a/pkg/live/rgstream.go
+++ b/pkg/live/rgstream.go
@@ -31,14 +31,8 @@ import (
 
 var (
 	excludedGKs = []schema.GroupKind{
-		{
-			Group: kptfilev1.KptFileGroup,
-			Kind:  kptfilev1.KptFileKind,
-		},
-		{
-			Group: rgfilev1alpha1.RGFileGroup,
-			Kind:  rgfilev1alpha1.RGFileKind,
-		},
+		kptfilev1.KptFileGVK().GroupKind(),
+		rgfilev1alpha1.ResourceGroupGVK().GroupKind(),
 	}
 )
 


Test patch:
diff --git a/commands/pkg/get/cmdget_test.go b/commands/pkg/get/cmdget_test.go
index 31afaa6d..a930caa5 100644
--- a/commands/pkg/get/cmdget_test.go
+++ b/commands/pkg/get/cmdget_test.go
@@ -66,8 +66,9 @@ func TestCmd_execute(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind,
+			},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: kptfilev1.GitOrigin,
@@ -126,8 +127,9 @@ func TestCmdMainBranch_execute(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind,
+			},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: kptfilev1.GitOrigin,
diff --git a/internal/util/fetch/fetch_test.go b/internal/util/fetch/fetch_test.go
index 0df81df2..c0c28174 100644
--- a/internal/util/fetch/fetch_test.go
+++ b/internal/util/fetch/fetch_test.go
@@ -196,8 +196,9 @@ func TestCommand_Run(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind,
+			},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: "git",
@@ -258,8 +259,8 @@ func TestCommand_Run_subdir(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: kptfilev1.GitOrigin,
@@ -334,8 +335,9 @@ func TestCommand_Run_branch(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind,
+			},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: kptfilev1.GitOrigin,
@@ -415,8 +417,9 @@ func TestCommand_Run_tag(t *testing.T) {
 				},
 			},
 			TypeMeta: yaml.TypeMeta{
-				APIVersion: kptfilev1.KptFileAPIVersion,
-				Kind:       kptfilev1.KptFileKind},
+				APIVersion: kptfilev1.KptFileGVK().GroupVersion().String(),
+				Kind:       kptfilev1.KptFileGVK().Kind,
+			},
 		},
 		Upstream: &kptfilev1.Upstream{
 			Type: "git",