Skip to content

Commit

Permalink
Implemented List function in the content service.
Browse files Browse the repository at this point in the history
  • Loading branch information
chhsia0 committed Oct 23, 2019
1 parent c18d7a0 commit d78e793
Show file tree
Hide file tree
Showing 25 changed files with 1,337 additions and 31 deletions.
49 changes: 49 additions & 0 deletions scm/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,52 @@ func (r Role) String() (s string) {
return "unknown"
}
}

// ContentKind defines the kind of a content in a directory.
type ContentKind int

// ContentKind values.
const (
ContentKindUnsupported ContentKind = iota
ContentKindFile
ContentKindDirectory
ContentKindSymlink
ContentKindGitlink
)

// String returns the string representation of ContentKind.
func (k ContentKind) String() string {
switch k {
case ContentKindFile:
return "file"
case ContentKindDirectory:
return "directory"
case ContentKindSymlink:
return "symlink"
case ContentKindGitlink:
return "gitlink"
default:
return "unsupported"
}
}

// UnmarshalJSON unmarshales the JSON-encoded ContentKind.
func (k *ContentKind) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return err
}
switch s {
case ContentKindFile.String():
*k = ContentKindFile
case ContentKindDirectory.String():
*k = ContentKindDirectory
case ContentKindSymlink.String():
*k = ContentKindSymlink
case ContentKindGitlink.String():
*k = ContentKindGitlink
default:
*k = ContentKindUnsupported
}
return nil
}
11 changes: 11 additions & 0 deletions scm/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ type (
Data []byte
}

// ContentInfo stores the kind of any content in a repository.
ContentInfo struct {
Path string
Kind ContentKind
}

// ContentService provides access to repositroy content.
ContentService interface {
// Find returns the repository file content by path.
Expand All @@ -35,5 +41,10 @@ type (

// Delete deletes a reository file.
Delete(ctx context.Context, repo, path, ref string) (*Response, error)

// List returns a list of contents in a repository directory by path. It is
// up to the driver to list the directory recursively or non-recursively,
// but a robust driver should return a non-recursive list if possible.
List(ctx context.Context, repo, path, ref string, opts ListOptions) ([]*ContentInfo, *Response, error)
}
)
56 changes: 53 additions & 3 deletions scm/driver/bitbucket/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ type contentService struct {

func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) {
endpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s", repo, ref, path)
buf := new(bytes.Buffer)
res, err := s.client.do(ctx, "GET", endpoint, nil, buf)
out := new(bytes.Buffer)
res, err := s.client.do(ctx, "GET", endpoint, nil, out)
return &scm.Content{
Path: path,
Data: buf.Bytes(),
Data: out.Bytes(),
}, res, err
}

Expand All @@ -37,3 +37,53 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params *
func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) {
return nil, scm.ErrNotSupported
}

func (s *contentService) List(ctx context.Context, repo, path, ref string, opts scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) {
endpoint := fmt.Sprintf("/2.0/repositories/%s/src/%s/%s?%s", repo, ref, path, encodeListOptions(opts))
out := new(contents)
res, err := s.client.do(ctx, "GET", endpoint, nil, out)
copyPagination(out.pagination, res)
return convertContentInfoList(out), res, err
}

type contents struct {
pagination
Values []*content `json:"values"`
}

type content struct {
Path string `json:"path"`
Type string `json:"type"`
Attributes []string `json:"attributes"`
}

func convertContentInfoList(from *contents) []*scm.ContentInfo {
to := []*scm.ContentInfo{}
for _, v := range from.Values {
to = append(to, convertContentInfo(v))
}
return to
}

func convertContentInfo(from *content) *scm.ContentInfo {
to := &scm.ContentInfo{Path: from.Path}
switch from.Type {
case "commit_file":
to.Kind = func() scm.ContentKind {
for _, attr := range from.Attributes {
switch attr {
case "link":
return scm.ContentKindSymlink
case "subrepository":
return scm.ContentKindGitlink
}
}
return scm.ContentKindFile
}()
case "commit_directory":
to.Kind = scm.ContentKindDirectory
default:
to.Kind = scm.ContentKindUnsupported
}
return to
}
25 changes: 25 additions & 0 deletions scm/driver/bitbucket/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,28 @@ func TestContentDelete(t *testing.T) {
t.Errorf("Expect Not Supported error")
}
}

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

gock.New("https://api.bitbucket.org").
Get("/2.0/repositories/atlassian/atlaskit/src/master/packages/activity").
Reply(200).
Type("application/json").
File("testdata/content_list.json")

client, _ := New("https://api.bitbucket.org")
got, _, err := client.Contents.List(context.Background(), "atlassian/atlaskit", "packages/activity", "master", scm.ListOptions{})
if err != nil {
t.Error(err)
}

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

if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Unexpected Results")
t.Log(diff)
}
}
1 change: 1 addition & 0 deletions scm/driver/bitbucket/testdata/content_list.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"pagelen":10,"values":[{"path":"packages/activity/build","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/build/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/dist","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/dist/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/docs","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/docs/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/src","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/src/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"path":"packages/activity/test","type":"commit_directory","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/test/?format=meta"}},"commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}}},{"mimetype":null,"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/.npmignore"}},"path":"packages/activity/.npmignore","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":10},{"mimetype":null,"links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/LICENSE"}},"path":"packages/activity/LICENSE","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":558},{"mimetype":"text/vnd.trolltech.linguist","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/index.ts"}},"path":"packages/activity/index.ts","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":494},{"mimetype":"application/json","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json"}},"path":"packages/activity/package.json","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":1914},{"mimetype":"text/vnd.trolltech.linguist","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts"},"meta":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts?format=meta"},"history":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/filehistory/710db794f15bd187db9e7a7b952aac48ebac08bb/packages/activity/package.json.d.ts"}},"path":"packages/activity/package.json.d.ts","commit":{"type":"commit","hash":"710db794f15bd187db9e7a7b952aac48ebac08bb","links":{"self":{"href":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/commit/710db794f15bd187db9e7a7b952aac48ebac08bb"},"html":{"href":"https://bitbucket.org/atlassian/atlaskit/commits/710db794f15bd187db9e7a7b952aac48ebac08bb"}}},"attributes":[],"type":"commit_file","size":61}],"page":1,"next":"https://api.bitbucket.org/2.0/repositories/atlassian/atlaskit/src/master/packages/activity?page=8xhd"}
42 changes: 42 additions & 0 deletions scm/driver/bitbucket/testdata/content_list.json.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
[
{
"path": "packages/activity/build",
"kind": "directory"
},
{
"path": "packages/activity/dist",
"kind": "directory"
},
{
"path": "packages/activity/docs",
"kind": "directory"
},
{
"path": "packages/activity/src",
"kind": "directory"
},
{
"path": "packages/activity/test",
"kind": "directory"
},
{
"path": "packages/activity/.npmignore",
"kind": "file"
},
{
"path": "packages/activity/LICENSE",
"kind": "file"
},
{
"path": "packages/activity/index.ts",
"kind": "file"
},
{
"path": "packages/activity/package.json",
"kind": "file"
},
{
"path": "packages/activity/package.json.d.ts",
"kind": "file"
}
]
48 changes: 41 additions & 7 deletions scm/driver/gitea/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"bytes"
"context"
"fmt"
"strings"

"github.com/drone/go-scm/scm"
)
Expand All @@ -18,14 +17,12 @@ type contentService struct {
}

func (s *contentService) Find(ctx context.Context, repo, path, ref string) (*scm.Content, *scm.Response, error) {
ref = strings.TrimPrefix(ref, "refs/heads/")
ref = strings.TrimPrefix(ref, "refs/tags/")
endpoint := fmt.Sprintf("api/v1/repos/%s/raw/%s/%s", repo, ref, path)
buf := new(bytes.Buffer)
res, err := s.client.do(ctx, "GET", endpoint, nil, buf)
endpoint := fmt.Sprintf("api/v1/repos/%s/raw/%s/%s", repo, scm.TrimRef(ref), path)
out := new(bytes.Buffer)
res, err := s.client.do(ctx, "GET", endpoint, nil, out)
return &scm.Content{
Path: path,
Data: buf.Bytes(),
Data: out.Bytes(),
}, res, err
}

Expand All @@ -40,3 +37,40 @@ func (s *contentService) Update(ctx context.Context, repo, path string, params *
func (s *contentService) Delete(ctx context.Context, repo, path, ref string) (*scm.Response, error) {
return nil, scm.ErrNotSupported
}

func (s *contentService) List(ctx context.Context, repo, path, ref string, _ scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) {
endpoint := fmt.Sprintf("api/v1/repos/%s/contents/%s?ref=%s", repo, path, ref)
out := []*content{}
res, err := s.client.do(ctx, "GET", endpoint, nil, &out)
return convertContentInfoList(out), res, err
}

type content struct {
Path string `json:"path"`
Type string `json:"type"`
}

func convertContentInfoList(from []*content) []*scm.ContentInfo {
to := []*scm.ContentInfo{}
for _, v := range from {
to = append(to, convertContentInfo(v))
}
return to
}

func convertContentInfo(from *content) *scm.ContentInfo {
to := &scm.ContentInfo{Path: from.Path}
switch from.Type {
case "file":
to.Kind = scm.ContentKindFile
case "dir":
to.Kind = scm.ContentKindDirectory
case "symlink":
to.Kind = scm.ContentKindSymlink
case "submodule":
to.Kind = scm.ContentKindGitlink
default:
to.Kind = scm.ContentKindUnsupported
}
return to
}
35 changes: 35 additions & 0 deletions scm/driver/gitea/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ package gitea

import (
"context"
"encoding/json"
"io/ioutil"
"testing"

"github.com/drone/go-scm/scm"
"github.com/google/go-cmp/cmp"
"github.com/h2non/gock"
)

Expand Down Expand Up @@ -63,3 +66,35 @@ func TestContentDelete(t *testing.T) {
t.Errorf("Expect Not Supported error")
}
}

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

gock.New("https://try.gitea.io").
Get("/api/v1/repos/go-gitea/gitea/contents/docs/content/doc").
MatchParam("ref", "master").
Reply(200).
Type("application/json").
File("testdata/content_list.json")

client, _ := New("https://try.gitea.io")
got, _, err := client.Contents.List(
context.Background(),
"go-gitea/gitea",
"docs/content/doc",
"master",
scm.ListOptions{},
)
if err != nil {
t.Error(err)
}

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

if diff := cmp.Diff(got, want); diff != "" {
t.Errorf("Unexpected Results")
t.Log(diff)
}
}
1 change: 1 addition & 0 deletions scm/driver/gitea/testdata/content_list.json

Large diffs are not rendered by default.

Loading

0 comments on commit d78e793

Please sign in to comment.