From aae9d61883a7c58927afe172bcfb96def69c92e3 Mon Sep 17 00:00:00 2001 From: Henrik Huitti Date: Thu, 12 Jun 2025 10:09:38 +0300 Subject: [PATCH] Support for pull request file changes in bitbucketdatacenter (#5205) Co-authored-by: Anbraten <6918444+anbraten@users.noreply.github.com> --- docs/docs/20-usage/20-workflow-syntax.md | 3 +- .../10-configuration/12-forges/11-overview.md | 2 +- go.mod | 2 +- go.sum | 4 +- .../bitbucketdatacenter.go | 37 +++++++++++++++++-- server/forge/bitbucketdatacenter/convert.go | 2 +- .../forge/bitbucketdatacenter/convert_test.go | 2 + 7 files changed, 42 insertions(+), 10 deletions(-) diff --git a/docs/docs/20-usage/20-workflow-syntax.md b/docs/docs/20-usage/20-workflow-syntax.md index 646312bb7..7971876e7 100644 --- a/docs/docs/20-usage/20-workflow-syntax.md +++ b/docs/docs/20-usage/20-workflow-syntax.md @@ -393,8 +393,7 @@ when: #### `path` :::info -Path conditions are applied only to **push** and **pull_request** events. -It is currently **only available** for GitHub, GitLab and Gitea (version 1.18.0 and newer) +Path conditions are applied only to **push** and **pull_request** events. This feature is currently available for all forges except Bitbucket Cloud. ::: Execute a step only on a pipeline with certain files being changed: diff --git a/docs/docs/30-administration/10-configuration/12-forges/11-overview.md b/docs/docs/30-administration/10-configuration/12-forges/11-overview.md index 701a7a489..ca1c79b6b 100644 --- a/docs/docs/30-administration/10-configuration/12-forges/11-overview.md +++ b/docs/docs/30-administration/10-configuration/12-forges/11-overview.md @@ -10,6 +10,6 @@ | Event: Release | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | | Event: Deploy¹ | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | | [Multiple workflows](../../../20-usage/25-workflows.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| [when.path filter](../../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | +| [when.path filter](../../../20-usage/20-workflow-syntax.md#path) | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | ¹ The deployment event can be triggered for all forges from Woodpecker directly. However, only GitHub can trigger them using webhooks. diff --git a/go.mod b/go.mod index ba7deb5a5..9bb1a575b 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,7 @@ require ( github.com/mattn/go-sqlite3 v1.14.28 github.com/moby/term v0.5.2 github.com/muesli/termenv v0.16.0 - github.com/neticdk/go-bitbucket v1.0.2 + github.com/neticdk/go-bitbucket v1.0.3 github.com/oklog/ulid/v2 v2.1.1 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.22.0 diff --git a/go.sum b/go.sum index 54ec5758d..02437f1d4 100644 --- a/go.sum +++ b/go.sum @@ -440,8 +440,8 @@ github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/neticdk/go-bitbucket v1.0.2 h1:zNyz/fJ7ANcyfNj3ld1zjEaTG+5iRkQ/R4+FY7Kfe6A= -github.com/neticdk/go-bitbucket v1.0.2/go.mod h1:p1jIRloOKeteK0S5QwyFR2csHyQ7w5AhotXlo+LAs8M= +github.com/neticdk/go-bitbucket v1.0.3 h1:d4uk+WwwxanJZMMyP6DC1dZDnqopPTzzpcijdDkRt9w= +github.com/neticdk/go-bitbucket v1.0.3/go.mod h1:p1jIRloOKeteK0S5QwyFR2csHyQ7w5AhotXlo+LAs8M= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= diff --git a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go index ea1d4604a..afef944dc 100644 --- a/server/forge/bitbucketdatacenter/bitbucketdatacenter.go +++ b/server/forge/bitbucketdatacenter/bitbucketdatacenter.go @@ -481,6 +481,7 @@ func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model var repo *model.Repo var pipe *model.Pipeline + switch e := ev.(type) { case *bb.RepositoryPushEvent: repo = convertRepo(&e.Repository, nil, "") @@ -494,7 +495,7 @@ func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model user, repo, err := c.getUserAndRepo(ctx, repo) if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to get user and repo: %w", err) } err = bb.ValidateSignature(r, payload, []byte(repo.Hash)) @@ -502,9 +503,15 @@ func (c *client) Hook(ctx context.Context, r *http.Request) (*model.Repo, *model return nil, nil, fmt.Errorf("unable to validate signature on incoming webhook payload: %w", err) } - pipe, err = c.updatePipelineFromCommit(ctx, user, repo, pipe) + switch e := ev.(type) { + case *bb.RepositoryPushEvent: + pipe, err = c.updatePipelineFromCommit(ctx, user, repo, pipe) + case *bb.PullRequestEvent: + pipe, err = c.updatePipelineFromPullRequest(ctx, user, repo, pipe, e.PullRequest.ID) + } + if err != nil { - return nil, nil, err + return nil, nil, fmt.Errorf("failed to update pipeline: %w", err) } if pipe == nil { @@ -572,6 +579,30 @@ func (c *client) updatePipelineFromCommit(ctx context.Context, u *model.User, r return p, nil } +func (c *client) updatePipelineFromPullRequest(ctx context.Context, u *model.User, r *model.Repo, p *model.Pipeline, pullRequestID uint64) (*model.Pipeline, error) { + bc, err := c.newClient(ctx, u) + if err != nil { + return nil, fmt.Errorf("unable to create bitbucket client: %w", err) + } + + opts := &bb.ListOptions{} + for { + changes, resp, err := bc.Projects.ListPullRequestChanges(ctx, r.Owner, r.Name, pullRequestID, opts) + if err != nil { + return nil, fmt.Errorf("unable to list changes in pull request: %w", err) + } + for _, ch := range changes { + p.ChangedFiles = append(p.ChangedFiles, ch.Path.Title) + } + if resp.LastPage { + break + } + opts.Start = resp.NextPageStart + } + + return p, nil +} + // Teams fetches all the projects for a given user and converts them into teams. func (c *client) Teams(ctx context.Context, u *model.User) ([]*model.Team, error) { opts := &bb.ListOptions{Limit: listLimit} diff --git a/server/forge/bitbucketdatacenter/convert.go b/server/forge/bitbucketdatacenter/convert.go index 14890ec2b..9eb5fcee3 100644 --- a/server/forge/bitbucketdatacenter/convert.go +++ b/server/forge/bitbucketdatacenter/convert.go @@ -114,7 +114,7 @@ func convertPullRequestEvent(ev *bb.PullRequestEvent, baseURL string) *model.Pip Commit: ev.PullRequest.Source.Latest, Branch: ev.PullRequest.Source.DisplayID, Title: ev.PullRequest.Title, - Message: "", + Message: ev.PullRequest.Title, Avatar: bitbucketAvatarURL(baseURL, ev.Actor.Slug), Author: authorLabel(ev.Actor.Name), Email: ev.Actor.Email, diff --git a/server/forge/bitbucketdatacenter/convert_test.go b/server/forge/bitbucketdatacenter/convert_test.go index b3e3c6bbc..e48f12f92 100644 --- a/server/forge/bitbucketdatacenter/convert_test.go +++ b/server/forge/bitbucketdatacenter/convert_test.go @@ -223,6 +223,7 @@ func Test_convertPullRequestEvent(t *testing.T) { Event: model.EventPull, Refspec: "branch:main", Title: "my title", + Message: "my title", }, to) } @@ -278,6 +279,7 @@ func Test_convertPullRequestCloseEvent(t *testing.T) { Event: model.EventPullClosed, Refspec: "branch:main", Title: "my title", + Message: "my title", }, to) }