woodpecker/server/forge/bitbucketdatacenter/convert.go
2024-11-18 14:49:12 +01:00

175 lines
5 KiB
Go

// Copyright 2024 Woodpecker Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package bitbucketdatacenter
import (
"fmt"
"net/url"
"strings"
"time"
bb "github.com/neticdk/go-bitbucket/bitbucket"
"golang.org/x/oauth2"
"go.woodpecker-ci.org/woodpecker/v2/server/model"
)
func convertStatus(status model.StatusValue) bb.BuildStatusState {
switch status {
case model.StatusPending, model.StatusRunning:
return bb.BuildStatusStateInProgress
case model.StatusSuccess:
return bb.BuildStatusStateSuccessful
default:
return bb.BuildStatusStateFailed
}
}
func convertID(id uint64) model.ForgeRemoteID {
return model.ForgeRemoteID(fmt.Sprintf("%d", id))
}
func anonymizeLink(link string) (href string) {
parsed, err := url.Parse(link)
if err != nil {
return link
}
parsed.User = nil
return parsed.String()
}
func convertRepo(from *bb.Repository, perm *model.Perm, branch string) *model.Repo {
r := &model.Repo{
ForgeRemoteID: convertID(from.ID),
Name: from.Slug,
Owner: from.Project.Key,
Branch: branch,
SCMKind: model.RepoGit,
IsSCMPrivate: true, // Since we have to use Netrc it has to always be private :/ TODO: Is this really true?
FullName: fmt.Sprintf("%s/%s", from.Project.Key, from.Slug),
Perm: perm,
PREnabled: true,
}
for _, l := range from.Links["clone"] {
if l.Name == "http" {
r.Clone = anonymizeLink(l.Href)
}
}
if l, ok := from.Links["self"]; ok && len(l) > 0 {
r.ForgeURL = l[0].Href
}
return r
}
func convertRepositoryPushEvent(ev *bb.RepositoryPushEvent, baseURL string) *model.Pipeline {
if len(ev.Changes) == 0 {
return nil
}
change := ev.Changes[0]
if change.ToHash == "0000000000000000000000000000000000000000" {
// No ToHash present - could be "DELETE"
return nil
}
if change.Type == bb.RepositoryPushEventChangeTypeDelete {
return nil
}
pipeline := &model.Pipeline{
Commit: change.ToHash,
Branch: change.Ref.DisplayID,
Message: "",
Avatar: bitbucketAvatarURL(baseURL, ev.Actor.Slug),
Author: authorLabel(ev.Actor.Name),
Email: ev.Actor.Email,
Timestamp: time.Time(ev.Date).UTC().Unix(),
Ref: ev.Changes[0].RefId,
ForgeURL: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, ev.Repository.Project.Key, ev.Repository.Slug, change.ToHash),
}
if strings.HasPrefix(ev.Changes[0].RefId, "refs/tags/") {
pipeline.Event = model.EventTag
} else {
pipeline.Event = model.EventPush
}
return pipeline
}
func convertPullRequestEvent(ev *bb.PullRequestEvent, baseURL string) *model.Pipeline {
pipeline := &model.Pipeline{
Commit: ev.PullRequest.Source.Latest,
Branch: ev.PullRequest.Source.DisplayID,
Title: ev.PullRequest.Title,
Message: "",
Avatar: bitbucketAvatarURL(baseURL, ev.Actor.Slug),
Author: authorLabel(ev.Actor.Name),
Email: ev.Actor.Email,
Timestamp: time.Time(ev.Date).UTC().Unix(),
Ref: fmt.Sprintf("refs/pull-requests/%d/from", ev.PullRequest.ID),
ForgeURL: fmt.Sprintf("%s/projects/%s/repos/%s/commits/%s", baseURL, ev.PullRequest.Source.Repository.Project.Key, ev.PullRequest.Source.Repository.Slug, ev.PullRequest.Source.Latest),
Refspec: fmt.Sprintf("%s:%s", ev.PullRequest.Source.DisplayID, ev.PullRequest.Target.DisplayID),
FromFork: ev.PullRequest.Source.Repository.ID != ev.PullRequest.Target.Repository.ID,
}
if ev.EventKey == bb.EventKeyPullRequestMerged || ev.EventKey == bb.EventKeyPullRequestDeclined || ev.EventKey == bb.EventKeyPullRequestDeleted {
pipeline.Event = model.EventPullClosed
} else {
pipeline.Event = model.EventPull
}
return pipeline
}
func authorLabel(name string) string {
var result string
const maxNameLength = 40
if len(name) > maxNameLength {
result = name[0:37] + "..."
} else {
result = name
}
return result
}
func convertUser(user *bb.User, baseURL string) *model.User {
return &model.User{
ForgeRemoteID: model.ForgeRemoteID(fmt.Sprintf("%d", user.ID)),
Login: user.Slug,
Email: user.Email,
Avatar: bitbucketAvatarURL(baseURL, user.Slug),
}
}
func bitbucketAvatarURL(baseURL, slug string) string {
return fmt.Sprintf("%s/users/%s/avatar.png", baseURL, slug)
}
func convertListOptions(p *model.ListOptions) bb.ListOptions {
if p.All {
return bb.ListOptions{}
}
return bb.ListOptions{Limit: uint(p.PerPage), Start: uint((p.Page - 1) * p.PerPage)}
}
func updateUserCredentials(u *model.User, t *oauth2.Token) {
u.Token = t.AccessToken
u.Secret = t.RefreshToken
u.Expiry = t.Expiry.UTC().Unix()
}