github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/services/scm_provider/utils.go (about) 1 package scm_provider 2 3 import ( 4 "context" 5 "fmt" 6 "regexp" 7 "strings" 8 9 argoprojiov1alpha1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1" 10 ) 11 12 func compileFilters(filters []argoprojiov1alpha1.SCMProviderGeneratorFilter) ([]*Filter, error) { 13 outFilters := make([]*Filter, 0, len(filters)) 14 for _, filter := range filters { 15 outFilter := &Filter{} 16 var err error 17 if filter.RepositoryMatch != nil { 18 outFilter.RepositoryMatch, err = regexp.Compile(*filter.RepositoryMatch) 19 if err != nil { 20 return nil, fmt.Errorf("error compiling RepositoryMatch regexp %q: %v", *filter.RepositoryMatch, err) 21 } 22 outFilter.FilterType = FilterTypeRepo 23 } 24 if filter.LabelMatch != nil { 25 outFilter.LabelMatch, err = regexp.Compile(*filter.LabelMatch) 26 if err != nil { 27 return nil, fmt.Errorf("error compiling LabelMatch regexp %q: %v", *filter.LabelMatch, err) 28 } 29 outFilter.FilterType = FilterTypeRepo 30 } 31 if filter.PathsExist != nil { 32 outFilter.PathsExist = filter.PathsExist 33 outFilter.FilterType = FilterTypeBranch 34 } 35 if filter.PathsDoNotExist != nil { 36 outFilter.PathsDoNotExist = filter.PathsDoNotExist 37 outFilter.FilterType = FilterTypeBranch 38 } 39 if filter.BranchMatch != nil { 40 outFilter.BranchMatch, err = regexp.Compile(*filter.BranchMatch) 41 if err != nil { 42 return nil, fmt.Errorf("error compiling BranchMatch regexp %q: %v", *filter.BranchMatch, err) 43 } 44 outFilter.FilterType = FilterTypeBranch 45 } 46 outFilters = append(outFilters, outFilter) 47 } 48 return outFilters, nil 49 } 50 51 func matchFilter(ctx context.Context, provider SCMProviderService, repo *Repository, filter *Filter) (bool, error) { 52 if filter.RepositoryMatch != nil && !filter.RepositoryMatch.MatchString(repo.Repository) { 53 return false, nil 54 } 55 56 if filter.BranchMatch != nil && !filter.BranchMatch.MatchString(repo.Branch) { 57 return false, nil 58 } 59 60 if filter.LabelMatch != nil { 61 found := false 62 for _, label := range repo.Labels { 63 if filter.LabelMatch.MatchString(label) { 64 found = true 65 break 66 } 67 } 68 if !found { 69 return false, nil 70 } 71 } 72 73 if len(filter.PathsExist) != 0 { 74 for _, path := range filter.PathsExist { 75 path = strings.TrimRight(path, "/") 76 hasPath, err := provider.RepoHasPath(ctx, repo, path) 77 if err != nil { 78 return false, err 79 } 80 if !hasPath { 81 return false, nil 82 } 83 } 84 } 85 if len(filter.PathsDoNotExist) != 0 { 86 for _, path := range filter.PathsDoNotExist { 87 path = strings.TrimRight(path, "/") 88 hasPath, err := provider.RepoHasPath(ctx, repo, path) 89 if err != nil { 90 return false, err 91 } 92 if hasPath { 93 return false, nil 94 } 95 } 96 } 97 98 return true, nil 99 } 100 101 func ListRepos(ctx context.Context, provider SCMProviderService, filters []argoprojiov1alpha1.SCMProviderGeneratorFilter, cloneProtocol string) ([]*Repository, error) { 102 compiledFilters, err := compileFilters(filters) 103 if err != nil { 104 return nil, err 105 } 106 repos, err := provider.ListRepos(ctx, cloneProtocol) 107 if err != nil { 108 return nil, err 109 } 110 repoFilters := getApplicableFilters(compiledFilters)[FilterTypeRepo] 111 if len(repoFilters) == 0 { 112 repos, err := getBranches(ctx, provider, repos, compiledFilters) 113 if err != nil { 114 return nil, err 115 } 116 return repos, nil 117 } 118 filteredRepos := make([]*Repository, 0, len(repos)) 119 for _, repo := range repos { 120 for _, filter := range repoFilters { 121 matches, err := matchFilter(ctx, provider, repo, filter) 122 if err != nil { 123 return nil, err 124 } 125 if matches { 126 filteredRepos = append(filteredRepos, repo) 127 break 128 } 129 } 130 } 131 132 repos, err = getBranches(ctx, provider, filteredRepos, compiledFilters) 133 if err != nil { 134 return nil, err 135 } 136 return repos, nil 137 } 138 139 func getBranches(ctx context.Context, provider SCMProviderService, repos []*Repository, compiledFilters []*Filter) ([]*Repository, error) { 140 reposWithBranches := []*Repository{} 141 for _, repo := range repos { 142 reposFilled, err := provider.GetBranches(ctx, repo) 143 if err != nil { 144 return nil, err 145 } 146 reposWithBranches = append(reposWithBranches, reposFilled...) 147 } 148 branchFilters := getApplicableFilters(compiledFilters)[FilterTypeBranch] 149 if len(branchFilters) == 0 { 150 return reposWithBranches, nil 151 } 152 filteredRepos := make([]*Repository, 0, len(reposWithBranches)) 153 for _, repo := range reposWithBranches { 154 for _, filter := range branchFilters { 155 matches, err := matchFilter(ctx, provider, repo, filter) 156 if err != nil { 157 return nil, err 158 } 159 if matches { 160 filteredRepos = append(filteredRepos, repo) 161 break 162 } 163 } 164 } 165 return filteredRepos, nil 166 } 167 168 // getApplicableFilters returns a map of filters separated by type. 169 func getApplicableFilters(filters []*Filter) map[FilterType][]*Filter { 170 filterMap := map[FilterType][]*Filter{ 171 FilterTypeBranch: {}, 172 FilterTypeRepo: {}, 173 } 174 for _, filter := range filters { 175 if filter.FilterType == FilterTypeBranch { 176 filterMap[FilterTypeBranch] = append(filterMap[FilterTypeBranch], filter) 177 } else if filter.FilterType == FilterTypeRepo { 178 filterMap[FilterTypeRepo] = append(filterMap[FilterTypeRepo], filter) 179 } 180 } 181 return filterMap 182 }