Skip to content

Commit

Permalink
Merge pull request #261 from adivishy1/master
Browse files Browse the repository at this point in the history
[feat]: [CDS-73572]: Support List Repo Live Search for all git providers
  • Loading branch information
rajatharanganath authored Jul 19, 2023
2 parents 3947016 + 70cccf8 commit beec4da
Show file tree
Hide file tree
Showing 39 changed files with 757 additions and 30 deletions.
13 changes: 13 additions & 0 deletions scm/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ type (
PageListOptions ListOptions
}

// RepoListOptions specifies optional repo search term and pagination
// parameters.
RepoListOptions struct {
ListOptions
RepoSearchTerm
}

// RepoSearchTerm specifies searchable parameters.
RepoSearchTerm struct {
RepoName string
User string
}

// ListOptions specifies optional pagination
// parameters.
ListOptions struct {
Expand Down
4 changes: 2 additions & 2 deletions scm/driver/azure/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func TestGitListBranchesV2(t *testing.T) {
Get("/ORG/PROJ/_apis/git/repositories/REPOID/").
Reply(200).
Type("application/json").
File("testdata/branchesFilter.json")
File("testdata/branches_filter.json")

client := NewDefault("ORG", "PROJ")
got, _, err := client.Git.ListBranchesV2(context.Background(), "REPOID", scm.BranchListOptions{SearchTerm: "main"})
Expand All @@ -140,7 +140,7 @@ func TestGitListBranchesV2(t *testing.T) {
}

want := []*scm.Reference{}
raw, _ := ioutil.ReadFile("testdata/branchesFilter.json.golden")
raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden")
_ = json.Unmarshal(raw, &want)

if diff := cmp.Diff(got, want); diff != "" {
Expand Down
6 changes: 6 additions & 0 deletions scm/driver/azure/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*
return convertRepositoryList(out), res, err
}

// ListV2 returns the user repository list.
func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
// Azure does not support search filters, hence calling List api without search filtering
return s.List(ctx, opts.ListOptions)
}

// ListHooks returns a list or repository hooks.
func (s *RepositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
// https://docs.microsoft.com/en-us/rest/api/azure/devops/hooks/subscriptions/list?view=azure-devops-rest-6.0
Expand Down
13 changes: 6 additions & 7 deletions scm/driver/bitbucket/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,20 +216,19 @@ func TestGitListBranchesV2(t *testing.T) {
MatchParam("pagelen", "30").
Reply(200).
Type("application/json").
File("testdata/branchesFilter.json")
File("testdata/branches_filter.json")

client, _ := New("https://api.bitbucket.org")
got, res, err := client.Git.ListBranchesV2(context.Background(), "atlassian/stash-example-plugin", scm.BranchListOptions{SearchTerm: "mast", PageListOptions: struct {
URL string
Page int
Size int
}{Page: 1, Size: 30}})
got, res, err := client.Git.ListBranchesV2(context.Background(), "atlassian/stash-example-plugin", scm.BranchListOptions{
SearchTerm: "mast",
PageListOptions: scm.ListOptions{Page: 1, Size: 30},
})
if err != nil {
t.Error(err)
}

want := []*scm.Reference{}
raw, _ := ioutil.ReadFile("testdata/branchesFilter.json.golden")
raw, _ := ioutil.ReadFile("testdata/branches_filter.json.golden")
json.Unmarshal(raw, &want)

if diff := cmp.Diff(got, want); diff != "" {
Expand Down
12 changes: 12 additions & 0 deletions scm/driver/bitbucket/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*
return convertRepositoryList(out), res, err
}

// ListV2 returns the user repository list based on the searchTerm passed.
func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
path := fmt.Sprintf("2.0/repositories?%s", encodeRepoListOptions(opts))
if opts.ListOptions.URL != "" {
path = opts.ListOptions.URL
}
out := new(repositories)
res, err := s.client.do(ctx, "GET", path, nil, &out)
copyPagination(out.pagination, res)
return convertRepositoryList(out), res, err
}

// ListHooks returns a list or repository hooks.
func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
path := fmt.Sprintf("2.0/repositories/%s/hooks?%s", repo, encodeListOptions(opts))
Expand Down
31 changes: 31 additions & 0 deletions scm/driver/bitbucket/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,37 @@ func TestRepositoryList(t *testing.T) {
}
}

func TestRepositoryListV2(t *testing.T) {
defer gock.Off()

gock.New("https://api.bitbucket.org").
Get("/2.0/repositories").
MatchParam("q", "name~\\\"plugin1\\\"").
MatchParam("role", "member").
Reply(200).
Type("application/json").
File("testdata/repos_filter.json")

got := []*scm.Repository{}
opts := scm.RepoListOptions{RepoSearchTerm: scm.RepoSearchTerm{RepoName: "plugin1"}}
client, _ := New("https://api.bitbucket.org")

repos, _, err := client.Repositories.ListV2(context.Background(), opts)
if err != nil {
t.Error(err)
}
got = append(got, repos...)

want := []*scm.Repository{}
raw, _ := ioutil.ReadFile("testdata/repos_filter.json.golden")
json.Unmarshal(raw, &want)

if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Unexpected Results")
t.Log(diff)
}
}

func TestStatusList(t *testing.T) {
defer gock.Off()

Expand Down
110 changes: 110 additions & 0 deletions scm/driver/bitbucket/testdata/repos_filter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{
"pagelen": 1,
"values": [
{
"scm": "git",
"website": "",
"has_wiki": false,
"uuid": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}",
"links": {
"watchers": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/watchers"
},
"branches": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/refs\/branches"
},
"tags": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/refs\/tags"
},
"commits": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/commits"
},
"clone": [
{
"href": "https:\/\/[email protected]\/atlassian\/stash-example-plugin1.git",
"name": "https"
},
{
"href": "[email protected]:atlassian\/stash-example-plugin1.git",
"name": "ssh"
}
],
"self": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1"
},
"source": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/src"
},
"html": {
"href": "https:\/\/bitbucket.org\/atlassian\/stash-example-plugin1"
},
"avatar": {
"href": "https:\/\/bytebucket.org\/ravatar\/%7B7dd600e6-0d9c-4801-b967-cb4cc17359ff%7D?ts=default"
},
"hooks": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/hooks"
},
"forks": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/forks"
},
"downloads": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/downloads"
},
"pullrequests": {
"href": "https:\/\/api.bitbucket.org\/2.0\/repositories\/atlassian\/stash-example-plugin1\/pullrequests"
}
},
"fork_policy": "allow_forks",
"name": "stash-example-plugin1",
"project": {
"key": "PROJ",
"type": "project",
"uuid": "{8b56daff-dbc7-4cae-a7a3-1228c526906b}",
"links": {
"self": {
"href": "https:\/\/api.bitbucket.org\/2.0\/teams\/atlassian\/projects\/PROJ"
},
"html": {
"href": "https:\/\/bitbucket.org\/account\/user\/atlassian\/projects\/PROJ"
},
"avatar": {
"href": "https:\/\/bitbucket.org\/account\/user\/atlassian\/projects\/PROJ\/avatar\/32"
}
},
"name": "Project: Atlassian"
},
"language": "",
"created_on": "2013-04-15T03:05:05.595458+00:00",
"mainbranch": {
"type": "branch",
"name": "master"
},
"full_name": "atlassian\/stash-example-plugin1",
"has_issues": false,
"owner": {
"username": "atlassian",
"display_name": "Atlassian",
"type": "team",
"uuid": "{02b941e3-cfaa-40f9-9a58-cec53e20bdc3}",
"links": {
"self": {
"href": "https:\/\/api.bitbucket.org\/2.0\/teams\/atlassian"
},
"html": {
"href": "https:\/\/bitbucket.org\/atlassian\/"
},
"avatar": {
"href": "https:\/\/bitbucket.org\/account\/atlassian\/avatar\/32\/"
}
}
},
"updated_on": "2018-04-01T16:36:35.970175+00:00",
"size": 1116345,
"type": "repository",
"slug": "stash-example-plugin1",
"is_private": true,
"description": "Examples on how to decorate various pages around Stash."
}
],
"next": "https:\/\/api.bitbucket.org\/2.0\/repositories?pagelen=1&after=PLACEHOLDER&role=member"
}
15 changes: 15 additions & 0 deletions scm/driver/bitbucket/testdata/repos_filter.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[
{
"ID": "{7dd600e6-0d9c-4801-b967-cb4cc17359ff}",
"Namespace": "atlassian",
"Name": "stash-example-plugin1",
"Perm": null,
"Branch": "master",
"Private": true,
"Clone": "https://bitbucket.org/atlassian/stash-example-plugin1.git",
"CloneSSH": "[email protected]:atlassian/stash-example-plugin1.git",
"Link": "https://bitbucket.org/atlassian/stash-example-plugin1",
"Created": "2013-04-15T03:05:05.595458Z",
"Updated": "2018-04-01T16:36:35.970175Z"
}
]
33 changes: 28 additions & 5 deletions scm/driver/bitbucket/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ func encodeBranchListOptions(opts scm.BranchListOptions) string {
sb.WriteString("\"")
params.Set("q", sb.String())
}
if opts.PageListOptions.Page != 0 {
params.Set("page", strconv.Itoa(opts.PageListOptions.Page))
}
if opts.PageListOptions.Size != 0 {
params.Set("pagelen", strconv.Itoa(opts.PageListOptions.Size))
if opts.PageListOptions != (scm.ListOptions{}) {
if opts.PageListOptions.Page != 0 {
params.Set("page", strconv.Itoa(opts.PageListOptions.Page))
}
if opts.PageListOptions.Size != 0 {
params.Set("pagelen", strconv.Itoa(opts.PageListOptions.Size))
}
}
return params.Encode()
}
Expand Down Expand Up @@ -66,6 +68,27 @@ func encodeListRoleOptions(opts scm.ListOptions) string {
return params.Encode()
}

func encodeRepoListOptions(opts scm.RepoListOptions) string {
params := url.Values{}
if opts.RepoSearchTerm.RepoName != "" {
var sb strings.Builder
sb.WriteString("name~\"")
sb.WriteString(opts.RepoSearchTerm.RepoName)
sb.WriteString("\"")
params.Set("q", sb.String())
}
if opts.ListOptions != (scm.ListOptions{}) {
if opts.ListOptions.Page != 0 {
params.Set("page", strconv.Itoa(opts.ListOptions.Page))
}
if opts.ListOptions.Size != 0 {
params.Set("pagelen", strconv.Itoa(opts.ListOptions.Size))
}
}
params.Set("role", "member")
return params.Encode()
}

func encodeCommitListOptions(opts scm.CommitListOptions) string {
params := url.Values{}
if opts.Page != 0 {
Expand Down
5 changes: 5 additions & 0 deletions scm/driver/gitea/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*
return convertRepositoryList(out), res, err
}

func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
// gitea does not support search filters, hence calling List api without search filtering
return s.List(ctx, opts.ListOptions)
}

func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
path := fmt.Sprintf("api/v1/repos/%s/hooks?%s", repo, encodeListOptions(opts))
out := []*hook{}
Expand Down
4 changes: 4 additions & 0 deletions scm/driver/gitee/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*
res, err := s.client.do(ctx, "GET", path, nil, &out)
return convertRepositoryList(out), res, err
}
func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
// gitee does not support search filters, hence calling List api without search filtering
return s.List(ctx, opts.ListOptions)
}

func (s *RepositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
path := fmt.Sprintf("repos/%s/hooks?%s", repo, encodeListOptions(opts))
Expand Down
12 changes: 12 additions & 0 deletions scm/driver/github/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ type repository struct {
} `json:"permissions"`
}

type searchRepositoryList struct {
Repositories []*repository `json:"items"`
}

type hook struct {
ID int `json:"id,omitempty"`
Name string `json:"name"`
Expand Down Expand Up @@ -110,6 +114,14 @@ func (s *RepositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*
return convertRepositoryList(out), res, err
}

// ListV2 returns the user repository list based on the searchTerm passed.
func (s *RepositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
path := fmt.Sprintf("search/repositories?%s", encodeRepoListOptions(opts))
out := new(searchRepositoryList)
res, err := s.client.do(ctx, "GET", path, nil, &out)
return convertRepositoryList(out.Repositories), res, err
}

// List returns the github app installation repository list.
func (s *RepositoryService) ListByInstallation(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) {
path := fmt.Sprintf("installation/repositories?%s", encodeListOptions(opts))
Expand Down
Loading

0 comments on commit beec4da

Please sign in to comment.