Repository: argoproj-labs/applicationset
Pull request #41 (2020-09-04 14:53:17)

Use cluster name for generator param.
The secret name is quite long and an implementation detail. The actual
name as far as argocd is linked to the kubeconfig context name and quite
likely shorter.

mgoodness: LGTM

Patch:
diff --git a/Makefile b/Makefile
index 657b2a3..756cc34 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,5 @@
 VERSION?=$(shell cat VERSION)
-IMAGE_TAG?=v$(VERSION)
-IMAGE_PREFIX?=argoprojlabs
+IMAGE?=argoprojlabs/argocd-applicationset:v$(VERSION)
 DOCKER_PUSH?=true
 
 .PHONY: build
@@ -9,8 +8,13 @@ build:
 
 .PHONY: image
 image:
-	docker build -t $(IMAGE_PREFIX)/argocd-applicationset:$(IMAGE_TAG) .
-	@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE_PREFIX)/argocd-applicationset:$(IMAGE_TAG) ; fi
+	docker build -t $(IMAGE) .
+	@if [ "$(DOCKER_PUSH)" = "true" ] ; then docker push $(IMAGE) ; fi
+
+.PHONY: deploy
+deploy:
+	kustomize build manifests/cluster-install | kubectl apply -f -
+	kubectl patch deployment -n argocd argocd-applicationset-controller --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value": "$(IMAGE)"}]'
 
 # Generate manifests e.g. CRD, RBAC etc.
 .PHONY: manifests
diff --git a/README.md b/README.md
index 5c006f5..79a4a62 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,22 @@ compatibility are made, at least until merging into Argo CD proper.
 ## Proposal:
 * https://docs.google.com/document/d/1juWGr20FQaJmuuTIS8mBFmWWDU422M_FQMuhp5c1jt4/edit?usp=sharing
 
+## Development Instructions
+
+The following assumes you have: 
+
+ 1. Installed a recent version of [kustomize](https://github.com/kubernetes-sigs/kustomize) (3.x+). 
+ 1. Created a container repository for your development image.
+ 1. Deployed ArgoCD into the "argocd" namespace.
+ 
+To build and push a container with your current code, and deploy Kubernetes manifests for the controller Deployment:
+
+```bash
+IMAGE="username/argocd-applicationset:v0.0.1" make image deploy
+```
+
+The ApplicationSet controller should now be running in the "argocd" namespace.
+
 ## Example Spec:
 
 ```yaml
@@ -40,3 +56,4 @@ spec:
 ```
 
 Additional examples are available in the [examples](./examples) directory.
+
diff --git a/api/v1alpha1/applicationset_types.go b/api/v1alpha1/applicationset_types.go
index dc9fdca..34a8403 100644
--- a/api/v1alpha1/applicationset_types.go
+++ b/api/v1alpha1/applicationset_types.go
@@ -72,6 +72,7 @@ type ClusterGenerator struct {
 type GitGenerator struct {
 	RepoURL     string                      `json:"repoURL"`
 	Directories []GitDirectoryGeneratorItem `json:"directories,omitempty"`
+	Revision    string                      `json:"revision"`
 }
 
 type GitDirectoryGeneratorItem struct {
diff --git a/go.mod b/go.mod
index 38d7d0b..96873a1 100644
--- a/go.mod
+++ b/go.mod
@@ -5,28 +5,20 @@ go 1.13
 require (
 	github.com/Masterminds/semver v1.5.0 // indirect
 	github.com/argoproj/argo-cd v1.5.6
+	github.com/argoproj/gitops-engine v0.1.3
 	github.com/argoproj/pkg v0.0.0-20200424003221-9b858eff18a1 // indirect
-	github.com/ghodss/yaml v1.0.0 // indirect
 	github.com/gogo/protobuf v1.3.1 // indirect
-	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
-	github.com/grpc-ecosystem/grpc-gateway v1.3.1 // indirect
-	github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
 	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
 	github.com/pkg/errors v0.9.1
-	github.com/sergi/go-diff v1.1.0 // indirect
 	github.com/sirupsen/logrus v1.4.2
 	github.com/stretchr/testify v1.4.0
 	github.com/valyala/fasttemplate v1.1.1
-	github.com/yudai/gojsondiff v1.0.1-0.20180504020246-0525c875b75c // indirect
-	github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
-	github.com/yudai/pp v2.0.1+incompatible // indirect
+	google.golang.org/grpc v1.23.0
 	gopkg.in/src-d/go-git.v4 v4.13.1 // indirect
-	gopkg.in/yaml.v2 v2.2.8 // indirect
 	k8s.io/api v0.17.2
 	k8s.io/apimachinery v0.17.2
 	k8s.io/client-go v11.0.1-0.20190816222228-6d55c1b1f1ca+incompatible
 	k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a // indirect
-	k8s.io/kubectl v0.16.6 // indirect
 	k8s.io/kubernetes v1.16.6
 	k8s.io/utils v0.0.0-20191114200735-6ca3b61696b6 // indirect
 	sigs.k8s.io/controller-runtime v0.5.0
diff --git a/go.sum b/go.sum
index 4a6c216..644ffca 100644
--- a/go.sum
+++ b/go.sum
@@ -45,6 +45,9 @@ github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo
 github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
 github.com/argoproj/argo-cd v1.5.6 h1:yrzJuSTf/YBFLugB6DwiS8spDbRKFVyGg8Few5SPLfA=
 github.com/argoproj/argo-cd v1.5.6/go.mod h1:UPOPiF6Y1y/oTL3X1KcuLbu7ljD7f4+SIaXvlowBmhE=
+github.com/argoproj/gitops-engine v0.1.3 h1:eQp1bfqaeaATcu4XErlxNb6aVsN4rC7suL/Fqx/9E+k=
+github.com/argoproj/gitops-engine v0.1.3/go.mod h1:UmBGlQLT/MPNiMmbnouZRWhkk3slPuozMsENdXMkIMs=
+github.com/argoproj/pkg v0.0.0-20200102163130-2dd1f3f6b4de/go.mod h1:2EZ44RG/CcgtPTwrRR0apOc7oU6UIw8GjCUJWZ8X3bM=
 github.com/argoproj/pkg v0.0.0-20200424003221-9b858eff18a1 h1:BCuMRvKYHPuPN2Gep3uY+XOScGNCBFbF/pXYlhmyJjg=
 github.com/argoproj/pkg v0.0.0-20200424003221-9b858eff18a1/go.mod h1:2EZ44RG/CcgtPTwrRR0apOc7oU6UIw8GjCUJWZ8X3bM=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -211,6 +214,7 @@ github.com/go-toolsmith/pkgload v0.0.0-20181119091011-e9e65178eee8/go.mod h1:WoM
 github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Ilcwuh3clNrQJc=
 github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
 github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
+github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
 github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
@@ -284,6 +288,7 @@ github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.m
 github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79 h1:lR9ssWAqp9qL0bALxqEEkuudiP1eweOdv9jsRK3e7lE=
 github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.3.0 h1:HJtP6RRwj2EpPCD/mhAWzSvLL/dFTdPm1UrWwanoFos=
@@ -510,6 +515,7 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW
 github.com/storageos/go-api v0.0.0-20180912212459-343b3eff91fc/go.mod h1:ZrLn+e0ZuF3Y65PNF6dIwbJPZqfmtCXxFm9ckv0agOY=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
 github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
 github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
diff --git a/main.go b/main.go
index 919ce1c..f2acbaf 100644
--- a/main.go
+++ b/main.go
@@ -1,7 +1,9 @@
 package main
 
 import (
+	"context"
 	"flag"
+	"github.com/argoproj-labs/applicationset/pkg/services"
 	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	"os"
 
@@ -13,6 +15,7 @@ import (
 
 	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
 	"github.com/argoproj-labs/applicationset/pkg/controllers"
+	"k8s.io/client-go/kubernetes"
 	// +kubebuilder:scaffold:imports
 )
 
@@ -34,11 +37,15 @@ func main() {
 	var metricsAddr string
 	var probeBindAddr string
 	var enableLeaderElection bool
+	var namespace string
+	var argocdRepoServer string
 	flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.")
 	flag.StringVar(&metricsAddr, "probe-addr", ":8081", "The address the probe endpoint binds to.")
 	flag.BoolVar(&enableLeaderElection, "enable-leader-election", false,
 		"Enable leader election for controller manager. "+
 			"Enabling this will ensure there is only one active controller manager.")
+	flag.StringVar(&namespace, "namespace", "argocd", "Argo CD repo namesapce")
+	flag.StringVar(&argocdRepoServer, "argocd-repo-server", "argocd-repo-server:8081", "Argo CD repo server address")
 	flag.Parse()
 
 	ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
@@ -56,10 +63,13 @@ func main() {
 		os.Exit(1)
 	}
 
+	k8s := kubernetes.NewForConfigOrDie(mgr.GetConfig())
+
 	if err = (&controllers.ApplicationSetReconciler{
-		Client:   mgr.GetClient(),
-		Scheme:   mgr.GetScheme(),
-		Recorder: mgr.GetEventRecorderFor("applicationset-controller"),
+		Client:      mgr.GetClient(),
+		Scheme:      mgr.GetScheme(),
+		Recorder:    mgr.GetEventRecorderFor("applicationset-controller"),
+		AppsService: services.NewArgoCDService(context.Background(), k8s, namespace, argocdRepoServer),
 	}).SetupWithManager(mgr); err != nil {
 		setupLog.Error(err, "unable to create controller", "controller", "ApplicationSet")
 		os.Exit(1)
diff --git a/manifests/base/kustomization.yaml b/manifests/base/kustomization.yaml
index 869f7ae..95fa5a6 100644
--- a/manifests/base/kustomization.yaml
+++ b/manifests/base/kustomization.yaml
@@ -1,6 +1,8 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
+namespace: argocd
+
 resources:
   - deployment.yaml
   - rbac.yaml
diff --git a/manifests/base/rbac.yaml b/manifests/base/rbac.yaml
index 31291b7..9cf2616 100644
--- a/manifests/base/rbac.yaml
+++ b/manifests/base/rbac.yaml
@@ -43,7 +43,6 @@ rules:
       - ''
     resources:
       - events
-      - pods
     verbs:
       - create
       - delete
@@ -56,6 +55,7 @@ rules:
       - ''
     resources:
       - secrets
+      - configmaps
     verbs:
       - get
       - list
diff --git a/manifests/cluster-install/kustomization.yaml b/manifests/cluster-install/kustomization.yaml
index 55f0aea..552d8de 100644
--- a/manifests/cluster-install/kustomization.yaml
+++ b/manifests/cluster-install/kustomization.yaml
@@ -1,6 +1,8 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
+namespace: argocd
+
 resources:
   - ../namespace-install
   - ../cluster-rbac
diff --git a/manifests/cluster-rbac/kustomization.yaml b/manifests/cluster-rbac/kustomization.yaml
index 4c4dbe4..7221e60 100644
--- a/manifests/cluster-rbac/kustomization.yaml
+++ b/manifests/cluster-rbac/kustomization.yaml
@@ -1,5 +1,7 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
+namespace: argocd
+
 resources:
   - rbac.yaml
diff --git a/manifests/cluster-rbac/rbac.yaml b/manifests/cluster-rbac/rbac.yaml
index de86378..c9fcbcd 100644
--- a/manifests/cluster-rbac/rbac.yaml
+++ b/manifests/cluster-rbac/rbac.yaml
@@ -33,7 +33,6 @@ rules:
       - ''
     resources:
       - events
-      - pods
     verbs:
       - create
       - delete
@@ -46,6 +45,7 @@ rules:
       - ''
     resources:
       - secrets
+      - configmaps
     verbs:
       - get
       - list
diff --git a/manifests/crds/applicationset-crd.yaml b/manifests/crds/applicationset-crd.yaml
index eed0966..e087c1d 100644
--- a/manifests/crds/applicationset-crd.yaml
+++ b/manifests/crds/applicationset-crd.yaml
@@ -2,6 +2,9 @@
 apiVersion: apiextensions.k8s.io/v1beta1
 kind: CustomResourceDefinition
 metadata:
+  annotations:
+    controller-gen.kubebuilder.io/version: v0.3.0
+  creationTimestamp: null
   labels:
     app.kubernetes.io/name: applicationsets.argoproj.io
     app.kubernetes.io/part-of: argocd-applicationset
@@ -113,8 +116,11 @@ spec:
                         type: array
                       repoURL:
                         type: string
+                      revision:
+                        type: string
                     required:
-                      - repoURL
+                    - repoURL
+                    - revision
                     type: object
                   list:
                     description: ListGenerator include items info
diff --git a/manifests/namespace-install/kustomization.yaml b/manifests/namespace-install/kustomization.yaml
index 82a46a0..937f87c 100644
--- a/manifests/namespace-install/kustomization.yaml
+++ b/manifests/namespace-install/kustomization.yaml
@@ -1,6 +1,8 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
+namespace: argocd
+
 resources:
   - ../base
   - ../crds
diff --git a/pkg/controllers/applicationset_controller.go b/pkg/controllers/applicationset_controller.go
index 1fccb1e..344d04e 100644
--- a/pkg/controllers/applicationset_controller.go
+++ b/pkg/controllers/applicationset_controller.go
@@ -20,6 +20,8 @@ import (
 	"context"
 	"fmt"
 	"github.com/argoproj-labs/applicationset/pkg/generators"
+	"github.com/argoproj-labs/applicationset/pkg/services"
+	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/tools/record"
@@ -34,14 +36,15 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
-	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 )
 
 // ApplicationSetReconciler reconciles a ApplicationSet object
 type ApplicationSetReconciler struct {
 	client.Client
-	Scheme   *runtime.Scheme
-	Recorder record.EventRecorder
+	Scheme         	*runtime.Scheme
+	Recorder       	record.EventRecorder
+	RepoServerAddr 	string
+	AppsService		services.Apps
 }
 
 // +kubebuilder:rbac:groups=argoproj.io,resources=applicationsets,verbs=get;list;watch;create;update;patch;delete
@@ -60,9 +63,11 @@ func (r *ApplicationSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
 
 	listGenerator := generators.NewListGenerator()
 	clusterGenerator := generators.NewClusterGenerator(r.Client)
+	GitGenerator := generators.NewGitGenerator(r.AppsService)
 
 	// desiredApplications is the main list of all expected Applications from all generators in this appset.
 	var desiredApplications []argov1alpha1.Application
+
 	for _, tmpGenerator := range applicationSetInfo.Spec.Generators {
 		var apps []argov1alpha1.Application
 		var err error
@@ -70,11 +75,15 @@ func (r *ApplicationSetReconciler) Reconcile(req ctrl.Request) (ctrl.Result, err
 			apps, err = listGenerator.GenerateApplications(&tmpGenerator, &applicationSetInfo)
 		} else if tmpGenerator.Clusters != nil {
 			apps, err = clusterGenerator.GenerateApplications(&tmpGenerator, &applicationSetInfo)
+		} else if tmpGenerator.Git != nil {
+			apps, err = GitGenerator.GenerateApplications(&tmpGenerator, &applicationSetInfo)
 		}
 		log.Infof("apps from generator: %+v", apps)
 		if err != nil {
 			log.WithError(err).Error("error generating applications")
+			continue
 		}
+		
 		desiredApplications = append(desiredApplications, apps...)
 
 	}
diff --git a/pkg/generators/cluster.go b/pkg/generators/cluster.go
index d525efa..bbc3422 100644
--- a/pkg/generators/cluster.go
+++ b/pkg/generators/cluster.go
@@ -60,6 +60,7 @@ func (g *ClusterGenerator) GenerateApplications(
 	log.Debug("clusters matching labels", "count", len(clusterSecretList.Items))
 
 	var tmplApplication argov1alpha1.Application
+	tmplApplication.Labels = appSet.Spec.Template.Labels
 	tmplApplication.Namespace = appSet.Spec.Template.Namespace
 	tmplApplication.Name = appSet.Spec.Template.Name
 	tmplApplication.Spec = appSet.Spec.Template.Spec
@@ -68,7 +69,7 @@ func (g *ClusterGenerator) GenerateApplications(
 
 	for _, cluster := range clusterSecretList.Items {
 		params := make(map[string]string)
-		params["name"] = cluster.Name
+		params["name"] = string(cluster.Data["name"])
 		params["server"] = string(cluster.Data["server"])
 		for key, value := range cluster.ObjectMeta.Labels {
 			params[fmt.Sprintf("metadata.labels.%s", key)] = value
diff --git a/pkg/generators/git.go b/pkg/generators/git.go
index 590abff..0c07c9e 100644
--- a/pkg/generators/git.go
+++ b/pkg/generators/git.go
@@ -1,27 +1,102 @@
 package generators
 
 import (
+	"context"
 	"fmt"
 	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
+	"github.com/argoproj-labs/applicationset/pkg/services"
+	"github.com/argoproj-labs/applicationset/pkg/utils"
 	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	log "github.com/sirupsen/logrus"
+	"path"
 )
 
 var _ Generator = (*GitGenerator)(nil)
 
 type GitGenerator struct {
+	repos services.Apps
 }
 
-func NewGitGenerator() Generator {
-	g := &GitGenerator{}
+func NewGitGenerator(repos services.Apps) Generator {
+	g := &GitGenerator{
+		repos: repos,
+	}
 	return g
 }
 
-func (g *GitGenerator) GenerateApplications(
-	appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator,
-	appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
-	if appSet == nil {
+func (g *GitGenerator) GenerateApplications(appSetGenerator *argoprojiov1alpha1.ApplicationSetGenerator, appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application, error) {
+	if appSetGenerator == nil || appSet == nil {
 		return nil, fmt.Errorf("ApplicationSet is empty")
 	}
 
-	return nil, nil
+	if appSetGenerator.Git == nil {
+		return nil, fmt.Errorf("git variable empty")
+	}
+
+	allApps, err := g.repos.GetApps(context.TODO(), appSetGenerator.Git.RepoURL, appSetGenerator.Git.Revision)
+	if err != nil {
+		return nil, err
+	}
+
+	log.WithFields(log.Fields{
+		"allAps": allApps,
+		"total": len(allApps),
+		"repoURL": appSetGenerator.Git.RepoURL,
+		"revision": appSetGenerator.Git.Revision,
+	}).Info("applications result from the repo service")
+
+	requestedApps := g.filter(appSetGenerator.Git.Directories, allApps)
+
+	res := g.generateApplications(requestedApps, appSet)
+
+	return res, nil
+}
+
+func (g *GitGenerator) filter(Directories []argoprojiov1alpha1.GitDirectoryGeneratorItem, allApps []string) []string {
+	res := []string{}
+	for _, requestedPath := range Directories {
+		for _, appPath := range allApps {
+			match, err := path.Match(requestedPath.Path, appPath)
+			if err != nil {
+				log.WithError(err).WithField("requestedPath", requestedPath).
+					WithField("appPath", appPath).Error("error while matching appPath to requestedPath")
+				continue
+			}
+			if match {
+				res = append(res, appPath)
+			}
+		}
+	}
+	return res
+}
+
+func (g *GitGenerator) generateApplications(requestedApps []string, appSet *argoprojiov1alpha1.ApplicationSet) ([]argov1alpha1.Application) {
+
+	res := make([]argov1alpha1.Application, len(requestedApps))
+	for i, a := range requestedApps {
+		app, err := g.generateApplication(appSet, a)
+		if err != nil {
+			log.WithError(err).WithField("app", a).Error("error while generating app")
+			continue
+		}
+		res[i] = *app
+	}
+
+	return res
+}
+
+
+func (g *GitGenerator) generateApplication(appSet *argoprojiov1alpha1.ApplicationSet, appPath string) (*argov1alpha1.Application, error) {
+	var tmplApplication argov1alpha1.Application
+	tmplApplication.Namespace = appSet.Spec.Template.Namespace
+	tmplApplication.Name = appSet.Spec.Template.Name
+	tmplApplication.Spec = appSet.Spec.Template.Spec
+
+	params := make(map[string]string, 2)
+	params["path"] = appPath
+	params["path.basename"] = path.Base(appPath)
+
+	tmpApplication, err := utils.RenderTemplateParams(&tmplApplication, params)
+
+	return tmpApplication, err
 }
diff --git a/pkg/services/repo_service.go b/pkg/services/repo_service.go
new file mode 100644
index 0000000..cad70dc
--- /dev/null
+++ b/pkg/services/repo_service.go
@@ -0,0 +1,71 @@
+package services
+
+import (
+	"context"
+	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/reposerver/apiclient"
+	"github.com/argoproj/argo-cd/util/db"
+	"github.com/argoproj/argo-cd/util/settings"
+	"github.com/argoproj/gitops-engine/pkg/utils/io"
+	"github.com/pkg/errors"
+	log "github.com/sirupsen/logrus"
+	"k8s.io/client-go/kubernetes"
+)
+
+// RepositoryDB Is a lean facade for ArgoDB,
+// Using a lean interface makes it more easy to test the functionality the git generator uses
+type RepositoryDB interface {
+	GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error)
+}
+
+type argoCDService struct {
+	repositoriesDB 		RepositoryDB
+	repoClientset 		apiclient.Clientset
+}
+
+type Apps interface {
+	GetApps(ctx context.Context, repoURL string, revision string) ([]string, error)
+}
+
+func NewArgoCDService(ctx context.Context, clientset kubernetes.Interface, namespace string, repoServerAddress string) Apps {
+	settingsMgr := settings.NewSettingsManager(ctx, clientset, namespace)
+
+	return &argoCDService{
+		repositoriesDB: db.NewDB(namespace, settingsMgr, clientset).(RepositoryDB),
+		repoClientset: apiclient.NewRepoServerClientset(repoServerAddress, 5),
+	}
+}
+
+func (a *argoCDService) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
+	repo, err := a.repositoriesDB.GetRepository(ctx, repoURL)
+	if err != nil {
+
+		return nil, errors.Wrap(err, "Error in GetRepository")
+	}
+	log.Infof("repo - %#v", repo)
+
+	conn, repoClient, err := a.repoClientset.NewRepoServerClient()
+	defer io.Close(conn)
+	if err != nil {
+		return nil, errors.Wrap(err, "Error in creating repo service client")
+	}
+
+	apps, err := repoClient.ListApps(ctx, &apiclient.ListAppsRequest{
+		Repo: repo,
+		Revision: revision,
+	})
+	log.Infof("apps - %#v", apps)
+	if err != nil {
+		return nil, errors.Wrap(err, "Error in ListApps")
+	}
+
+	res := []string{}
+
+	for name, _ := range apps.Apps {
+		res = append(res, name)
+	}
+
+	log.Infof("res - %#v", apps)
+
+	return res, nil
+}


Test patch:
diff --git a/pkg/generators/cluster_test.go b/pkg/generators/cluster_test.go
index c8b5f19..b30d6f9 100644
--- a/pkg/generators/cluster_test.go
+++ b/pkg/generators/cluster_test.go
@@ -16,8 +16,9 @@ import (
 	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
 	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
 
-	"github.com/stretchr/testify/assert"
 	"testing"
+
+	"github.com/stretchr/testify/assert"
 )
 
 type possiblyErroringFakeCtrlRuntimeClient struct {
@@ -27,7 +28,7 @@ type possiblyErroringFakeCtrlRuntimeClient struct {
 
 func (p *possiblyErroringFakeCtrlRuntimeClient) List(ctx context.Context, secretList runtime.Object, opts ...client.ListOption) error {
 	if p.shouldError {
-		return errors.New("Could not list Secrets.")
+		return errors.New("could not list Secrets")
 	}
 	return p.Client.List(ctx, secretList, opts...)
 }
@@ -40,6 +41,9 @@ func getRenderTemplate(appName, clusterName, server, environmentLabel string) *a
 			Finalizers: []string{
 				"resources-finalizer.argocd.argoproj.io",
 			},
+			Labels: map[string]string{
+				"environment": environmentLabel,
+			},
 		},
 		Spec: argov1alpha1.ApplicationSpec{
 			Source: argov1alpha1.ApplicationSource{
@@ -95,7 +99,7 @@ func TestGenerateApplications(t *testing.T) {
 			},
 			Data: map[string][]byte{
 				"config": []byte(base64.StdEncoding.EncodeToString([]byte("foo"))),
-				"name":   []byte(base64.StdEncoding.EncodeToString([]byte("productuion-01"))),
+				"name":   []byte(base64.StdEncoding.EncodeToString([]byte("production-01"))),
 				"server": []byte("https://production-01.example.com"),
 			},
 			Type: corev1.SecretType("Opaque"),
@@ -104,6 +108,9 @@ func TestGenerateApplications(t *testing.T) {
 
 	applicationSetTemplate := argoprojiov1alpha1.ApplicationSetTemplate{
 		ObjectMeta: metav1.ObjectMeta{
+			Labels: map[string]string{
+				"environment": "{{metadata.labels.environment}}",
+			},
 			Name:      "{{name}}-app",
 			Namespace: "namespace",
 		},
@@ -200,7 +207,7 @@ func TestGenerateApplications(t *testing.T) {
 			metav1.LabelSelector{},
 			nil,
 			true,
-			errors.New("Could not list Secrets."),
+			errors.New("could not list Secrets"),
 		},
 	}
 
diff --git a/pkg/generators/git_test.go b/pkg/generators/git_test.go
new file mode 100644
index 0000000..6a43fb3
--- /dev/null
+++ b/pkg/generators/git_test.go
@@ -0,0 +1,177 @@
+package generators
+
+import (
+	"context"
+	"fmt"
+	argoprojiov1alpha1 "github.com/argoproj-labs/applicationset/api/v1alpha1"
+	argov1alpha1 "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/reposerver/apiclient"
+	"github.com/argoproj/argo-cd/util"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"testing"
+)
+
+type clientSet struct {
+	RepoServerServiceClient apiclient.RepoServerServiceClient
+}
+
+func (c *clientSet) NewRepoServerClient() (util.Closer, apiclient.RepoServerServiceClient, error) {
+	return util.NewCloser(func() error { return nil }), c.RepoServerServiceClient, nil
+}
+
+type argoCDServiceMock struct {
+	mock.Mock
+}
+
+func (a argoCDServiceMock) GetApps(ctx context.Context, repoURL string, revision string) ([]string, error) {
+	args := a.Called(ctx, repoURL, revision)
+
+	return args.Get(0).([]string), args.Error(1)
+}
+
+func getGitRenderTemplate(name, path string) *argov1alpha1.Application {
+	return &argov1alpha1.Application{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      name,
+			Namespace: "namespace",
+			Finalizers: []string{
+				"resources-finalizer.argocd.argoproj.io",
+			},
+		},
+		Spec: argov1alpha1.ApplicationSpec{
+			Source: argov1alpha1.ApplicationSource{
+				RepoURL:        "RepoURL",
+				Path:           path,
+				TargetRevision: "HEAD",
+			},
+			Destination: argov1alpha1.ApplicationDestination{
+				Server:    "server",
+				Namespace: "destinationNamespace",
+			},
+			Project: "project",
+		},
+	}
+}
+
+func TestGitGenerateApplications(t *testing.T) {
+
+	appSetTemplate := argoprojiov1alpha1.ApplicationSetTemplate{
+		ObjectMeta: metav1.ObjectMeta{
+			Name:      "{{path.basename}}",
+			Namespace: "namespace",
+		},
+		Spec: argov1alpha1.ApplicationSpec{
+			Source: argov1alpha1.ApplicationSource{
+				RepoURL:        "RepoURL",
+				Path:           "{{path}}",
+				TargetRevision: "HEAD",
+			},
+			Destination: argov1alpha1.ApplicationDestination{
+				Server:    "server",
+				Namespace: "destinationNamespace",
+			},
+			Project: "project",
+		},
+	}
+
+	cases := []struct {
+		name		  string
+		template      argoprojiov1alpha1.ApplicationSetTemplate
+		directories   []argoprojiov1alpha1.GitDirectoryGeneratorItem
+		repoApps      []string
+		repoError     error
+		expected      []argov1alpha1.Application
+		expectedError error
+	}{
+		{
+			name: "happy flow - created apps",
+			template: appSetTemplate,
+			directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{"*"}},
+			repoApps: []string{
+					"app1",
+					"app2",
+					"p1/app3",
+			},
+			repoError: nil,
+			expected: []argov1alpha1.Application{
+				*getGitRenderTemplate("app1", "app1"),
+				*getGitRenderTemplate("app2", "app2"),
+			},
+			expectedError: nil,
+		},
+		{
+			name: "It filters application according to the paths",
+			template: appSetTemplate,
+			directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{"p1/*"}, {"p1/*/*"}},
+			repoApps: []string{
+				"app1",
+				"p1/app2",
+				"p1/p2/app3",
+				"p1/p2/p3/app4",
+			},
+			repoError: nil,
+			expected: []argov1alpha1.Application{
+				*getGitRenderTemplate("app2", "p1/app2"),
+				*getGitRenderTemplate("app3", "p1/p2/app3"),
+			},
+			expectedError: nil,
+		},
+		{
+			name: "handles empty response from repo server",
+			template: appSetTemplate,
+			directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{"*"}},
+			repoApps: []string{},
+			repoError: nil,
+			expected: []argov1alpha1.Application{},
+			expectedError:nil,
+		},
+		{
+			name: "handles error from repo server",
+			template: appSetTemplate,
+			directories: []argoprojiov1alpha1.GitDirectoryGeneratorItem{{"*"}},
+			repoApps: []string{},
+			repoError: fmt.Errorf("error"),
+			expected: []argov1alpha1.Application{},
+			expectedError: fmt.Errorf("error"),
+		},
+	}
+
+	for _, c := range cases {
+		cc := c
+		t.Run(cc.name, func(t *testing.T) {
+			argoCDServiceMock := argoCDServiceMock{}
+			argoCDServiceMock.On("GetApps", mock.Anything, mock.Anything, mock.Anything).Return(c.repoApps, c.repoError)
+
+			var gitGenerator = NewGitGenerator(argoCDServiceMock)
+			applicationSetInfo := argoprojiov1alpha1.ApplicationSet{
+				ObjectMeta: metav1.ObjectMeta{
+					Name: "set",
+				},
+				Spec: argoprojiov1alpha1.ApplicationSetSpec{
+					Generators: []argoprojiov1alpha1.ApplicationSetGenerator{{
+						Git: &argoprojiov1alpha1.GitGenerator{
+							RepoURL:     "RepoURL",
+							Revision:    "Revision",
+							Directories: c.directories,
+						},
+					}},
+					Template: c.template,
+				},
+			}
+
+			got, err := gitGenerator.GenerateApplications(&applicationSetInfo.Spec.Generators[0], &applicationSetInfo)
+
+			if c.expectedError != nil {
+				assert.EqualError(t, err, c.expectedError.Error())
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, c.expected, got)
+			}
+
+			argoCDServiceMock.AssertExpectations(t)
+		})
+	}
+
+}
diff --git a/pkg/services/repo_service_test.go b/pkg/services/repo_service_test.go
new file mode 100644
index 0000000..0efd053
--- /dev/null
+++ b/pkg/services/repo_service_test.go
@@ -0,0 +1,161 @@
+package services
+
+import (
+	"context"
+	"errors"
+	"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
+	"github.com/argoproj/argo-cd/reposerver/apiclient"
+	"github.com/argoproj/argo-cd/util"
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+	"google.golang.org/grpc"
+	"testing"
+)
+
+type ArgocdRepositoryMock struct {
+	mock.Mock
+}
+
+func (a ArgocdRepositoryMock) GetRepository(ctx context.Context, url string) (*v1alpha1.Repository, error) {
+	args := a.Called(ctx, url)
+
+	return args.Get(0).(*v1alpha1.Repository), args.Error(1)
+
+}
+
+type repoServerClientMock struct {
+	mock.Mock
+}
+
+func (r repoServerClientMock) GenerateManifest(ctx context.Context, in *apiclient.ManifestRequest, opts ...grpc.CallOption) (*apiclient.ManifestResponse, error) {
+	return nil, nil
+}
+func (r repoServerClientMock) ListApps(ctx context.Context, in *apiclient.ListAppsRequest, opts ...grpc.CallOption) (*apiclient.AppList, error) {
+	args := r.Called(ctx, in)
+
+	return args.Get(0).(*apiclient.AppList), args.Error(1)
+}
+func (r repoServerClientMock) GetAppDetails(ctx context.Context, in *apiclient.RepoServerAppDetailsQuery, opts ...grpc.CallOption) (*apiclient.RepoAppDetailsResponse, error) {
+	return nil, nil
+}
+func (r repoServerClientMock) GetRevisionMetadata(ctx context.Context, in *apiclient.RepoServerRevisionMetadataRequest, opts ...grpc.CallOption) (*v1alpha1.RevisionMetadata, error) {
+	return nil, nil
+}
+func (r repoServerClientMock) GetHelmCharts(ctx context.Context, in *apiclient.HelmChartsRequest, opts ...grpc.CallOption) (*apiclient.HelmChartsResponse, error) {
+	return nil, nil
+}
+
+type closer struct {
+	mock.Mock
+}
+
+func (c closer) Close() error{
+	return nil
+}
+
+type repoClientsetMock struct {
+	mock.Mock
+}
+
+func (r repoClientsetMock) NewRepoServerClient() (util.Closer, apiclient.RepoServerServiceClient, error) {
+	args := r.Called()
+
+	return closer{}, args.Get(0).(apiclient.RepoServerServiceClient), args.Error(1)
+}
+
+
+func TestGetApps(t *testing.T) {
+
+	for _, c := range []struct {
+		name			string
+		repoURL     	string
+		revision		string
+		repoRes			*v1alpha1.Repository
+		repoErr			error
+		appRes			*apiclient.AppList
+		appError		error
+		expected   		[]string
+		expectedError	error
+	}{
+		{
+			"Happy Flow",
+			"repoURL",
+			"revision",
+			&v1alpha1.Repository{
+			},
+			nil,
+			&apiclient.AppList {
+				Apps: map[string]string{
+					"app1": "",
+					"app2": "",
+				},
+			},
+			nil,
+			[]string{"app1", "app2"},
+			nil,
+		},
+		{
+			"handles GetRepository error",
+			"repoURL",
+			"revision",
+			&v1alpha1.Repository{
+			},
+			errors.New("error"),
+			&apiclient.AppList {
+				Apps: map[string]string{
+					"app1": "",
+					"app2": "",
+				},
+			},
+			nil,
+			[]string{},
+			errors.New("Error in GetRepository: error"),
+		},
+		{
+			"handles ListApps error",
+			"repoURL",
+			"revision",
+			&v1alpha1.Repository{
+			},
+			nil,
+			&apiclient.AppList {
+				Apps: map[string]string{
+					"app1": "",
+					"app2": "",
+				},
+			},
+			errors.New("error"),
+			[]string{},
+			errors.New("Error in ListApps: error"),
+		},
+	}{
+		cc := c
+		t.Run(cc.name, func(t *testing.T) {
+			argocdRepositoryMock := ArgocdRepositoryMock{}
+			repoServerClientMock := repoServerClientMock{}
+			repoClientsetMock := repoClientsetMock{}
+
+			argocdRepositoryMock.On("GetRepository", mock.Anything, cc.repoURL).Return(cc.repoRes, cc.repoErr)
+
+			repoServerClientMock.On("ListApps", mock.Anything, &apiclient.ListAppsRequest{
+				Repo: cc.repoRes,
+				Revision: cc.revision,
+			}).Return(cc.appRes, cc.appError)
+
+			repoClientsetMock.On("NewRepoServerClient").Return(repoServerClientMock, nil)
+
+			argocd := argoCDService{
+				repositoriesDB: argocdRepositoryMock,
+				repoClientset: repoClientsetMock,
+			}
+			got, err := argocd.GetApps(context.TODO(), cc.repoURL, cc.revision)
+
+			if cc.expectedError != nil {
+				assert.EqualError(t, err, cc.expectedError.Error())
+			} else {
+				assert.Equal(t, got, cc.expected)
+				assert.NoError(t, err)
+			}
+		})
+	}
+}