[feat]: [CDS-73572]: Support List Repo Live Search for all git providers

pull/261/head
Adithya Viswanathan 10 months ago
parent 39470167b5
commit 70cccf871a

@ -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 {

@ -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"})
@ -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 != "" {

@ -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

@ -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 != "" {

@ -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))

@ -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()

@ -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:\/\/brydzewski@bitbucket.org\/atlassian\/stash-example-plugin1.git",
"name": "https"
},
{
"href": "git@bitbucket.org: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"
}

@ -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": "git@bitbucket.org: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"
}
]

@ -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()
}
@ -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 {

@ -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{}

@ -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))

@ -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"`
@ -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))

@ -131,6 +131,48 @@ func TestRepositoryList(t *testing.T) {
t.Run("Page", testPage(res))
}
func TestRepositoryListV2(t *testing.T) {
defer gock.Off()
gock.New("https://api.github.com").
Get("/search/repositories").
MatchParam("q", "testRepoin:name").
MatchParam("q", "user:user123").
MatchParam("page", "1").
MatchParam("per_page", "30").
Reply(200).
Type("application/json").
SetHeaders(mockHeaders).
SetHeaders(mockPageHeaders).
File("testdata/repos_filter.json")
client := NewDefault()
got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{
ListOptions: scm.ListOptions{Page: 1, Size: 30},
RepoSearchTerm: scm.RepoSearchTerm{
RepoName: "testRepo",
User: "user123",
},
})
if err != nil {
t.Error(err)
return
}
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)
}
t.Run("Request", testRequest(res))
t.Run("Rate", testRate(res))
t.Run("Page", testPage(res))
}
func TestGithubAppInstallationList(t *testing.T) {
defer gock.Off()

@ -0,0 +1,107 @@
{
"total_count": 5,
"incomplete_results": false,
"items": [
{
"id": 508719340,
"node_id": "R_kgDOHlJw7A",
"name": "testRepo2",
"full_name": "user123/testRepo2",
"private": false,
"owner": {
"login": "user123",
"id": 103414561,
"node_id": "U_kgDOBin7IQ",
"avatar_url": "https://avatars.githubusercontent.com/u/103414561?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/user123",
"html_url": "https://github.com/user123",
"followers_url": "https://api.github.com/users/user123/followers",
"following_url": "https://api.github.com/users/user123/following{/other_user}",
"gists_url": "https://api.github.com/users/user123/gists{/gist_id}",
"starred_url": "https://api.github.com/users/user123/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/user123/subscriptions",
"organizations_url": "https://api.github.com/users/user123/orgs",
"repos_url": "https://api.github.com/users/user123/repos",
"events_url": "https://api.github.com/users/user123/events{/privacy}",
"received_events_url": "https://api.github.com/users/user123/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/user123/testRepo2",
"description": null,
"fork": false,
"url": "https://api.github.com/repos/user123/testRepo2",
"forks_url": "https://api.github.com/repos/user123/testRepo2/forks",
"keys_url": "https://api.github.com/repos/user123/testRepo2/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/user123/testRepo2/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/user123/testRepo2/teams",
"hooks_url": "https://api.github.com/repos/user123/testRepo2/hooks",
"issue_events_url": "https://api.github.com/repos/user123/testRepo2/issues/events{/number}",
"events_url": "https://api.github.com/repos/user123/testRepo2/events",
"assignees_url": "https://api.github.com/repos/user123/testRepo2/assignees{/user}",
"branches_url": "https://api.github.com/repos/user123/testRepo2/branches{/branch}",
"tags_url": "https://api.github.com/repos/user123/testRepo2/tags",
"blobs_url": "https://api.github.com/repos/user123/testRepo2/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/user123/testRepo2/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/user123/testRepo2/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/user123/testRepo2/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/user123/testRepo2/statuses/{sha}",
"languages_url": "https://api.github.com/repos/user123/testRepo2/languages",
"stargazers_url": "https://api.github.com/repos/user123/testRepo2/stargazers",
"contributors_url": "https://api.github.com/repos/user123/testRepo2/contributors",
"subscribers_url": "https://api.github.com/repos/user123/testRepo2/subscribers",
"subscription_url": "https://api.github.com/repos/user123/testRepo2/subscription",
"commits_url": "https://api.github.com/repos/user123/testRepo2/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/user123/testRepo2/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/user123/testRepo2/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/user123/testRepo2/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/user123/testRepo2/contents/{+path}",
"compare_url": "https://api.github.com/repos/user123/testRepo2/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/user123/testRepo2/merges",
"archive_url": "https://api.github.com/repos/user123/testRepo2/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/user123/testRepo2/downloads",
"issues_url": "https://api.github.com/repos/user123/testRepo2/issues{/number}",
"pulls_url": "https://api.github.com/repos/user123/testRepo2/pulls{/number}",
"milestones_url": "https://api.github.com/repos/user123/testRepo2/milestones{/number}",
"notifications_url": "https://api.github.com/repos/user123/testRepo2/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/user123/testRepo2/labels{/name}",
"releases_url": "https://api.github.com/repos/user123/testRepo2/releases{/id}",
"deployments_url": "https://api.github.com/repos/user123/testRepo2/deployments",
"created_at": "2022-06-29T14:11:36Z",
"updated_at": "2023-06-27T07:10:05Z",
"pushed_at": "2023-06-07T05:36:36Z",
"git_url": "git://github.com/user123/testRepo2.git",
"ssh_url": "git@github.com:user123/testRepo2.git",
"clone_url": "https://github.com/user123/testRepo2.git",
"svn_url": "https://github.com/user123/testRepo2",
"homepage": null,
"size": 53,
"stargazers_count": 0,
"watchers_count": 0,
"language": null,
"has_issues": true,
"has_projects": true,
"has_downloads": true,
"has_wiki": true,
"has_pages": false,
"has_discussions": false,
"forks_count": 0,
"mirror_url": null,
"archived": false,
"disabled": false,
"open_issues_count": 2,
"license": null,
"allow_forking": true,
"is_template": false,
"web_commit_signoff_required": false,
"topics": [],
"visibility": "public",
"forks": 0,
"open_issues": 2,
"watchers": 0,
"default_branch": "main",
"score": 1.0
}
]
}

@ -0,0 +1,20 @@
[
{
"ID": "508719340",
"Namespace": "user123",
"Name": "testRepo2",
"Perm": {
"Pull": false,
"Push": false,
"Admin": false
},
"Branch": "main",
"Private": false,
"Visibility": 1,
"Clone": "https://github.com/user123/testRepo2.git",
"CloneSSH": "git@github.com:user123/testRepo2.git",
"Link": "https://github.com/user123/testRepo2",
"Created": "2022-06-29T14:11:36Z",
"Updated": "2023-06-27T07:10:05Z"
}
]

@ -7,6 +7,7 @@ package github
import (
"net/url"
"strconv"
"strings"
"github.com/drone/go-scm/scm"
)
@ -22,6 +23,33 @@ func encodeListOptions(opts scm.ListOptions) string {
return params.Encode()
}
func encodeRepoListOptions(opts scm.RepoListOptions) string {
var sb strings.Builder
if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) {
if opts.RepoSearchTerm.RepoName != "" {
sb.WriteString("q=")
sb.WriteString(opts.RepoSearchTerm.RepoName)
sb.WriteString("in:name+user:")
sb.WriteString(opts.RepoSearchTerm.User)
} else {
sb.WriteString("q=")
sb.WriteString("user:")
sb.WriteString(opts.RepoSearchTerm.User)
}
}
if opts.ListOptions != (scm.ListOptions{}) {
if opts.ListOptions.Page != 0 {
sb.WriteString("&page=")
sb.WriteString(strconv.Itoa(opts.ListOptions.Page))
}
if opts.ListOptions.Size != 0 {
sb.WriteString("&per_page=")
sb.WriteString(strconv.Itoa(opts.ListOptions.Size))
}
}
return sb.String()
}
func encodeCommitListOptions(opts scm.CommitListOptions) string {
params := url.Values{}
if opts.Page != 0 {

@ -215,7 +215,7 @@ func TestGitListBranchesWithBranchFilter(t *testing.T) {
Type("application/json").
SetHeaders(mockHeaders).
SetHeaders(mockPageHeaders).
File("testdata/branchesFilter.json")
File("testdata/branches_filter.json")
client := NewDefault()
got, res, err := client.Git.ListBranchesV2(context.Background(), "diaspora/diaspora", scm.BranchListOptions{SearchTerm: "mast"})
@ -225,7 +225,7 @@ func TestGitListBranchesWithBranchFilter(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 != "" {

@ -94,6 +94,14 @@ 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) {
// We pass the repo searchTerm in the query params and gitlab filters repos based on this search term
path := fmt.Sprintf("api/v4/projects?%s", encodeRepoListOptions(opts))
out := []*repository{}
res, err := s.client.do(ctx, "GET", path, nil, &out)
return convertRepositoryList(out), res, err
}
func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
path := fmt.Sprintf("api/v4/projects/%s/hooks?%s", encode(repo), encodeListOptions(opts))
out := []*hook{}

@ -163,6 +163,45 @@ func TestRepositoryList(t *testing.T) {
t.Run("Page", testPage(res))
}
func TestRepositoryListV2(t *testing.T) {
defer gock.Off()
gock.New("https://gitlab.com").
Get("/api/v4/projects").
MatchParam("search", "diaspora").
MatchParam("page", "1").
MatchParam("per_page", "30").
MatchParam("membership", "true").
Reply(200).
Type("application/json").
SetHeaders(mockHeaders).
SetHeaders(mockPageHeaders).
File("testdata/repos_filter.json")
client := NewDefault()
got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{
ListOptions: scm.ListOptions{Page: 1, Size: 30},
RepoSearchTerm: scm.RepoSearchTerm{RepoName: "diaspora"},
})
if err != nil {
t.Error(err)
return
}
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)
}
t.Run("Request", testRequest(res))
t.Run("Rate", testRate(res))
t.Run("Page", testPage(res))
}
func TestStatusList(t *testing.T) {
defer gock.Off()

@ -0,0 +1,59 @@
[
{
"id": 178504,
"description": "",
"default_branch": "master",
"tag_list": [],
"ssh_url_to_repo": "git@gitlab.com:diaspora/diaspora.git",
"http_url_to_repo": "https://gitlab.com/diaspora/diaspora.git",
"web_url": "https://gitlab.com/diaspora/diaspora",
"name": "Diaspora",
"name_with_namespace": "diaspora / Diaspora",
"path": "diaspora",
"path_with_namespace": "diaspora/diaspora",
"avatar_url": null,
"star_count": 0,
"forks_count": 0,
"created_at": "2015-03-03T18:37:05.387Z",
"last_activity_at": "2015-03-03T18:37:20.795Z",
"_links": {
"self": "http://gitlab.com/api/v4/projects/178504",
"issues": "http://gitlab.com/api/v4/projects/178504/issues",
"merge_requests": "http://gitlab.com/api/v4/projects/178504/merge_requests",
"repo_branches": "http://gitlab.com/api/v4/projects/178504/repository/branches",
"labels": "http://gitlab.com/api/v4/projects/178504/labels",
"events": "http://gitlab.com/api/v4/projects/178504/events",
"members": "http://gitlab.com/api/v4/projects/178504/members"
},
"archived": false,
"visibility": "public",
"resolve_outdated_diff_discussions": null,
"container_registry_enabled": null,
"issues_enabled": true,
"merge_requests_enabled": true,
"wiki_enabled": true,
"jobs_enabled": true,
"snippets_enabled": false,
"shared_runners_enabled": true,
"lfs_enabled": true,
"creator_id": 57658,
"namespace": {
"id": 120836,
"name": "diaspora",
"path": "diaspora",
"kind": "group",
"full_path": "diaspora",
"parent_id": null
},
"import_status": "finished",
"open_issues_count": 0,
"public_jobs": true,
"ci_config_path": null,
"shared_with_groups": [],
"only_allow_merge_if_pipeline_succeeds": false,
"request_access_enabled": true,
"only_allow_merge_if_all_discussions_are_resolved": null,
"printing_merge_request_link_enabled": true,
"approvals_before_merge": 0
}
]

@ -0,0 +1,20 @@
[
{
"ID": "178504",
"Namespace": "diaspora",
"Name": "diaspora",
"Perm": {
"Pull": true,
"Push": false,
"Admin": false
},
"Branch": "master",
"Private": false,
"Visibility": 1,
"Clone": "https://gitlab.com/diaspora/diaspora.git",
"CloneSSH": "git@gitlab.com:diaspora/diaspora.git",
"Link": "https://gitlab.com/diaspora/diaspora",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
}
]

@ -29,11 +29,13 @@ func encodeBranchListOptions(opts scm.BranchListOptions) string {
if opts.SearchTerm != "" {
params.Set("search", opts.SearchTerm)
}
if opts.PageListOptions.Page != 0 {
params.Set("page", strconv.Itoa(opts.PageListOptions.Page))
}
if opts.PageListOptions.Size != 0 {
params.Set("per_page", 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("per_page", strconv.Itoa(opts.PageListOptions.Size))
}
}
return params.Encode()
}
@ -61,6 +63,25 @@ func encodeMemberListOptions(opts scm.ListOptions) string {
return params.Encode()
}
func encodeRepoListOptions(opts scm.RepoListOptions) string {
params := url.Values{}
params.Set("membership", "true")
if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) {
if opts.RepoSearchTerm.RepoName != "" {
params.Set("search", opts.RepoSearchTerm.RepoName)
}
}
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("per_page", strconv.Itoa(opts.ListOptions.Size))
}
}
return params.Encode()
}
func encodeCommitListOptions(opts scm.CommitListOptions) string {
params := url.Values{}
if opts.Page != 0 {

@ -45,6 +45,11 @@ func (s *repositoryService) List(ctx context.Context, _ scm.ListOptions) ([]*scm
return convertRepositoryList(out), res, err
}
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)
}
func (s *repositoryService) ListHooks(ctx context.Context, repo string, _ scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
path := fmt.Sprintf("api/v1/repos/%s/hooks", repo)
out := []*hook{}

@ -52,6 +52,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) {
// harness 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) {
harnessURI := buildHarnessURI(s.client.account, s.client.organization, s.client.project, repo)
path := fmt.Sprintf("api/v1/repos/%s/webhooks?sort=display_name&order=asc&%s", harnessURI, encodeListOptions(opts))

@ -155,7 +155,7 @@ func TestGitListBranchesWithBranchFilter(t *testing.T) {
MatchParam("filterText", "mast").
Reply(200).
Type("application/json").
File("testdata/branchesFilter.json")
File("testdata/branches_filter.json")
client, _ := New("http://example.com:7990")
got, _, err := client.Git.ListBranchesV2(context.Background(), "PRJ/my-repo", scm.BranchListOptions{SearchTerm: "mast"})
@ -164,7 +164,7 @@ func TestGitListBranchesWithBranchFilter(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 != "" {

@ -180,6 +180,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("rest/api/1.0/repos?%s", encodeRepoListOptions(opts))
out := new(repositories)
res, err := s.client.do(ctx, "GET", path, nil, &out)
if res != nil && !out.pagination.LastPage.Bool {
res.Page.First = 1
res.Page.Next = opts.ListOptions.Page + 1
}
return convertRepositoryList(out), res, err
}
// listWrite returns the user repository list.
func (s *repositoryService) listWrite(ctx context.Context, repo string) ([]*scm.Repository, *scm.Response, error) {
_, name := scm.Split(repo)

@ -319,6 +319,47 @@ func TestRepositoryList(t *testing.T) {
}
}
func TestRepositoryListV2(t *testing.T) {
defer gock.Off()
gock.New("http://example.com:7990").
Get("/rest/api/1.0/repos").
MatchParam("name", "quux").
MatchParam("limit", "25").
MatchParam("start", "50").
MatchParam("permission", "REPO_READ").
Reply(200).
Type("application/json").
File("testdata/repos_filter.json")
client, _ := New("http://example.com:7990")
got, res, err := client.Repositories.ListV2(context.Background(), scm.RepoListOptions{
ListOptions: scm.ListOptions{Page: 3, Size: 25},
RepoSearchTerm: scm.RepoSearchTerm{
RepoName: "quux",
},
})
if err != nil {
t.Error(err)
}
if got, want := res.Page.First, 1; got != want {
t.Errorf("Want Page.First %d, got %d", want, got)
}
if got, want := res.Page.Next, 4; got != want {
t.Errorf("Want Page.Next %d, got %d", want, got)
}
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) {
client, _ := New("http://example.com:7990")
_, _, err := client.Repositories.ListStatus(context.Background(), "PRJ/my-repo", "a6e5e7d797edf751cbd839d6bd4aef86c941eec9", scm.ListOptions{Size: 30, Page: 1})

@ -0,0 +1,49 @@
{
"size": 25,
"limit": 25,
"isLastPage": false,
"values": [
{
"slug": "quux",
"id": 2,
"name": "quux",
"scmId": "git",
"state": "AVAILABLE",
"statusMessage": "Available",
"forkable": true,
"project": {
"key": "PRJ",
"id": 2,
"name": "different_name",
"public": false,
"type": "NORMAL",
"links": {
"self": [
{
"href": "http://example.com:7990/projects/PRJ"
}
]
}
},
"public": false,
"links": {
"clone": [
{
"href": "ssh://git@example.com:7999/prj/quux.git",
"name": "ssh"
},
{
"href": "http://jcitizen@example.com:7990/scm/prj/quux.git",
"name": "http"
}
],
"self": [
{
"href": "http://example.com:7990/projects/PRJ/repos/quux/browse"
}
]
}
}
],
"start": 0
}

@ -0,0 +1,15 @@
[
{
"ID": "2",
"Namespace": "PRJ",
"Name": "quux",
"Perm": null,
"Branch": "master",
"Private": true,
"Clone": "http://example.com:7990/scm/prj/quux.git",
"CloneSSH": "ssh://git@example.com:7999/prj/quux.git",
"Link": "http://example.com:7990/projects/PRJ/repos/quux/browse",
"Created": "0001-01-01T00:00:00Z",
"Updated": "0001-01-01T00:00:00Z"
}
]

@ -30,13 +30,15 @@ func encodeBranchListOptions(opts scm.BranchListOptions) string {
if opts.SearchTerm != "" {
params.Set("filterText", opts.SearchTerm)
}
if opts.PageListOptions.Page > 1 {
params.Set("start", strconv.Itoa(
(opts.PageListOptions.Page-1)*opts.PageListOptions.Size),
)
}
if opts.PageListOptions.Size != 0 {
params.Set("limit", strconv.Itoa(opts.PageListOptions.Size))
if opts.PageListOptions != (scm.ListOptions{}) {
if opts.PageListOptions.Page > 1 {
params.Set("start", strconv.Itoa(
(opts.PageListOptions.Page-1)*opts.PageListOptions.Size),
)
}
if opts.PageListOptions.Size != 0 {
params.Set("limit", strconv.Itoa(opts.PageListOptions.Size))
}
}
return params.Encode()
}
@ -55,6 +57,27 @@ func encodeListRoleOptions(opts scm.ListOptions) string {
return params.Encode()
}
func encodeRepoListOptions(opts scm.RepoListOptions) string {
params := url.Values{}
if opts.RepoSearchTerm != (scm.RepoSearchTerm{}) {
if opts.RepoSearchTerm.RepoName != "" {
params.Set("name", opts.RepoSearchTerm.RepoName)
}
}
if opts.ListOptions != (scm.ListOptions{}) {
if opts.ListOptions.Page > 1 {
params.Set("start", strconv.Itoa(
(opts.ListOptions.Page-1)*opts.ListOptions.Size),
)
}
if opts.ListOptions.Size != 0 {
params.Set("limit", strconv.Itoa(opts.ListOptions.Size))
}
}
params.Set("permission", "REPO_READ")
return params.Encode()
}
func encodePullRequestListOptions(opts scm.PullRequestListOptions) string {
params := url.Values{}
if opts.Page > 1 {

@ -120,6 +120,9 @@ type (
// List returns a list of repositories.
List(context.Context, ListOptions) ([]*Repository, *Response, error)
// ListV2 returns a list of repositories based on the searchTerm passed.
ListV2(context.Context, RepoListOptions) ([]*Repository, *Response, error)
// ListHooks returns a list or repository hooks.
ListHooks(context.Context, string, ListOptions) ([]*Hook, *Response, error)

Loading…
Cancel
Save