From e3d9743ba75127981a7ab3dc00328a6ac9c6c25d Mon Sep 17 00:00:00 2001 From: David Schafhauser <36130316+dschafhauser@users.noreply.github.com> Date: Thu, 20 Jan 2022 15:35:36 +0800 Subject: [PATCH] Add support for filtering by topics for GitLab SCM (#181) * fix: emit warning for filtering by topics for Bitbucket * feat: add support for filtering topics for GitLab * fix: reset GHORG_TOPICS env var between tests Co-authored-by: Schafhauser, David --- scm/bitbucket.go | 5 ++ scm/filter.go | 25 ++++++++++ scm/filter_test.go | 112 +++++++++++++++++++++++++++++++++++++++++++++ scm/gitea.go | 17 +------ scm/github.go | 26 ++--------- scm/gitlab.go | 4 ++ 6 files changed, 152 insertions(+), 37 deletions(-) create mode 100644 scm/filter.go create mode 100644 scm/filter_test.go diff --git a/scm/bitbucket.go b/scm/bitbucket.go index cf1388d..d30ce32 100644 --- a/scm/bitbucket.go +++ b/scm/bitbucket.go @@ -4,6 +4,7 @@ import ( "os" "strings" + "github.com/gabrie30/ghorg/colorlog" "github.com/ktrysmt/go-bitbucket" ) @@ -70,6 +71,10 @@ func (_ Bitbucket) filter(resp interface{}) (repoData []Repo, err error) { link := l.(map[string]interface{})["href"] linkType := l.(map[string]interface{})["name"] + if os.Getenv("GHORG_TOPICS") != "" { + colorlog.PrintError("WARNING: Filtering by topics is not supported for Bitbucket SCM") + } + if os.Getenv("GHORG_MATCH_PREFIX") != "" { repoName := strings.ToLower(clone["name"].(string)) foundPrefix := false diff --git a/scm/filter.go b/scm/filter.go new file mode 100644 index 0000000..86798d8 --- /dev/null +++ b/scm/filter.go @@ -0,0 +1,25 @@ +package scm + +import ( + "os" + "strings" +) + +func hasMatchingTopic(rpTopics []string) bool { + envTopics := strings.Split(os.Getenv("GHORG_TOPICS"), ",") + + // If user defined a list of topics, check if any match with this repo + if os.Getenv("GHORG_TOPICS") != "" { + for _, rpTopic := range rpTopics { + for _, envTopic := range envTopics { + if rpTopic == envTopic { + return true + } + } + } + return false + } + + // If no user defined topics are specified, accept any topics + return true +} diff --git a/scm/filter_test.go b/scm/filter_test.go new file mode 100644 index 0000000..c7735ca --- /dev/null +++ b/scm/filter_test.go @@ -0,0 +1,112 @@ +package scm + +import ( + "os" + "testing" +) + +func TestMatchingTopicsWithNoEnvTopics(t *testing.T) { + os.Setenv("GHORG_TOPICS", "") + + t.Run("When repo topics are empty", func(tt *testing.T) { + rpTopics := []string{} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When any repo topics are set", func(tt *testing.T) { + rpTopics := []string{"myTopic", "anotherTopic", "3rdTopic"} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) +} + +func TestMatchingTopicsWithSingleEnvTopic(t *testing.T) { + os.Setenv("GHORG_TOPICS", "myTopic") + + t.Run("When repo topic is empty", func(tt *testing.T) { + rpTopics := []string{} + + want := false + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When single repo topic matches", func(tt *testing.T) { + rpTopics := []string{"myTopic"} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When one of multiple repo topics matches", func(tt *testing.T) { + rpTopics := []string{"anotherTopic", "myTopic", "3rdTopic"} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + os.Setenv("GHORG_TOPICS", "") +} + +func TestMatchingTopicsWithMultipleEnvTopics(t *testing.T) { + os.Setenv("GHORG_TOPICS", "myTopic,3rdTopic") + + t.Run("When repo topic is empty", func(tt *testing.T) { + rpTopics := []string{} + + want := false + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When Repo topic matches none", func(tt *testing.T) { + rpTopics := []string{"anotherTopic"} + + want := false + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When Repo topic matches at least one", func(tt *testing.T) { + rpTopics := []string{"3rdTopic"} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + t.Run("When Repo topic matches multiple", func(tt *testing.T) { + rpTopics := []string{"3rdTopic", "myTopic"} + + want := true + got := hasMatchingTopic(rpTopics) + if want != got { + tt.Errorf("Expected %v repo, got: %v", want, got) + } + }) + + os.Setenv("GHORG_TOPICS", "") +} diff --git a/scm/gitea.go b/scm/gitea.go index e7a7b25..6a31e25 100644 --- a/scm/gitea.go +++ b/scm/gitea.go @@ -118,8 +118,6 @@ func (_ Gitea) NewClient() (Client, error) { } func (c Gitea) filter(rps []*gitea.Repository) (repoData []Repo, err error) { - envTopics := strings.Split(os.Getenv("GHORG_TOPICS"), ",") - for _, rp := range rps { if os.Getenv("GHORG_SKIP_ARCHIVED") == "true" { @@ -134,25 +132,12 @@ func (c Gitea) filter(rps []*gitea.Repository) (repoData []Repo, err error) { } } - // If user defined a list of topics, check if any match with this repo if os.Getenv("GHORG_TOPICS") != "" { rpTopics, _, err := c.ListRepoTopics(rp.Owner.UserName, rp.Name, gitea.ListRepoTopicsOptions{}) if err != nil { return []Repo{}, err } - foundTopic := false - for _, topic := range rpTopics { - for _, envTopic := range envTopics { - if topic == envTopic { - foundTopic = true - break - } - } - if foundTopic == true { - break - } - } - if foundTopic == false { + if !hasMatchingTopic(rpTopics) { continue } } diff --git a/scm/github.go b/scm/github.go index d2a88a2..2034047 100644 --- a/scm/github.go +++ b/scm/github.go @@ -38,8 +38,6 @@ func (c Github) GetOrgRepos(targetOrg string) ([]Repo, error) { ListOptions: github.ListOptions{PerPage: c.perPage}, } - envTopics := strings.Split(os.Getenv("GHORG_TOPICS"), ",") - // get all pages of results var allRepos []*github.Repository for { @@ -60,7 +58,7 @@ func (c Github) GetOrgRepos(targetOrg string) ([]Repo, error) { opt.Page = resp.NextPage } - return c.filter(allRepos, envTopics), nil + return c.filter(allRepos), nil } // GetUserRepos gets user repos @@ -74,8 +72,6 @@ func (c Github) GetUserRepos(targetUser string) ([]Repo, error) { ListOptions: github.ListOptions{PerPage: c.perPage}, } - envTopics := strings.Split(os.Getenv("GHORG_TOPICS"), ",") - // get all pages of results var allRepos []*github.Repository @@ -107,7 +103,7 @@ func (c Github) GetUserRepos(targetUser string) ([]Repo, error) { opt.Page = resp.NextPage } - return c.filter(allRepos, envTopics), nil + return c.filter(allRepos), nil } // NewClient create new github scm client @@ -137,7 +133,7 @@ func (_ Github) addTokenToHTTPSCloneURL(url string, token string) string { return "https://" + token + "@" + splitURL[1] } -func (c Github) filter(allRepos []*github.Repository, envTopics []string) []Repo { +func (c Github) filter(allRepos []*github.Repository) []Repo { var repoData []Repo for _, ghRepo := range allRepos { @@ -154,20 +150,8 @@ func (c Github) filter(allRepos []*github.Repository, envTopics []string) []Repo } } - // If user defined a list of topics, check if any match with this repo - if os.Getenv("GHORG_TOPICS") != "" { - foundTopic := false - for _, topic := range ghRepo.Topics { - for _, envTopic := range envTopics { - if topic == envTopic { - foundTopic = true - continue - } - } - } - if foundTopic == false { - continue - } + if !hasMatchingTopic(ghRepo.Topics) { + continue } if os.Getenv("GHORG_MATCH_PREFIX") != "" { diff --git a/scm/gitlab.go b/scm/gitlab.go index 4713928..3d3713f 100644 --- a/scm/gitlab.go +++ b/scm/gitlab.go @@ -233,6 +233,10 @@ func (c Gitlab) filter(ps []*gitlab.Project) []Repo { } } + if !hasMatchingTopic(p.Topics) { + continue + } + if os.Getenv("GHORG_MATCH_PREFIX") != "" { repoName := strings.ToLower(p.Name) foundPrefix := false