Repository: argoproj/argo-cd
Pull request #5060 (2020-12-15 05:21:13)

fix: add grpc health check
Signed-off-by: May Zhang <may_zhang@intuit.com>

In order to use grpc_health_probe, grpc health check needs to be registered.

fyi: https://github.com/grpc-ecosystem/grpc-health-probe


Note on DCO:

If the DCO action in the integration test fails, one or more of your commits are not signed off. Please click on the *Details* link next to the DCO action for instructions on how to resolve this.

Checklist:

* [ ] 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.
* [ ] 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 have signed off all my commits as required by [DCO](https://github.com/argoproj/argoproj/tree/master/community#contributing-to-argo)
* [ ] My build is green ([troubleshooting builds](https://argoproj.github.io/argo-cd/developer-guide/ci/)). 



alexmt: Please fix linter errors

Patch:
diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go
index dde841eff..3c39a53af 100644
--- a/cmd/argocd/commands/app.go
+++ b/cmd/argocd/commands/app.go
@@ -1055,7 +1055,7 @@ func getLocalObjectsString(app *argoappv1.Application, local, localRepoRoot, app
 	res, err := repository.GenerateManifests(local, localRepoRoot, app.Spec.Source.TargetRevision, &repoapiclient.ManifestRequest{
 		Repo:              &argoappv1.Repository{Repo: app.Spec.Source.RepoURL},
 		AppLabelKey:       appLabelKey,
-		AppLabelValue:     app.Name,
+		AppName:           app.Name,
 		Namespace:         app.Spec.Destination.Namespace,
 		ApplicationSource: &app.Spec.Source,
 		KustomizeOptions:  kustomizeOptions,
diff --git a/controller/state.go b/controller/state.go
index 4c92755f4..56bec2c30 100644
--- a/controller/state.go
+++ b/controller/state.go
@@ -160,7 +160,7 @@ func (m *appStateManager) getRepoObjs(app *v1alpha1.Application, source v1alpha1
 		Revision:          revision,
 		NoCache:           noCache,
 		AppLabelKey:       appLabelKey,
-		AppLabelValue:     app.Name,
+		AppName:           app.Name,
 		Namespace:         app.Spec.Destination.Namespace,
 		ApplicationSource: &source,
 		Plugins:           tools,
diff --git a/docs/user-guide/parameters.md b/docs/user-guide/parameters.md
index d00768175..d055a9233 100644
--- a/docs/user-guide/parameters.md
+++ b/docs/user-guide/parameters.md
@@ -54,6 +54,8 @@ argocd app create redis --repo https://github.com/helm/charts.git --path stable/
 
 ## Store Overrides In Git
 
+> The following is available from v1.8 or later
+
 The config management tool specific overrides can be specified in `.argocd-source.yaml` file stored in the source application
 directory in the Git repository.
 
@@ -77,3 +79,16 @@ The `.argocd-source` is trying to solve two following main use cases:
 for projects like [argocd-image-updater](https://github.com/argoproj-labs/argocd-image-updater).
 - Support "discovering" applications in the Git repository by projects like [applicationset](https://github.com/argoproj-labs/applicationset)
 (see [git files generator](https://github.com/argoproj-labs/applicationset/blob/master/examples/git-files-discovery.yaml))
+
+> The following is available from v1.9 or later
+
+You can also store parameter overrides in an application specific file, if you
+are sourcing multiple applications from a single path in your repository.
+
+The application specific file must be named `.argocd-source-<appname>.yaml`,
+where `<appname>` is the name of the application the overrides are valid for.
+
+If there exists an non-application specific `.argocd-source.yaml`, parameters
+included in that file will be merged first, and then the application specific
+parameters are merged, which can also contain overrides to the parameters
+stored in the non-application specific file.
\ No newline at end of file
diff --git a/docs/user-guide/sync-waves.md b/docs/user-guide/sync-waves.md
index 0309fa9d6..6481e3a7e 100644
--- a/docs/user-guide/sync-waves.md
+++ b/docs/user-guide/sync-waves.md
@@ -6,7 +6,7 @@
 
 Argo CD executes a sync operation in a number of steps. At a high-level, there are three phases *pre-sync*, *sync* and *post-sync*.  
 
-Within each phase you can have one or more waves, than allows you to ensure certain resources are healthy before subsequent resources are synced.   
+Within each phase you can have one or more waves, that allows you to ensure certain resources are healthy before subsequent resources are synced.   
 
 ## How Do I Configure Phases?
 
diff --git a/reposerver/apiclient/repository.pb.go b/reposerver/apiclient/repository.pb.go
index 804d7d39f..b8d03b4f6 100644
--- a/reposerver/apiclient/repository.pb.go
+++ b/reposerver/apiclient/repository.pb.go
@@ -34,10 +34,11 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
 type ManifestRequest struct {
 	Repo *v1alpha1.Repository `protobuf:"bytes,1,opt,name=repo,proto3" json:"repo,omitempty"`
 	// revision, potentially un-resolved
-	Revision          string                             `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
-	NoCache           bool                               `protobuf:"varint,3,opt,name=noCache,proto3" json:"noCache,omitempty"`
-	AppLabelKey       string                             `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
-	AppLabelValue     string                             `protobuf:"bytes,5,opt,name=appLabelValue,proto3" json:"appLabelValue,omitempty"`
+	Revision    string `protobuf:"bytes,2,opt,name=revision,proto3" json:"revision,omitempty"`
+	NoCache     bool   `protobuf:"varint,3,opt,name=noCache,proto3" json:"noCache,omitempty"`
+	AppLabelKey string `protobuf:"bytes,4,opt,name=appLabelKey,proto3" json:"appLabelKey,omitempty"`
+	// Name of the application for which the request is triggered
+	AppName           string                             `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"`
 	Namespace         string                             `protobuf:"bytes,8,opt,name=namespace,proto3" json:"namespace,omitempty"`
 	ApplicationSource *v1alpha1.ApplicationSource        `protobuf:"bytes,10,opt,name=applicationSource,proto3" json:"applicationSource,omitempty"`
 	Repos             []*v1alpha1.Repository             `protobuf:"bytes,11,rep,name=repos,proto3" json:"repos,omitempty"`
@@ -113,9 +114,9 @@ func (m *ManifestRequest) GetAppLabelKey() string {
 	return ""
 }
 
-func (m *ManifestRequest) GetAppLabelValue() string {
+func (m *ManifestRequest) GetAppName() string {
 	if m != nil {
-		return m.AppLabelValue
+		return m.AppName
 	}
 	return ""
 }
@@ -478,6 +479,7 @@ type RepoServerAppDetailsQuery struct {
 	Source               *v1alpha1.ApplicationSource `protobuf:"bytes,2,opt,name=source,proto3" json:"source,omitempty"`
 	Repos                []*v1alpha1.Repository      `protobuf:"bytes,3,rep,name=repos,proto3" json:"repos,omitempty"`
 	KustomizeOptions     *v1alpha1.KustomizeOptions  `protobuf:"bytes,4,opt,name=kustomizeOptions,proto3" json:"kustomizeOptions,omitempty"`
+	AppName              string                      `protobuf:"bytes,5,opt,name=appName,proto3" json:"appName,omitempty"`
 	XXX_NoUnkeyedLiteral struct{}                    `json:"-"`
 	XXX_unrecognized     []byte                      `json:"-"`
 	XXX_sizecache        int32                       `json:"-"`
@@ -544,6 +546,13 @@ func (m *RepoServerAppDetailsQuery) GetKustomizeOptions() *v1alpha1.KustomizeOpt
 	return nil
 }
 
+func (m *RepoServerAppDetailsQuery) GetAppName() string {
+	if m != nil {
+		return m.AppName
+	}
+	return ""
+}
+
 // RepoAppDetailsResponse application details
 type RepoAppDetailsResponse struct {
 	Type                 string            `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
@@ -1228,87 +1237,87 @@ func init() {
 
 var fileDescriptor_dd8723cfcc820480 = []byte{
 	// 1292 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0x5b, 0x6f, 0x1b, 0x45,
-	0x14, 0xce, 0xda, 0xce, 0xc5, 0xc7, 0x6d, 0xe2, 0x4c, 0x4b, 0x59, 0x4c, 0x6a, 0x85, 0x15, 0x54,
-	0x81, 0x52, 0x9b, 0x86, 0x0a, 0xaa, 0x56, 0xaa, 0x14, 0x7a, 0x45, 0x49, 0xd5, 0x74, 0x03, 0x95,
-	0xb8, 0x48, 0xd5, 0x64, 0x7d, 0xb2, 0x1e, 0xbc, 0xde, 0x1d, 0x76, 0xc6, 0x46, 0xe9, 0x1f, 0x80,
-	0x77, 0xc4, 0x6f, 0xe0, 0x1d, 0x89, 0x07, 0x5e, 0x11, 0x42, 0x3c, 0xf2, 0x13, 0x50, 0x7f, 0x09,
-	0x9a, 0xd9, 0xdb, 0x78, 0xed, 0xe4, 0xc5, 0xbd, 0xbc, 0x24, 0x33, 0x67, 0xce, 0x6d, 0xce, 0x7c,
-	0xf3, 0xcd, 0xf1, 0xc2, 0xa5, 0x18, 0x79, 0x24, 0x30, 0x1e, 0x63, 0xdc, 0xd5, 0x43, 0x26, 0xa3,
-	0xf8, 0xd8, 0x18, 0x76, 0x78, 0x1c, 0xc9, 0x88, 0x40, 0x21, 0x69, 0x9d, 0xf7, 0x23, 0x3f, 0xd2,
-	0xe2, 0xae, 0x1a, 0x25, 0x1a, 0xad, 0x0d, 0x3f, 0x8a, 0xfc, 0x00, 0xbb, 0x94, 0xb3, 0x2e, 0x0d,
-	0xc3, 0x48, 0x52, 0xc9, 0xa2, 0x50, 0xa4, 0xab, 0xce, 0xe0, 0xba, 0xe8, 0xb0, 0x48, 0xaf, 0x7a,
-	0x51, 0x8c, 0xdd, 0xf1, 0xd5, 0xae, 0x8f, 0x21, 0xc6, 0x54, 0x62, 0x2f, 0xd5, 0xf9, 0xdc, 0x67,
-	0xb2, 0x3f, 0x3a, 0xec, 0x78, 0xd1, 0xb0, 0x4b, 0x63, 0x1d, 0xe2, 0x3b, 0x3d, 0xb8, 0xe2, 0xf5,
-	0xba, 0x7c, 0xe0, 0x2b, 0x63, 0xd1, 0xa5, 0x9c, 0x07, 0xcc, 0xd3, 0xce, 0xbb, 0xe3, 0xab, 0x34,
-	0xe0, 0x7d, 0x3a, 0xe5, 0xca, 0xf9, 0x7d, 0x09, 0xd6, 0x1e, 0xd2, 0x90, 0x1d, 0xa1, 0x90, 0x2e,
-	0x7e, 0x3f, 0x42, 0x21, 0xc9, 0x57, 0x50, 0x53, 0x9b, 0xb0, 0xad, 0x4d, 0x6b, 0xab, 0xb1, 0x7d,
-	0xb7, 0x53, 0x44, 0xeb, 0x64, 0xd1, 0xf4, 0xe0, 0xa9, 0xd7, 0xeb, 0xf0, 0x81, 0xdf, 0x51, 0xd1,
-	0x3a, 0x46, 0xb4, 0x4e, 0x16, 0xad, 0xe3, 0xe6, 0xb5, 0x70, 0xb5, 0x4b, 0xd2, 0x82, 0x95, 0x18,
-	0xc7, 0x4c, 0xb0, 0x28, 0xb4, 0x2b, 0x9b, 0xd6, 0x56, 0xdd, 0xcd, 0xe7, 0xc4, 0x86, 0xe5, 0x30,
-	0xba, 0x4d, 0xbd, 0x3e, 0xda, 0xd5, 0x4d, 0x6b, 0x6b, 0xc5, 0xcd, 0xa6, 0x64, 0x13, 0x1a, 0x94,
-	0xf3, 0x3d, 0x7a, 0x88, 0xc1, 0x2e, 0x1e, 0xdb, 0x35, 0x6d, 0x68, 0x8a, 0xc8, 0xbb, 0x70, 0x36,
-	0x9b, 0x3e, 0xa1, 0xc1, 0x08, 0xed, 0x45, 0xad, 0x33, 0x29, 0x24, 0x1b, 0x50, 0x0f, 0xe9, 0x10,
-	0x05, 0xa7, 0x1e, 0xda, 0x2b, 0x5a, 0xa3, 0x10, 0x90, 0x67, 0xb0, 0x6e, 0x6c, 0xe2, 0x20, 0x1a,
-	0xc5, 0x1e, 0xda, 0xa0, 0x6b, 0xb0, 0x37, 0x47, 0x0d, 0x76, 0xca, 0x3e, 0xdd, 0xe9, 0x30, 0xe4,
-	0x1b, 0x58, 0xd4, 0xb8, 0xb1, 0x1b, 0x9b, 0xd5, 0x17, 0x57, 0xf3, 0xc4, 0x27, 0x19, 0xc0, 0x32,
-	0x0f, 0x46, 0x3e, 0x0b, 0x85, 0x7d, 0x46, 0xbb, 0x7f, 0x3c, 0x87, 0xfb, 0xdb, 0x51, 0x78, 0xc4,
-	0xfc, 0x87, 0x34, 0xa4, 0x3e, 0x0e, 0x31, 0x94, 0xfb, 0xda, 0xb3, 0x9b, 0x45, 0x20, 0x3f, 0x40,
-	0x73, 0x30, 0x12, 0x32, 0x1a, 0xb2, 0x67, 0xf8, 0x88, 0x6b, 0x64, 0xdb, 0x67, 0x75, 0x11, 0x77,
-	0xe7, 0x88, 0xba, 0x5b, 0x72, 0xe9, 0x4e, 0x05, 0x51, 0x20, 0x19, 0x8c, 0x0e, 0xf1, 0x09, 0xc6,
-	0x1a, 0x5d, 0xab, 0x09, 0x48, 0x0c, 0x51, 0x02, 0x23, 0x96, 0xce, 0x84, 0xbd, 0xb6, 0x59, 0x4d,
-	0x60, 0x94, 0x8b, 0xc8, 0x16, 0xac, 0x8d, 0x31, 0x66, 0x47, 0xc7, 0x07, 0xcc, 0x0f, 0xa9, 0x1c,
-	0xc5, 0x68, 0x37, 0x35, 0x14, 0xcb, 0x62, 0xe7, 0x6f, 0x0b, 0x9a, 0xc5, 0xbd, 0x11, 0x3c, 0x0a,
-	0x85, 0xc6, 0xd7, 0x30, 0x95, 0x09, 0xdb, 0xd2, 0xee, 0x0b, 0xc1, 0x24, 0xfa, 0x2a, 0x65, 0xf4,
-	0x5d, 0x80, 0xa5, 0x84, 0x5d, 0x34, 0xf8, 0xeb, 0x6e, 0x3a, 0x9b, 0xb8, 0x31, 0xb5, 0xd2, 0x8d,
-	0x69, 0x03, 0x08, 0x8d, 0x9f, 0x2f, 0x8e, 0x39, 0xda, 0x4b, 0x7a, 0xd5, 0x90, 0x10, 0x07, 0xce,
-	0x24, 0x79, 0xbb, 0x28, 0x46, 0x81, 0xb4, 0x97, 0xb5, 0xc6, 0x84, 0xcc, 0x09, 0x60, 0x6d, 0x8f,
-	0xa9, 0x3d, 0x1c, 0x89, 0x97, 0x7f, 0xff, 0x9d, 0x4f, 0xa0, 0xa6, 0x22, 0xa9, 0x5d, 0x1d, 0xc6,
-	0x34, 0xf4, 0xfa, 0x98, 0x15, 0x2a, 0x9f, 0x13, 0x02, 0x35, 0x49, 0x7d, 0x61, 0x57, 0xb4, 0x5c,
-	0x8f, 0x9d, 0x9f, 0xac, 0x24, 0xcd, 0x1d, 0xce, 0xc5, 0xeb, 0xa5, 0x29, 0x67, 0x04, 0xcb, 0x3b,
-	0x9c, 0xab, 0x64, 0xc8, 0x55, 0xa8, 0x51, 0xce, 0x93, 0x1d, 0x34, 0xb6, 0x2f, 0x76, 0x8c, 0xc7,
-	0x20, 0x55, 0x51, 0xff, 0xc5, 0xdd, 0x50, 0x2a, 0xcf, 0x4a, 0xb5, 0xf5, 0x29, 0xd4, 0x73, 0x11,
-	0x69, 0x42, 0x75, 0x80, 0xc7, 0x7a, 0x03, 0x75, 0x57, 0x0d, 0xc9, 0x79, 0x58, 0x1c, 0x6b, 0xfe,
-	0x4a, 0xa2, 0x26, 0x93, 0x1b, 0x95, 0xeb, 0x96, 0xf3, 0x5b, 0x15, 0xde, 0x52, 0x79, 0x1e, 0x68,
-	0x58, 0xec, 0x70, 0x7e, 0x07, 0x25, 0x65, 0x81, 0x78, 0x3c, 0xc2, 0xf8, 0xf8, 0x65, 0xd6, 0xa2,
-	0x07, 0x4b, 0x09, 0xa4, 0x74, 0x4e, 0x2f, 0x9a, 0x0b, 0x53, 0xdf, 0x05, 0x01, 0x56, 0x5f, 0x02,
-	0x01, 0xce, 0xe2, 0xa4, 0xda, 0x2b, 0xe0, 0x24, 0xe7, 0xc7, 0x0a, 0x5c, 0x50, 0xe9, 0x14, 0xc7,
-	0x95, 0x73, 0x85, 0x42, 0xb9, 0xba, 0xb5, 0xc9, 0xe1, 0xeb, 0x31, 0xb9, 0x06, 0xcb, 0x03, 0x11,
-	0x85, 0x21, 0xca, 0xb4, 0xd6, 0x2d, 0x13, 0x52, 0xbb, 0xc9, 0xd2, 0x0e, 0xe7, 0x07, 0x1c, 0x3d,
-	0x37, 0x53, 0x25, 0x97, 0xa1, 0xd6, 0xc7, 0x60, 0xa8, 0x79, 0xa3, 0xb1, 0xfd, 0xa6, 0x69, 0xf2,
-	0x00, 0x83, 0x61, 0xa6, 0xaf, 0x95, 0xc8, 0x0d, 0xa8, 0xe7, 0x59, 0xa6, 0x35, 0xd8, 0x98, 0x08,
-	0x92, 0x2d, 0x66, 0x66, 0x85, 0xba, 0xb2, 0xed, 0xb1, 0x18, 0x3d, 0xa5, 0xa8, 0x1f, 0xd8, 0x92,
-	0xed, 0x9d, 0x6c, 0x31, 0xb7, 0xcd, 0xd5, 0x9d, 0x3f, 0x2d, 0x78, 0xa7, 0x80, 0xaf, 0x9b, 0x5e,
-	0xa6, 0x87, 0x28, 0x69, 0x8f, 0x4a, 0xfa, 0x9a, 0x3b, 0x8f, 0x4b, 0xb0, 0xea, 0xf5, 0xd1, 0x1b,
-	0x14, 0xac, 0x9f, 0x34, 0x20, 0x25, 0xa9, 0xf3, 0x57, 0x05, 0x56, 0x27, 0x4f, 0x41, 0x1d, 0xa3,
-	0xe2, 0xf0, 0xec, 0x18, 0xd5, 0x98, 0xec, 0xc3, 0x19, 0x0c, 0xc7, 0x2c, 0x8e, 0x42, 0xf5, 0x40,
-	0x66, 0x90, 0xfe, 0xf0, 0xe4, 0xb3, 0xec, 0xdc, 0x35, 0xd4, 0x13, 0xb6, 0x98, 0xf0, 0x40, 0x06,
-	0x00, 0x9c, 0xc6, 0x74, 0x88, 0x12, 0x63, 0x05, 0xdd, 0xea, 0xbc, 0xd0, 0x4d, 0xc2, 0xef, 0x67,
-	0x3e, 0x5d, 0xc3, 0x7d, 0xeb, 0x29, 0xac, 0x4f, 0xe5, 0x33, 0x83, 0xaa, 0xae, 0x99, 0x54, 0xd5,
-	0xd8, 0x6e, 0xcf, 0xd8, 0x9e, 0xe1, 0xc6, 0xa4, 0xb2, 0x3f, 0x2a, 0xd0, 0x30, 0x90, 0x39, 0xb3,
-	0x86, 0x6d, 0x00, 0x6d, 0x70, 0x8f, 0x05, 0x98, 0x54, 0xb0, 0xee, 0x1a, 0x12, 0xd2, 0x9f, 0x51,
-	0x91, 0x07, 0x73, 0x54, 0x44, 0xe5, 0x33, 0xb3, 0x1c, 0xea, 0x61, 0xd6, 0x71, 0x45, 0xda, 0x53,
-	0xa6, 0x33, 0x22, 0x61, 0xf5, 0x88, 0x05, 0xb8, 0x5f, 0x64, 0xb1, 0xa4, 0xb3, 0xd8, 0x9b, 0x33,
-	0x8b, 0x7b, 0xa6, 0x53, 0xb7, 0x14, 0xc3, 0xf9, 0x00, 0x9a, 0xe5, 0x2b, 0xaa, 0x32, 0x64, 0x43,
-	0xea, 0xe7, 0x75, 0x4a, 0x67, 0xce, 0x2f, 0x16, 0x90, 0xe9, 0x93, 0x38, 0xa9, 0xdc, 0x83, 0xeb,
-	0x22, 0xeb, 0x9d, 0x92, 0xfb, 0x61, 0x48, 0xc8, 0x2e, 0x34, 0x7a, 0x28, 0x24, 0x0b, 0x75, 0xc2,
-	0x29, 0x71, 0xbc, 0x7f, 0xfa, 0x91, 0xdf, 0x29, 0x0c, 0x5c, 0xd3, 0xda, 0xf9, 0x12, 0x2e, 0x9e,
-	0xaa, 0x6d, 0xf4, 0x42, 0xd6, 0x44, 0x2f, 0x74, 0x6a, 0x07, 0xe5, 0x10, 0x68, 0x96, 0x19, 0xc8,
-	0x09, 0x61, 0x5d, 0xd5, 0xf4, 0x76, 0x9f, 0xc6, 0xf2, 0x55, 0xf4, 0x37, 0x37, 0xa1, 0x9e, 0xc7,
-	0x9b, 0x59, 0xe8, 0x16, 0xac, 0x8c, 0xb3, 0x06, 0x34, 0x69, 0x70, 0xf2, 0xb9, 0xb3, 0x03, 0xc4,
-	0x4c, 0x36, 0x7d, 0x28, 0x2e, 0xc3, 0x22, 0x93, 0x38, 0xcc, 0xba, 0x8c, 0x37, 0xca, 0xfc, 0xae,
-	0xd5, 0xdd, 0x44, 0x67, 0xfb, 0xd7, 0x1a, 0xac, 0x17, 0x34, 0xab, 0xfe, 0x32, 0x0f, 0xc9, 0x23,
-	0x68, 0xde, 0x4f, 0x7f, 0xf7, 0x65, 0x3d, 0x2b, 0x79, 0xdb, 0xf4, 0x53, 0xfa, 0x05, 0xd8, 0xda,
-	0x98, 0xbd, 0x98, 0x64, 0xe4, 0x2c, 0x90, 0x9b, 0xb0, 0x92, 0x35, 0x8d, 0x93, 0x8e, 0x4a, 0xad,
-	0x64, 0xab, 0x69, 0x2e, 0xaa, 0x05, 0x67, 0x81, 0xdc, 0x4a, 0x8c, 0x55, 0x1b, 0x34, 0x6d, 0x6c,
-	0x34, 0x78, 0xad, 0x73, 0x33, 0x1a, 0x2a, 0x67, 0x81, 0x7c, 0x0b, 0x67, 0xef, 0x6b, 0xea, 0x4c,
-	0x9f, 0x54, 0xf2, 0xde, 0x64, 0x90, 0x13, 0x7a, 0xa4, 0x96, 0x53, 0x56, 0x9b, 0x7e, 0x95, 0x9d,
-	0x05, 0xf2, 0xb3, 0x05, 0xe7, 0xee, 0xa3, 0x2c, 0xbf, 0x50, 0xe4, 0xca, 0xec, 0x20, 0x27, 0xbc,
-	0x64, 0xad, 0xdd, 0xb9, 0x50, 0x35, 0xe9, 0xd3, 0x59, 0x20, 0xfb, 0x7a, 0xcf, 0x05, 0x3a, 0xc8,
-	0xc5, 0x99, 0x30, 0xc8, 0x4b, 0xd7, 0x3e, 0x69, 0x39, 0xdb, 0xe7, 0x67, 0xb7, 0xfe, 0x79, 0xde,
-	0xb6, 0xfe, 0x7d, 0xde, 0xb6, 0xfe, 0x7b, 0xde, 0xb6, 0xbe, 0xfe, 0xe8, 0xb4, 0x2f, 0x0a, 0xc6,
-	0x97, 0x0f, 0xca, 0x99, 0x17, 0x30, 0x0c, 0xe5, 0xe1, 0x92, 0xfe, 0x7e, 0xf0, 0xf1, 0xff, 0x01,
-	0x00, 0x00, 0xff, 0xff, 0xaa, 0x90, 0xca, 0xf2, 0x18, 0x11, 0x00, 0x00,
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x58, 0xdd, 0x6e, 0x1b, 0xc5,
+	0x17, 0xcf, 0xda, 0xce, 0x87, 0x8f, 0xdb, 0xc4, 0x99, 0xf6, 0xdf, 0xff, 0x62, 0x52, 0x2b, 0xac,
+	0x44, 0x15, 0x28, 0xb5, 0x69, 0xa8, 0xa0, 0x6a, 0xa5, 0x4a, 0xa1, 0x9f, 0x28, 0x29, 0x4d, 0x37,
+	0x80, 0xc4, 0x87, 0x54, 0x4d, 0xd6, 0x27, 0xeb, 0xc1, 0xeb, 0xdd, 0x61, 0x67, 0x6c, 0x94, 0xbe,
+	0x00, 0xdc, 0x23, 0x9e, 0x01, 0xf1, 0x08, 0xdc, 0x22, 0x84, 0xb8, 0xe0, 0x82, 0x47, 0x40, 0x7d,
+	0x12, 0x34, 0xb3, 0x5f, 0xe3, 0xb5, 0x93, 0x1b, 0x37, 0xed, 0x4d, 0x32, 0x73, 0xbe, 0xcf, 0x99,
+	0xdf, 0x9c, 0x39, 0x5e, 0xb8, 0x12, 0x23, 0x8f, 0x04, 0xc6, 0x63, 0x8c, 0xbb, 0x7a, 0xc9, 0x64,
+	0x14, 0x1f, 0x1b, 0xcb, 0x0e, 0x8f, 0x23, 0x19, 0x11, 0x28, 0x28, 0xad, 0x8b, 0x7e, 0xe4, 0x47,
+	0x9a, 0xdc, 0x55, 0xab, 0x44, 0xa2, 0xb5, 0xe1, 0x47, 0x91, 0x1f, 0x60, 0x97, 0x72, 0xd6, 0xa5,
+	0x61, 0x18, 0x49, 0x2a, 0x59, 0x14, 0x8a, 0x94, 0xeb, 0x0c, 0x6e, 0x8a, 0x0e, 0x8b, 0x34, 0xd7,
+	0x8b, 0x62, 0xec, 0x8e, 0xaf, 0x77, 0x7d, 0x0c, 0x31, 0xa6, 0x12, 0x7b, 0xa9, 0xcc, 0x27, 0x3e,
+	0x93, 0xfd, 0xd1, 0x61, 0xc7, 0x8b, 0x86, 0x5d, 0x1a, 0x6b, 0x17, 0xdf, 0xea, 0xc5, 0x35, 0xaf,
+	0xd7, 0xe5, 0x03, 0x5f, 0x29, 0x8b, 0x2e, 0xe5, 0x3c, 0x60, 0x9e, 0x36, 0xde, 0x1d, 0x5f, 0xa7,
+	0x01, 0xef, 0xd3, 0x29, 0x53, 0xce, 0xaf, 0x4b, 0xb0, 0xf6, 0x98, 0x86, 0xec, 0x08, 0x85, 0x74,
+	0xf1, 0xbb, 0x11, 0x0a, 0x49, 0xbe, 0x84, 0x9a, 0x4a, 0xc2, 0xb6, 0x36, 0xad, 0xad, 0xc6, 0xf6,
+	0xfd, 0x4e, 0xe1, 0xad, 0x93, 0x79, 0xd3, 0x8b, 0x67, 0x5e, 0xaf, 0xc3, 0x07, 0x7e, 0x47, 0x79,
+	0xeb, 0x18, 0xde, 0x3a, 0x99, 0xb7, 0x8e, 0x9b, 0xd7, 0xc2, 0xd5, 0x26, 0x49, 0x0b, 0x56, 0x62,
+	0x1c, 0x33, 0xc1, 0xa2, 0xd0, 0xae, 0x6c, 0x5a, 0x5b, 0x75, 0x37, 0xdf, 0x13, 0x1b, 0x96, 0xc3,
+	0xe8, 0x2e, 0xf5, 0xfa, 0x68, 0x57, 0x37, 0xad, 0xad, 0x15, 0x37, 0xdb, 0x92, 0x4d, 0x68, 0x50,
+	0xce, 0xf7, 0xe8, 0x21, 0x06, 0xbb, 0x78, 0x6c, 0xd7, 0xb4, 0xa2, 0x49, 0x52, 0xba, 0x94, 0xf3,
+	0x4f, 0xe9, 0x10, 0xed, 0x45, 0xcd, 0xcd, 0xb6, 0x64, 0x03, 0xea, 0x21, 0x1d, 0xa2, 0xe0, 0xd4,
+	0x43, 0x7b, 0x45, 0xf3, 0x0a, 0x02, 0x79, 0x0e, 0xeb, 0x46, 0xe0, 0x07, 0xd1, 0x28, 0xf6, 0xd0,
+	0x06, 0x9d, 0xf7, 0xde, 0x1c, 0x79, 0xef, 0x94, 0x6d, 0xba, 0xd3, 0x6e, 0xc8, 0xd7, 0xb0, 0xa8,
+	0xb1, 0x62, 0x37, 0x36, 0xab, 0x2f, 0xaf, 0xce, 0x89, 0x4d, 0x32, 0x80, 0x65, 0x1e, 0x8c, 0x7c,
+	0x16, 0x0a, 0xfb, 0x9c, 0x36, 0xff, 0x74, 0x0e, 0xf3, 0x77, 0xa3, 0xf0, 0x88, 0xf9, 0x8f, 0x69,
+	0x48, 0x7d, 0x1c, 0x62, 0x28, 0xf7, 0xb5, 0x65, 0x37, 0xf3, 0x40, 0xbe, 0x87, 0xe6, 0x60, 0x24,
+	0x64, 0x34, 0x64, 0xcf, 0xf1, 0x09, 0xd7, 0x68, 0xb6, 0xcf, 0xeb, 0x22, 0xee, 0xce, 0xe1, 0x75,
+	0xb7, 0x64, 0xd2, 0x9d, 0x72, 0xa2, 0x80, 0x31, 0x18, 0x1d, 0xe2, 0x17, 0x18, 0x6b, 0x44, 0xad,
+	0x26, 0xc0, 0x30, 0x48, 0x09, 0x74, 0x58, 0xba, 0x13, 0xf6, 0xda, 0x66, 0x35, 0x81, 0x4e, 0x4e,
+	0x22, 0x5b, 0xb0, 0x36, 0xc6, 0x98, 0x1d, 0x1d, 0x1f, 0x30, 0x3f, 0xa4, 0x72, 0x14, 0xa3, 0xdd,
+	0xd4, 0xf0, 0x2b, 0x93, 0x9d, 0x3f, 0x2d, 0x68, 0x16, 0x77, 0x45, 0xf0, 0x28, 0x14, 0x1a, 0x5f,
+	0xc3, 0x94, 0x26, 0x6c, 0x4b, 0x9b, 0x2f, 0x08, 0x93, 0xe8, 0xab, 0x94, 0xd1, 0x77, 0x09, 0x96,
+	0x92, 0x8e, 0xa2, 0x01, 0x5f, 0x77, 0xd3, 0xdd, 0xc4, 0x2d, 0xa9, 0x95, 0x6e, 0x49, 0x1b, 0x40,
+	0x68, 0xfc, 0x7c, 0x76, 0xcc, 0xd1, 0x5e, 0xd2, 0x5c, 0x83, 0x42, 0x1c, 0x38, 0x97, 0xc4, 0xed,
+	0xa2, 0x18, 0x05, 0xd2, 0x5e, 0xd6, 0x12, 0x13, 0x34, 0x27, 0x80, 0xb5, 0x3d, 0xa6, 0x72, 0x38,
+	0x12, 0x67, 0x7f, 0xe7, 0x9d, 0x0f, 0xa1, 0xa6, 0x3c, 0xa9, 0xac, 0x0e, 0x63, 0x1a, 0x7a, 0x7d,
+	0xcc, 0x0a, 0x95, 0xef, 0x09, 0x81, 0x9a, 0xa4, 0xbe, 0xb0, 0x2b, 0x9a, 0xae, 0xd7, 0xce, 0x8f,
+	0x56, 0x12, 0xe6, 0x0e, 0xe7, 0xe2, 0xf5, 0xb6, 0x26, 0x67, 0x04, 0xcb, 0x3b, 0x9c, 0xab, 0x60,
+	0xc8, 0x75, 0xa8, 0x51, 0xce, 0x93, 0x0c, 0x1a, 0xdb, 0x97, 0x3b, 0xc6, 0x03, 0x90, 0x8a, 0xa8,
+	0xff, 0xe2, 0x7e, 0x28, 0x95, 0x65, 0x25, 0xda, 0xfa, 0x08, 0xea, 0x39, 0x89, 0x34, 0xa1, 0x3a,
+	0xc0, 0x63, 0x9d, 0x40, 0xdd, 0x55, 0x4b, 0x72, 0x11, 0x16, 0xc7, 0x34, 0x18, 0x65, 0xf8, 0x48,
+	0x36, 0xb7, 0x2a, 0x37, 0x2d, 0xe7, 0xef, 0x2a, 0xbc, 0xa1, 0xe2, 0x3c, 0xd0, 0xb0, 0xd8, 0xe1,
+	0xfc, 0x1e, 0x4a, 0xca, 0x02, 0xf1, 0x74, 0x84, 0xf1, 0xf1, 0x59, 0xd6, 0xa2, 0x07, 0x4b, 0x09,
+	0xa4, 0x74, 0x4c, 0x2f, 0xbb, 0x17, 0xa6, 0xb6, 0x8b, 0x06, 0x58, 0x3d, 0x83, 0x06, 0x38, 0xab,
+	0x27, 0xd5, 0x5e, 0x45, 0x4f, 0x3a, 0xf1, 0x29, 0x72, 0x7e, 0xa8, 0xc0, 0x25, 0x15, 0x68, 0x71,
+	0x90, 0x79, 0x17, 0x51, 0xf8, 0x57, 0xf7, 0x39, 0x81, 0x85, 0x5e, 0x93, 0x1b, 0xb0, 0x3c, 0x10,
+	0x51, 0x18, 0xa2, 0x4c, 0x4f, 0xa1, 0x65, 0x82, 0x6d, 0x37, 0x61, 0xed, 0x70, 0x7e, 0xc0, 0xd1,
+	0x73, 0x33, 0x51, 0x72, 0x15, 0x6a, 0x7d, 0x0c, 0x86, 0xba, 0xa3, 0x34, 0xb6, 0xff, 0x6f, 0xaa,
+	0x3c, 0xc2, 0x60, 0x98, 0xc9, 0x6b, 0x21, 0x72, 0x0b, 0xea, 0x79, 0xfc, 0x69, 0x75, 0x36, 0x26,
+	0x9c, 0x64, 0xcc, 0x4c, 0xad, 0x10, 0x57, 0xba, 0x3d, 0x16, 0xa3, 0xa7, 0x04, 0x75, 0xa6, 0x25,
+	0xdd, 0x7b, 0x19, 0x33, 0xd7, 0xcd, 0xc5, 0x9d, 0xdf, 0x2d, 0x78, 0xab, 0x00, 0xb6, 0x9b, 0x5e,
+	0xb3, 0xc7, 0x28, 0x69, 0x8f, 0x4a, 0xfa, 0x9a, 0xe7, 0x90, 0x2b, 0xb0, 0xea, 0xf5, 0xd1, 0x1b,
+	0x14, 0xef, 0x41, 0x32, 0x8e, 0x94, 0xa8, 0xce, 0x1f, 0x15, 0x58, 0x9d, 0x3c, 0x05, 0x75, 0x8c,
+	0xaa, 0xbb, 0x67, 0xc7, 0xa8, 0xd6, 0x64, 0x1f, 0xce, 0x61, 0x38, 0x66, 0x71, 0x14, 0xaa, 0xa7,
+	0x33, 0x03, 0xfb, 0x7b, 0x27, 0x9f, 0x65, 0xe7, 0xbe, 0x21, 0x9e, 0xf4, 0x91, 0x09, 0x0b, 0x64,
+	0x00, 0xc0, 0x69, 0x4c, 0x87, 0x28, 0x31, 0x56, 0xa0, 0xae, 0xce, 0x0b, 0xea, 0xc4, 0xfd, 0x7e,
+	0x66, 0xd3, 0x35, 0xcc, 0xb7, 0x9e, 0xc1, 0xfa, 0x54, 0x3c, 0x33, 0x9a, 0xd8, 0x0d, 0xb3, 0x89,
+	0x35, 0xb6, 0xdb, 0x33, 0xd2, 0x33, 0xcc, 0x98, 0x4d, 0xee, 0xb7, 0x0a, 0x34, 0x0c, 0x64, 0xce,
+	0xac, 0x61, 0x1b, 0x40, 0x2b, 0x3c, 0x60, 0x01, 0x26, 0x15, 0xac, 0xbb, 0x06, 0x85, 0xf4, 0x67,
+	0x54, 0xe4, 0xd1, 0x1c, 0x15, 0x51, 0xf1, 0xcc, 0x2c, 0x87, 0x7a, 0xb2, 0xb5, 0x5f, 0x91, 0x5e,
+	0xee, 0x74, 0x47, 0x24, 0xac, 0x1e, 0xb1, 0x00, 0xf7, 0x8b, 0x28, 0x96, 0x74, 0x14, 0x7b, 0x73,
+	0x46, 0xf1, 0xc0, 0x34, 0xea, 0x96, 0x7c, 0x38, 0xef, 0x42, 0xb3, 0x7c, 0x45, 0x55, 0x84, 0x6c,
+	0x48, 0xfd, 0xbc, 0x4e, 0xe9, 0xce, 0xf9, 0xd9, 0x02, 0x32, 0x7d, 0x12, 0x27, 0x95, 0x7b, 0x70,
+	0x53, 0x64, 0x53, 0x55, 0x72, 0x3f, 0x0c, 0x0a, 0xd9, 0x85, 0x46, 0x0f, 0x85, 0x64, 0xa1, 0x0e,
+	0x38, 0x6d, 0x1c, 0xef, 0x9c, 0x7e, 0xe4, 0xf7, 0x0a, 0x05, 0xd7, 0xd4, 0x76, 0x3e, 0x87, 0xcb,
+	0xa7, 0x4a, 0x1b, 0x53, 0x92, 0x35, 0x31, 0x25, 0x9d, 0x3a, 0x5b, 0x39, 0x04, 0x9a, 0xe5, 0x0e,
+	0xe4, 0x84, 0xb0, 0xae, 0x6a, 0x7a, 0xb7, 0x4f, 0x63, 0xf9, 0x2a, 0x26, 0x9f, 0xdb, 0x50, 0xcf,
+	0xfd, 0xcd, 0x2c, 0x74, 0x0b, 0x56, 0xc6, 0xd9, 0x68, 0x9a, 0x8c, 0x3e, 0xf9, 0xde, 0xd9, 0x01,
+	0x62, 0x06, 0x9b, 0x3e, 0x14, 0x57, 0x61, 0x91, 0x49, 0x1c, 0x66, 0xf3, 0xc7, 0xff, 0xca, 0xfd,
+	0x5d, 0x8b, 0xbb, 0x89, 0xcc, 0xf6, 0x2f, 0x35, 0x58, 0x2f, 0xda, 0xac, 0xfa, 0xcb, 0x3c, 0x24,
+	0x4f, 0xa0, 0xf9, 0x30, 0xfd, 0x15, 0x98, 0x4d, 0xb3, 0xe4, 0x4d, 0xd3, 0x4e, 0xe9, 0xf7, 0x60,
+	0x6b, 0x63, 0x36, 0x33, 0x89, 0xc8, 0x59, 0x20, 0xb7, 0x61, 0x25, 0x1b, 0x27, 0x27, 0x0d, 0x95,
+	0x86, 0xcc, 0x56, 0xd3, 0x64, 0x2a, 0x86, 0xb3, 0x40, 0xee, 0x24, 0xca, 0x6a, 0x40, 0x9a, 0x56,
+	0x36, 0x46, 0xbf, 0xd6, 0x85, 0x19, 0xa3, 0x96, 0xb3, 0x40, 0xbe, 0x81, 0xf3, 0x0f, 0x75, 0xeb,
+	0x4c, 0x9f, 0x54, 0xf2, 0xf6, 0xa4, 0x93, 0x13, 0xa6, 0xa7, 0x96, 0x53, 0x16, 0x9b, 0x7e, 0x95,
+	0x9d, 0x05, 0xf2, 0x93, 0x05, 0x17, 0x1e, 0xa2, 0x2c, 0xbf, 0x50, 0xe4, 0xda, 0x6c, 0x27, 0x27,
+	0xbc, 0x64, 0xad, 0xdd, 0xb9, 0x50, 0x35, 0x69, 0xd3, 0x59, 0x20, 0xfb, 0x3a, 0xe7, 0x02, 0x1d,
+	0xe4, 0xf2, 0x4c, 0x18, 0xe4, 0xa5, 0x6b, 0x9f, 0xc4, 0xce, 0xf2, 0xfc, 0xf8, 0xce, 0x5f, 0x2f,
+	0xda, 0xd6, 0x3f, 0x2f, 0xda, 0xd6, 0xbf, 0x2f, 0xda, 0xd6, 0x57, 0xef, 0x9f, 0xf6, 0x7d, 0xc1,
+	0xf8, 0x0e, 0x42, 0x39, 0xf3, 0x02, 0x86, 0xa1, 0x3c, 0x5c, 0xd2, 0x5f, 0x13, 0x3e, 0xf8, 0x2f,
+	0x00, 0x00, 0xff, 0xff, 0x73, 0xa9, 0x07, 0xe6, 0x26, 0x11, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1694,10 +1703,10 @@ func (m *ManifestRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
 		i--
 		dAtA[i] = 0x42
 	}
-	if len(m.AppLabelValue) > 0 {
-		i -= len(m.AppLabelValue)
-		copy(dAtA[i:], m.AppLabelValue)
-		i = encodeVarintRepository(dAtA, i, uint64(len(m.AppLabelValue)))
+	if len(m.AppName) > 0 {
+		i -= len(m.AppName)
+		copy(dAtA[i:], m.AppName)
+		i = encodeVarintRepository(dAtA, i, uint64(len(m.AppName)))
 		i--
 		dAtA[i] = 0x2a
 	}
@@ -2011,6 +2020,13 @@ func (m *RepoServerAppDetailsQuery) MarshalToSizedBuffer(dAtA []byte) (int, erro
 		i -= len(m.XXX_unrecognized)
 		copy(dAtA[i:], m.XXX_unrecognized)
 	}
+	if len(m.AppName) > 0 {
+		i -= len(m.AppName)
+		copy(dAtA[i:], m.AppName)
+		i = encodeVarintRepository(dAtA, i, uint64(len(m.AppName)))
+		i--
+		dAtA[i] = 0x2a
+	}
 	if m.KustomizeOptions != nil {
 		{
 			size, err := m.KustomizeOptions.MarshalToSizedBuffer(dAtA[:i])
@@ -2666,7 +2682,7 @@ func (m *ManifestRequest) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovRepository(uint64(l))
 	}
-	l = len(m.AppLabelValue)
+	l = len(m.AppName)
 	if l > 0 {
 		n += 1 + l + sovRepository(uint64(l))
 	}
@@ -2855,6 +2871,10 @@ func (m *RepoServerAppDetailsQuery) Size() (n int) {
 		l = m.KustomizeOptions.Size()
 		n += 1 + l + sovRepository(uint64(l))
 	}
+	l = len(m.AppName)
+	if l > 0 {
+		n += 1 + l + sovRepository(uint64(l))
+	}
 	if m.XXX_unrecognized != nil {
 		n += len(m.XXX_unrecognized)
 	}
@@ -3276,7 +3296,7 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
 			iNdEx = postIndex
 		case 5:
 			if wireType != 2 {
-				return fmt.Errorf("proto: wrong wireType = %d for field AppLabelValue", wireType)
+				return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType)
 			}
 			var stringLen uint64
 			for shift := uint(0); ; shift += 7 {
@@ -3304,7 +3324,7 @@ func (m *ManifestRequest) Unmarshal(dAtA []byte) error {
 			if postIndex > l {
 				return io.ErrUnexpectedEOF
 			}
-			m.AppLabelValue = string(dAtA[iNdEx:postIndex])
+			m.AppName = string(dAtA[iNdEx:postIndex])
 			iNdEx = postIndex
 		case 8:
 			if wireType != 2 {
@@ -4515,6 +4535,38 @@ func (m *RepoServerAppDetailsQuery) Unmarshal(dAtA []byte) error {
 				return err
 			}
 			iNdEx = postIndex
+		case 5:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field AppName", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowRepository
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthRepository
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthRepository
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.AppName = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
 		default:
 			iNdEx = preIndex
 			skippy, err := skipRepository(dAtA[iNdEx:])
diff --git a/reposerver/cache/cache.go b/reposerver/cache/cache.go
index 34e9ba86f..9fd7b1a48 100644
--- a/reposerver/cache/cache.go
+++ b/reposerver/cache/cache.go
@@ -69,12 +69,12 @@ func (c *Cache) SetApps(repoUrl, revision string, apps map[string]string) error
 	return c.cache.SetItem(listApps(repoUrl, revision), apps, c.repoCacheExpiration, apps == nil)
 }
 
-func manifestCacheKey(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appLabelValue string) string {
-	return fmt.Sprintf("mfst|%s|%s|%s|%s|%d", appLabelKey, appLabelValue, revision, namespace, appSourceKey(appSrc))
+func manifestCacheKey(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appName string) string {
+	return fmt.Sprintf("mfst|%s|%s|%s|%s|%d", appLabelKey, appName, revision, namespace, appSourceKey(appSrc))
 }
 
-func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appLabelValue string, res *CachedManifestResponse) error {
-	err := c.cache.GetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appLabelValue), res)
+func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appName string, res *CachedManifestResponse) error {
+	err := c.cache.GetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appName), res)
 
 	if err != nil {
 		return err
@@ -87,9 +87,9 @@ func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, n
 
 	// If the expected hash of the cache entry does not match the actual hash value...
 	if hash != res.CacheEntryHash {
-		log.Warnf("Manifest hash did not match expected value, treating as a cache miss: %s", appLabelValue)
+		log.Warnf("Manifest hash did not match expected value, treating as a cache miss: %s", appName)
 
-		err = c.DeleteManifests(revision, appSrc, namespace, appLabelKey, appLabelValue)
+		err = c.DeleteManifests(revision, appSrc, namespace, appLabelKey, appName)
 		if err != nil {
 			return fmt.Errorf("Unable to delete manifest after hash mismatch, %v", err)
 		}
@@ -104,7 +104,7 @@ func (c *Cache) GetManifests(revision string, appSrc *appv1.ApplicationSource, n
 	return nil
 }
 
-func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appLabelValue string, res *CachedManifestResponse) error {
+func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appName string, res *CachedManifestResponse) error {
 
 	// Generate and apply the cache entry hash, before writing
 	if res != nil {
@@ -116,11 +116,11 @@ func (c *Cache) SetManifests(revision string, appSrc *appv1.ApplicationSource, n
 		res.CacheEntryHash = hash
 	}
 
-	return c.cache.SetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appLabelValue), res, c.repoCacheExpiration, res == nil)
+	return c.cache.SetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appName), res, c.repoCacheExpiration, res == nil)
 }
 
-func (c *Cache) DeleteManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appLabelValue string) error {
-	return c.cache.SetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appLabelValue), "", c.repoCacheExpiration, true)
+func (c *Cache) DeleteManifests(revision string, appSrc *appv1.ApplicationSource, namespace string, appLabelKey string, appName string) error {
+	return c.cache.SetItem(manifestCacheKey(revision, appSrc, namespace, appLabelKey, appName), "", c.repoCacheExpiration, true)
 }
 
 func appDetailsCacheKey(revision string, appSrc *appv1.ApplicationSource) string {
diff --git a/reposerver/repository/repository.go b/reposerver/repository/repository.go
index 6592dab22..cc52b0d15 100644
--- a/reposerver/repository/repository.go
+++ b/reposerver/repository/repository.go
@@ -57,6 +57,8 @@ const (
 	cachedManifestGenerationPrefix = "Manifest generation error (cached)"
 	helmDepUpMarkerFile            = ".argocd-helm-dep-up"
 	allowConcurrencyFile           = ".argocd-allow-concurrency"
+	repoSourceFile                 = ".argocd-source.yaml"
+	appSourceFile                  = ".argocd-source-%s.yaml"
 )
 
 // Service implements ManifestService interface
@@ -324,7 +326,7 @@ func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc op
 			// Retrieve a new copy (if available) of the cached response: this ensures we are updating the latest copy of the cache,
 			// rather than a copy of the cache that occurred before (a potentially lengthy) manifest generation.
 			innerRes := &cache.CachedManifestResponse{}
-			cacheErr := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, innerRes)
+			cacheErr := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName, innerRes)
 			if cacheErr != nil && cacheErr != reposervercache.ErrCacheMiss {
 				log.Warnf("manifest cache set error %s: %v", q.ApplicationSource.String(), cacheErr)
 				return nil, cacheErr
@@ -339,7 +341,7 @@ func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc op
 			// Update the cache to include failure information
 			innerRes.NumberOfConsecutiveFailures++
 			innerRes.MostRecentError = err.Error()
-			cacheErr = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, innerRes)
+			cacheErr = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName, innerRes)
 			if cacheErr != nil {
 				log.Warnf("manifest cache set error %s: %v", q.ApplicationSource.String(), cacheErr)
 				return nil, cacheErr
@@ -358,7 +360,7 @@ func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc op
 	}
 	manifestGenResult.Revision = commitSHA
 	manifestGenResult.VerifyResult = ctx.verificationResult
-	err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, &manifestGenCacheEntry)
+	err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName, &manifestGenCacheEntry)
 	if err != nil {
 		log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err)
 	}
@@ -373,7 +375,7 @@ func (s *Service) runManifestGen(repoRoot, commitSHA, cacheKey string, ctxSrc op
 // If true is returned, either the second or third parameter (but not both) will contain a value from the cache (a ManifestResponse, or error, respectively)
 func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRequest, firstInvocation bool) (bool, interface{}, error) {
 	res := cache.CachedManifestResponse{}
-	err := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, &res)
+	err := s.cache.GetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName, &res)
 	if err == nil {
 
 		// The cache contains an existing value
@@ -392,7 +394,7 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe
 					// After X minutes, reset the cache and retry the operation (eg perhaps the error is ephemeral and has passed)
 					if elapsedTimeInMinutes >= s.initConstants.PauseGenerationOnFailureForMinutes {
 						// We can now try again, so reset the cache state and run the operation below
-						err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue)
+						err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName)
 						if err != nil {
 							log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err)
 						}
@@ -406,7 +408,7 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe
 
 					if res.NumberOfCachedResponsesReturned >= s.initConstants.PauseGenerationOnFailureForRequests {
 						// We can now try again, so reset the error cache state and run the operation below
-						err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue)
+						err = s.cache.DeleteManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName)
 						if err != nil {
 							log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err)
 						}
@@ -424,7 +426,7 @@ func (s *Service) getManifestCacheEntry(cacheKey string, q *apiclient.ManifestRe
 					// Increment the number of returned cached responses and push that new value to the cache
 					// (if we have not already done so previously in this function)
 					res.NumberOfCachedResponsesReturned++
-					err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppLabelValue, &res)
+					err = s.cache.SetManifests(cacheKey, q.ApplicationSource, q.Namespace, q.AppLabelKey, q.AppName, &res)
 					if err != nil {
 						log.Warnf("manifest cache set error %s/%s: %v", q.ApplicationSource.String(), cacheKey, err)
 					}
@@ -504,7 +506,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
 	}
 
 	templateOpts := &helm.TemplateOpts{
-		Name:        q.AppLabelValue,
+		Name:        q.AppName,
 		Namespace:   q.Namespace,
 		KubeVersion: text.SemVer(q.KubeVersion),
 		APIVersions: q.ApiVersions,
@@ -577,7 +579,7 @@ func helmTemplate(appPath string, repoRoot string, env *v1alpha1.Env, q *apiclie
 		}
 	}
 	if templateOpts.Name == "" {
-		templateOpts.Name = q.AppLabelValue
+		templateOpts.Name = q.AppName
 	}
 	for i, j := range templateOpts.Set {
 		templateOpts.Set[i] = env.Envsubst(j)
@@ -628,7 +630,7 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest
 	var targetObjs []*unstructured.Unstructured
 	var dest *v1alpha1.ApplicationDestination
 
-	appSourceType, err := GetAppSourceType(q.ApplicationSource, appPath)
+	appSourceType, err := GetAppSourceType(q.ApplicationSource, appPath, q.AppName)
 	if err != nil {
 		return nil, err
 	}
@@ -685,8 +687,8 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest
 		}
 
 		for _, target := range targets {
-			if q.AppLabelKey != "" && q.AppLabelValue != "" && !kube.IsCRD(target) {
-				err = argokube.SetAppInstanceLabel(target, q.AppLabelKey, q.AppLabelValue)
+			if q.AppLabelKey != "" && q.AppName != "" && !kube.IsCRD(target) {
+				err = argokube.SetAppInstanceLabel(target, q.AppLabelKey, q.AppName)
 				if err != nil {
 					return nil, err
 				}
@@ -712,7 +714,7 @@ func GenerateManifests(appPath, repoRoot, revision string, q *apiclient.Manifest
 
 func newEnv(q *apiclient.ManifestRequest, revision string) *v1alpha1.Env {
 	return &v1alpha1.Env{
-		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppLabelValue},
+		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAME", Value: q.AppName},
 		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_NAMESPACE", Value: q.Namespace},
 		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_REVISION", Value: revision},
 		&v1alpha1.EnvEntry{Name: "ARGOCD_APP_SOURCE_REPO_URL", Value: q.Repo.Repo},
@@ -721,38 +723,54 @@ func newEnv(q *apiclient.ManifestRequest, revision string) *v1alpha1.Env {
 	}
 }
 
-func mergeSourceParameters(source *v1alpha1.ApplicationSource, path string) error {
-	appFilePath := filepath.Join(path, ".argocd-source.yaml")
-	info, err := os.Stat(appFilePath)
-	if os.IsNotExist(err) {
-		return nil
-	} else if info != nil && info.IsDir() {
-		return nil
-	} else if err != nil {
-		return err
-	}
-	patch, err := json.Marshal(source)
-	if err != nil {
-		return err
-	}
+// mergeSourceParameters merges parameter overrides from one or more files in
+// the Git repo into the given ApplicationSource objects.
+//
+// If .argocd-source.yaml exists at application's path in repository, it will
+// be read and merged. If appName is not the empty string, and a file named
+// .argocd-source-<appName>.yaml exists, it will also be read and merged.
+func mergeSourceParameters(source *v1alpha1.ApplicationSource, path, appName string) error {
+	repoFilePath := filepath.Join(path, repoSourceFile)
+	overrides := []string{repoFilePath}
+	if appName != "" {
+		overrides = append(overrides, filepath.Join(path, fmt.Sprintf(appSourceFile, appName)))
+	}
+
+	var merged v1alpha1.ApplicationSource = *source.DeepCopy()
+
+	for _, filename := range overrides {
+		info, err := os.Stat(filename)
+		if os.IsNotExist(err) {
+			continue
+		} else if info != nil && info.IsDir() {
+			continue
+		} else if err != nil {
+			// filename should be part of error message here
+			return err
+		}
 
-	data, err := ioutil.ReadFile(appFilePath)
-	if err != nil {
-		return err
-	}
-	data, err = yaml.YAMLToJSON(data)
-	if err != nil {
-		return err
-	}
-	data, err = jsonpatch.MergePatch(data, patch)
-	if err != nil {
-		return err
-	}
-	var merged v1alpha1.ApplicationSource
-	err = json.Unmarshal(data, &merged)
-	if err != nil {
-		return err
+		data, err := json.Marshal(merged)
+		if err != nil {
+			return fmt.Errorf("%s: %v", filename, err)
+		}
+		patch, err := ioutil.ReadFile(filename)
+		if err != nil {
+			return fmt.Errorf("%s: %v", filename, err)
+		}
+		patch, err = yaml.YAMLToJSON(patch)
+		if err != nil {
+			return fmt.Errorf("%s: %v", filename, err)
+		}
+		data, err = jsonpatch.MergePatch(data, patch)
+		if err != nil {
+			return fmt.Errorf("%s: %v", filename, err)
+		}
+		err = json.Unmarshal(data, &merged)
+		if err != nil {
+			return fmt.Errorf("%s: %v", filename, err)
+		}
 	}
+
 	// make sure only config management tools related properties are used and ignore everything else
 	merged.Chart = source.Chart
 	merged.Path = source.Path
@@ -764,10 +782,10 @@ func mergeSourceParameters(source *v1alpha1.ApplicationSource, path string) erro
 }
 
 // GetAppSourceType returns explicit application source type or examines a directory and determines its application source type
-func GetAppSourceType(source *v1alpha1.ApplicationSource, path string) (v1alpha1.ApplicationSourceType, error) {
-	err := mergeSourceParameters(source, path)
+func GetAppSourceType(source *v1alpha1.ApplicationSource, path, appName string) (v1alpha1.ApplicationSourceType, error) {
+	err := mergeSourceParameters(source, path, appName)
 	if err != nil {
-		return "", fmt.Errorf("error while parsing .argocd-source.yaml: %v", err)
+		return "", fmt.Errorf("error while parsing source parameters: %v", err)
 	}
 
 	appSourceType, err := source.ExplicitType()
@@ -1049,7 +1067,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *apiclient.RepoServerAppD
 		appPath := ctx.appPath
 
 		res := &apiclient.RepoAppDetailsResponse{}
-		appSourceType, err := GetAppSourceType(q.Source, appPath)
+		appSourceType, err := GetAppSourceType(q.Source, appPath, q.AppName)
 		if err != nil {
 			return nil, err
 		}
diff --git a/reposerver/repository/repository.proto b/reposerver/repository/repository.proto
index 986d14092..6c6dc7234 100644
--- a/reposerver/repository/repository.proto
+++ b/reposerver/repository/repository.proto
@@ -15,7 +15,8 @@ message ManifestRequest {
     string revision = 2;
     bool noCache = 3;
     string appLabelKey = 4;
-    string appLabelValue = 5;
+    // Name of the application for which the request is triggered
+    string appName = 5;
     string namespace = 8;
     github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationSource applicationSource = 10;
     repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repos = 11;
@@ -65,6 +66,7 @@ message RepoServerAppDetailsQuery {
     github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.ApplicationSource source = 2;
     repeated github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.Repository repos = 3;
     github.com.argoproj.argo_cd.pkg.apis.application.v1alpha1.KustomizeOptions kustomizeOptions = 4;
+    string appName = 5;
 }
 
 // RepoAppDetailsResponse application details
diff --git a/reposerver/server.go b/reposerver/server.go
index 2a10db079..0109fdf5c 100644
--- a/reposerver/server.go
+++ b/reposerver/server.go
@@ -4,8 +4,17 @@ import (
 	"crypto/tls"
 	"os"
 
-	"github.com/argoproj/argo-cd/common"
+	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
+	grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
+	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
+	log "github.com/sirupsen/logrus"
+	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
+	"google.golang.org/grpc/health"
+	"google.golang.org/grpc/health/grpc_health_v1"
+	"google.golang.org/grpc/reflection"
 
+	"github.com/argoproj/argo-cd/common"
 	versionpkg "github.com/argoproj/argo-cd/pkg/apiclient/version"
 	"github.com/argoproj/argo-cd/reposerver/apiclient"
 	reposervercache "github.com/argoproj/argo-cd/reposerver/cache"
@@ -14,14 +23,6 @@ import (
 	"github.com/argoproj/argo-cd/server/version"
 	grpc_util "github.com/argoproj/argo-cd/util/grpc"
 	tlsutil "github.com/argoproj/argo-cd/util/tls"
-
-	grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
-	grpc_logrus "github.com/grpc-ecosystem/go-grpc-middleware/logging/logrus"
-	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
-	log "github.com/sirupsen/logrus"
-	"google.golang.org/grpc"
-	"google.golang.org/grpc/credentials"
-	"google.golang.org/grpc/reflection"
 )
 
 // ArgoCDRepoServer is the repo server implementation
@@ -82,6 +83,9 @@ func (a *ArgoCDRepoServer) CreateGRPC() *grpc.Server {
 	manifestService := repository.NewService(a.metricsServer, a.cache, a.initConstants)
 	apiclient.RegisterRepoServerServiceServer(server, manifestService)
 
+	healthService := health.NewServer()
+	grpc_health_v1.RegisterHealthServer(server, healthService)
+
 	// Register reflection service on gRPC server.
 	reflection.Register(server)
 
diff --git a/server/application/application.go b/server/application/application.go
index 21b07fd42..746c2e697 100644
--- a/server/application/application.go
+++ b/server/application/application.go
@@ -274,7 +274,7 @@ func (s *Server) GetManifests(ctx context.Context, q *application.ApplicationMan
 		Repo:              repo,
 		Revision:          revision,
 		AppLabelKey:       appInstanceLabelKey,
-		AppLabelValue:     a.Name,
+		AppName:           a.Name,
 		Namespace:         a.Spec.Destination.Namespace,
 		ApplicationSource: &a.Spec.Source,
 		Repos:             helmRepos,
diff --git a/util/argo/argo.go b/util/argo/argo.go
index 9630a68e9..ce918a8bf 100644
--- a/util/argo/argo.go
+++ b/util/argo/argo.go
@@ -415,7 +415,7 @@ func verifyGenerateManifests(
 		},
 		Repos:             helmRepos,
 		Revision:          spec.Source.TargetRevision,
-		AppLabelValue:     app.Name,
+		AppName:           app.Name,
 		Namespace:         spec.Destination.Namespace,
 		ApplicationSource: &spec.Source,
 		Plugins:           plugins,


Test patch:
diff --git a/reposerver/repository/repository_test.go b/reposerver/repository/repository_test.go
index 7f3a75c64..98e7aa402 100644
--- a/reposerver/repository/repository_test.go
+++ b/reposerver/repository/repository_test.go
@@ -7,6 +7,7 @@ import (
 	"fmt"
 	"io/ioutil"
 	"os"
+	"os/exec"
 	"path/filepath"
 	"regexp"
 	"strings"
@@ -17,6 +18,7 @@ import (
 	"github.com/ghodss/yaml"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/mock"
+	"github.com/stretchr/testify/require"
 	v1 "k8s.io/api/apps/v1"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime"
@@ -269,7 +271,7 @@ func TestManifestGenErrorCacheByNumRequests(t *testing.T) {
 		assert.NotNil(t, manifestRequest)
 
 		cachedManifestResponse := &cache.CachedManifestResponse{}
-		err := service.cache.GetManifests(mock.Anything, manifestRequest.ApplicationSource, manifestRequest.Namespace, manifestRequest.AppLabelKey, manifestRequest.AppLabelValue, cachedManifestResponse)
+		err := service.cache.GetManifests(mock.Anything, manifestRequest.ApplicationSource, manifestRequest.Namespace, manifestRequest.AppLabelKey, manifestRequest.AppName, cachedManifestResponse)
 		assert.Nil(t, err)
 		return cachedManifestResponse
 	}
@@ -329,8 +331,8 @@ func TestManifestGenErrorCacheByNumRequests(t *testing.T) {
 				fmt.Printf("%d )-------------------------------------------\n", invocationCount)
 
 				manifestRequest := &apiclient.ManifestRequest{
-					Repo:          &argoappv1.Repository{},
-					AppLabelValue: "test",
+					Repo:    &argoappv1.Repository{},
+					AppName: "test",
 					ApplicationSource: &argoappv1.ApplicationSource{
 						Path: "./testdata/invalid-helm",
 					},
@@ -426,8 +428,8 @@ func TestManifestGenErrorCacheFileContentsChange(t *testing.T) {
 		}
 
 		res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-			Repo:          &argoappv1.Repository{},
-			AppLabelValue: "test",
+			Repo:    &argoappv1.Repository{},
+			AppName: "test",
 			ApplicationSource: &argoappv1.ApplicationSource{
 				Path: ".",
 			},
@@ -478,8 +480,8 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) {
 			// 1) Put the cache into the failure state
 			for x := 0; x < 2; x++ {
 				res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-					Repo:          &argoappv1.Repository{},
-					AppLabelValue: "test",
+					Repo:    &argoappv1.Repository{},
+					AppName: "test",
 					ApplicationSource: &argoappv1.ApplicationSource{
 						Path: "./testdata/invalid-helm",
 					},
@@ -497,8 +499,8 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) {
 			// 2) Jump forward X-1 minutes in time, where X is the expiration boundary
 			currentTime = currentTime.Add(time.Duration(tt.PauseGenerationOnFailureForMinutes-1) * time.Minute)
 			res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-				Repo:          &argoappv1.Repository{},
-				AppLabelValue: "test",
+				Repo:    &argoappv1.Repository{},
+				AppName: "test",
 				ApplicationSource: &argoappv1.ApplicationSource{
 					Path: "./testdata/invalid-helm",
 				},
@@ -512,8 +514,8 @@ func TestManifestGenErrorCacheByMinutesElapsed(t *testing.T) {
 			currentTime = currentTime.Add(2 * time.Minute)
 
 			res, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-				Repo:          &argoappv1.Repository{},
-				AppLabelValue: "test",
+				Repo:    &argoappv1.Repository{},
+				AppName: "test",
 				ApplicationSource: &argoappv1.ApplicationSource{
 					Path: "./testdata/invalid-helm",
 				},
@@ -542,8 +544,8 @@ func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) {
 	// 1) Put the cache into the failure state
 	for x := 0; x < 2; x++ {
 		res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-			Repo:          &argoappv1.Repository{},
-			AppLabelValue: "test",
+			Repo:    &argoappv1.Repository{},
+			AppName: "test",
 			ApplicationSource: &argoappv1.ApplicationSource{
 				Path: "./testdata/invalid-helm",
 			},
@@ -559,8 +561,8 @@ func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) {
 
 	// 2) Call generateManifest with NoCache enabled
 	res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./testdata/invalid-helm",
 		},
@@ -573,8 +575,8 @@ func TestManifestGenErrorCacheRespectsNoCache(t *testing.T) {
 
 	// 4) Call generateManifest
 	res, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./testdata/invalid-helm",
 		},
@@ -590,8 +592,8 @@ func TestGenerateHelmWithValues(t *testing.T) {
 	service := newService("../..")
 
 	res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -626,8 +628,8 @@ func TestGenerateHelmWithValues(t *testing.T) {
 func TestGenerateHelmWithValuesDirectoryTraversal(t *testing.T) {
 	service := newService("../..")
 	_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -641,8 +643,8 @@ func TestGenerateHelmWithValuesDirectoryTraversal(t *testing.T) {
 	// Test the case where the path is "."
 	service = newService("./testdata/my-chart")
 	_, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: ".",
 		},
@@ -694,8 +696,8 @@ func TestGenerateHelmWithURL(t *testing.T) {
 	service := newService("../..")
 
 	_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -712,8 +714,8 @@ func TestGenerateHelmWithURL(t *testing.T) {
 func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) {
 	service := newService("../..")
 	_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -726,8 +728,8 @@ func TestGenerateHelmWithValuesDirectoryTraversalOutsideRepo(t *testing.T) {
 
 	service = newService("./testdata/my-chart")
 	_, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: ".",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -755,8 +757,8 @@ func TestGenerateHelmWithAbsoluteFileParameter(t *testing.T) {
 	assert.NoError(t, err)
 
 	_, err = service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -782,8 +784,8 @@ func TestGenerateHelmWithFileParameter(t *testing.T) {
 	service := newService("../..")
 
 	_, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo:          &argoappv1.Repository{},
-		AppLabelValue: "test",
+		Repo:    &argoappv1.Repository{},
+		AppName: "test",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path: "./util/helm/testdata/redis",
 			Helm: &argoappv1.ApplicationSourceHelm{
@@ -829,15 +831,15 @@ func TestGenerateNullList(t *testing.T) {
 }
 
 func TestIdentifyAppSourceTypeByAppDirWithKustomizations(t *testing.T) {
-	sourceType, err := GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml")
+	sourceType, err := GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/kustomization_yaml", "testapp")
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 
-	sourceType, err = GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/kustomization_yml")
+	sourceType, err = GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/kustomization_yml", "testapp")
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 
-	sourceType, err = GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/Kustomization")
+	sourceType, err = GetAppSourceType(&argoappv1.ApplicationSource{}, "./testdata/Kustomization", "testapp")
 	assert.Nil(t, err)
 	assert.Equal(t, argoappv1.ApplicationSourceTypeKustomize, sourceType)
 }
@@ -846,8 +848,8 @@ func TestRunCustomTool(t *testing.T) {
 	service := newService(".")
 
 	res, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		AppLabelValue: "test-app",
-		Namespace:     "test-namespace",
+		AppName:   "test-app",
+		Namespace: "test-namespace",
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Plugin: &argoappv1.ApplicationSourcePlugin{
 				Name: "test",
@@ -895,14 +897,16 @@ func TestListApps(t *testing.T) {
 	assert.NoError(t, err)
 
 	expectedApps := map[string]string{
-		"Kustomization":      "Kustomize",
-		"app-parameters":     "Kustomize",
-		"invalid-helm":       "Helm",
-		"invalid-kustomize":  "Kustomize",
-		"kustomization_yaml": "Kustomize",
-		"kustomization_yml":  "Kustomize",
-		"my-chart":           "Helm",
-		"my-chart-2":         "Helm",
+		"Kustomization":                  "Kustomize",
+		"app-parameters/multi":           "Kustomize",
+		"app-parameters/single-app-only": "Kustomize",
+		"app-parameters/single-global":   "Kustomize",
+		"invalid-helm":                   "Helm",
+		"invalid-kustomize":              "Kustomize",
+		"kustomization_yaml":             "Kustomize",
+		"kustomization_yml":              "Kustomize",
+		"my-chart":                       "Helm",
+		"my-chart-2":                     "Helm",
 	}
 	assert.Equal(t, expectedApps, res.Apps)
 }
@@ -1078,9 +1082,9 @@ func Test_newEnv(t *testing.T) {
 		&argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_PATH", Value: "my-path"},
 		&argoappv1.EnvEntry{Name: "ARGOCD_APP_SOURCE_TARGET_REVISION", Value: "my-target-revision"},
 	}, newEnv(&apiclient.ManifestRequest{
-		AppLabelValue: "my-app-name",
-		Namespace:     "my-namespace",
-		Repo:          &argoappv1.Repository{Repo: "https://github.com/my-org/my-repo"},
+		AppName:   "my-app-name",
+		Namespace: "my-namespace",
+		Repo:      &argoappv1.Repository{Repo: "https://github.com/my-org/my-repo"},
 		ApplicationSource: &argoappv1.ApplicationSource{
 			Path:           "my-path",
 			TargetRevision: "my-target-revision",
@@ -1102,52 +1106,205 @@ func TestService_newHelmClientResolveRevision(t *testing.T) {
 }
 
 func TestGetAppDetailsWithAppParameterFile(t *testing.T) {
-	service := newService(".")
-	details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
-		Repo: &argoappv1.Repository{},
-		Source: &argoappv1.ApplicationSource{
-			Path: "./testdata/app-parameters",
-		},
+	t.Run("No app name set and app specific file exists", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "multi", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+			})
+			require.NoError(t, err)
+			assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.2"}, details.Kustomize.Images)
+		})
+	})
+	t.Run("No app specific override", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "single-global", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "testapp",
+			})
+			require.NoError(t, err)
+			assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.2"}, details.Kustomize.Images)
+		})
+	})
+	t.Run("Only app specific override", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "testapp",
+			})
+			require.NoError(t, err)
+			assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.3"}, details.Kustomize.Images)
+		})
 	})
-	if !assert.NoError(t, err) {
-		return
+	t.Run("App specific override", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "multi", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "testapp",
+			})
+			require.NoError(t, err)
+			assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.3"}, details.Kustomize.Images)
+		})
+	})
+	t.Run("App specific overrides containing non-mergeable field", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "multi", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "unmergeable",
+			})
+			require.NoError(t, err)
+			assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.3"}, details.Kustomize.Images)
+		})
+	})
+	t.Run("Broken app-specific overrides", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "multi", func(t *testing.T, path string) {
+			details, err := service.GetAppDetails(context.Background(), &apiclient.RepoServerAppDetailsQuery{
+				Repo: &argoappv1.Repository{},
+				Source: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "broken",
+			})
+			assert.Error(t, err)
+			assert.Nil(t, details)
+		})
+	})
+}
+
+// There are unit test that will use kustomize set and by that modify the
+// kustomization.yaml. For proper testing, we need to copy the testdata to a
+// temporary path, run the tests, and then throw the copy away again.
+func mkTempParameters(source string) string {
+	tempDir, err := ioutil.TempDir("./testdata", "app-parameters")
+	if err != nil {
+		panic(err)
+	}
+	cmd := exec.Command("cp", "-R", source, tempDir)
+	err = cmd.Run()
+	if err != nil {
+		os.RemoveAll(tempDir)
+		panic(err)
 	}
-	assert.EqualValues(t, []string{"gcr.io/heptio-images/ks-guestbook-demo:0.2"}, details.Kustomize.Images)
+	return tempDir
+}
+
+// Simple wrapper run a test with a temporary copy of the testdata, because
+// the test would modify the data when run.
+func runWithTempTestdata(t *testing.T, path string, runner func(t *testing.T, path string)) {
+	tempDir := mkTempParameters("./testdata/app-parameters")
+	defer os.RemoveAll(tempDir)
+	runner(t, filepath.Join(tempDir, "app-parameters", path))
 }
 
 func TestGenerateManifestsWithAppParameterFile(t *testing.T) {
-	service := newService(".")
-	manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
-		Repo: &argoappv1.Repository{},
-		ApplicationSource: &argoappv1.ApplicationSource{
-			Path: "./testdata/app-parameters",
-		},
+	t.Run("Single global override", func(t *testing.T) {
+		runWithTempTestdata(t, "single-global", func(t *testing.T, path string) {
+			service := newService(".")
+			manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
+				Repo: &argoappv1.Repository{},
+				ApplicationSource: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+			})
+			require.NoError(t, err)
+			resourceByKindName := make(map[string]*unstructured.Unstructured)
+			for _, manifest := range manifests.Manifests {
+				var un unstructured.Unstructured
+				err := yaml.Unmarshal([]byte(manifest), &un)
+				if !assert.NoError(t, err) {
+					return
+				}
+				resourceByKindName[fmt.Sprintf("%s/%s", un.GetKind(), un.GetName())] = &un
+			}
+			deployment, ok := resourceByKindName["Deployment/guestbook-ui"]
+			require.True(t, ok)
+			containers, ok, _ := unstructured.NestedSlice(deployment.Object, "spec", "template", "spec", "containers")
+			require.True(t, ok)
+			image, ok, _ := unstructured.NestedString(containers[0].(map[string]interface{}), "image")
+			require.True(t, ok)
+			assert.Equal(t, "gcr.io/heptio-images/ks-guestbook-demo:0.2", image)
+		})
+	})
+
+	t.Run("Application specific override", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) {
+			manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
+				Repo: &argoappv1.Repository{},
+				ApplicationSource: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "testapp",
+			})
+			require.NoError(t, err)
+			resourceByKindName := make(map[string]*unstructured.Unstructured)
+			for _, manifest := range manifests.Manifests {
+				var un unstructured.Unstructured
+				err := yaml.Unmarshal([]byte(manifest), &un)
+				if !assert.NoError(t, err) {
+					return
+				}
+				resourceByKindName[fmt.Sprintf("%s/%s", un.GetKind(), un.GetName())] = &un
+			}
+			deployment, ok := resourceByKindName["Deployment/guestbook-ui"]
+			require.True(t, ok)
+			containers, ok, _ := unstructured.NestedSlice(deployment.Object, "spec", "template", "spec", "containers")
+			require.True(t, ok)
+			image, ok, _ := unstructured.NestedString(containers[0].(map[string]interface{}), "image")
+			require.True(t, ok)
+			assert.Equal(t, "gcr.io/heptio-images/ks-guestbook-demo:0.3", image)
+		})
+	})
+
+	t.Run("Application specific override for other app", func(t *testing.T) {
+		service := newService(".")
+		runWithTempTestdata(t, "single-app-only", func(t *testing.T, path string) {
+			manifests, err := service.GenerateManifest(context.Background(), &apiclient.ManifestRequest{
+				Repo: &argoappv1.Repository{},
+				ApplicationSource: &argoappv1.ApplicationSource{
+					Path: path,
+				},
+				AppName: "testapp2",
+			})
+			require.NoError(t, err)
+			resourceByKindName := make(map[string]*unstructured.Unstructured)
+			for _, manifest := range manifests.Manifests {
+				var un unstructured.Unstructured
+				err := yaml.Unmarshal([]byte(manifest), &un)
+				if !assert.NoError(t, err) {
+					return
+				}
+				resourceByKindName[fmt.Sprintf("%s/%s", un.GetKind(), un.GetName())] = &un
+			}
+			deployment, ok := resourceByKindName["Deployment/guestbook-ui"]
+			require.True(t, ok)
+			containers, ok, _ := unstructured.NestedSlice(deployment.Object, "spec", "template", "spec", "containers")
+			require.True(t, ok)
+			image, ok, _ := unstructured.NestedString(containers[0].(map[string]interface{}), "image")
+			require.True(t, ok)
+			assert.Equal(t, "gcr.io/heptio-images/ks-guestbook-demo:0.1", image)
+		})
 	})
-	if !assert.NoError(t, err) {
-		return
-	}
-	resourceByKindName := make(map[string]*unstructured.Unstructured)
-	for _, manifest := range manifests.Manifests {
-		var un unstructured.Unstructured
-		err := yaml.Unmarshal([]byte(manifest), &un)
-		if !assert.NoError(t, err) {
-			return
-		}
-		resourceByKindName[fmt.Sprintf("%s/%s", un.GetKind(), un.GetName())] = &un
-	}
-	deployment, ok := resourceByKindName["Deployment/guestbook-ui"]
-	if !assert.True(t, ok) {
-		return
-	}
-	containers, ok, _ := unstructured.NestedSlice(deployment.Object, "spec", "template", "spec", "containers")
-	if !assert.True(t, ok) {
-		return
-	}
-	image, ok, _ := unstructured.NestedString(containers[0].(map[string]interface{}), "image")
-	if !assert.True(t, ok) {
-		return
-	}
-	assert.Equal(t, "gcr.io/heptio-images/ks-guestbook-demo:0.2", image)
 }
 
 func TestGenerateManifestWithAnnotatedAndRegularGitTagHashes(t *testing.T) {
diff --git a/reposerver/repository/testdata/app-parameters/multi/.argocd-source-broken.yaml b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-broken.yaml
new file mode 100644
index 000000000..a2a93cfc1
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-broken.yaml
@@ -0,0 +1,4 @@
+aloi
+kustomize:
+  images:
+    - gcr.io/heptio-images/ks-guestbook-demo:0.2
diff --git a/reposerver/repository/testdata/app-parameters/multi/.argocd-source-testapp.yaml b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-testapp.yaml
new file mode 100644
index 000000000..4ae4c973e
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-testapp.yaml
@@ -0,0 +1,3 @@
+kustomize:
+  images:
+    - gcr.io/heptio-images/ks-guestbook-demo:0.3
diff --git a/reposerver/repository/testdata/app-parameters/multi/.argocd-source-unmergeable.yaml b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-unmergeable.yaml
new file mode 100644
index 000000000..baae7e746
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/multi/.argocd-source-unmergeable.yaml
@@ -0,0 +1,6 @@
+repo: https://somewhere
+kustomize:
+  images:
+    - gcr.io/heptio-images/ks-guestbook-demo:0.3
+  invalid:
+    - I don't know
diff --git a/reposerver/repository/testdata/app-parameters/.argocd-source.yaml b/reposerver/repository/testdata/app-parameters/multi/.argocd-source.yaml
similarity index 100%
rename from reposerver/repository/testdata/app-parameters/.argocd-source.yaml
rename to reposerver/repository/testdata/app-parameters/multi/.argocd-source.yaml
diff --git a/reposerver/repository/testdata/app-parameters/guestbook.yaml b/reposerver/repository/testdata/app-parameters/multi/guestbook.yaml
similarity index 100%
rename from reposerver/repository/testdata/app-parameters/guestbook.yaml
rename to reposerver/repository/testdata/app-parameters/multi/guestbook.yaml
diff --git a/reposerver/repository/testdata/app-parameters/kustomization.yaml b/reposerver/repository/testdata/app-parameters/multi/kustomization.yaml
similarity index 90%
rename from reposerver/repository/testdata/app-parameters/kustomization.yaml
rename to reposerver/repository/testdata/app-parameters/multi/kustomization.yaml
index 79b9d3242..4b35aa588 100644
--- a/reposerver/repository/testdata/app-parameters/kustomization.yaml
+++ b/reposerver/repository/testdata/app-parameters/multi/kustomization.yaml
@@ -5,4 +5,4 @@ resources:
 - guestbook.yaml
 images:
 - name: gcr.io/heptio-images/ks-guestbook-demo
-  newTag: "0.2"
+  newTag: "0.1"
diff --git a/reposerver/repository/testdata/app-parameters/single-app-only/.argocd-source-testapp.yaml b/reposerver/repository/testdata/app-parameters/single-app-only/.argocd-source-testapp.yaml
new file mode 100644
index 000000000..4ae4c973e
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-app-only/.argocd-source-testapp.yaml
@@ -0,0 +1,3 @@
+kustomize:
+  images:
+    - gcr.io/heptio-images/ks-guestbook-demo:0.3
diff --git a/reposerver/repository/testdata/app-parameters/single-app-only/guestbook.yaml b/reposerver/repository/testdata/app-parameters/single-app-only/guestbook.yaml
new file mode 100644
index 000000000..7afcc593a
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-app-only/guestbook.yaml
@@ -0,0 +1,18 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: guestbook-ui
+spec:
+  selector:
+    matchLabels:
+      app: guestbook-ui
+  template:
+    metadata:
+      labels:
+        app: guestbook-ui
+    spec:
+      containers:
+        - image: gcr.io/heptio-images/ks-guestbook-demo:0.1
+          name: guestbook-ui
+          ports:
+            - containerPort: 81
diff --git a/reposerver/repository/testdata/app-parameters/single-app-only/kustomization.yaml b/reposerver/repository/testdata/app-parameters/single-app-only/kustomization.yaml
new file mode 100644
index 000000000..4b35aa588
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-app-only/kustomization.yaml
@@ -0,0 +1,8 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+resources:
+- guestbook.yaml
+images:
+- name: gcr.io/heptio-images/ks-guestbook-demo
+  newTag: "0.1"
diff --git a/reposerver/repository/testdata/app-parameters/single-global/.argocd-source.yaml b/reposerver/repository/testdata/app-parameters/single-global/.argocd-source.yaml
new file mode 100644
index 000000000..592624a90
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-global/.argocd-source.yaml
@@ -0,0 +1,3 @@
+kustomize:
+  images:
+    - gcr.io/heptio-images/ks-guestbook-demo:0.2
\ No newline at end of file
diff --git a/reposerver/repository/testdata/app-parameters/single-global/guestbook.yaml b/reposerver/repository/testdata/app-parameters/single-global/guestbook.yaml
new file mode 100644
index 000000000..7afcc593a
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-global/guestbook.yaml
@@ -0,0 +1,18 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: guestbook-ui
+spec:
+  selector:
+    matchLabels:
+      app: guestbook-ui
+  template:
+    metadata:
+      labels:
+        app: guestbook-ui
+    spec:
+      containers:
+        - image: gcr.io/heptio-images/ks-guestbook-demo:0.1
+          name: guestbook-ui
+          ports:
+            - containerPort: 81
diff --git a/reposerver/repository/testdata/app-parameters/single-global/kustomization.yaml b/reposerver/repository/testdata/app-parameters/single-global/kustomization.yaml
new file mode 100644
index 000000000..4b35aa588
--- /dev/null
+++ b/reposerver/repository/testdata/app-parameters/single-global/kustomization.yaml
@@ -0,0 +1,8 @@
+apiVersion: kustomize.config.k8s.io/v1beta1
+kind: Kustomization
+
+resources:
+- guestbook.yaml
+images:
+- name: gcr.io/heptio-images/ks-guestbook-demo
+  newTag: "0.1"