Repository: argoproj/argo-cd
Pull request #4683 (2020-10-27 19:08:54)

fix: Automated smoke test that mimics user behavior UI (#4393)
Signed-off-by: Keith Chong <kykchong@redhat.com>

This is part II of the automated UI tests for https://github.com/argoproj/argo-cd/issues/4393

The PR simply adds the unique identifiers to the relevant UI components, plus some formatting changes so as to not exceed 180 characters per line.  Feel free to suggest a new format of the identifiers, but they should be unique. I used the page/source as the 'prefix' to ensure there are no id clashes with similarly named components in other pages.

For example, if it is the `New App` button shown on the applications list page (application-list.tsx), the identifier is:
`applications-list-button-add-new`

For example, if it is the `Application Name` field shown on the application create sliding panel (application-create-panel.tsx), the identifier is:  `application-create-field-app-name`

Checklist:

* [x] Either (a) I've created an [enhancement proposal](https://github.com/argoproj/argo-cd/issues/new/choose) and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes.
* [x] The title of the PR states what changed and the related issues number (used for the release note).
* [ ] I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them.
* [ ] Does this PR require documentation updates?
* [ ] I've updated documentation as required by this PR.
* [ ] Optional. My organization is added to USERS.md.
* [ ] I've signed the CLA and my build is green ([troubleshooting builds](https://argoproj.github.io/argo-cd/developer-guide/ci/)). 


keithchong: Hi @alexmt, does the PR build pull in the latest ArgoUI?  When I build the UI, I don't see these build error.
alexmt: hello @keithchong , it does not. You need to run `yarn add https://github.com/argoproj/argo-ui.git` to pull latest version and regenerate yarn.lock file.

Patch:
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 6a08122ca..f5344da2b 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -6,8 +6,7 @@ labels: 'bug'
 assignees: ''
 ---
 
-If you are trying to resolve an environment-specific issue or have a one-off question about the edge case that does not require a feature then please consider asking a
-question in argocd slack [channel](https://argoproj.github.io/community/join-slack).
+If you are trying to resolve an environment-specific issue or have a one-off question about the edge case that does not require a feature then please consider asking a question in argocd slack [channel](https://argoproj.github.io/community/join-slack).
 
 Checklist:
 
diff --git a/cmd/argocd-application-controller/main.go b/cmd/argocd-application-controller/main.go
index d10e772c4..8358e25eb 100644
--- a/cmd/argocd-application-controller/main.go
+++ b/cmd/argocd-application-controller/main.go
@@ -7,8 +7,6 @@ import (
 	"os"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/argoproj/pkg/stats"
 	"github.com/go-redis/redis/v8"
 	log "github.com/sirupsen/logrus"
@@ -33,6 +31,8 @@ import (
 	appstatecache "github.com/argoproj/argo-cd/util/cache/appstate"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/env"
+	"github.com/argoproj/argo-cd/util/errors"
+	kubeutil "github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/settings"
 )
 
@@ -87,7 +87,7 @@ func newCommand() *cobra.Command {
 			errors.CheckError(err)
 
 			settingsMgr := settings.NewSettingsManager(ctx, kubeClient, namespace)
-			kubectl := &kube.KubectlCmd{}
+			kubectl := kubeutil.NewKubectl()
 			clusterFilter := getClusterFilter()
 			appController, err := controller.NewApplicationController(
 				namespace,
diff --git a/cmd/argocd-repo-server/main.go b/cmd/argocd-repo-server/main.go
index 8c46b86ab..ba17dd9cb 100644
--- a/cmd/argocd-repo-server/main.go
+++ b/cmd/argocd-repo-server/main.go
@@ -8,7 +8,6 @@ import (
 	"os"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/pkg/stats"
 	"github.com/go-redis/redis/v8"
 	log "github.com/sirupsen/logrus"
@@ -22,6 +21,7 @@ import (
 	cacheutil "github.com/argoproj/argo-cd/util/cache"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/env"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/gpg"
 	"github.com/argoproj/argo-cd/util/tls"
 )
diff --git a/cmd/argocd-server/commands/root.go b/cmd/argocd-server/commands/root.go
index f3fd593b9..764b8770e 100644
--- a/cmd/argocd-server/commands/root.go
+++ b/cmd/argocd-server/commands/root.go
@@ -4,15 +4,13 @@ import (
 	"context"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/pkg/stats"
 	"github.com/go-redis/redis/v8"
+	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/clientcmd"
 
-	log "github.com/sirupsen/logrus"
-
 	"github.com/argoproj/argo-cd/common"
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
@@ -21,6 +19,7 @@ import (
 	servercache "github.com/argoproj/argo-cd/server/cache"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/env"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/tls"
 )
diff --git a/cmd/argocd-server/main.go b/cmd/argocd-server/main.go
index e69617659..0f747842c 100644
--- a/cmd/argocd-server/main.go
+++ b/cmd/argocd-server/main.go
@@ -1,9 +1,8 @@
 package main
 
 import (
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	commands "github.com/argoproj/argo-cd/cmd/argocd-server/commands"
+	"github.com/argoproj/argo-cd/util/errors"
 
 	// load the gcp plugin (required to authenticate against GKE clusters).
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
diff --git a/cmd/argocd-util/commands/apps.go b/cmd/argocd-util/commands/apps.go
index 172784508..c5b8ee311 100644
--- a/cmd/argocd-util/commands/apps.go
+++ b/cmd/argocd-util/commands/apps.go
@@ -9,8 +9,6 @@ import (
 	"sort"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/ghodss/yaml"
 	"github.com/spf13/cobra"
 	apiv1 "k8s.io/api/core/v1"
@@ -32,6 +30,7 @@ import (
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/config"
 	"github.com/argoproj/argo-cd/util/db"
+	"github.com/argoproj/argo-cd/util/errors"
 	kubeutil "github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/settings"
 )
@@ -291,7 +290,7 @@ func reconcileApplications(
 	}
 
 	appStateManager := controller.NewAppStateManager(
-		argoDB, appClientset, repoServerClient, namespace, &kube.KubectlCmd{}, settingsMgr, stateCache, projInformer, server)
+		argoDB, appClientset, repoServerClient, namespace, kubeutil.NewKubectl(), settingsMgr, stateCache, projInformer, server)
 
 	appsList, err := appClientset.ArgoprojV1alpha1().Applications(namespace).List(context.Background(), v1.ListOptions{LabelSelector: selector})
 	if err != nil {
@@ -333,5 +332,5 @@ func reconcileApplications(
 }
 
 func newLiveStateCache(argoDB db.ArgoDB, appInformer kubecache.SharedIndexInformer, settingsMgr *settings.SettingsManager, server *metrics.MetricsServer) cache.LiveStateCache {
-	return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, &kube.KubectlCmd{}, server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, nil)
+	return cache.NewLiveStateCache(argoDB, appInformer, settingsMgr, kubeutil.NewKubectl(), server, func(managedByApp map[string]bool, ref apiv1.ObjectReference) {}, nil)
 }
diff --git a/cmd/argocd-util/commands/projects.go b/cmd/argocd-util/commands/projects.go
index 8d21a98e9..d5276bc3a 100644
--- a/cmd/argocd-util/commands/projects.go
+++ b/cmd/argocd-util/commands/projects.go
@@ -11,8 +11,8 @@ import (
 	appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
 	appclient "github.com/argoproj/argo-cd/pkg/client/clientset/versioned/typed/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/spf13/cobra"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/cmd/argocd-util/commands/settings.go b/cmd/argocd-util/commands/settings.go
index d618f1e65..607917c4f 100644
--- a/cmd/argocd-util/commands/settings.go
+++ b/cmd/argocd-util/commands/settings.go
@@ -13,7 +13,6 @@ import (
 	"text/tabwriter"
 
 	healthutil "github.com/argoproj/gitops-engine/pkg/health"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -28,6 +27,7 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/argo/normalizers"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/lua"
 	"github.com/argoproj/argo-cd/util/settings"
 )
diff --git a/cmd/argocd-util/main.go b/cmd/argocd-util/main.go
index 6b86d4c20..8511db9ad 100644
--- a/cmd/argocd-util/main.go
+++ b/cmd/argocd-util/main.go
@@ -11,7 +11,6 @@ import (
 	"reflect"
 	"syscall"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
@@ -31,6 +30,7 @@ import (
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/db"
 	"github.com/argoproj/argo-cd/util/dex"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/settings"
 
 	// load the gcp plugin (required to authenticate against GKE clusters).
diff --git a/cmd/argocd/commands/account.go b/cmd/argocd/commands/account.go
index 2cc7b6b22..a3c4c18a2 100644
--- a/cmd/argocd/commands/account.go
+++ b/cmd/argocd/commands/account.go
@@ -10,8 +10,6 @@ import (
 	"text/tabwriter"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	timeutil "github.com/argoproj/pkg/time"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
@@ -23,6 +21,8 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apiclient/session"
 	"github.com/argoproj/argo-cd/server/rbacpolicy"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/localconfig"
 	sessionutil "github.com/argoproj/argo-cd/util/session"
 )
diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go
index dbc9dec69..fa0fb1ff2 100644
--- a/cmd/argocd/commands/app.go
+++ b/cmd/argocd/commands/app.go
@@ -20,8 +20,6 @@ import (
 	"github.com/argoproj/gitops-engine/pkg/health"
 	"github.com/argoproj/gitops-engine/pkg/sync/hook"
 	"github.com/argoproj/gitops-engine/pkg/sync/ignore"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
@@ -49,7 +47,9 @@ import (
 	"github.com/argoproj/argo-cd/util/argo"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/config"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/git"
+	argoio "github.com/argoproj/argo-cd/util/io"
 	argokube "github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/templates"
 	"github.com/argoproj/argo-cd/util/text/label"
@@ -1140,7 +1140,7 @@ func NewApplicationDiffCommand(clientOpts *argocdclient.ClientOptions) *cobra.Co
 				normalizer, err := argo.NewDiffNormalizer(app.Spec.IgnoreDifferences, overrides)
 				errors.CheckError(err)
 
-				diffRes, err := diff.Diff(item.target, item.live, normalizer, diff.GetDefaultDiffOptions())
+				diffRes, err := diff.Diff(item.target, item.live, diff.WithNormalizer(normalizer))
 				errors.CheckError(err)
 
 				if diffRes.Modified || item.target == nil || item.live == nil {
diff --git a/cmd/argocd/commands/app_actions.go b/cmd/argocd/commands/app_actions.go
index 91794feb2..eb00ed6b3 100644
--- a/cmd/argocd/commands/app_actions.go
+++ b/cmd/argocd/commands/app_actions.go
@@ -8,14 +8,14 @@ import (
 	"strconv"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	applicationpkg "github.com/argoproj/argo-cd/pkg/apiclient/application"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 type DisplayedAction struct {
diff --git a/cmd/argocd/commands/cert.go b/cmd/argocd/commands/cert.go
index b4e754a53..e62a9f0d0 100644
--- a/cmd/argocd/commands/cert.go
+++ b/cmd/argocd/commands/cert.go
@@ -9,14 +9,14 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	certificatepkg "github.com/argoproj/argo-cd/pkg/apiclient/certificate"
 	appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	certutil "github.com/argoproj/argo-cd/util/cert"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewCertCommand returns a new instance of an `argocd repo` command
diff --git a/cmd/argocd/commands/cluster.go b/cmd/argocd/commands/cluster.go
index 48220280d..645872f57 100644
--- a/cmd/argocd/commands/cluster.go
+++ b/cmd/argocd/commands/cluster.go
@@ -9,8 +9,6 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"k8s.io/client-go/kubernetes"
@@ -22,6 +20,8 @@ import (
 	clusterpkg "github.com/argoproj/argo-cd/pkg/apiclient/cluster"
 	argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/clusterauth"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewClusterCommand returns a new instance of an `argocd cluster` command
diff --git a/cmd/argocd/commands/context.go b/cmd/argocd/commands/context.go
index e4f34d045..9cad666ab 100644
--- a/cmd/argocd/commands/context.go
+++ b/cmd/argocd/commands/context.go
@@ -8,11 +8,11 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/localconfig"
 )
 
diff --git a/cmd/argocd/commands/gpg.go b/cmd/argocd/commands/gpg.go
index d96a93418..438a342cb 100644
--- a/cmd/argocd/commands/gpg.go
+++ b/cmd/argocd/commands/gpg.go
@@ -8,13 +8,13 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	gpgkeypkg "github.com/argoproj/argo-cd/pkg/apiclient/gpgkey"
 	appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/util/errors"
+	argoio "github.com/argoproj/argo-cd/util/io"
 )
 
 // NewGPGCommand returns a new instance of an `argocd repo` command
diff --git a/cmd/argocd/commands/login.go b/cmd/argocd/commands/login.go
index 2f810aae1..67cf246b6 100644
--- a/cmd/argocd/commands/login.go
+++ b/cmd/argocd/commands/login.go
@@ -11,8 +11,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/coreos/go-oidc"
 	"github.com/dgrijalva/jwt-go"
 	log "github.com/sirupsen/logrus"
@@ -24,7 +22,9 @@ import (
 	sessionpkg "github.com/argoproj/argo-cd/pkg/apiclient/session"
 	settingspkg "github.com/argoproj/argo-cd/pkg/apiclient/settings"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
 	grpc_util "github.com/argoproj/argo-cd/util/grpc"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/localconfig"
 	oidcutil "github.com/argoproj/argo-cd/util/oidc"
 	"github.com/argoproj/argo-cd/util/rand"
diff --git a/cmd/argocd/commands/logout.go b/cmd/argocd/commands/logout.go
index b433c4aec..832efdcfb 100644
--- a/cmd/argocd/commands/logout.go
+++ b/cmd/argocd/commands/logout.go
@@ -4,11 +4,11 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/localconfig"
 )
 
diff --git a/cmd/argocd/commands/project.go b/cmd/argocd/commands/project.go
index 1c0f73abe..b88f2fe21 100644
--- a/cmd/argocd/commands/project.go
+++ b/cmd/argocd/commands/project.go
@@ -12,8 +12,6 @@ import (
 	"text/tabwriter"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	humanize "github.com/dustin/go-humanize"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
@@ -28,8 +26,10 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/config"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/git"
 	"github.com/argoproj/argo-cd/util/gpg"
+	argoio "github.com/argoproj/argo-cd/util/io"
 )
 
 type projectOpts struct {
diff --git a/cmd/argocd/commands/project_role.go b/cmd/argocd/commands/project_role.go
index ef2abf94b..fb10ac331 100644
--- a/cmd/argocd/commands/project_role.go
+++ b/cmd/argocd/commands/project_role.go
@@ -8,8 +8,6 @@ import (
 	"text/tabwriter"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	timeutil "github.com/argoproj/pkg/time"
 	jwtgo "github.com/dgrijalva/jwt-go"
 	"github.com/spf13/cobra"
@@ -17,6 +15,8 @@ import (
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	projectpkg "github.com/argoproj/argo-cd/pkg/apiclient/project"
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 const (
diff --git a/cmd/argocd/commands/projectwindows.go b/cmd/argocd/commands/projectwindows.go
index 2b808e556..e32952480 100644
--- a/cmd/argocd/commands/projectwindows.go
+++ b/cmd/argocd/commands/projectwindows.go
@@ -8,13 +8,13 @@ import (
 	"strings"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	projectpkg "github.com/argoproj/argo-cd/pkg/apiclient/project"
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewProjectWindowsCommand returns a new instance of the `argocd proj windows` command
diff --git a/cmd/argocd/commands/relogin.go b/cmd/argocd/commands/relogin.go
index 344baab8f..61cf46310 100644
--- a/cmd/argocd/commands/relogin.go
+++ b/cmd/argocd/commands/relogin.go
@@ -5,14 +5,14 @@ import (
 	"fmt"
 	"os"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/coreos/go-oidc"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	settingspkg "github.com/argoproj/argo-cd/pkg/apiclient/settings"
+	"github.com/argoproj/argo-cd/util/errors"
+	argoio "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/localconfig"
 	"github.com/argoproj/argo-cd/util/session"
 )
diff --git a/cmd/argocd/commands/repo.go b/cmd/argocd/commands/repo.go
index 9bbc35a90..035416e82 100644
--- a/cmd/argocd/commands/repo.go
+++ b/cmd/argocd/commands/repo.go
@@ -7,8 +7,6 @@ import (
 	"os"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
@@ -17,7 +15,9 @@ import (
 	repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
 	appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/git"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewRepoCommand returns a new instance of an `argocd repo` command
diff --git a/cmd/argocd/commands/repocreds.go b/cmd/argocd/commands/repocreds.go
index 5be819e2d..44fdbbb20 100644
--- a/cmd/argocd/commands/repocreds.go
+++ b/cmd/argocd/commands/repocreds.go
@@ -7,8 +7,6 @@ import (
 	"os"
 	"text/tabwriter"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
@@ -16,7 +14,9 @@ import (
 	repocredspkg "github.com/argoproj/argo-cd/pkg/apiclient/repocreds"
 	appsv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/cli"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/git"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewRepoCredsCommand returns a new instance of an `argocd repocreds` command
diff --git a/cmd/argocd/commands/root.go b/cmd/argocd/commands/root.go
index 0ffc35636..0b33a5e73 100644
--- a/cmd/argocd/commands/root.go
+++ b/cmd/argocd/commands/root.go
@@ -1,13 +1,13 @@
 package commands
 
 import (
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/spf13/cobra"
 	"k8s.io/client-go/tools/clientcmd"
 
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	"github.com/argoproj/argo-cd/util/cli"
 	"github.com/argoproj/argo-cd/util/config"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/localconfig"
 )
 
diff --git a/cmd/argocd/commands/version.go b/cmd/argocd/commands/version.go
index a4d71c06e..c3a669ed1 100644
--- a/cmd/argocd/commands/version.go
+++ b/cmd/argocd/commands/version.go
@@ -8,12 +8,11 @@ import (
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
-
 	"github.com/argoproj/argo-cd/common"
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	"github.com/argoproj/argo-cd/pkg/apiclient/version"
+	"github.com/argoproj/argo-cd/util/errors"
+	argoio "github.com/argoproj/argo-cd/util/io"
 )
 
 // NewVersionCmd returns a new `version` command to be used as a sub-command to root
diff --git a/cmd/argocd/main.go b/cmd/argocd/main.go
index 394501165..5e1e67133 100644
--- a/cmd/argocd/main.go
+++ b/cmd/argocd/main.go
@@ -1,9 +1,8 @@
 package main
 
 import (
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	commands "github.com/argoproj/argo-cd/cmd/argocd/commands"
+	"github.com/argoproj/argo-cd/util/errors"
 
 	// load the gcp plugin (required to authenticate against GKE clusters).
 	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
diff --git a/controller/appcontroller.go b/controller/appcontroller.go
index a5ad93143..52e0e70cf 100644
--- a/controller/appcontroller.go
+++ b/controller/appcontroller.go
@@ -13,11 +13,11 @@ import (
 	"sync"
 	"time"
 
+	logutils "github.com/argoproj/argo-cd/util/log"
+
 	"github.com/argoproj/gitops-engine/pkg/diff"
 	"github.com/argoproj/gitops-engine/pkg/health"
 	synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	log "github.com/sirupsen/logrus"
 	"golang.org/x/sync/semaphore"
@@ -49,6 +49,7 @@ import (
 	"github.com/argoproj/argo-cd/util/argo"
 	appstatecache "github.com/argoproj/argo-cd/util/cache/appstate"
 	"github.com/argoproj/argo-cd/util/db"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/glob"
 	settings_util "github.com/argoproj/argo-cd/util/settings"
 )
@@ -195,7 +196,7 @@ func (ctrl *ApplicationController) GetMetricsServer() *metrics.MetricsServer {
 	return ctrl.metricsServer
 }
 
-func (ctrl *ApplicationController) onKubectlRun(command string) (io.Closer, error) {
+func (ctrl *ApplicationController) onKubectlRun(command string) (kube.CleanupFunc, error) {
 	ctrl.metricsServer.IncKubectlExec(command)
 	if ctrl.kubectlSemaphore != nil {
 		if err := ctrl.kubectlSemaphore.Acquire(context.Background(), 1); err != nil {
@@ -203,13 +204,12 @@ func (ctrl *ApplicationController) onKubectlRun(command string) (io.Closer, erro
 		}
 		ctrl.metricsServer.IncKubectlExecPending(command)
 	}
-	return io.NewCloser(func() error {
+	return func() {
 		if ctrl.kubectlSemaphore != nil {
 			ctrl.kubectlSemaphore.Release(1)
 			ctrl.metricsServer.DecKubectlExecPending(command)
 		}
-		return nil
-	}), nil
+	}, nil
 }
 
 func isSelfReferencedApp(app *appv1.Application, ref v1.ObjectReference) bool {
@@ -409,7 +409,10 @@ func (ctrl *ApplicationController) managedResources(comparisonResult *comparison
 			if err != nil {
 				return nil, err
 			}
-			resDiffPtr, err := diff.Diff(target, live, comparisonResult.diffNormalizer, compareOptions)
+			resDiffPtr, err := diff.Diff(target, live,
+				diff.WithNormalizer(comparisonResult.diffNormalizer),
+				diff.WithLogr(logutils.NewLogrusLogger(log.New())),
+				diff.IgnoreAggregatedRoles(compareOptions.IgnoreAggregatedRoles))
 			if err != nil {
 				return nil, err
 			}
@@ -914,7 +917,7 @@ func (ctrl *ApplicationController) processRequestedAppOperation(app *appv1.Appli
 }
 
 func (ctrl *ApplicationController) setOperationState(app *appv1.Application, state *appv1.OperationState) {
-	kube.RetryUntilSucceed(context.Background(), updateOperationStateTimeout, "Update application operation state", func() error {
+	kube.RetryUntilSucceed(context.Background(), updateOperationStateTimeout, "Update application operation state", logutils.NewLogrusLogger(log.New()), func() error {
 		if state.Phase == "" {
 			// expose any bugs where we neglect to set phase
 			panic("no phase was set")
diff --git a/controller/cache/cache.go b/controller/cache/cache.go
index f9ea4cb3f..d3521cd00 100644
--- a/controller/cache/cache.go
+++ b/controller/cache/cache.go
@@ -23,6 +23,7 @@ import (
 	appv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/argo"
 	"github.com/argoproj/argo-cd/util/db"
+	logutils "github.com/argoproj/argo-cd/util/log"
 	"github.com/argoproj/argo-cd/util/lua"
 	"github.com/argoproj/argo-cd/util/settings"
 )
@@ -264,6 +265,7 @@ func (c *liveStateCache) getCluster(server string) (clustercache.ClusterCache, e
 			// want the full resource to be available in our cache (to diff), so we store all CRDs
 			return res, res.AppName != "" || un.GroupVersionKind().Kind == kube.CustomResourceDefinitionKind
 		}),
+		clustercache.SetLogr(logutils.NewLogrusLogger(log.WithField("server", cluster.Server))),
 	)
 
 	_ = clusterCache.OnResourceUpdated(func(newRes *clustercache.Resource, oldRes *clustercache.Resource, namespaceResources map[kube.ResourceKey]*clustercache.Resource) {
@@ -434,7 +436,7 @@ func (c *liveStateCache) Init() error {
 func (c *liveStateCache) Run(ctx context.Context) error {
 	go c.watchSettings(ctx)
 
-	kube.RetryUntilSucceed(ctx, clustercache.ClusterRetryTimeout, "watch clusters", func() error {
+	kube.RetryUntilSucceed(ctx, clustercache.ClusterRetryTimeout, "watch clusters", logutils.NewLogrusLogger(log.New()), func() error {
 		return c.db.WatchClusters(ctx, c.handleAddEvent, c.handleModEvent, c.handleDeleteEvent)
 	})
 
diff --git a/controller/state.go b/controller/state.go
index cff645f0c..2e3d828eb 100644
--- a/controller/state.go
+++ b/controller/state.go
@@ -12,7 +12,6 @@ import (
 	hookutil "github.com/argoproj/gitops-engine/pkg/sync/hook"
 	"github.com/argoproj/gitops-engine/pkg/sync/ignore"
 	resourceutil "github.com/argoproj/gitops-engine/pkg/sync/resource"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	kubeutil "github.com/argoproj/gitops-engine/pkg/utils/kube"
 	log "github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -32,6 +31,7 @@ import (
 	"github.com/argoproj/argo-cd/util/db"
 	"github.com/argoproj/argo-cd/util/gpg"
 	argohealth "github.com/argoproj/argo-cd/util/health"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/settings"
 	"github.com/argoproj/argo-cd/util/stats"
 )
@@ -426,12 +426,15 @@ func (m *appStateManager) CompareAppState(app *v1alpha1.Application, project *ap
 	compareOptions, err := m.settingsMgr.GetResourceCompareOptions()
 	if err != nil {
 		log.Warnf("Could not get compare options from ConfigMap (assuming defaults): %v", err)
-		compareOptions = diff.GetDefaultDiffOptions()
+		compareOptions = settings.GetDefaultDiffOptions()
 	}
 
 	logCtx.Debugf("built managed objects list")
 	// Do the actual comparison
-	diffResults, err := diff.DiffArray(reconciliation.Target, reconciliation.Live, diffNormalizer, compareOptions)
+	diffResults, err := diff.DiffArray(
+		reconciliation.Target, reconciliation.Live,
+		diff.WithNormalizer(diffNormalizer),
+		diff.IgnoreAggregatedRoles(compareOptions.IgnoreAggregatedRoles))
 	if err != nil {
 		diffResults = &diff.DiffResultList{}
 		failedToLoadObjs = true
diff --git a/controller/sync.go b/controller/sync.go
index 706f1b1ff..dedfc71c3 100644
--- a/controller/sync.go
+++ b/controller/sync.go
@@ -19,6 +19,7 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	listersv1alpha1 "github.com/argoproj/argo-cd/pkg/client/listers/application/v1alpha1"
 	"github.com/argoproj/argo-cd/util/argo"
+	logutils "github.com/argoproj/argo-cd/util/log"
 	"github.com/argoproj/argo-cd/util/lua"
 	"github.com/argoproj/argo-cd/util/rand"
 )
@@ -126,7 +127,14 @@ func (m *appStateManager) SyncAppState(app *v1alpha1.Application, state *v1alpha
 			Order:       i + 1,
 		})
 	}
-	syncCtx, err := sync.NewSyncContext(compareResult.syncStatus.Revision, compareResult.reconciliationResult, restConfig, rawConfig, m.kubectl, app.Spec.Destination.Namespace, logEntry,
+	syncCtx, err := sync.NewSyncContext(
+		compareResult.syncStatus.Revision,
+		compareResult.reconciliationResult,
+		restConfig,
+		rawConfig,
+		m.kubectl,
+		app.Spec.Destination.Namespace,
+		sync.WithLogr(logutils.NewLogrusLogger(logEntry)),
 		sync.WithHealthOverride(lua.ResourceHealthOverrides(resourceOverrides)),
 		sync.WithPermissionValidator(func(un *unstructured.Unstructured, res *v1.APIResource) error {
 			if !proj.IsGroupKindPermitted(un.GroupVersionKind().GroupKind(), res.Namespaced) {
diff --git a/go.mod b/go.mod
index f6b299ceb..61e098b29 100644
--- a/go.mod
+++ b/go.mod
@@ -7,8 +7,9 @@ require (
 	github.com/TomOnTime/utfutil v0.0.0-20180511104225-09c41003ee1d
 	github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect
 	github.com/alicebob/miniredis v2.5.0+incompatible
-	github.com/argoproj/gitops-engine v0.1.3-0.20201014183719-4eb3ca3feefb
+	github.com/argoproj/gitops-engine v0.1.3-0.20201027001456-31311943a57a
 	github.com/argoproj/pkg v0.2.0
+	github.com/bombsimon/logrusr v0.0.0-20200131103305-03a291ce59b4
 	github.com/casbin/casbin v1.9.1
 	github.com/chai2010/gettext-go v0.0.0-20170215093142-bf70f2a70fb1 // indirect
 	github.com/coreos/go-oidc v2.1.0+incompatible
@@ -18,6 +19,7 @@ require (
 	github.com/evanphx/json-patch v4.9.0+incompatible
 	github.com/fsnotify/fsnotify v1.4.9
 	github.com/ghodss/yaml v1.0.0
+	github.com/go-logr/logr v0.2.1
 	github.com/go-openapi/loads v0.19.4
 	github.com/go-openapi/runtime v0.19.4
 	github.com/go-openapi/spec v0.19.3
diff --git a/go.sum b/go.sum
index 5d9ed22bc..ad7a36508 100644
--- a/go.sum
+++ b/go.sum
@@ -84,8 +84,8 @@ github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
-github.com/argoproj/gitops-engine v0.1.3-0.20201014183719-4eb3ca3feefb h1:lf5CH6YyPqBJhg7DEI7h75A/Bu4Sfv9OjPePr0mlDl0=
-github.com/argoproj/gitops-engine v0.1.3-0.20201014183719-4eb3ca3feefb/go.mod h1:q1l0iuCyihknkeO3ne6cvOuagsp2NR+7ijRovlDz254=
+github.com/argoproj/gitops-engine v0.1.3-0.20201027001456-31311943a57a h1:ShQaYWNaNKJ8iy65vkftl6jYbDU2kLiAdQ0XJ8LSlOo=
+github.com/argoproj/gitops-engine v0.1.3-0.20201027001456-31311943a57a/go.mod h1:7Hzxz1c5YFXpAsM+i9L4LzKPnt8oY0t9QaGgEEUbQuc=
 github.com/argoproj/pkg v0.2.0 h1:ETgC600kr8WcAi3MEVY5sA1H7H/u1/IysYOobwsZ8No=
 github.com/argoproj/pkg v0.2.0/go.mod h1:F4TZgInLUEjzsWFB/BTJBsewoEy0ucnKSq6vmQiD/yc=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -111,6 +111,8 @@ github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb
 github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs=
 github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
 github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
+github.com/bombsimon/logrusr v0.0.0-20200131103305-03a291ce59b4 h1:Myj4mlaLi25AoncNPb8uf+Riru0Mp4xw7S9RUxBCYxk=
+github.com/bombsimon/logrusr v0.0.0-20200131103305-03a291ce59b4/go.mod h1:Jq0nHtvxabKE5EMwAAdgTaz7dfWE8C4i11NOltxGQpc=
 github.com/caddyserver/caddy v1.0.3/go.mod h1:G+ouvOY32gENkJC+jhgl62TyhvqEsFaDiZ4uw0RzP1E=
 github.com/casbin/casbin v1.9.1 h1:ucjbS5zTrmSLtH4XogqOG920Poe6QatdXtz1FEbApeM=
 github.com/casbin/casbin v1.9.1/go.mod h1:z8uPsfBJGUsnkagrt3G8QvjgTKFMBJ32UP8HpZllfog=
@@ -236,6 +238,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-logr/logr v0.2.1 h1:fV3MLmabKIZ383XifUjFSwcoGee0v9qgPp8wy5svibE=
+github.com/go-logr/logr v0.2.1/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
 github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
 github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
 github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
@@ -324,6 +328,8 @@ github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200j
 github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
 github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
+github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
 github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
diff --git a/pkg/apiclient/apiclient.go b/pkg/apiclient/apiclient.go
index 136145434..f862e8351 100644
--- a/pkg/apiclient/apiclient.go
+++ b/pkg/apiclient/apiclient.go
@@ -15,9 +15,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/argoproj/argo-cd/util/kube"
-
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/coreos/go-oidc"
 	"github.com/dgrijalva/jwt-go"
 	log "github.com/sirupsen/logrus"
@@ -43,6 +40,8 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	argoappv1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	grpc_util "github.com/argoproj/argo-cd/util/grpc"
+	argoio "github.com/argoproj/argo-cd/util/io"
+	"github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/localconfig"
 	oidcutil "github.com/argoproj/argo-cd/util/oidc"
 	tls_util "github.com/argoproj/argo-cd/util/tls"
diff --git a/pkg/apiclient/grpcproxy.go b/pkg/apiclient/grpcproxy.go
index a7fb83902..0c8e3ed65 100644
--- a/pkg/apiclient/grpcproxy.go
+++ b/pkg/apiclient/grpcproxy.go
@@ -11,13 +11,13 @@ import (
 	"strconv"
 	"strings"
 
-	argocderrors "github.com/argoproj/gitops-engine/pkg/utils/errors"
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/metadata"
 	"google.golang.org/grpc/status"
 
+	argocderrors "github.com/argoproj/argo-cd/util/errors"
+	argoio "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/rand"
 )
 
diff --git a/reposerver/apiclient/clientset.go b/reposerver/apiclient/clientset.go
index 788363f8b..945fdbbeb 100644
--- a/reposerver/apiclient/clientset.go
+++ b/reposerver/apiclient/clientset.go
@@ -4,7 +4,6 @@ import (
 	"crypto/tls"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
 	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
 	log "github.com/sirupsen/logrus"
@@ -12,6 +11,7 @@ import (
 	"google.golang.org/grpc/credentials"
 
 	argogrpc "github.com/argoproj/argo-cd/util/grpc"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 const (
diff --git a/reposerver/apiclient/mocks/Clientset.go b/reposerver/apiclient/mocks/Clientset.go
index 9f33e845f..a41b33455 100644
--- a/reposerver/apiclient/mocks/Clientset.go
+++ b/reposerver/apiclient/mocks/Clientset.go
@@ -3,7 +3,7 @@ package mocks
 import (
 	apiclient "github.com/argoproj/argo-cd/reposerver/apiclient"
 
-	io "github.com/argoproj/gitops-engine/pkg/utils/io"
+	io "github.com/argoproj/argo-cd/util/io"
 )
 
 type Clientset struct {
diff --git a/reposerver/repository/lock.go b/reposerver/repository/lock.go
index 385ac4a1d..86cb37186 100644
--- a/reposerver/repository/lock.go
+++ b/reposerver/repository/lock.go
@@ -4,7 +4,7 @@ import (
 	"io"
 	"sync"
 
-	ioutil "github.com/argoproj/gitops-engine/pkg/utils/io"
+	ioutil "github.com/argoproj/argo-cd/util/io"
 )
 
 func NewRepositoryLock() *repositoryLock {
diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go
index 68c040803..c222c0a39 100644
--- a/reposerver/repository/repository.go
+++ b/reposerver/repository/repository.go
@@ -17,7 +17,6 @@ import (
 
 	"github.com/Masterminds/semver"
 	"github.com/TomOnTime/utfutil"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	textutils "github.com/argoproj/gitops-engine/pkg/utils/text"
 	"github.com/argoproj/pkg/sync"
@@ -44,6 +43,7 @@ import (
 	"github.com/argoproj/argo-cd/util/git"
 	"github.com/argoproj/argo-cd/util/gpg"
 	"github.com/argoproj/argo-cd/util/helm"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/ksonnet"
 	argokube "github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/kustomize"
diff --git a/server/application/application.go b/server/application/application.go
index ac2fdc4dd..f3fd7ca02 100644
--- a/server/application/application.go
+++ b/server/application/application.go
@@ -16,7 +16,6 @@ import (
 	"github.com/Masterminds/semver"
 	"github.com/argoproj/gitops-engine/pkg/diff"
 	"github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/argoproj/gitops-engine/pkg/utils/text"
 	"github.com/argoproj/pkg/sync"
@@ -53,6 +52,7 @@ import (
 	"github.com/argoproj/argo-cd/util/env"
 	"github.com/argoproj/argo-cd/util/git"
 	"github.com/argoproj/argo-cd/util/helm"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/lua"
 	"github.com/argoproj/argo-cd/util/rbac"
 	"github.com/argoproj/argo-cd/util/session"
diff --git a/server/repository/repository.go b/server/repository/repository.go
index fee4dd86f..7672bb8b8 100644
--- a/server/repository/repository.go
+++ b/server/repository/repository.go
@@ -4,7 +4,6 @@ import (
 	"fmt"
 	"reflect"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/argoproj/gitops-engine/pkg/utils/text"
 	log "github.com/sirupsen/logrus"
@@ -21,6 +20,7 @@ import (
 	"github.com/argoproj/argo-cd/server/rbacpolicy"
 	"github.com/argoproj/argo-cd/util/argo"
 	"github.com/argoproj/argo-cd/util/db"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/rbac"
 	"github.com/argoproj/argo-cd/util/settings"
 )
diff --git a/server/server.go b/server/server.go
index e2531e847..ff42dca80 100644
--- a/server/server.go
+++ b/server/server.go
@@ -19,9 +19,6 @@ import (
 	// nolint:staticcheck
 	golang_proto "github.com/golang/protobuf/proto"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
-	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/argoproj/pkg/jwt/zjwt"
 	"github.com/argoproj/pkg/sync"
 	"github.com/dgrijalva/jwt-go"
@@ -89,9 +86,12 @@ import (
 	"github.com/argoproj/argo-cd/util/dex"
 	dexutil "github.com/argoproj/argo-cd/util/dex"
 	"github.com/argoproj/argo-cd/util/env"
+	"github.com/argoproj/argo-cd/util/errors"
 	grpc_util "github.com/argoproj/argo-cd/util/grpc"
 	"github.com/argoproj/argo-cd/util/healthz"
 	httputil "github.com/argoproj/argo-cd/util/http"
+	"github.com/argoproj/argo-cd/util/io"
+	kubeutil "github.com/argoproj/argo-cd/util/kube"
 	"github.com/argoproj/argo-cd/util/oidc"
 	"github.com/argoproj/argo-cd/util/rbac"
 	util_session "github.com/argoproj/argo-cd/util/session"
@@ -516,7 +516,7 @@ func (a *ArgoCDServer) newGRPCServer() *grpc.Server {
 	)))
 	grpcS := grpc.NewServer(sOpts...)
 	db := db.NewDB(a.Namespace, a.settingsMgr, a.KubeClientset)
-	kubectl := &kube.KubectlCmd{}
+	kubectl := kubeutil.NewKubectl()
 	clusterService := cluster.NewServer(db, a.enf, a.Cache, kubectl)
 	repoService := repository.NewServer(a.RepoClientset, db, a.enf, a.Cache, a.settingsMgr)
 	repoCredsService := repocreds.NewServer(a.RepoClientset, db, a.enf, a.settingsMgr)
diff --git a/server/session/ratelimiter.go b/server/session/ratelimiter.go
index 5bc432604..cd1b2ed98 100644
--- a/server/session/ratelimiter.go
+++ b/server/session/ratelimiter.go
@@ -1,12 +1,11 @@
 package session
 
 import (
+	util "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/session"
 
-	"golang.org/x/sync/semaphore"
-
-	util "github.com/argoproj/gitops-engine/pkg/utils/io"
 	log "github.com/sirupsen/logrus"
+	"golang.org/x/sync/semaphore"
 )
 
 func NewLoginRateLimiter(maxNumber int) func() (util.Closer, error) {
diff --git a/server/session/session.go b/server/session/session.go
index ab8fa6a93..480dec68c 100644
--- a/server/session/session.go
+++ b/server/session/session.go
@@ -3,12 +3,12 @@ package session
 import (
 	"context"
 
-	util "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"google.golang.org/grpc/codes"
 	"google.golang.org/grpc/status"
 
 	"github.com/argoproj/argo-cd/pkg/apiclient/session"
 	"github.com/argoproj/argo-cd/server/rbacpolicy"
+	util "github.com/argoproj/argo-cd/util/io"
 	sessionmgr "github.com/argoproj/argo-cd/util/session"
 )
 
diff --git a/server/version/version.go b/server/version/version.go
index 806cfcbd4..d1ab03254 100644
--- a/server/version/version.go
+++ b/server/version/version.go
@@ -1,17 +1,24 @@
 package version
 
 import (
-	"github.com/argoproj/gitops-engine/pkg/utils/kube"
-	"github.com/golang/protobuf/ptypes/empty"
-	"golang.org/x/net/context"
+	"errors"
+	"fmt"
+	"os/exec"
+	"regexp"
+	"strings"
 
+	"github.com/argoproj/gitops-engine/pkg/utils/tracing"
+	"github.com/golang/protobuf/ptypes/empty"
 	"github.com/google/go-jsonnet"
+	"github.com/sirupsen/logrus"
+	"golang.org/x/net/context"
 
 	"github.com/argoproj/argo-cd/common"
 	"github.com/argoproj/argo-cd/pkg/apiclient/version"
 	"github.com/argoproj/argo-cd/util/helm"
 	ksutil "github.com/argoproj/argo-cd/util/ksonnet"
 	"github.com/argoproj/argo-cd/util/kustomize"
+	"github.com/argoproj/argo-cd/util/log"
 )
 
 type Server struct {
@@ -22,6 +29,27 @@ type Server struct {
 	jsonnetVersion   string
 }
 
+func getVersion() (string, error) {
+	span := tracing.NewLoggingTracer(log.NewLogrusLogger(logrus.New())).StartSpan("Version")
+	defer span.Finish()
+	cmd := exec.Command("kubectl", "version", "--client")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return "", fmt.Errorf("could not get kubectl version: %s", err)
+	}
+
+	re := regexp.MustCompile(`GitVersion:"([a-zA-Z0-9\.\-]+)"`)
+	matches := re.FindStringSubmatch(string(out))
+	if len(matches) != 2 {
+		return "", errors.New("could not get kubectl version")
+	}
+	version := matches[1]
+	if version[0] != 'v' {
+		version = "v" + version
+	}
+	return strings.TrimSpace(version), nil
+}
+
 // Version returns the version of the API server
 func (s *Server) Version(context.Context, *empty.Empty) (*version.VersionMessage, error) {
 	vers := common.GetVersion()
@@ -50,7 +78,7 @@ func (s *Server) Version(context.Context, *empty.Empty) (*version.VersionMessage
 		}
 	}
 	if s.kubectlVersion == "" {
-		kubectlVersion, err := kube.Version()
+		kubectlVersion, err := getVersion()
 		if err == nil {
 			s.kubectlVersion = kubectlVersion
 		} else {
diff --git a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx
index 5a7f47a13..e29cbe12b 100644
--- a/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx
+++ b/ui/src/app/applications/components/application-create-panel/application-create-panel.tsx
@@ -180,19 +180,31 @@ export const ApplicationCreatePanel = (props: {
                                                     </button>
                                                 )}
                                                 <div className='argo-form-row'>
-                                                    <FormField formApi={api} label='Application Name' field='metadata.name' component={Text} />
+                                                    <FormField
+                                                        formApi={api}
+                                                        label='Application Name'
+                                                        qeId='application-create-field-app-name'
+                                                        field='metadata.name'
+                                                        component={Text}
+                                                    />
                                                 </div>
                                                 <div className='argo-form-row'>
                                                     <FormField
                                                         formApi={api}
                                                         label='Project'
+                                                        qeId='application-create-field-project'
                                                         field='spec.project'
                                                         component={AutocompleteField}
                                                         componentProps={{items: projects}}
                                                     />
                                                 </div>
                                                 <div className='argo-form-row'>
-                                                    <FormField formApi={api} field='spec.syncPolicy.automated' component={AutoSyncFormField} />
+                                                    <FormField
+                                                        formApi={api}
+                                                        field='spec.syncPolicy.automated'
+                                                        qeId='application-create-field-sync-policy'
+                                                        component={AutoSyncFormField}
+                                                    />
                                                 </div>
                                                 <div className='argo-form-row'>
                                                     <label>Sync Options</label>
@@ -210,6 +222,7 @@ export const ApplicationCreatePanel = (props: {
                                                         <FormField
                                                             formApi={api}
                                                             label='Repository URL'
+                                                            qeId='application-create-field-repository-url'
                                                             field='spec.source.repoURL'
                                                             component={AutocompleteField}
                                                             componentProps={{items: repos}}
@@ -228,6 +241,7 @@ export const ApplicationCreatePanel = (props: {
                                                                             {repoType.toUpperCase()} <i className='fa fa-caret-down' />
                                                                         </p>
                                                                     )}
+                                                                    qeId='application-create-dropdown-source-repository'
                                                                     items={['git', 'helm'].map((type: 'git' | 'helm') => ({
                                                                         title: type.toUpperCase(),
                                                                         action: () => {
@@ -265,6 +279,7 @@ export const ApplicationCreatePanel = (props: {
                                                                     <FormField
                                                                         formApi={api}
                                                                         label='Path'
+                                                                        qeId='application-create-field-path'
                                                                         field='spec.source.path'
                                                                         component={AutocompleteField}
                                                                         componentProps={{
@@ -326,6 +341,7 @@ export const ApplicationCreatePanel = (props: {
                                                             <FormField
                                                                 formApi={api}
                                                                 label='Cluster URL'
+                                                                qeId='application-create-field-cluster-url'
                                                                 field='spec.destination.server'
                                                                 componentProps={{items: clusters.map(cluster => cluster.server)}}
                                                                 component={AutocompleteField}
@@ -336,6 +352,7 @@ export const ApplicationCreatePanel = (props: {
                                                             <FormField
                                                                 formApi={api}
                                                                 label='Cluster Name'
+                                                                qeId='application-create-field-cluster-name'
                                                                 field='spec.destination.name'
                                                                 componentProps={{items: clusters.map(cluster => cluster.name)}}
                                                                 component={AutocompleteField}
@@ -350,6 +367,7 @@ export const ApplicationCreatePanel = (props: {
                                                                         {destFormat} <i className='fa fa-caret-down' />
                                                                     </p>
                                                                 )}
+                                                                qeId='application-create-dropdown-destination'
                                                                 items={['URL', 'NAME'].map((type: 'URL' | 'NAME') => ({
                                                                     title: type,
                                                                     action: () => {
@@ -370,7 +388,13 @@ export const ApplicationCreatePanel = (props: {
                                                     </div>
                                                 </div>
                                                 <div className='argo-form-row'>
-                                                    <FormField formApi={api} label='Namespace' field='spec.destination.namespace' component={Text} />
+                                                    <FormField
+                                                        qeId='application-create-field-namespace'
+                                                        formApi={api}
+                                                        label='Namespace'
+                                                        field='spec.destination.namespace'
+                                                        component={Text}
+                                                    />
                                                 </div>
                                             </div>
                                         );
@@ -430,6 +454,7 @@ export const ApplicationCreatePanel = (props: {
                                                                         {type} <i className='fa fa-caret-down' />
                                                                     </p>
                                                                 )}
+                                                                qeId='application-create-dropdown-source'
                                                                 items={appTypes.map(item => ({
                                                                     title: item.type,
                                                                     action: () => {
diff --git a/ui/src/app/applications/components/application-sync-panel/application-sync-panel.tsx b/ui/src/app/applications/components/application-sync-panel/application-sync-panel.tsx
index e77de490d..a56434f1d 100644
--- a/ui/src/app/applications/components/application-sync-panel/application-sync-panel.tsx
+++ b/ui/src/app/applications/components/application-sync-panel/application-sync-panel.tsx
@@ -27,7 +27,11 @@ export const ApplicationSyncPanel = ({application, selectedResource, hide}: {app
                     onClose={() => hide()}
                     header={
                         <div>
-                            <button className='argo-button argo-button--base' disabled={isPending} onClick={() => form.submitForm(null)}>
+                            <button
+                                qe-id='application-sync-panel-button-synchronize'
+                                className='argo-button argo-button--base'
+                                disabled={isPending}
+                                onClick={() => form.submitForm(null)}>
                                 <Spinner show={isPending} style={{marginRight: '5px'}} />
                                 Synchronize
                             </button>{' '}
diff --git a/ui/src/app/applications/components/applications-list/applications-list.tsx b/ui/src/app/applications/components/applications-list/applications-list.tsx
index e1c094a77..cdbc5a6be 100644
--- a/ui/src/app/applications/components/applications-list/applications-list.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-list.tsx
@@ -222,6 +222,7 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
                                     {
                                         title: 'New App',
                                         iconClassName: 'fa fa-plus',
+                                        qeId: 'applications-list-button-new-app',
                                         action: () => ctx.navigation.goto('.', {new: '{}'})
                                     },
                                     {
@@ -248,7 +249,10 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
                                                 <EmptyState icon='argo-icon-application'>
                                                     <h4>No applications yet</h4>
                                                     <h5>Create new application to start managing resources in your cluster</h5>
-                                                    <button className='argo-button argo-button--base' onClick={() => ctx.navigation.goto('.', {new: JSON.stringify({})})}>
+                                                    <button
+                                                        qe-id='applications-list-button-create-application'
+                                                        className='argo-button argo-button--base'
+                                                        onClick={() => ctx.navigation.goto('.', {new: JSON.stringify({})})}>
                                                         Create application
                                                     </button>
                                                 </EmptyState>
@@ -382,7 +386,11 @@ export const ApplicationsList = (props: RouteComponentProps<{}>) => {
                             onClose={() => ctx.navigation.goto('.', {new: null})}
                             header={
                                 <div>
-                                    <button className='argo-button argo-button--base' disabled={isAppCreatePending} onClick={() => createApi && createApi.submitForm(null)}>
+                                    <button
+                                        qe-id='applications-list-button-create'
+                                        className='argo-button argo-button--base'
+                                        disabled={isAppCreatePending}
+                                        onClick={() => createApi && createApi.submitForm(null)}>
                                         <Spinner show={isAppCreatePending} style={{marginRight: '5px'}} />
                                         Create
                                     </button>{' '}
diff --git a/ui/src/app/applications/components/applications-list/applications-tiles.tsx b/ui/src/app/applications/components/applications-list/applications-tiles.tsx
index 7ee7782c3..aab5f2a2f 100644
--- a/ui/src/app/applications/components/applications-list/applications-tiles.tsx
+++ b/ui/src/app/applications/components/applications-list/applications-tiles.tsx
@@ -75,7 +75,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
                                         <div className='columns small-3' title='Status:'>
                                             Status:
                                         </div>
-                                        <div className='columns small-9'>
+                                        <div className='columns small-9' qe-id='applications-tiles-health-status'>
                                             <AppUtils.HealthStatusIcon state={app.status.health} /> {app.status.health.status}
                                             &nbsp;
                                             <AppUtils.ComparisonStatusIcon status={app.status.sync.status} /> {app.status.sync.status}
@@ -133,6 +133,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
                                         <div className='columns applications-list__entry--actions'>
                                             <a
                                                 className='argo-button argo-button--base'
+                                                qe-id='applications-tiles-button-sync'
                                                 onClick={e => {
                                                     e.stopPropagation();
                                                     syncApplication(app.metadata.name);
@@ -142,6 +143,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
                                             &nbsp;
                                             <a
                                                 className='argo-button argo-button--base'
+                                                qe-id='applications-tiles-button-refresh'
                                                 {...AppUtils.refreshLinkAttrs(app)}
                                                 onClick={e => {
                                                     e.stopPropagation();
@@ -153,6 +155,7 @@ export const ApplicationTiles = ({applications, syncApplication, refreshApplicat
                                             &nbsp;
                                             <a
                                                 className='argo-button argo-button--base'
+                                                qe-id='applications-tiles-button-delete'
                                                 onClick={e => {
                                                     e.stopPropagation();
                                                     deleteApplication(app.metadata.name);
diff --git a/ui/src/app/applications/components/utils.tsx b/ui/src/app/applications/components/utils.tsx
index cbf1baa2f..dc6c4011e 100644
--- a/ui/src/app/applications/components/utils.tsx
+++ b/ui/src/app/applications/components/utils.tsx
@@ -85,7 +85,7 @@ export const OperationPhaseIcon = ({app}: {app: appModels.Application}) => {
             color = COLORS.operation.running;
             break;
     }
-    return <i title={getOperationStateTitle(app)} className={className} style={{color}} />;
+    return <i title={getOperationStateTitle(app)} qe-id='utils-operations-status-title' className={className} style={{color}} />;
 };
 
 export const ComparisonStatusIcon = ({status, resource, label}: {status: appModels.SyncStatusCode; resource?: {requiresPruning?: boolean}; label?: boolean}) => {
@@ -114,7 +114,7 @@ export const ComparisonStatusIcon = ({status, resource, label}: {status: appMode
     }
     return (
         <React.Fragment>
-            <i title={title} className={className} style={{color}} /> {label && title}
+            <i qe-id='utils-sync-status-title' title={title} className={className} style={{color}} /> {label && title}
         </React.Fragment>
     );
 };
@@ -179,7 +179,7 @@ export const HealthStatusIcon = ({state}: {state: appModels.HealthStatus}) => {
     if (state.message) {
         title = `${state.status}: ${state.message};`;
     }
-    return <i title={title} className={'fa ' + icon} style={{color}} />;
+    return <i qe-id='utils-health-status-title' title={title} className={'fa ' + icon} style={{color}} />;
 };
 
 export const ResourceResultIcon = ({resource}: {resource: appModels.ResourceResult}) => {
diff --git a/ui/yarn.lock b/ui/yarn.lock
index 080db61a0..3d618c2e4 100644
--- a/ui/yarn.lock
+++ b/ui/yarn.lock
@@ -1824,7 +1824,7 @@ are-we-there-yet@~1.1.2:
 
 "argo-ui@https://github.com/argoproj/argo-ui.git":
   version "1.0.0"
-  resolved "https://github.com/argoproj/argo-ui.git#5371e5ba1645d52679e7a57814c7793c830d0f02"
+  resolved "https://github.com/argoproj/argo-ui.git#3d2740a5531f77e137ea6470314a03a0fdf5f937"
   dependencies:
     "@fortawesome/fontawesome-free" "^5.8.1"
     "@tippy.js/react" "^2.1.2"
diff --git a/util/argo/argo.go b/util/argo/argo.go
index f7dd86799..972762209 100644
--- a/util/argo/argo.go
+++ b/util/argo/argo.go
@@ -7,7 +7,6 @@ import (
 	"strings"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	log "github.com/sirupsen/logrus"
 	"google.golang.org/grpc/codes"
@@ -25,6 +24,7 @@ import (
 	"github.com/argoproj/argo-cd/util/db"
 	"github.com/argoproj/argo-cd/util/git"
 	"github.com/argoproj/argo-cd/util/helm"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/settings"
 )
 
diff --git a/util/cache/redis.go b/util/cache/redis.go
index ab280567b..3510646b7 100644
--- a/util/cache/redis.go
+++ b/util/cache/redis.go
@@ -4,7 +4,8 @@ import (
 	"context"
 	"time"
 
-	ioutil "github.com/argoproj/gitops-engine/pkg/utils/io"
+	ioutil "github.com/argoproj/argo-cd/util/io"
+
 	rediscache "github.com/go-redis/cache/v8"
 	"github.com/go-redis/redis/v8"
 )
diff --git a/util/cli/cli.go b/util/cli/cli.go
index 77c346301..2c8ca3f87 100644
--- a/util/cli/cli.go
+++ b/util/cli/cli.go
@@ -14,8 +14,6 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/google/shlex"
 	log "github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
@@ -27,6 +25,8 @@ import (
 	"sigs.k8s.io/yaml"
 
 	"github.com/argoproj/argo-cd/common"
+	"github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // NewVersionCmd returns a new `version` command to be used as a sub-command to root
diff --git a/util/dex/dex.go b/util/dex/dex.go
index 4dbeba2bd..9676d1efa 100644
--- a/util/dex/dex.go
+++ b/util/dex/dex.go
@@ -12,7 +12,7 @@ import (
 	"regexp"
 	"strconv"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 var messageRe = regexp.MustCompile(`<p>(.*)([\s\S]*?)<\/p>`)
diff --git a/util/errors/errors.go b/util/errors/errors.go
new file mode 100644
index 000000000..f7f718682
--- /dev/null
+++ b/util/errors/errors.go
@@ -0,0 +1,59 @@
+package errors
+
+import (
+	"os"
+
+	log "github.com/sirupsen/logrus"
+)
+
+const (
+	// ErrorCommandSpecific is reserved for command specific indications
+	ErrorCommandSpecific = 1
+	// ErrorConnectionFailure is returned on connection failure to API endpoint
+	ErrorConnectionFailure = 11
+	// ErrorAPIResponse is returned on unexpected API response, i.e. authorization failure
+	ErrorAPIResponse = 12
+	// ErrorResourceDoesNotExist is returned when the requested resource does not exist
+	ErrorResourceDoesNotExist = 13
+	// ErrorGeneric is returned for generic error
+	ErrorGeneric = 20
+)
+
+// CheckError logs a fatal message and exits with ErrorGeneric if err is not nil
+func CheckError(err error) {
+	if err != nil {
+		Fatal(ErrorGeneric, err)
+	}
+}
+
+// CheckErrorWithCode is a convenience function to exit if an error is non-nil and exit if it was
+func CheckErrorWithCode(err error, exitcode int) {
+	if err != nil {
+		Fatal(exitcode, err)
+	}
+}
+
+// FailOnErr panics if there is an error. It returns the first value so you can use it if you cast it:
+// text := FailOrErr(Foo)).(string)
+func FailOnErr(v interface{}, err error) interface{} {
+	CheckError(err)
+	return v
+}
+
+// Fatal is a wrapper for logrus.Fatal() to exit with custom code
+func Fatal(exitcode int, args ...interface{}) {
+	exitfunc := func() {
+		os.Exit(exitcode)
+	}
+	log.RegisterExitHandler(exitfunc)
+	log.Fatal(args...)
+}
+
+// Fatalf is a wrapper for logrus.Fatalf() to exit with custom code
+func Fatalf(exitcode int, format string, args ...interface{}) {
+	exitfunc := func() {
+		os.Exit(exitcode)
+	}
+	log.RegisterExitHandler(exitfunc)
+	log.Fatalf(format, args...)
+}
diff --git a/util/exec/exec.go b/util/exec/exec.go
index cfd57575c..e35df987c 100644
--- a/util/exec/exec.go
+++ b/util/exec/exec.go
@@ -6,6 +6,10 @@ import (
 	"os/exec"
 	"time"
 
+	"github.com/sirupsen/logrus"
+
+	"github.com/argoproj/argo-cd/util/log"
+
 	argoexec "github.com/argoproj/pkg/exec"
 
 	tracing "github.com/argoproj/gitops-engine/pkg/utils/tracing"
@@ -30,7 +34,7 @@ func Run(cmd *exec.Cmd) (string, error) {
 }
 
 func RunWithRedactor(cmd *exec.Cmd, redactor func(text string) string) (string, error) {
-	span := tracing.StartSpan(fmt.Sprintf("exec %v", cmd.Args[0]))
+	span := tracing.NewLoggingTracer(log.NewLogrusLogger(logrus.New())).StartSpan(fmt.Sprintf("exec %v", cmd.Args[0]))
 	span.SetBaggageItem("dir", fmt.Sprintf("%v", cmd.Dir))
 	span.SetBaggageItem("args", fmt.Sprintf("%v", cmd.Args))
 	defer span.Finish()
diff --git a/util/helm/client.go b/util/helm/client.go
index a5ca3de87..9f85c4fe9 100644
--- a/util/helm/client.go
+++ b/util/helm/client.go
@@ -17,12 +17,12 @@ import (
 	"time"
 
 	"github.com/Masterminds/semver"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/pkg/sync"
 	log "github.com/sirupsen/logrus"
 	"gopkg.in/yaml.v2"
 
 	executil "github.com/argoproj/argo-cd/util/exec"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 var (
diff --git a/util/helm/cmd.go b/util/helm/cmd.go
index 3c3a84222..838ff9d46 100644
--- a/util/helm/cmd.go
+++ b/util/helm/cmd.go
@@ -9,9 +9,8 @@ import (
 	"path/filepath"
 	"regexp"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
-
 	executil "github.com/argoproj/argo-cd/util/exec"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 // A thin wrapper around the "helm" command, adding logging and error translation.
diff --git a/util/helm/mocks/Client.go b/util/helm/mocks/Client.go
index 9253a3742..c0f2d7e6a 100644
--- a/util/helm/mocks/Client.go
+++ b/util/helm/mocks/Client.go
@@ -5,7 +5,7 @@ package mocks
 import (
 	helm "github.com/argoproj/argo-cd/util/helm"
 
-	io "github.com/argoproj/gitops-engine/pkg/utils/io"
+	io "github.com/argoproj/argo-cd/util/io"
 
 	mock "github.com/stretchr/testify/mock"
 
diff --git a/util/io/closer.go b/util/io/closer.go
new file mode 100644
index 000000000..7ca4981e9
--- /dev/null
+++ b/util/io/closer.go
@@ -0,0 +1,33 @@
+package io
+
+import log "github.com/sirupsen/logrus"
+
+var (
+	NopCloser = NewCloser(func() error {
+		return nil
+	})
+)
+
+type Closer interface {
+	Close() error
+}
+
+type inlineCloser struct {
+	close func() error
+}
+
+func (c *inlineCloser) Close() error {
+	return c.close()
+}
+
+func NewCloser(close func() error) Closer {
+	return &inlineCloser{close: close}
+}
+
+// Close is a convenience function to close a object that has a Close() method, ignoring any errors
+// Used to satisfy errcheck lint
+func Close(c Closer) {
+	if err := c.Close(); err != nil {
+		log.Warnf("failed to close %v: %v", c, err)
+	}
+}
diff --git a/util/kube/kubectl.go b/util/kube/kubectl.go
new file mode 100644
index 000000000..bca8aa3ed
--- /dev/null
+++ b/util/kube/kubectl.go
@@ -0,0 +1,23 @@
+package kube
+
+import (
+	"os"
+
+	"github.com/argoproj/argo-cd/util/log"
+
+	"github.com/argoproj/gitops-engine/pkg/utils/kube"
+	"github.com/argoproj/gitops-engine/pkg/utils/tracing"
+	"github.com/sirupsen/logrus"
+)
+
+var tracer tracing.Tracer = &tracing.NopTracer{}
+
+func init() {
+	if os.Getenv("ARGOCD_TRACING_ENABLED") == "1" {
+		tracer = tracing.NewLoggingTracer(log.NewLogrusLogger(logrus.New()))
+	}
+}
+
+func NewKubectl() kube.Kubectl {
+	return &kube.KubectlCmd{Tracer: tracer, Log: log.NewLogrusLogger(logrus.New())}
+}
diff --git a/util/kube/portforwarder.go b/util/kube/portforwarder.go
index c915709f8..addcb3ad9 100644
--- a/util/kube/portforwarder.go
+++ b/util/kube/portforwarder.go
@@ -9,13 +9,14 @@ import (
 	"net/http"
 	"os"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/pkg/errors"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/tools/clientcmd"
 	"k8s.io/client-go/tools/portforward"
 	"k8s.io/client-go/transport/spdy"
+
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 func PortForward(podSelector string, targetPort int, namespace string) (int, error) {
diff --git a/util/log/logrus.go b/util/log/logrus.go
new file mode 100644
index 000000000..ecb725a61
--- /dev/null
+++ b/util/log/logrus.go
@@ -0,0 +1,11 @@
+package log
+
+import (
+	adapter "github.com/bombsimon/logrusr"
+	"github.com/go-logr/logr"
+	"github.com/sirupsen/logrus"
+)
+
+func NewLogrusLogger(fieldLogger logrus.FieldLogger) logr.Logger {
+	return adapter.NewLogger(fieldLogger)
+}
diff --git a/util/settings/settings.go b/util/settings/settings.go
index 45772728a..7c9b487d2 100644
--- a/util/settings/settings.go
+++ b/util/settings/settings.go
@@ -15,7 +15,6 @@ import (
 	"sync"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/diff"
 	"github.com/ghodss/yaml"
 	log "github.com/sirupsen/logrus"
 	apiv1 "k8s.io/api/core/v1"
@@ -280,7 +279,7 @@ const (
 )
 
 type ArgoCDDiffOptions struct {
-	diff.DiffOptions
+	IgnoreAggregatedRoles bool `json:"ignoreAggregatedRoles,omitempty"`
 
 	// If set to true then differences caused by status are ignored.
 	IgnoreResourceStatusField IgnoreStatus `json:"ignoreResourceStatusField,omitempty"`
@@ -518,10 +517,14 @@ func addStatusOverrideToGK(resourceOverrides map[string]v1alpha1.ResourceOverrid
 	}
 }
 
+func GetDefaultDiffOptions() ArgoCDDiffOptions {
+	return ArgoCDDiffOptions{IgnoreAggregatedRoles: false}
+}
+
 // GetResourceCompareOptions loads the resource compare options settings from the ConfigMap
-func (mgr *SettingsManager) GetResourceCompareOptions() (diff.DiffOptions, error) {
+func (mgr *SettingsManager) GetResourceCompareOptions() (ArgoCDDiffOptions, error) {
 	// We have a sane set of default diff options
-	diffOptions := diff.GetDefaultDiffOptions()
+	diffOptions := GetDefaultDiffOptions()
 
 	argoCDCM, err := mgr.getConfigMap()
 	if err != nil {


Test patch:
diff --git a/cmd/argocd-util/commands/settings_test.go b/cmd/argocd-util/commands/settings_test.go
index b8c43fc1b..9fce15fef 100644
--- a/cmd/argocd-util/commands/settings_test.go
+++ b/cmd/argocd-util/commands/settings_test.go
@@ -10,9 +10,9 @@ import (
 	"testing"
 
 	"github.com/argoproj/argo-cd/common"
+	utils "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/settings"
 
-	utils "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/stretchr/testify/assert"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
diff --git a/reposerver/repository/lock_test.go b/reposerver/repository/lock_test.go
index a3ec5d274..b3b5f449b 100644
--- a/reposerver/repository/lock_test.go
+++ b/reposerver/repository/lock_test.go
@@ -8,7 +8,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
-	util "github.com/argoproj/gitops-engine/pkg/utils/io"
+	util "github.com/argoproj/argo-cd/util/io"
 )
 
 // execute given action and return false if action have not completed within 1 second
diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go
index 86827ac52..4792c8993 100644
--- a/reposerver/repository/repository_test.go
+++ b/reposerver/repository/repository_test.go
@@ -15,7 +15,6 @@ import (
 	"time"
 
 	"github.com/Masterminds/semver"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/ghodss/yaml"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
@@ -33,6 +32,7 @@ import (
 	gitmocks "github.com/argoproj/argo-cd/util/git/mocks"
 	"github.com/argoproj/argo-cd/util/helm"
 	helmmocks "github.com/argoproj/argo-cd/util/helm/mocks"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 const testSignature = `gpg: Signature made Wed Feb 26 23:22:34 2020 CET
diff --git a/resource_customizations/custom_actions_test.go b/resource_customizations/custom_actions_test.go
index 853a85146..9c74d0146 100644
--- a/resource_customizations/custom_actions_test.go
+++ b/resource_customizations/custom_actions_test.go
@@ -98,7 +98,7 @@ func TestLuaResourceActionsScript(t *testing.T) {
 
 				expectedObj := getObj(filepath.Join(dir, test.ExpectedOutputPath))
 				// Ideally, we would use a assert.Equal to detect the difference, but the Lua VM returns a object with float64 instead of the original int32.  As a result, the assert.Equal is never true despite that the change has been applied.
-				diffResult, err := diff.Diff(expectedObj, result, testNormalizer{}, diff.GetDefaultDiffOptions())
+				diffResult, err := diff.Diff(expectedObj, result, diff.WithNormalizer(testNormalizer{}))
 				assert.NoError(t, err)
 				if diffResult.Modified {
 					t.Error("Output does not match input:")
diff --git a/resource_customizations/health_test.go b/resource_customizations/health_test.go
index 09eb2f90d..2f669c82b 100644
--- a/resource_customizations/health_test.go
+++ b/resource_customizations/health_test.go
@@ -8,11 +8,11 @@ import (
 	"testing"
 
 	"github.com/argoproj/gitops-engine/pkg/health"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/ghodss/yaml"
 	"github.com/stretchr/testify/assert"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/lua"
 )
 
diff --git a/server/account/account_test.go b/server/account/account_test.go
index 86e3f23e6..91982166c 100644
--- a/server/account/account_test.go
+++ b/server/account/account_test.go
@@ -5,7 +5,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/dgrijalva/jwt-go"
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
@@ -18,6 +17,7 @@ import (
 	"github.com/argoproj/argo-cd/pkg/apiclient/account"
 	sessionpkg "github.com/argoproj/argo-cd/pkg/apiclient/session"
 	"github.com/argoproj/argo-cd/server/session"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/password"
 	"github.com/argoproj/argo-cd/util/rbac"
 	sessionutil "github.com/argoproj/argo-cd/util/session"
diff --git a/server/application/application_test.go b/server/application/application_test.go
index b18bb7a3a..b49473256 100644
--- a/server/application/application_test.go
+++ b/server/application/application_test.go
@@ -7,7 +7,6 @@ import (
 	"time"
 
 	synccommon "github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube/kubetest"
 	"github.com/argoproj/pkg/sync"
 	"github.com/dgrijalva/jwt-go"
@@ -38,6 +37,7 @@ import (
 	"github.com/argoproj/argo-cd/util/assets"
 	"github.com/argoproj/argo-cd/util/cache"
 	"github.com/argoproj/argo-cd/util/db"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/rbac"
 	"github.com/argoproj/argo-cd/util/settings"
 )
diff --git a/server/session/ratelimiter_test.go b/server/session/ratelimiter_test.go
index 8a3968cb7..1b9524e79 100644
--- a/server/session/ratelimiter_test.go
+++ b/server/session/ratelimiter_test.go
@@ -3,9 +3,9 @@ package session
 import (
 	"testing"
 
-	util "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/stretchr/testify/assert"
 
+	util "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/session"
 )
 
diff --git a/test/e2e/accounts_test.go b/test/e2e/accounts_test.go
index 8b04de5f7..10fff428c 100644
--- a/test/e2e/accounts_test.go
+++ b/test/e2e/accounts_test.go
@@ -4,7 +4,6 @@ import (
 	"context"
 	"testing"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/pkg/errors"
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
@@ -13,6 +12,7 @@ import (
 	argocdclient "github.com/argoproj/argo-cd/pkg/apiclient"
 	"github.com/argoproj/argo-cd/pkg/apiclient/session"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 func TestCreateAndUseAccount(t *testing.T) {
diff --git a/test/e2e/app_autosync_test.go b/test/e2e/app_autosync_test.go
index 4e8588ec6..a6385ea5d 100644
--- a/test/e2e/app_autosync_test.go
+++ b/test/e2e/app_autosync_test.go
@@ -7,13 +7,13 @@ import (
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/stretchr/testify/assert"
 	"k8s.io/apimachinery/pkg/types"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 func TestAutoSyncSelfHealDisabled(t *testing.T) {
diff --git a/test/e2e/app_management_test.go b/test/e2e/app_management_test.go
index 278e66b25..a6143b0e6 100644
--- a/test/e2e/app_management_test.go
+++ b/test/e2e/app_management_test.go
@@ -15,8 +15,6 @@ import (
 	"github.com/argoproj/gitops-engine/pkg/diff"
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/argoproj/pkg/errors"
 	log "github.com/sirupsen/logrus"
@@ -37,6 +35,8 @@ import (
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
 	. "github.com/argoproj/argo-cd/util/argo"
+	. "github.com/argoproj/argo-cd/util/errors"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/settings"
 )
 
diff --git a/test/e2e/cluster_test.go b/test/e2e/cluster_test.go
index a3475d56a..9c94d987e 100644
--- a/test/e2e/cluster_test.go
+++ b/test/e2e/cluster_test.go
@@ -6,9 +6,8 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 func TestClusterList(t *testing.T) {
diff --git a/test/e2e/custom_tool_test.go b/test/e2e/custom_tool_test.go
index 73005aecd..ba66eebd4 100644
--- a/test/e2e/custom_tool_test.go
+++ b/test/e2e/custom_tool_test.go
@@ -8,12 +8,12 @@ import (
 
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/stretchr/testify/assert"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 // make sure we can echo back the Git creds
diff --git a/test/e2e/fixture/app/actions.go b/test/e2e/fixture/app/actions.go
index b52f06964..cd4f2d4b0 100644
--- a/test/e2e/fixture/app/actions.go
+++ b/test/e2e/fixture/app/actions.go
@@ -4,12 +4,12 @@ import (
 	"fmt"
 	"io/ioutil"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	log "github.com/sirupsen/logrus"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/grpc"
 )
 
diff --git a/test/e2e/fixture/app/consequences.go b/test/e2e/fixture/app/consequences.go
index 1c73e0659..1fecf4e4a 100644
--- a/test/e2e/fixture/app/consequences.go
+++ b/test/e2e/fixture/app/consequences.go
@@ -5,12 +5,12 @@ import (
 	"time"
 
 	"github.com/argoproj/gitops-engine/pkg/health"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	log "github.com/sirupsen/logrus"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 // this implements the "then" part of given/when/then
diff --git a/test/e2e/fixture/certs/certs.go b/test/e2e/fixture/certs/certs.go
index 20b5fff07..eff09a96b 100644
--- a/test/e2e/fixture/certs/certs.go
+++ b/test/e2e/fixture/certs/certs.go
@@ -5,9 +5,8 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 // Add a custom CA certificate to the test and also create the certificate file
diff --git a/test/e2e/fixture/fixture.go b/test/e2e/fixture/fixture.go
index 2e03f0566..ba11fd458 100644
--- a/test/e2e/fixture/fixture.go
+++ b/test/e2e/fixture/fixture.go
@@ -11,8 +11,6 @@ import (
 	"testing"
 	"time"
 
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/argoproj/pkg/errors"
 	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/ghodss/yaml"
@@ -29,7 +27,9 @@ import (
 	sessionpkg "github.com/argoproj/argo-cd/pkg/apiclient/session"
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	appclientset "github.com/argoproj/argo-cd/pkg/client/clientset/versioned"
+	. "github.com/argoproj/argo-cd/util/errors"
 	grpcutil "github.com/argoproj/argo-cd/util/grpc"
+	"github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/rand"
 	"github.com/argoproj/argo-cd/util/settings"
 )
diff --git a/test/e2e/fixture/gpgkeys/gpgkeys.go b/test/e2e/fixture/gpgkeys/gpgkeys.go
index 0d30e8131..968493d7b 100644
--- a/test/e2e/fixture/gpgkeys/gpgkeys.go
+++ b/test/e2e/fixture/gpgkeys/gpgkeys.go
@@ -6,9 +6,8 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 // Add GPG public key via API and create appropriate file where the ConfigMap mount would de it as well
diff --git a/test/e2e/fixture/repos/repos.go b/test/e2e/fixture/repos/repos.go
index eee84ae27..64d6d2220 100644
--- a/test/e2e/fixture/repos/repos.go
+++ b/test/e2e/fixture/repos/repos.go
@@ -3,9 +3,8 @@ package repos
 import (
 	"path/filepath"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 var (
diff --git a/test/e2e/fixture/tmpl.go b/test/e2e/fixture/tmpl.go
index bd418d8fa..c489ebb2e 100644
--- a/test/e2e/fixture/tmpl.go
+++ b/test/e2e/fixture/tmpl.go
@@ -6,7 +6,7 @@ import (
 	"strings"
 	"text/template"
 
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 // utility method to template a string using a map
diff --git a/test/e2e/fixture/versions.go b/test/e2e/fixture/versions.go
index be431d3eb..c76aef5fc 100644
--- a/test/e2e/fixture/versions.go
+++ b/test/e2e/fixture/versions.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 	"strings"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 type Versions struct {
diff --git a/test/e2e/helm_test.go b/test/e2e/helm_test.go
index e0bf6410d..b3160894a 100644
--- a/test/e2e/helm_test.go
+++ b/test/e2e/helm_test.go
@@ -11,7 +11,6 @@ import (
 
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/stretchr/testify/assert"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -22,6 +21,7 @@ import (
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
 	"github.com/argoproj/argo-cd/test/e2e/fixture/repos"
+	. "github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/settings"
 )
 
diff --git a/test/e2e/hook_test.go b/test/e2e/hook_test.go
index ec7f95bcb..177725534 100644
--- a/test/e2e/hook_test.go
+++ b/test/e2e/hook_test.go
@@ -10,11 +10,11 @@ import (
 
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 func TestPreSyncHookSuccessful(t *testing.T) {
diff --git a/test/e2e/jsonnet_test.go b/test/e2e/jsonnet_test.go
index a01305a5c..6adf0df9f 100644
--- a/test/e2e/jsonnet_test.go
+++ b/test/e2e/jsonnet_test.go
@@ -4,13 +4,13 @@ import (
 	"testing"
 
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/argoproj/gitops-engine/pkg/utils/kube"
 	"github.com/stretchr/testify/assert"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 func TestJsonnetAppliedCorrectly(t *testing.T) {
diff --git a/test/e2e/kustomize_test.go b/test/e2e/kustomize_test.go
index 480b932a1..7901fc337 100644
--- a/test/e2e/kustomize_test.go
+++ b/test/e2e/kustomize_test.go
@@ -5,12 +5,12 @@ import (
 
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/stretchr/testify/assert"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 func TestKustomize2AppSource(t *testing.T) {
diff --git a/test/e2e/repo_creds_test.go b/test/e2e/repo_creds_test.go
index eb24f18d5..35e458807 100644
--- a/test/e2e/repo_creds_test.go
+++ b/test/e2e/repo_creds_test.go
@@ -4,10 +4,9 @@ import (
 	"fmt"
 	"testing"
 
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
-
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	. "github.com/argoproj/argo-cd/util/errors"
 )
 
 // make sure you cannot create an app from a private repo without set-up
diff --git a/test/e2e/repo_management_test.go b/test/e2e/repo_management_test.go
index ad5a0fd95..1944ca94f 100644
--- a/test/e2e/repo_management_test.go
+++ b/test/e2e/repo_management_test.go
@@ -4,13 +4,13 @@ import (
 	"context"
 	"testing"
 
-	argoio "github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/stretchr/testify/assert"
 
 	repositorypkg "github.com/argoproj/argo-cd/pkg/apiclient/repository"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	"github.com/argoproj/argo-cd/test/e2e/fixture/app"
 	"github.com/argoproj/argo-cd/test/e2e/fixture/repos"
+	argoio "github.com/argoproj/argo-cd/util/io"
 	"github.com/argoproj/argo-cd/util/settings"
 )
 
diff --git a/test/e2e/selective_sync_test.go b/test/e2e/selective_sync_test.go
index a8232b96c..b66171f76 100644
--- a/test/e2e/selective_sync_test.go
+++ b/test/e2e/selective_sync_test.go
@@ -7,12 +7,12 @@ import (
 
 	"github.com/argoproj/gitops-engine/pkg/health"
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	. "github.com/argoproj/gitops-engine/pkg/utils/errors"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	. "github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/rand"
 )
 
diff --git a/test/e2e/sync_options_test.go b/test/e2e/sync_options_test.go
index 231980211..2913db902 100644
--- a/test/e2e/sync_options_test.go
+++ b/test/e2e/sync_options_test.go
@@ -6,13 +6,13 @@ import (
 	"testing"
 
 	. "github.com/argoproj/gitops-engine/pkg/sync/common"
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/types"
 
 	. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"github.com/argoproj/argo-cd/test/e2e/fixture"
 	. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 // TestSyncOptionsValidateFalse verifies we can disable validation during kubectl apply, using the
diff --git a/test/fixture/path/hack_path.go b/test/fixture/path/hack_path.go
index 22ac35c1f..9e83ce512 100644
--- a/test/fixture/path/hack_path.go
+++ b/test/fixture/path/hack_path.go
@@ -5,7 +5,7 @@ import (
 	"os"
 	"path/filepath"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 type AddBinDirToPath struct {
diff --git a/test/fixture/revision_metadata/author.go b/test/fixture/revision_metadata/author.go
index 1f65b4de3..d1887a30b 100644
--- a/test/fixture/revision_metadata/author.go
+++ b/test/fixture/revision_metadata/author.go
@@ -6,7 +6,7 @@ import (
 
 	argoexec "github.com/argoproj/pkg/exec"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 var Author string
diff --git a/ui/src/app/applications/components/__snapshots__/utils.test.tsx.snap b/ui/src/app/applications/components/__snapshots__/utils.test.tsx.snap
index c6b2034d0..454b152fc 100644
--- a/ui/src/app/applications/components/__snapshots__/utils.test.tsx.snap
+++ b/ui/src/app/applications/components/__snapshots__/utils.test.tsx.snap
@@ -4,6 +4,7 @@ exports[`ComparisonStatusIcon.OutOfSync 1`] = `
 Array [
   <i
     className="fa fa-arrow-alt-circle-up"
+    qe-id="utils-sync-status-title"
     style={
       Object {
         "color": "#f4c030",
@@ -19,6 +20,7 @@ exports[`ComparisonStatusIcon.Synced 1`] = `
 Array [
   <i
     className="fa fa-check-circle"
+    qe-id="utils-sync-status-title"
     style={
       Object {
         "color": "#18BE94",
@@ -34,6 +36,7 @@ exports[`ComparisonStatusIcon.Unknown 1`] = `
 Array [
   <i
     className="fa fa-circle-notch fa-spin"
+    qe-id="utils-sync-status-title"
     style={
       Object {
         "color": "#CCD6DD",
@@ -48,6 +51,7 @@ Array [
 exports[`HealthStatusIcon.Degraded 1`] = `
 <i
   className="fa fa-heart-broken"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#E96D76",
@@ -60,6 +64,7 @@ exports[`HealthStatusIcon.Degraded 1`] = `
 exports[`HealthStatusIcon.Healthy 1`] = `
 <i
   className="fa fa-heart"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#18BE94",
@@ -72,6 +77,7 @@ exports[`HealthStatusIcon.Healthy 1`] = `
 exports[`HealthStatusIcon.Missing 1`] = `
 <i
   className="fa fa-question-circle"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#CCD6DD",
@@ -84,6 +90,7 @@ exports[`HealthStatusIcon.Missing 1`] = `
 exports[`HealthStatusIcon.Progressing 1`] = `
 <i
   className="fa fa fa-circle-notch fa-spin"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#0DADEA",
@@ -96,6 +103,7 @@ exports[`HealthStatusIcon.Progressing 1`] = `
 exports[`HealthStatusIcon.Suspended 1`] = `
 <i
   className="fa fa-heart"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#CCD6DD",
@@ -108,6 +116,7 @@ exports[`HealthStatusIcon.Suspended 1`] = `
 exports[`HealthStatusIcon.Unknown 1`] = `
 <i
   className="fa fa-question-circle"
+  qe-id="utils-health-status-title"
   style={
     Object {
       "color": "#CCD6DD",
@@ -121,6 +130,7 @@ exports[`OperationState.Deleting 1`] = `
 Array [
   <i
     className="fa fa-circle-notch fa-spin"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#0DADEA",
@@ -137,6 +147,7 @@ exports[`OperationState.Sync OK 1`] = `
 Array [
   <i
     className="fa fa-check-circle"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#18BE94",
@@ -153,6 +164,7 @@ exports[`OperationState.Sync error 1`] = `
 Array [
   <i
     className="fa fa-times-circle"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#E96D76",
@@ -169,6 +181,7 @@ exports[`OperationState.Sync failed 1`] = `
 Array [
   <i
     className="fa fa-times-circle"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#E96D76",
@@ -185,6 +198,7 @@ exports[`OperationState.Syncing 1`] = `
 Array [
   <i
     className="fa fa-circle-notch fa-spin"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#0DADEA",
@@ -201,6 +215,7 @@ exports[`OperationState.Unknown 1`] = `
 Array [
   <i
     className="fa fa-circle-notch fa-spin"
+    qe-id="utils-operations-status-title"
     style={
       Object {
         "color": "#0DADEA",
diff --git a/util/clusterauth/clusterauth_test.go b/util/clusterauth/clusterauth_test.go
index b7384d429..dce221fc7 100644
--- a/util/clusterauth/clusterauth_test.go
+++ b/util/clusterauth/clusterauth_test.go
@@ -5,7 +5,6 @@ import (
 	"io/ioutil"
 	"testing"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/ghodss/yaml"
 	"github.com/stretchr/testify/assert"
 	corev1 "k8s.io/api/core/v1"
@@ -14,6 +13,8 @@ import (
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/kubernetes/fake"
 	kubetesting "k8s.io/client-go/testing"
+
+	"github.com/argoproj/argo-cd/util/errors"
 )
 
 const (
diff --git a/util/env/env_test.go b/util/env/env_test.go
index 89acf98e4..bbd51b59c 100644
--- a/util/env/env_test.go
+++ b/util/env/env_test.go
@@ -5,7 +5,7 @@ import (
 	"os"
 	"testing"
 
-	util "github.com/argoproj/gitops-engine/pkg/utils/io"
+	util "github.com/argoproj/argo-cd/util/io"
 
 	"github.com/stretchr/testify/assert"
 )
diff --git a/util/helm/client_test.go b/util/helm/client_test.go
index aacb3f1aa..248df2487 100644
--- a/util/helm/client_test.go
+++ b/util/helm/client_test.go
@@ -5,8 +5,9 @@ import (
 	"testing"
 
 	"github.com/Masterminds/semver"
-	"github.com/argoproj/gitops-engine/pkg/utils/io"
 	"github.com/stretchr/testify/assert"
+
+	"github.com/argoproj/argo-cd/util/io"
 )
 
 func TestIndex(t *testing.T) {
diff --git a/util/session/sessionmanager_test.go b/util/session/sessionmanager_test.go
index 785a045c5..e4afa2a22 100644
--- a/util/session/sessionmanager_test.go
+++ b/util/session/sessionmanager_test.go
@@ -9,7 +9,6 @@ import (
 	"testing"
 	"time"
 
-	"github.com/argoproj/gitops-engine/pkg/utils/errors"
 	"github.com/dgrijalva/jwt-go"
 	"github.com/stretchr/testify/assert"
 	"google.golang.org/grpc/codes"
@@ -19,6 +18,7 @@ import (
 	"k8s.io/client-go/kubernetes/fake"
 
 	"github.com/argoproj/argo-cd/common"
+	"github.com/argoproj/argo-cd/util/errors"
 	"github.com/argoproj/argo-cd/util/password"
 	"github.com/argoproj/argo-cd/util/settings"
 )
diff --git a/util/settings/settings_test.go b/util/settings/settings_test.go
index 73aaa71b2..b8f6fe6df 100644
--- a/util/settings/settings_test.go
+++ b/util/settings/settings_test.go
@@ -7,7 +7,6 @@ import (
 	"github.com/argoproj/argo-cd/common"
 	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 
-	"github.com/argoproj/gitops-engine/pkg/diff"
 	"github.com/stretchr/testify/assert"
 	v1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -260,7 +259,7 @@ func TestGetResourceCompareOptions(t *testing.T) {
 			"resource.compareoptions": "",
 		})
 		compareOptions, err := settingsManager.GetResourceCompareOptions()
-		defaultOptions := diff.GetDefaultDiffOptions()
+		defaultOptions := GetDefaultDiffOptions()
 		assert.NoError(t, err)
 		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
 	}
@@ -269,7 +268,7 @@ func TestGetResourceCompareOptions(t *testing.T) {
 	{
 		_, settingsManager := fixtures(map[string]string{})
 		compareOptions, err := settingsManager.GetResourceCompareOptions()
-		defaultOptions := diff.GetDefaultDiffOptions()
+		defaultOptions := GetDefaultDiffOptions()
 		assert.NoError(t, err)
 		assert.Equal(t, defaultOptions.IgnoreAggregatedRoles, compareOptions.IgnoreAggregatedRoles)
 	}