mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2025-09-13 15:39:55 +00:00
Support bitbucket Dir() / multi-workflows (#2045)
This commit is contained in:
committed by
GitHub
parent
c36cb9da65
commit
4ad2c4eb45
@@ -8,7 +8,7 @@
|
|||||||
| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
| Event: Tag | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
||||||
| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
| Event: Pull-Request | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| Event: Deploy | :white_check_mark: | :x: | :x: | :x: |
|
| Event: Deploy | :white_check_mark: | :x: | :x: | :x: |
|
||||||
| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: |
|
| [Multiple workflows](../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: |
|
||||||
| [when.path filter](../../20-usage/20-pipeline-syntax.md#path) | :white_check_mark: | :white_check_mark:¹ | :white_check_mark: | :x: |
|
| [when.path filter](../../20-usage/20-pipeline-syntax.md#path) | :white_check_mark: | :white_check_mark:¹ | :white_check_mark: | :x: |
|
||||||
|
|
||||||
¹ for pull requests at least Gitea version 1.17 is required
|
¹ for pull requests at least Gitea version 1.17 is required
|
||||||
|
@@ -20,17 +20,17 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
|
|
||||||
shared_utils "github.com/woodpecker-ci/woodpecker/shared/utils"
|
|
||||||
|
|
||||||
"github.com/woodpecker-ci/woodpecker/server"
|
"github.com/woodpecker-ci/woodpecker/server"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge"
|
"github.com/woodpecker-ci/woodpecker/server/forge"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge/bitbucket/internal"
|
"github.com/woodpecker-ci/woodpecker/server/forge/bitbucket/internal"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/forge/common"
|
"github.com/woodpecker-ci/woodpecker/server/forge/common"
|
||||||
forge_types "github.com/woodpecker-ci/woodpecker/server/forge/types"
|
forge_types "github.com/woodpecker-ci/woodpecker/server/forge/types"
|
||||||
"github.com/woodpecker-ci/woodpecker/server/model"
|
"github.com/woodpecker-ci/woodpecker/server/model"
|
||||||
|
shared_utils "github.com/woodpecker-ci/woodpecker/shared/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bitbucket cloud endpoints.
|
// Bitbucket cloud endpoints.
|
||||||
@@ -223,8 +223,52 @@ func (c *config) File(ctx context.Context, u *model.User, r *model.Repo, p *mode
|
|||||||
return []byte(*config), err
|
return []byte(*config), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *config) Dir(_ context.Context, _ *model.User, _ *model.Repo, _ *model.Pipeline, _ string) ([]*forge_types.FileMeta, error) {
|
// Dir fetches a folder from the bitbucket repository
|
||||||
return nil, forge_types.ErrNotImplemented
|
func (c *config) Dir(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, f string) ([]*forge_types.FileMeta, error) {
|
||||||
|
var page *string
|
||||||
|
repoPathFiles := []*forge_types.FileMeta{}
|
||||||
|
client := c.newClient(ctx, u)
|
||||||
|
for {
|
||||||
|
filesResp, err := client.GetRepoFiles(r.Owner, r.Name, p.Commit, f, page)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, file := range filesResp.Values {
|
||||||
|
_, filename := filepath.Split(file.Path)
|
||||||
|
repoFile := forge_types.FileMeta{
|
||||||
|
Name: filename,
|
||||||
|
}
|
||||||
|
if file.Type == "commit_file" {
|
||||||
|
fileData, err := c.newClient(ctx, u).FindSource(r.Owner, r.Name, p.Commit, file.Path)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if fileData != nil {
|
||||||
|
repoFile.Data = []byte(*fileData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
repoPathFiles = append(repoPathFiles, &repoFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for more results page
|
||||||
|
if filesResp.Next == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
nextPageURL, err := url.Parse(*filesResp.Next)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
params, err := url.ParseQuery(nextPageURL.RawQuery)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
nextPage := params.Get("page")
|
||||||
|
if len(nextPage) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
page = &nextPage
|
||||||
|
}
|
||||||
|
return repoPathFiles, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status creates a pipeline status for the Bitbucket commit.
|
// Status creates a pipeline status for the Bitbucket commit.
|
||||||
|
@@ -178,6 +178,20 @@ func Test_bitbucket(t *testing.T) {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
g.Describe("When requesting repo directory contents", func() {
|
||||||
|
g.It("Should return the details", func() {
|
||||||
|
files, err := c.Dir(ctx, fakeUser, fakeRepo, fakePipeline, "/dir")
|
||||||
|
g.Assert(err).IsNil()
|
||||||
|
g.Assert(len(files)).Equal(3)
|
||||||
|
g.Assert(files[0].Name).Equal("README.md")
|
||||||
|
g.Assert(string(files[0].Data)).Equal("dummy payload")
|
||||||
|
})
|
||||||
|
g.It("Should handle not found errors", func() {
|
||||||
|
_, err := c.Dir(ctx, fakeUser, fakeRepo, fakePipeline, "/dir_not_found")
|
||||||
|
g.Assert(err).IsNotNil()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
g.Describe("When activating a repository", func() {
|
g.Describe("When activating a repository", func() {
|
||||||
g.It("Should error when malformed hook", func() {
|
g.It("Should error when malformed hook", func() {
|
||||||
err := c.Activate(ctx, fakeUser, fakeRepo, "%gh&%ij")
|
err := c.Activate(ctx, fakeUser, fakeRepo, "%gh&%ij")
|
||||||
|
@@ -108,6 +108,10 @@ func getRepoHooks(c *gin.Context) {
|
|||||||
|
|
||||||
func getRepoFile(c *gin.Context) {
|
func getRepoFile(c *gin.Context) {
|
||||||
switch c.Param("file") {
|
switch c.Param("file") {
|
||||||
|
case "dir":
|
||||||
|
c.String(200, repoDirPayload)
|
||||||
|
case "dir_not_found/":
|
||||||
|
c.String(404, "")
|
||||||
case "file_not_found":
|
case "file_not_found":
|
||||||
c.String(404, "")
|
c.String(404, "")
|
||||||
default:
|
default:
|
||||||
@@ -223,6 +227,27 @@ const repoHookPayload = `
|
|||||||
|
|
||||||
const repoFilePayload = "dummy payload"
|
const repoFilePayload = "dummy payload"
|
||||||
|
|
||||||
|
const repoDirPayload = `
|
||||||
|
{
|
||||||
|
"pagelen": 10,
|
||||||
|
"page": 1,
|
||||||
|
"values": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"type": "commit_file"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "test",
|
||||||
|
"type": "commit_directory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".gitignore",
|
||||||
|
"type": "commit_file"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const userPayload = `
|
const userPayload = `
|
||||||
{
|
{
|
||||||
"username": "superman",
|
"username": "superman",
|
||||||
|
@@ -48,6 +48,7 @@ const (
|
|||||||
pathOrgPerms = "%s/2.0/workspaces/%s/permissions?%s"
|
pathOrgPerms = "%s/2.0/workspaces/%s/permissions?%s"
|
||||||
pathPullRequests = "%s/2.0/repositories/%s/%s/pullrequests"
|
pathPullRequests = "%s/2.0/repositories/%s/%s/pullrequests"
|
||||||
pathBranchCommits = "%s/2.0/repositories/%s/%s/commits/%s"
|
pathBranchCommits = "%s/2.0/repositories/%s/%s/commits/%s"
|
||||||
|
pathDir = "%s/2.0/repositories/%s/%s/src/%s%s"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type Client struct {
|
||||||
@@ -233,6 +234,16 @@ func (c *Client) GetWorkspace(name string) (*Workspace, error) {
|
|||||||
return out, err
|
return out, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetRepoFiles(owner, name, revision, path string, page *string) (*DirResp, error) {
|
||||||
|
out := new(DirResp)
|
||||||
|
uri := fmt.Sprintf(pathDir, c.base, owner, name, revision, path)
|
||||||
|
if page != nil {
|
||||||
|
uri += "?page=" + *page
|
||||||
|
}
|
||||||
|
_, err := c.do(uri, get, nil, out)
|
||||||
|
return out, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) do(rawurl, method string, in, out interface{}) (*string, error) {
|
func (c *Client) do(rawurl, method string, in, out interface{}) (*string, error) {
|
||||||
uri, err := url.Parse(rawurl)
|
uri, err := url.Parse(rawurl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@@ -283,3 +283,16 @@ type CommitsResp struct {
|
|||||||
type Commit struct {
|
type Commit struct {
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DirResp struct {
|
||||||
|
Page uint `json:"page"`
|
||||||
|
PageLen uint `json:"pagelen"`
|
||||||
|
Next *string `json:"next"`
|
||||||
|
Values []*Dir `json:"values"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Dir struct {
|
||||||
|
Path string `json:"path"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Size uint `json:"size"`
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user