@@ -28,6 +28,7 @@ type GitGenerator struct {
2828 namespace string
2929}
3030
31+ // NewGitGenerator creates a new instance of Git Generator
3132func NewGitGenerator (repos services.Repos , namespace string ) Generator {
3233 g := & GitGenerator {
3334 repos : repos ,
@@ -37,20 +38,26 @@ func NewGitGenerator(repos services.Repos, namespace string) Generator {
3738 return g
3839}
3940
41+ // GetTemplate returns the ApplicationSetTemplate associated with the Git generator
42+ // from the provided ApplicationSetGenerator. This template defines how each
43+ // generated Argo CD Application should be rendered.
4044func (g * GitGenerator ) GetTemplate (appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator ) * argoprojiov1alpha1.ApplicationSetTemplate {
4145 return & appSetGenerator .Git .Template
4246}
4347
48+ // GetRequeueAfter returns the duration after which the Git generator should be
49+ // requeued for reconciliation. If RequeueAfterSeconds is set in the generator spec,
50+ // it uses that value. Otherwise, it falls back to a default requeue interval (3 minutes).
4451func (g * GitGenerator ) GetRequeueAfter (appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator ) time.Duration {
45- // Return a requeue default of 3 minutes, if no default is specified.
46-
4752 if appSetGenerator .Git .RequeueAfterSeconds != nil {
4853 return time .Duration (* appSetGenerator .Git .RequeueAfterSeconds ) * time .Second
4954 }
5055
5156 return getDefaultRequeueAfter ()
5257}
5358
59+ // GenerateParams generates a list of parameter maps for the ApplicationSet by evaluating the Git generator's configuration.
60+ // It supports both directory-based and file-based Git generators.
5461func (g * GitGenerator ) GenerateParams (appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator , appSet * argoprojiov1alpha1.ApplicationSet , client client.Client ) ([]map [string ]any , error ) {
5562 if appSetGenerator == nil {
5663 return nil , ErrEmptyAppSetGenerator
@@ -67,6 +74,7 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
6774 // When the project field is templated, the contents of the git repo are required to run the git generator and get the templated value,
6875 // but git generator cannot be called without verifying the commit signature.
6976 // In this case, we skip the signature verification.
77+ // If the project is templated, we skip the commit verification
7078 if ! strings .Contains (appSet .Spec .Template .Spec .Project , "{{" ) {
7179 project := appSet .Spec .Template .Spec .Project
7280 appProject := & argoprojiov1alpha1.AppProject {}
@@ -102,8 +110,10 @@ func (g *GitGenerator) GenerateParams(appSetGenerator *argoprojiov1alpha1.Applic
102110 return res , nil
103111}
104112
113+ // generateParamsForGitDirectories generates parameters for an ApplicationSet using a directory-based Git generator.
114+ // It fetches all directories from the given Git repository and revision, optionally using a revision cache and verifying commits.
115+ // It then filters the directories based on the generator's configuration and renders parameters for the resulting applications
105116func (g * GitGenerator ) generateParamsForGitDirectories (appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator , noRevisionCache , verifyCommit , useGoTemplate bool , project string , goTemplateOptions []string ) ([]map [string ]any , error ) {
106- // Directories, not files
107117 allPaths , err := g .repos .GetDirectories (context .TODO (), appSetGenerator .Git .RepoURL , appSetGenerator .Git .Revision , project , noRevisionCache , verifyCommit )
108118 if err != nil {
109119 return nil , fmt .Errorf ("error getting directories from repo: %w" , err )
@@ -127,41 +137,88 @@ func (g *GitGenerator) generateParamsForGitDirectories(appSetGenerator *argoproj
127137 return res , nil
128138}
129139
140+ // generateParamsForGitFiles generates parameters for an ApplicationSet using a file-based Git generator.
141+ // It retrieves and processes specified files from the Git repository, supporting both YAML and JSON formats,
142+ // and returns a list of parameter maps extracted from the content.
130143func (g * GitGenerator ) generateParamsForGitFiles (appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator , noRevisionCache , verifyCommit , useGoTemplate bool , project string , goTemplateOptions []string ) ([]map [string ]any , error ) {
131- // Get all files that match the requested path string, removing duplicates
132- allFiles := make (map [string ][]byte )
133- for _ , requestedPath := range appSetGenerator .Git .Files {
134- files , err := g .repos .GetFiles (context .TODO (), appSetGenerator .Git .RepoURL , appSetGenerator .Git .Revision , project , requestedPath .Path , noRevisionCache , verifyCommit )
144+ // fileContentMap maps absolute file paths to their byte content
145+ fileContentMap := make (map [string ][]byte )
146+ var includePatterns []string
147+ var excludePatterns []string
148+
149+ for _ , req := range appSetGenerator .Git .Files {
150+ if req .Exclude {
151+ excludePatterns = append (excludePatterns , req .Path )
152+ } else {
153+ includePatterns = append (includePatterns , req .Path )
154+ }
155+ }
156+
157+ // Fetch all files from include patterns
158+ for _ , includePattern := range includePatterns {
159+ retrievedFiles , err := g .repos .GetFiles (
160+ context .TODO (),
161+ appSetGenerator .Git .RepoURL ,
162+ appSetGenerator .Git .Revision ,
163+ project ,
164+ includePattern ,
165+ noRevisionCache ,
166+ verifyCommit ,
167+ )
135168 if err != nil {
136169 return nil , err
137170 }
138- for filePath , content := range files {
139- allFiles [ filePath ] = content
171+ for absPath , content := range retrievedFiles {
172+ fileContentMap [ absPath ] = content
140173 }
141174 }
142175
143- // Extract the unduplicated map into a list, and sort by path to ensure a deterministic
144- // processing order in the subsequent step
145- allPaths := []string {}
146- for path := range allFiles {
147- allPaths = append (allPaths , path )
176+ // Now remove files matching any exclude pattern
177+ for _ , excludePattern := range excludePatterns {
178+ matchingFiles , err := g .repos .GetFiles (
179+ context .TODO (),
180+ appSetGenerator .Git .RepoURL ,
181+ appSetGenerator .Git .Revision ,
182+ project ,
183+ excludePattern ,
184+ noRevisionCache ,
185+ verifyCommit ,
186+ )
187+ if err != nil {
188+ return nil , err
189+ }
190+ for absPath := range matchingFiles {
191+ // if the file doesn't exist already and you try to delete it from the map
192+ // the operation is a no-op. It’s safe and doesn't return an error or panic.
193+ // Hence, we can simply try to delete the file from the path without checking
194+ // if that file already exists in the map.
195+ delete (fileContentMap , absPath )
196+ }
148197 }
149- sort .Strings (allPaths )
150198
151- // Generate params from each path, and return
152- res := []map [string ]any {}
153- for _ , path := range allPaths {
199+ // Get a sorted list of file paths to ensure deterministic processing order
200+ var filePaths []string
201+ for path := range fileContentMap {
202+ filePaths = append (filePaths , path )
203+ }
204+ sort .Strings (filePaths )
205+
206+ var allParams []map [string ]any
207+ for _ , filePath := range filePaths {
154208 // A JSON / YAML file path can contain multiple sets of parameters (ie it is an array)
155- paramsArray , err := g .generateParamsFromGitFile (path , allFiles [ path ], appSetGenerator .Git .Values , useGoTemplate , goTemplateOptions , appSetGenerator .Git .PathParamPrefix )
209+ paramsFromFileArray , err := g .generateParamsFromGitFile (filePath , fileContentMap [ filePath ], appSetGenerator .Git .Values , useGoTemplate , goTemplateOptions , appSetGenerator .Git .PathParamPrefix )
156210 if err != nil {
157- return nil , fmt .Errorf ("unable to process file '%s': %w" , path , err )
211+ return nil , fmt .Errorf ("unable to process file '%s': %w" , filePath , err )
158212 }
159-
160- res = append (res , paramsArray ... )
213+ allParams = append (allParams , paramsFromFileArray ... )
161214 }
162- return res , nil
215+
216+ return allParams , nil
163217}
164218
219+ // generateParamsFromGitFile parses the content of a Git-tracked file and generates a slice of parameter maps.
220+ // The file can contain a single YAML/JSON object or an array of such objects. Depending on the useGoTemplate flag,
221+ // it either preserves structure for Go templating or flattens the objects for use as plain key-value parameters.
165222func (g * GitGenerator ) generateParamsFromGitFile (filePath string , fileContent []byte , values map [string ]string , useGoTemplate bool , goTemplateOptions []string , pathParamPrefix string ) ([]map [string ]any , error ) {
166223 objectsFound := []map [string ]any {}
167224
@@ -238,8 +295,10 @@ func (g *GitGenerator) generateParamsFromGitFile(filePath string, fileContent []
238295 return res , nil
239296}
240297
298+ // filterApps filters the list of all application paths based on inclusion and exclusion rules
299+ // defined in GitDirectoryGeneratorItems. Each item can either include or exclude matching paths.
241300func (g * GitGenerator ) filterApps (directories []argoprojiov1alpha1.GitDirectoryGeneratorItem , allPaths []string ) []string {
242- res := []string {}
301+ var res []string
243302 for _ , appPath := range allPaths {
244303 appInclude := false
245304 appExclude := false
@@ -266,6 +325,9 @@ func (g *GitGenerator) filterApps(directories []argoprojiov1alpha1.GitDirectoryG
266325 return res
267326}
268327
328+ // generateParamsFromApps generates a list of parameter maps based on the given app paths.
329+ // Each app path is converted into a parameter object with path metadata (basename, segments, etc.).
330+ // It supports both Go templates and flat key-value parameters.
269331func (g * GitGenerator ) generateParamsFromApps (requestedApps []string , appSetGenerator * argoprojiov1alpha1.ApplicationSetGenerator , useGoTemplate bool , goTemplateOptions []string ) ([]map [string ]any , error ) {
270332 res := make ([]map [string ]any , len (requestedApps ))
271333 for i , a := range requestedApps {
@@ -308,6 +370,7 @@ func (g *GitGenerator) generateParamsFromApps(requestedApps []string, appSetGene
308370 return res , nil
309371}
310372
373+ // resolveProjectName resolves a project name whether templated or not
311374func resolveProjectName (project string ) string {
312375 if strings .Contains (project , "{{" ) {
313376 return ""
0 commit comments