diff --git a/github/client_repository_tree.go b/github/client_repository_tree.go index 7007f43a..d632e625 100644 --- a/github/client_repository_tree.go +++ b/github/client_repository_tree.go @@ -18,6 +18,7 @@ package github import ( "context" + "strings" "github.com/fluxcd/go-git-providers/gitprovider" "github.com/google/go-github/v42/github" @@ -115,8 +116,8 @@ func (c *TreeClient) Get(ctx context.Context, sha string, recursive bool) (*gitp } -// List files (blob) in a tree -func (c *TreeClient) List(ctx context.Context, sha string, recursive bool) ([]*gitprovider.TreeEntry, error) { +// List files (blob) in a tree givent the tree sha (path is not used with Github Tree client) +func (c *TreeClient) List(ctx context.Context, sha string, path string, recursive bool) ([]*gitprovider.TreeEntry, error) { treeInfo, err := c.Get(ctx, sha, recursive) if err != nil { return nil, err @@ -124,14 +125,16 @@ func (c *TreeClient) List(ctx context.Context, sha string, recursive bool) ([]*g treeEntries := make([]*gitprovider.TreeEntry, 0) for _, treeEntry := range treeInfo.Tree { if treeEntry.Type == "blob" { - treeEntries = append(treeEntries, &gitprovider.TreeEntry{ - Path: treeEntry.Path, - Mode: treeEntry.Mode, - Type: treeEntry.Type, - Size: treeEntry.Size, - SHA: treeEntry.SHA, - URL: treeEntry.URL, - }) + if path == "" || (path != "" && strings.HasPrefix(treeEntry.Path, path)) { + treeEntries = append(treeEntries, &gitprovider.TreeEntry{ + Path: treeEntry.Path, + Mode: treeEntry.Mode, + Type: treeEntry.Type, + Size: treeEntry.Size, + SHA: treeEntry.SHA, + URL: treeEntry.URL, + }) + } } } diff --git a/github/integration_test.go b/github/integration_test.go index 88f1413d..e9e1b9bd 100644 --- a/github/integration_test.go +++ b/github/integration_test.go @@ -628,8 +628,8 @@ var _ = Describe("GitHub Provider", func() { itemsToBeIgnored += 1 } - // List tree items - treeEntries, err := userRepo.Trees().List(ctx, commitSha, true) + // List tree items with no path provided + treeEntries, err := userRepo.Trees().List(ctx, commitSha, "", true) Expect(err).ToNot(HaveOccurred()) // Tree Entries should have length 5 for : LICENSE, README.md, 3 blob (files) @@ -641,6 +641,16 @@ var _ = Describe("GitHub Provider", func() { Expect(treeEntry.Path).To(Equal(*files[ind-2].Path)) } + //List tree items with path provided to filter on + treeEntries, err = userRepo.Trees().List(ctx, commitSha, "clustersDir/", true) + Expect(err).ToNot(HaveOccurred()) + + // Tree Entries should have length 3 for :3 blob (files) + Expect(treeEntries).To(HaveLen(3)) + for ind, treeEntry := range treeEntries { + Expect(treeEntry.Path).To(Equal(*files[ind].Path)) + } + }) AfterSuite(func() { diff --git a/gitlab/client_repository_tree.go b/gitlab/client_repository_tree.go index 7dbfd391..80ea9788 100644 --- a/gitlab/client_repository_tree.go +++ b/gitlab/client_repository_tree.go @@ -21,6 +21,7 @@ import ( "fmt" "github.com/fluxcd/go-git-providers/gitprovider" + "github.com/xanzy/go-gitlab" ) // TreeClient implements the gitprovider.TreeClient interface. @@ -44,7 +45,32 @@ func (c *TreeClient) Get(ctx context.Context, sha string, recursive bool) (*gitp } -// List files (blob) in a tree -func (c *TreeClient) List(ctx context.Context, sha string, recursive bool) ([]*gitprovider.TreeEntry, error) { - return nil, fmt.Errorf("error listing tree items %s. not implemented in gitlab yet", sha) +// List files (blob) in a tree, sha is represented by the branch name +func (c *TreeClient) List(ctx context.Context, sha string, path string, recursive bool) ([]*gitprovider.TreeEntry, error) { + opts := &gitlab.ListTreeOptions{ + Path: &path, + Ref: &sha, + Recursive: &recursive, + } + + treeFiles, _, err := c.c.Client().Repositories.ListTree(getRepoPath(c.ref), opts) + if err != nil { + return nil, err + } + + treeEntries := make([]*gitprovider.TreeEntry, 0) + for _, treeEntry := range treeFiles { + if treeEntry.Type == "blob" { + size := 0 + treeEntries = append(treeEntries, &gitprovider.TreeEntry{ + Path: treeEntry.Path, + Mode: treeEntry.Mode, + Type: treeEntry.Type, + Size: size, + ID: treeEntry.ID, + }) + } + } + + return treeEntries, nil } diff --git a/gitlab/integration_test.go b/gitlab/integration_test.go index baaf9224..dc9e4294 100644 --- a/gitlab/integration_test.go +++ b/gitlab/integration_test.go @@ -937,6 +937,47 @@ var _ = Describe("GitLab Provider", func() { Expect(*downloadedFile).To(Equal(files[ind])) } + }) + It("should be possible list repo tree files", func() { + userRepoRef := newUserRepoRef(testUserName, testRepoName) + + userRepo, err := c.UserRepositories().Get(ctx, userRepoRef) + Expect(err).ToNot(HaveOccurred()) + + defaultBranch := userRepo.Get().DefaultBranch + + path0 := "clustersDir/cluster/machine.yaml" + content0 := "machine0 yaml content" + path1 := "clustersDir/cluster/machine1.yaml" + content1 := "machine1 yaml content" + path2 := "clustersDir/cluster2/clusterSubDir/machine2.yaml" + content2 := "machine2 yaml content" + + files := []gitprovider.CommitFile{ + { + Path: &path0, + Content: &content0, + }, + { + Path: &path1, + Content: &content1, + }, + { + Path: &path2, + Content: &content2, + }, + } + + // List tree items + treeEntries, err := userRepo.Trees().List(ctx, *defaultBranch, "clustersDir/", true) + Expect(err).ToNot(HaveOccurred()) + + // Tree Entries should have length 3 for : 3 blob (files) + Expect(treeEntries).To(HaveLen(3)) + for ind, treeEntry := range treeEntries { + Expect(treeEntry.Path).To(Equal(*files[ind].Path)) + } + }) AfterSuite(func() { diff --git a/gitprovider/client.go b/gitprovider/client.go index 1d2da343..86b4880b 100644 --- a/gitprovider/client.go +++ b/gitprovider/client.go @@ -251,6 +251,6 @@ type TreeClient interface { Create(ctx context.Context, tree *TreeInfo) (*TreeInfo, error) // Get retrieves tree information and items Get(ctx context.Context, sha string, recursive bool) (*TreeInfo, error) - // List retrieves list of tree files (files/blob) - List(ctx context.Context, sha string, recursive bool) ([]*TreeEntry, error) + // List retrieves list of tree files (files/blob) from given tree sha/id or path+branch + List(ctx context.Context, sha string, path string, recursive bool) ([]*TreeEntry, error) } diff --git a/gitprovider/types_repository.go b/gitprovider/types_repository.go index f05d75e0..24cc6ce6 100644 --- a/gitprovider/types_repository.go +++ b/gitprovider/types_repository.go @@ -243,6 +243,8 @@ type TreeEntry struct { Content string `json:"content"` // URL is the url that can be used to retrieve the details of the blob, tree of commit URL string `json:"url"` + // Id is the id of the tree entry retrieved from Gitlab (Optional) + ID string `json:"id"` } // TreeInfo contains high-level information about a git Tree representing the hierarchy between files in a Git repository diff --git a/stash/client_repository_tree.go b/stash/client_repository_tree.go index 2a8be8f6..86edeecc 100644 --- a/stash/client_repository_tree.go +++ b/stash/client_repository_tree.go @@ -45,6 +45,6 @@ func (c *TreeClient) Get(ctx context.Context, sha string, recursive bool) (*gitp } // List files (blob) in a tree -func (c *TreeClient) List(ctx context.Context, sha string, recursive bool) ([]*gitprovider.TreeEntry, error) { +func (c *TreeClient) List(ctx context.Context, sha string, path string, recursive bool) ([]*gitprovider.TreeEntry, error) { return nil, fmt.Errorf("error listing tree items %s. not implemented in stash yet", sha) }