Repository: GoogleContainerTools/kpt
Pull request #3487 (2022-08-23 20:25:13)

fix: rename example files to fix broken Go import
The presence of colons in the filenames prevented other Go projects from
importing kpt.

justinsb: LGTM but I think @droot should comment about how these were generated (i.e. do we want to update a makefile or similar)
rquitales: Hunted down the PR that introduced these files #3371. Looks like an adhoc command was used to generate the yaml by grabbing the cert-manager uber yaml from the github release and splitting it using `kubectl-slice -f cert-manager.yaml --template '{{ index "app" .metadata.labels }}/{{.kind | lower}}-{{.metadata.name|dottodash}}.yaml' -o cert-manager-basic`. This is documented in the README file of the cert-manager package. `kubectl-slice` does not have helper template functions to also convert colons to dashes.

If it helps, here's the adhoc command I used to batch rename the yaml files:
```sh
for file in $(fdfind ":"); do mv $file $(echo $file | sed "s/:/-/"); done
```

Patch:
diff --git a/go.mod b/go.mod
index c47c5136..3d642ce8 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/GoogleContainerTools/kpt
 go 1.18
 
 require (
-	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220707151439-cb4c4e496c92
+	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220821193112-4792e5fa18ee
 	github.com/bytecodealliance/wasmtime-go v0.39.0
 	github.com/cpuguy83/go-md2man/v2 v2.0.2
 	github.com/go-errors/errors v1.4.2
diff --git a/go.sum b/go.sum
index 00189ddf..8a4c4756 100644
--- a/go.sum
+++ b/go.sum
@@ -85,8 +85,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
-github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220707151439-cb4c4e496c92 h1:0h6lonywmlgUWEc62Nvjt3IqkzudXDbplILJc7wlayI=
-github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220707151439-cb4c4e496c92/go.mod h1:51Vk7QZ+XUzHCvQBi7t9tiWqTXvy6T13cv/inUXJJ0s=
+github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220821193112-4792e5fa18ee h1:FSW33xqr8SeoZWQ0MgKtjosMmaUBoHa/z0Tlp493528=
+github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220821193112-4792e5fa18ee/go.mod h1:VUrDv94BkVOEE/MEwwqVr7C1K0sWxF/QsoIZvpQacnA=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd h1:sjQovDkwrZp8u+gxLtPgKGjk5hCxuy2hrRejBTA9xFU=
 github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
 github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
diff --git a/internal/alpha/printers/table/printer.go b/internal/alpha/printers/table/printer.go
index 29ee4c52..5798bdd3 100644
--- a/internal/alpha/printers/table/printer.go
+++ b/internal/alpha/printers/table/printer.go
@@ -6,11 +6,14 @@ package table
 import (
 	"fmt"
 	"io"
+	"strings"
 	"time"
 
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/cli-runtime/pkg/genericclioptions"
 	"sigs.k8s.io/cli-utils/pkg/apply/event"
 	"sigs.k8s.io/cli-utils/pkg/common"
+	pollingevent "sigs.k8s.io/cli-utils/pkg/kstatus/polling/event"
 	printcommon "sigs.k8s.io/cli-utils/pkg/print/common"
 	"sigs.k8s.io/cli-utils/pkg/print/table"
 )
@@ -72,87 +75,23 @@ func (t *Printer) Print(ch <-chan event.Event, _ common.DryRunStrategy, _ bool)
 }
 
 // columns defines the columns we want to print
-//TODO: We should have the number of columns and their widths be
+// TODO: We should have the number of columns and their widths be
 // dependent on the space available.
 var (
-	actionColumnDef = table.ColumnDef{
-		// Column containing the resource type and name. Currently it does not
-		// print group or version since those are rarely needed to uniquely
-		// distinguish two resources from each other. Just name and kind should
-		// be enough in almost all cases and saves space in the output.
-		ColumnName:   "action",
-		ColumnHeader: "ACTION",
-		ColumnWidth:  12,
-		PrintResourceFunc: func(w io.Writer, width int, r table.Resource) (int,
-			error) {
-			var resInfo *resourceInfo
-			switch res := r.(type) {
-			case *resourceInfo:
-				resInfo = res
-			default:
-				return 0, nil
-			}
-
-			var text string
-			switch resInfo.ResourceAction {
-			case event.ApplyAction:
-				if resInfo.ApplyStatus != event.ApplyFailed {
-					text = resInfo.ApplyStatus.String()
-				}
-			case event.PruneAction:
-				if resInfo.PruneStatus != event.PruneFailed {
-					text = resInfo.PruneStatus.String()
-				}
-			}
-
-			if len(text) > width {
-				text = text[:width]
-			}
-			_, err := fmt.Fprint(w, text)
-			return len(text), err
-		},
-	}
-
-	reconciledColumnDef = table.ColumnDef{
-		// Column containing the reconciliation status.
-		ColumnName:   "reconciled",
-		ColumnHeader: "RECONCILED",
-		ColumnWidth:  10,
-		PrintResourceFunc: func(w io.Writer, width int, r table.Resource) (
-			int,
-			error,
-		) {
-			var resInfo *resourceInfo
-			switch res := r.(type) {
-			case *resourceInfo:
-				resInfo = res
-			default:
-				return 0, nil
-			}
-
-			var text string
-			switch resInfo.ResourceAction {
-			case event.WaitAction:
-				text = resInfo.WaitStatus.String()
-			}
-
-			if len(text) > width {
-				text = text[:width]
-			}
-			_, err := fmt.Fprint(w, text)
-			return len(text), err
-		},
+	unifiedStatusColumnDef = table.ColumnDef{
+		// Column containing the overall progress.
+		ColumnName:        "progress",
+		ColumnHeader:      "PROGRESS",
+		ColumnWidth:       80,
+		PrintResourceFunc: printProgress,
 	}
 
-	columns = []table.ColumnDefinition{
+	alphaColumns = []table.ColumnDefinition{
 		table.MustColumn("namespace"),
 		table.MustColumn("resource"),
-		actionColumnDef,
-		table.MustColumn("status"),
-		reconciledColumnDef,
-		table.MustColumn("conditions"),
-		table.MustColumn("age"),
-		table.MustColumn("message"),
+
+		// We are trying out a "single column" model here
+		unifiedStatusColumnDef,
 	}
 )
 
@@ -163,7 +102,7 @@ func (t *Printer) runPrintLoop(coll *resourceStateCollector, stop chan struct{})
 
 	baseTablePrinter := table.BaseTablePrinter{
 		IOStreams: t.IOStreams,
-		Columns:   columns,
+		Columns:   alphaColumns,
 	}
 
 	linesPrinted := baseTablePrinter.PrintTable(coll.LatestState(), 0)
@@ -187,3 +126,147 @@ func (t *Printer) runPrintLoop(coll *resourceStateCollector, stop chan struct{})
 	}()
 	return finished
 }
+
+func printProgress(w io.Writer, width int, r table.Resource) (int, error) {
+	var resInfo *resourceInfo
+	switch res := r.(type) {
+	case *resourceInfo:
+		resInfo = res
+	default:
+		return 0, fmt.Errorf("unexpected type %T", r)
+	}
+
+	text, details, err := getProgress(resInfo)
+	if err != nil {
+		return 0, err
+	}
+
+	if details != "" {
+		text += " " + details
+	}
+
+	if len(text) > width {
+		text = text[:width]
+	}
+	n, err := fmt.Fprint(w, text)
+	if err != nil {
+		return n, err
+	}
+	return len(text), err
+}
+
+func getProgress(resInfo *resourceInfo) (string, string, error) {
+	printStatus := false
+	var text string
+	var details string
+	switch resInfo.ResourceAction {
+	case event.ApplyAction:
+		switch resInfo.ApplyStatus {
+		case event.ApplyPending:
+			text = "PendingApply"
+		case event.ApplySuccessful:
+			text = "Applied"
+			printStatus = true
+		case event.ApplySkipped:
+			text = "SkippedApply"
+		case event.ApplyFailed:
+			text = "ApplyFailed"
+
+		default:
+			return "", "", fmt.Errorf("unknown ApplyStatus: %v", resInfo.ApplyStatus)
+		}
+
+	case event.PruneAction:
+		switch resInfo.PruneStatus {
+		case event.PrunePending:
+			text = "PendingDeletion"
+		case event.PruneSuccessful:
+			text = "Deleted"
+		case event.PruneSkipped:
+			text = "DeletionSkipped"
+		case event.PruneFailed:
+			text = "DeletionFailed"
+
+		default:
+			return "", "", fmt.Errorf("unknown PruneStatus: %v", resInfo.PruneStatus)
+		}
+
+	default:
+		return "", "", fmt.Errorf("unknown ResourceAction %v", resInfo.ResourceAction)
+	}
+
+	rs := resInfo.ResourceStatus()
+	if printStatus && rs != nil {
+		s := rs.Status.String()
+
+		color, setColor := printcommon.ColorForStatus(rs.Status)
+		if setColor {
+			s = printcommon.SprintfWithColor(color, s)
+		}
+
+		text = s
+
+		if resInfo.ResourceAction == event.WaitAction {
+			text += " WaitStatus:" + resInfo.WaitStatus.String()
+		}
+
+		conditionStrings := getConditions(rs)
+		text += " Conditions:" + strings.Join(conditionStrings, ",")
+
+		var message string
+		if rs.Error != nil {
+			message = rs.Error.Error()
+		} else {
+			message = rs.Message
+		}
+		// TODO: Map from status?
+		if message == "Resource is Ready" || message == "Resource is current" {
+			message = ""
+		}
+		if message != "" {
+			details += "Message:" + message
+		}
+	}
+
+	return text, details, nil
+}
+
+func getConditions(rs *pollingevent.ResourceStatus) []string {
+	u := rs.Resource
+	if u == nil {
+		return nil
+	}
+
+	// TODO: Should we be using kstatus here?
+
+	conditions, found, err := unstructured.NestedSlice(u.Object,
+		"status", "conditions")
+	if !found || err != nil || len(conditions) == 0 {
+		return nil
+	}
+
+	var conditionStrings []string
+	for _, cond := range conditions {
+		condition := cond.(map[string]interface{})
+		conditionType := condition["type"].(string)
+		conditionStatus := condition["status"].(string)
+		conditionReason := condition["reason"].(string)
+		var color printcommon.Color
+		switch conditionStatus {
+		case "True":
+			color = printcommon.GREEN
+		case "False":
+			color = printcommon.RED
+		default:
+			color = printcommon.YELLOW
+		}
+
+		text := conditionReason
+		if text == "" {
+			text = conditionType
+		}
+		s := printcommon.SprintfWithColor(color, text)
+		conditionStrings = append(conditionStrings, s)
+	}
+	return conditionStrings
+}
diff --git a/internal/cmdreporeg/command.go b/internal/cmdreporeg/command.go
index c523089a..2d908007 100644
--- a/internal/cmdreporeg/command.go
+++ b/internal/cmdreporeg/command.go
@@ -53,6 +53,7 @@ func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner
 
 	c.Flags().StringVar(&r.directory, "directory", "/", "Directory within the repository where to look for packages.")
 	c.Flags().StringVar(&r.branch, "branch", "main", "Branch in the repository where finalized packages are committed.")
+	c.Flags().BoolVar(&r.createBranch, "create-branch", false, "Create the package branch if it doesn't already exist.")
 	c.Flags().StringVar(&r.name, "name", "", "Name of the package repository. If unspecified, will use the name portion (last segment) of the repository URL.")
 	c.Flags().StringVar(&r.description, "description", "", "Brief description of the package repository.")
 	c.Flags().BoolVar(&r.deployment, "deployment", false, "Repository is a deployment repository; packages in a deployment repository are considered deployment-ready.")
@@ -76,6 +77,7 @@ type runner struct {
 	// Flags
 	directory        string
 	branch           string
+	createBranch     bool
 	name             string
 	description      string
 	deployment       bool
@@ -123,9 +125,10 @@ func (r *runner) runE(cmd *cobra.Command, args []string) error {
 		// 	return errors.E(op, err)
 		// }
 		git = &configapi.GitRepository{
-			Repo:      repository,
-			Branch:    r.branch,
-			Directory: r.directory,
+			Repo:         repository,
+			Branch:       r.branch,
+			CreateBranch: r.createBranch,
+			Directory:    r.directory,
 		}
 
 		if r.name == "" {
diff --git a/package-examples/cert-manager-basic/cainjector/role-cert-manager-cainjector:leaderelection.yaml b/package-examples/cert-manager-basic/cainjector/role-cert-manager-cainjector-leaderelection.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cainjector/role-cert-manager-cainjector:leaderelection.yaml
rename to package-examples/cert-manager-basic/cainjector/role-cert-manager-cainjector-leaderelection.yaml
diff --git a/package-examples/cert-manager-basic/cainjector/rolebinding-cert-manager-cainjector:leaderelection.yaml b/package-examples/cert-manager-basic/cainjector/rolebinding-cert-manager-cainjector-leaderelection.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cainjector/rolebinding-cert-manager-cainjector:leaderelection.yaml
rename to package-examples/cert-manager-basic/cainjector/rolebinding-cert-manager-cainjector-leaderelection.yaml
diff --git a/package-examples/cert-manager-basic/cert-manager/clusterrole-cert-manager-controller-approve:cert-manager-io.yaml b/package-examples/cert-manager-basic/cert-manager/clusterrole-cert-manager-controller-approve-cert-manager-io.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cert-manager/clusterrole-cert-manager-controller-approve:cert-manager-io.yaml
rename to package-examples/cert-manager-basic/cert-manager/clusterrole-cert-manager-controller-approve-cert-manager-io.yaml
diff --git a/package-examples/cert-manager-basic/cert-manager/clusterrolebinding-cert-manager-controller-approve:cert-manager-io.yaml b/package-examples/cert-manager-basic/cert-manager/clusterrolebinding-cert-manager-controller-approve-cert-manager-io.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cert-manager/clusterrolebinding-cert-manager-controller-approve:cert-manager-io.yaml
rename to package-examples/cert-manager-basic/cert-manager/clusterrolebinding-cert-manager-controller-approve-cert-manager-io.yaml
diff --git a/package-examples/cert-manager-basic/cert-manager/role-cert-manager:leaderelection.yaml b/package-examples/cert-manager-basic/cert-manager/role-cert-manager-leaderelection.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cert-manager/role-cert-manager:leaderelection.yaml
rename to package-examples/cert-manager-basic/cert-manager/role-cert-manager-leaderelection.yaml
diff --git a/package-examples/cert-manager-basic/cert-manager/rolebinding-cert-manager:leaderelection.yaml b/package-examples/cert-manager-basic/cert-manager/rolebinding-cert-manager-leaderelection.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/cert-manager/rolebinding-cert-manager:leaderelection.yaml
rename to package-examples/cert-manager-basic/cert-manager/rolebinding-cert-manager-leaderelection.yaml
diff --git a/package-examples/cert-manager-basic/webhook/clusterrole-cert-manager-webhook:subjectaccessreviews.yaml b/package-examples/cert-manager-basic/webhook/clusterrole-cert-manager-webhook-subjectaccessreviews.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/webhook/clusterrole-cert-manager-webhook:subjectaccessreviews.yaml
rename to package-examples/cert-manager-basic/webhook/clusterrole-cert-manager-webhook-subjectaccessreviews.yaml
diff --git a/package-examples/cert-manager-basic/webhook/clusterrolebinding-cert-manager-webhook:subjectaccessreviews.yaml b/package-examples/cert-manager-basic/webhook/clusterrolebinding-cert-manager-webhook-subjectaccessreviews.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/webhook/clusterrolebinding-cert-manager-webhook:subjectaccessreviews.yaml
rename to package-examples/cert-manager-basic/webhook/clusterrolebinding-cert-manager-webhook-subjectaccessreviews.yaml
diff --git a/package-examples/cert-manager-basic/webhook/role-cert-manager-webhook:dynamic-serving.yaml b/package-examples/cert-manager-basic/webhook/role-cert-manager-webhook-dynamic-serving.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/webhook/role-cert-manager-webhook:dynamic-serving.yaml
rename to package-examples/cert-manager-basic/webhook/role-cert-manager-webhook-dynamic-serving.yaml
diff --git a/package-examples/cert-manager-basic/webhook/rolebinding-cert-manager-webhook:dynamic-serving.yaml b/package-examples/cert-manager-basic/webhook/rolebinding-cert-manager-webhook-dynamic-serving.yaml
similarity index 100%
rename from package-examples/cert-manager-basic/webhook/rolebinding-cert-manager-webhook:dynamic-serving.yaml
rename to package-examples/cert-manager-basic/webhook/rolebinding-cert-manager-webhook-dynamic-serving.yaml
diff --git a/porch/controllers/config/crd/bases/config.cloud.google.com_remoterootsyncsets.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml
similarity index 99%
rename from porch/controllers/config/crd/bases/config.cloud.google.com_remoterootsyncsets.yaml
rename to porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml
index 86a6d2f3..8966c0b7 100644
--- a/porch/controllers/config/crd/bases/config.cloud.google.com_remoterootsyncsets.yaml
+++ b/porch/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml
@@ -19,9 +19,9 @@ metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.8.0
   creationTimestamp: null
-  name: remoterootsyncsets.config.cloud.google.com
+  name: remoterootsyncsets.config.porch.kpt.dev
 spec:
-  group: config.cloud.google.com
+  group: config.porch.kpt.dev
   names:
     kind: RemoteRootSyncSet
     listKind: RemoteRootSyncSetList
diff --git a/porch/controllers/config/crd/bases/config.cloud.google.com_rootsyncsets.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml
similarity index 99%
rename from porch/controllers/config/crd/bases/config.cloud.google.com_rootsyncsets.yaml
rename to porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml
index 657232c1..2ac1a385 100644
--- a/porch/controllers/config/crd/bases/config.cloud.google.com_rootsyncsets.yaml
+++ b/porch/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml
@@ -19,9 +19,9 @@ metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.8.0
   creationTimestamp: null
-  name: rootsyncsets.config.cloud.google.com
+  name: rootsyncsets.config.porch.kpt.dev
 spec:
-  group: config.cloud.google.com
+  group: config.porch.kpt.dev
   names:
     kind: RootSyncSet
     listKind: RootSyncSetList
diff --git a/porch/controllers/config/crd/bases/porch.kpt.dev_workloadidentitybindings.yaml b/porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml
similarity index 98%
rename from porch/controllers/config/crd/bases/porch.kpt.dev_workloadidentitybindings.yaml
rename to porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml
index 0868e3eb..645e231c 100644
--- a/porch/controllers/config/crd/bases/porch.kpt.dev_workloadidentitybindings.yaml
+++ b/porch/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml
@@ -19,9 +19,9 @@ metadata:
   annotations:
     controller-gen.kubebuilder.io/version: v0.8.0
   creationTimestamp: null
-  name: workloadidentitybindings.porch.kpt.dev
+  name: workloadidentitybindings.config.porch.kpt.dev
 spec:
-  group: porch.kpt.dev
+  group: config.porch.kpt.dev
   names:
     kind: WorkloadIdentityBinding
     listKind: WorkloadIdentityBindingList
diff --git a/porch/controllers/config/rbac/role.yaml b/porch/controllers/config/rbac/role.yaml
index f7f91cab..920baf25 100644
--- a/porch/controllers/config/rbac/role.yaml
+++ b/porch/controllers/config/rbac/role.yaml
@@ -17,7 +17,7 @@ apiVersion: rbac.authorization.k8s.io/v1
 kind: ClusterRole
 metadata:
   creationTimestamp: null
-  name: configmanagement-operator
+  name: porch-controllers
 rules:
 - apiGroups:
   - ""
@@ -27,9 +27,9 @@ rules:
   - create
   - patch
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
-  - remoterootsyncs
+  - remoterootsyncsets
   verbs:
   - create
   - delete
@@ -39,21 +39,21 @@ rules:
   - update
   - watch
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
-  - remoterootsyncs/finalizers
+  - remoterootsyncsets/finalizers
   verbs:
   - update
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
-  - remoterootsyncs/status
+  - remoterootsyncsets/status
   verbs:
   - get
   - patch
   - update
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
   - rootsyncsets
   verbs:
@@ -65,13 +65,13 @@ rules:
   - update
   - watch
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
   - rootsyncsets/finalizers
   verbs:
   - update
 - apiGroups:
-  - config.cloud.google.com
+  - config.porch.kpt.dev
   resources:
   - rootsyncsets/status
   verbs:
@@ -79,9 +79,9 @@ rules:
   - patch
   - update
 - apiGroups:
-  - coordination.k8s.io
+  - config.porch.kpt.dev
   resources:
-  - leases
+  - workloadidentitybindings
   verbs:
   - create
   - delete
@@ -91,28 +91,28 @@ rules:
   - update
   - watch
 - apiGroups:
-  - porch.kpt.dev
+  - config.porch.kpt.dev
   resources:
-  - workloadidentitybindings
+  - workloadidentitybindings/finalizers
   verbs:
-  - create
-  - delete
-  - get
-  - list
-  - patch
   - update
-  - watch
 - apiGroups:
-  - porch.kpt.dev
+  - config.porch.kpt.dev
   resources:
-  - workloadidentitybindings/finalizers
+  - workloadidentitybindings/status
   verbs:
+  - get
+  - patch
   - update
 - apiGroups:
-  - porch.kpt.dev
+  - coordination.k8s.io
   resources:
-  - workloadidentitybindings/status
+  - leases
   verbs:
+  - create
+  - delete
   - get
+  - list
   - patch
   - update
+  - watch
diff --git a/porch/controllers/main.go b/porch/controllers/main.go
index c3b41932..dd734cb5 100644
--- a/porch/controllers/main.go
+++ b/porch/controllers/main.go
@@ -14,7 +14,7 @@
 
 package main
 
-//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0 rbac:roleName=configmanagement-operator webhook paths="./..."
+//go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0 rbac:roleName=porch-controllers webhook paths="./..."
 
 //go:generate go run sigs.k8s.io/controller-tools/cmd/controller-gen@v0.8.0 crd paths="./..." output:crd:artifacts:config=config/crd/bases
 
@@ -88,7 +88,7 @@ func run(ctx context.Context) error {
 		Port:                       9443,
 		HealthProbeBindAddress:     ":8081",
 		LeaderElection:             false,
-		LeaderElectionID:           "porch-operators.config.cloud.google.com",
+		LeaderElectionID:           "porch-operators.config.porch.kpt.dev",
 		LeaderElectionResourceLock: resourcelock.LeasesResourceLock,
 	}
 
diff --git a/porch/controllers/remoterootsync/api/v1alpha1/groupversion_info.go b/porch/controllers/remoterootsync/api/v1alpha1/groupversion_info.go
index b3c81d39..aa52eab1 100644
--- a/porch/controllers/remoterootsync/api/v1alpha1/groupversion_info.go
+++ b/porch/controllers/remoterootsync/api/v1alpha1/groupversion_info.go
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package v1alpha1 contains API Schema definitions for the config.cloud.google.com v1alpha1 API group
+// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group
 // +kubebuilder:object:generate=true
-// +groupName=config.cloud.google.com
+// +groupName=config.porch.kpt.dev
 package v1alpha1
 
 import (
@@ -26,7 +26,7 @@ import (
 
 var (
 	// GroupVersion is group version used to register these objects
-	GroupVersion = schema.GroupVersion{Group: "config.cloud.google.com", Version: "v1alpha1"}
+	GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"}
 
 	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
 	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
diff --git a/porch/controllers/remoterootsync/config/samples/apply-to-gke.yaml b/porch/controllers/remoterootsync/config/samples/apply-to-gke.yaml
index 1d8f44b4..76514b81 100644
--- a/porch/controllers/remoterootsync/config/samples/apply-to-gke.yaml
+++ b/porch/controllers/remoterootsync/config/samples/apply-to-gke.yaml
@@ -26,7 +26,7 @@ spec:
 
 ---
 
-apiVersion: config.cloud.google.com/v1alpha1
+apiVersion: config.porch.kpt.dev/v1alpha1
 kind: RemoteRootSyncSet
 metadata:
   name: example-1
diff --git a/porch/controllers/remoterootsync/config/samples/hack-self-apply.yaml b/porch/controllers/remoterootsync/config/samples/hack-self-apply.yaml
index c439d2f6..9fda6390 100644
--- a/porch/controllers/remoterootsync/config/samples/hack-self-apply.yaml
+++ b/porch/controllers/remoterootsync/config/samples/hack-self-apply.yaml
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 
-apiVersion: config.cloud.google.com/v1alpha1
+apiVersion: config.porch.kpt.dev/v1alpha1
 kind: RemoteRootSyncSet
 metadata:
   name: loopback-apply
diff --git a/porch/controllers/remoterootsync/pkg/controllers/remoterootsyncset/remoterootsync_controller.go b/porch/controllers/remoterootsync/pkg/controllers/remoterootsyncset/remoterootsync_controller.go
index 997ef297..d8113e26 100644
--- a/porch/controllers/remoterootsync/pkg/controllers/remoterootsyncset/remoterootsync_controller.go
+++ b/porch/controllers/remoterootsync/pkg/controllers/remoterootsyncset/remoterootsync_controller.go
@@ -62,9 +62,9 @@ type RemoteRootSyncSetReconciler struct {
 	localRESTConfig *rest.Config
 }
 
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=remoterootsyncs,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=remoterootsyncs/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=remoterootsyncs/finalizers,verbs=update
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=remoterootsyncsets/finalizers,verbs=update
 
 // Reconcile implements the main kubernetes reconciliation loop.
 func (r *RemoteRootSyncSetReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
@@ -72,7 +72,7 @@ func (r *RemoteRootSyncSetReconciler) Reconcile(ctx context.Context, req ctrl.Re
 	if err := r.Get(ctx, req.NamespacedName, &subject); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}
-	myFinalizerName := "config.cloud.google.com/finalizer"
+	myFinalizerName := "config.porch.kpt.dev/finalizer"
 	if subject.ObjectMeta.DeletionTimestamp.IsZero() {
 		// The object is not being deleted, so if it does not have our finalizer,
 		// then lets add the finalizer and update the object. This is equivalent
diff --git a/porch/controllers/rootsyncset/api/v1alpha1/groupversion_info.go b/porch/controllers/rootsyncset/api/v1alpha1/groupversion_info.go
index 31b116ac..6866e810 100644
--- a/porch/controllers/rootsyncset/api/v1alpha1/groupversion_info.go
+++ b/porch/controllers/rootsyncset/api/v1alpha1/groupversion_info.go
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package v1alpha1 contains API Schema definitions for the config.cloud.google.com v1alpha1 API group
+// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group
 //+kubebuilder:object:generate=true
-//+groupName=config.cloud.google.com
+//+groupName=config.porch.kpt.dev
 package v1alpha1
 
 import (
@@ -26,7 +26,7 @@ import (
 
 var (
 	// GroupVersion is group version used to register these objects
-	GroupVersion = schema.GroupVersion{Group: "config.cloud.google.com", Version: "v1alpha1"}
+	GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"}
 
 	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
 	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
diff --git a/porch/controllers/rootsyncset/pkg/controllers/rootsyncset/controller.go b/porch/controllers/rootsyncset/pkg/controllers/rootsyncset/controller.go
index 572ac49d..878b306b 100644
--- a/porch/controllers/rootsyncset/pkg/controllers/rootsyncset/controller.go
+++ b/porch/controllers/rootsyncset/pkg/controllers/rootsyncset/controller.go
@@ -55,9 +55,9 @@ type RootSyncSetReconciler struct {
 	WorkloadIdentityHelper
 }
 
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=rootsyncsets,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=rootsyncsets/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=config.cloud.google.com,resources=rootsyncsets/finalizers,verbs=update
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=rootsyncsets/finalizers,verbs=update
 
 // Reconcile is part of the main kubernetes reconciliation loop which aims to
 // move the current state of the cluster closer to the desired state.
@@ -74,7 +74,7 @@ func (r *RootSyncSetReconciler) Reconcile(ctx context.Context, req ctrl.Request)
 	if err := r.Get(ctx, req.NamespacedName, &rootsyncset); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}
-	myFinalizerName := "config.cloud.google.com/finalizer"
+	myFinalizerName := "config.porch.kpt.dev/finalizer"
 	if rootsyncset.ObjectMeta.DeletionTimestamp.IsZero() {
 		// The object is not being deleted, so if it does not have our finalizer,
 		// then lets add the finalizer and update the object. This is equivalent
diff --git a/porch/controllers/workloadidentitybinding/api/v1alpha1/groupversion_info.go b/porch/controllers/workloadidentitybinding/api/v1alpha1/groupversion_info.go
index dfb0987d..aa52eab1 100644
--- a/porch/controllers/workloadidentitybinding/api/v1alpha1/groupversion_info.go
+++ b/porch/controllers/workloadidentitybinding/api/v1alpha1/groupversion_info.go
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// Package v1alpha1 contains API Schema definitions for the porch.kpt.dev v1alpha1 API group
+// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group
 // +kubebuilder:object:generate=true
-// +groupName=porch.kpt.dev
+// +groupName=config.porch.kpt.dev
 package v1alpha1
 
 import (
@@ -26,7 +26,7 @@ import (
 
 var (
 	// GroupVersion is group version used to register these objects
-	GroupVersion = schema.GroupVersion{Group: "porch.kpt.dev", Version: "v1alpha1"}
+	GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"}
 
 	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
 	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
diff --git a/porch/controllers/workloadidentitybinding/config/samples/simple.yaml b/porch/controllers/workloadidentitybinding/config/samples/simple.yaml
index 4c8a0bd6..02dee97a 100644
--- a/porch/controllers/workloadidentitybinding/config/samples/simple.yaml
+++ b/porch/controllers/workloadidentitybinding/config/samples/simple.yaml
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-apiVersion: porch.kpt.dev/v1alpha1
+apiVersion: config.porch.kpt.dev/v1alpha1
 kind: WorkloadIdentityBinding
 metadata:
   name: cnrm-controller-manager-example-project-id
diff --git a/porch/controllers/workloadidentitybinding/pkg/controllers/workloadidentitybinding/controller.go b/porch/controllers/workloadidentitybinding/pkg/controllers/workloadidentitybinding/controller.go
index be4da9f9..07f50f83 100644
--- a/porch/controllers/workloadidentitybinding/pkg/controllers/workloadidentitybinding/controller.go
+++ b/porch/controllers/workloadidentitybinding/pkg/controllers/workloadidentitybinding/controller.go
@@ -40,9 +40,9 @@ type WorkloadIdentityBindingReconciler struct {
 	restMapper    meta.RESTMapper
 }
 
-//+kubebuilder:rbac:groups=porch.kpt.dev,resources=workloadidentitybindings,verbs=get;list;watch;create;update;patch;delete
-//+kubebuilder:rbac:groups=porch.kpt.dev,resources=workloadidentitybindings/status,verbs=get;update;patch
-//+kubebuilder:rbac:groups=porch.kpt.dev,resources=workloadidentitybindings/finalizers,verbs=update
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings,verbs=get;list;watch;create;update;patch;delete
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/status,verbs=get;update;patch
+//+kubebuilder:rbac:groups=config.porch.kpt.dev,resources=workloadidentitybindings/finalizers,verbs=update
 
 // Reconcile implements the main kubernetes reconciliation loop.
 func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
@@ -50,7 +50,7 @@ func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req c
 	if err := r.Get(ctx, req.NamespacedName, &subject); err != nil {
 		return ctrl.Result{}, client.IgnoreNotFound(err)
 	}
-	// myFinalizerName := "config.cloud.google.com/finalizer"
+	// myFinalizerName := "config.porch.kpt.dev/finalizer"
 	// if subject.ObjectMeta.DeletionTimestamp.IsZero() {
 	// 	// The object is not being deleted, so if it does not have our finalizer,
 	// 	// then lets add the finalizer and update the object. This is equivalent
@@ -105,10 +105,14 @@ func (r *WorkloadIdentityBindingReconciler) Reconcile(ctx context.Context, req c
 
 func updateStatus(subject *api.WorkloadIdentityBinding, results *applyset.ApplyResults, err error) bool {
 	conditions := &subject.Status.Conditions
-	if err == nil {
-		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"})
-	} else {
+	if err != nil {
 		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "Error"})
+	} else if !results.AllApplied() {
+		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "ApplyInProgress"})
+	} else if !results.AllHealthy() {
+		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionFalse, Reason: "NotHealthy"})
+	} else {
+		meta.SetStatusCondition(conditions, metav1.Condition{Type: "Ready", Status: metav1.ConditionTrue, Reason: "Ready"})
 	}
 
 	// TODO: Check apply results and think about status conditions
diff --git a/porch/deployments/porch/9-controllers.yaml b/porch/deployments/porch/9-controllers.yaml
index ddefb83a..5861fb28 100644
--- a/porch/deployments/porch/9-controllers.yaml
+++ b/porch/deployments/porch/9-controllers.yaml
@@ -49,21 +49,49 @@ spec:
           value: "1"
 
 ---
-
+# TODO: Part of this is currently copied from porch/controller/config/rbac/role.yaml
+# We should find a better solution.
 kind: ClusterRole
 apiVersion: rbac.authorization.k8s.io/v1
 metadata:
   name: porch-controllers
 rules:
+- apiGroups: [""]
+  resources: ["events"]
+  verbs: ["create", "patch"]
+- apiGroups: ["coordination.k8s.io"]
+  resources: ["leases"]
+  verbs: ["create", "delete", "get", "list", "patch", "update", "watch"]
 - apiGroups: ["config.porch.kpt.dev"]
   resources: ["repositories"]
   verbs: ["get", "list", "watch", "create", "update", "patch"]
-- apiGroups: ["config.cloud.google.com"]
+- apiGroups: ["config.porch.kpt.dev"]
   resources: ["remoterootsyncsets"]
   verbs: ["get", "list", "watch", "create", "update", "patch"]
-- apiGroups: ["config.cloud.google.com"]
+- apiGroups: ["config.porch.kpt.dev"]
   resources: ["remoterootsyncsets/status"]
   verbs: ["get", "list", "watch", "create", "update", "patch"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["remoterootsyncsets/finalizers"]
+  verbs: ["update"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["rootsyncsets"]
+  verbs: ["get", "list", "watch", "create", "update", "patch"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["rootsyncsets/status"]
+  verbs: ["get", "list", "watch", "create", "update", "patch"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["rootsyncsets/finalizers"]
+  verbs: ["update"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["workloadidentitybindings"]
+  verbs: ["get", "list", "watch", "create", "update", "patch"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["workloadidentitybindings/status"]
+  verbs: ["get", "list", "watch", "create", "update", "patch"]
+- apiGroups: ["config.porch.kpt.dev"]
+  resources: ["workloadidentitybindings/finalizers"]
+  verbs: ["update"]
 
 ---
 
diff --git a/porch/go.mod b/porch/go.mod
index 05edbda1..bcf6c4fe 100644
--- a/porch/go.mod
+++ b/porch/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace v0.4.1
 	github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark v0.4.3
 	github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54
-	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220707151439-cb4c4e496c92
+	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20220821193112-4792e5fa18ee
 	github.com/bluekeyes/go-gitdiff v0.6.1
 	github.com/go-git/go-billy/v5 v5.3.1
 	github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f
diff --git a/porch/scripts/create-deployment-blueprint.sh b/porch/scripts/create-deployment-blueprint.sh
index 7a37115a..931b7ce1 100755
--- a/porch/scripts/create-deployment-blueprint.sh
+++ b/porch/scripts/create-deployment-blueprint.sh
@@ -168,10 +168,15 @@ function customize-sa {
 
 function main() {
   # RemoteRootSync controller
-  cp "${PORCH_DIR}/controllers/config/crd/bases/config.cloud.google.com_remoterootsyncsets.yaml" \
+  cp "${PORCH_DIR}/controllers/config/crd/bases/config.porch.kpt.dev_remoterootsyncsets.yaml" \
      "${DESTINATION}/0-remoterootsyncsets.yaml"
-  cp "${PORCH_DIR}/controllers/config/rbac/role.yaml" \
-     "${DESTINATION}/0-remoterootsync-role.yaml"
+  # WorkloadIdentityBinding controller
+  cp "${PORCH_DIR}/controllers/config/crd/bases/config.porch.kpt.dev_workloadidentitybindings.yaml" \
+     "${DESTINATION}/0-workloadidentitybindings.yaml"
+  # RootSyncSet controller
+  cp "${PORCH_DIR}/controllers/config/crd/bases/config.porch.kpt.dev_rootsyncsets.yaml" \
+     "${DESTINATION}/0-rootsyncsets.yaml"
+
   # Repository CRD
   cp "./api/porchconfig/v1alpha1/config.porch.kpt.dev_repositories.yaml" \
      "${DESTINATION}/0-repositories.yaml"


Test patch:
diff --git a/internal/cmdreporeg/command_test.go b/internal/cmdreporeg/command_test.go
index 7d077ff5..67e28c82 100644
--- a/internal/cmdreporeg/command_test.go
+++ b/internal/cmdreporeg/command_test.go
@@ -100,6 +100,7 @@ func TestRepoReg(t *testing.T) {
 				"--deployment",
 				"--directory=/catalog",
 				"--branch=main-branch",
+				"--create-branch",
 				"--namespace=repository-namespace",
 			},
 			actions: []httpAction{
diff --git a/internal/cmdreporeg/testdata/full-repository.yaml b/internal/cmdreporeg/testdata/full-repository.yaml
index 486034f4..a3650ae6 100644
--- a/internal/cmdreporeg/testdata/full-repository.yaml
+++ b/internal/cmdreporeg/testdata/full-repository.yaml
@@ -10,6 +10,7 @@ spec:
     description: '"Test Repository Description"'
     git:
         branch: main-branch
+        createBranch: true
         directory: /catalog
         repo: https://github.com/platkrm/test-blueprints.git
         secretRef: