You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
383 lines
10 KiB
Go
383 lines
10 KiB
Go
// Copyright 2017 Drone.IO Inc. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package bitbucket
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/url"
|
|
"time"
|
|
|
|
"git.awesome-for.me/liuzhiguo/go-scm/scm"
|
|
)
|
|
|
|
type cloneLink struct {
|
|
link
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
type repository struct {
|
|
UUID string `json:"uuid"`
|
|
SCM string `json:"scm"`
|
|
FullName string `json:"full_name"`
|
|
IsPrivate bool `json:"is_private"`
|
|
CreatedOn time.Time `json:"created_on"`
|
|
UpdatedOn time.Time `json:"updated_on"`
|
|
Mainbranch struct {
|
|
Type string `json:"type"`
|
|
Name string `json:"name"`
|
|
} `json:"mainbranch"`
|
|
Links struct {
|
|
HTML link `json:"html"`
|
|
Clone []cloneLink `json:"clone"`
|
|
} `json:"links"`
|
|
}
|
|
|
|
type perms struct {
|
|
Values []*perm `json:"values"`
|
|
}
|
|
|
|
type perm struct {
|
|
Permissions string `json:"permission"`
|
|
}
|
|
|
|
type hooks struct {
|
|
pagination
|
|
Values []*hook `json:"values"`
|
|
}
|
|
|
|
type hook struct {
|
|
Description string `json:"description"`
|
|
URL string `json:"url"`
|
|
SkipCertVerification bool `json:"skip_cert_verification,omitempty"`
|
|
Active bool `json:"active"`
|
|
Events []string `json:"events"`
|
|
UUID string `json:"uuid"`
|
|
}
|
|
|
|
type hookInput struct {
|
|
Description string `json:"description"`
|
|
URL string `json:"url"`
|
|
SkipCertVerification bool `json:"skip_cert_verification,omitempty"`
|
|
Active bool `json:"active"`
|
|
Events []string `json:"events"`
|
|
}
|
|
|
|
type repositoryService struct {
|
|
client *wrapper
|
|
}
|
|
|
|
// Find returns the repository by name.
|
|
func (s *repositoryService) Find(ctx context.Context, repo string) (*scm.Repository, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s", repo)
|
|
out := new(repository)
|
|
res, err := s.client.do(ctx, "GET", path, nil, out)
|
|
return convertRepository(out), res, err
|
|
}
|
|
|
|
// FindHook returns a repository hook.
|
|
func (s *repositoryService) FindHook(ctx context.Context, repo string, id string) (*scm.Hook, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s/hooks/%s", repo, id)
|
|
out := new(hook)
|
|
res, err := s.client.do(ctx, "GET", path, nil, out)
|
|
return convertHook(out), res, err
|
|
}
|
|
|
|
// FindPerms returns the repository permissions.
|
|
func (s *repositoryService) FindPerms(ctx context.Context, repo string) (*scm.Perm, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/user/permissions/repositories?q=repository.full_name=%q", repo)
|
|
out := new(perms)
|
|
res, err := s.client.do(ctx, "GET", path, nil, out)
|
|
return convertPerms(out), res, err
|
|
}
|
|
|
|
// List returns the user repository list.
|
|
func (s *repositoryService) List(ctx context.Context, opts scm.ListOptions) ([]*scm.Repository, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories?%s", encodeListRoleOptions(opts))
|
|
if opts.URL != "" {
|
|
path = opts.URL
|
|
}
|
|
out := new(repositories)
|
|
res, err := s.client.do(ctx, "GET", path, nil, &out)
|
|
copyPagination(out.pagination, res)
|
|
return convertRepositoryList(out), res, err
|
|
}
|
|
|
|
// ListV2 returns the user repository list based on the searchTerm passed.
|
|
func (s *repositoryService) ListV2(ctx context.Context, opts scm.RepoListOptions) ([]*scm.Repository, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories?%s", encodeRepoListOptions(opts))
|
|
if opts.ListOptions.URL != "" {
|
|
path = opts.ListOptions.URL
|
|
}
|
|
out := new(repositories)
|
|
res, err := s.client.do(ctx, "GET", path, nil, &out)
|
|
copyPagination(out.pagination, res)
|
|
return convertRepositoryList(out), res, err
|
|
}
|
|
|
|
// ListHooks returns a list or repository hooks.
|
|
func (s *repositoryService) ListHooks(ctx context.Context, repo string, opts scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s/hooks?%s", repo, encodeListOptions(opts))
|
|
out := new(hooks)
|
|
res, err := s.client.do(ctx, "GET", path, nil, out)
|
|
copyPagination(out.pagination, res)
|
|
return convertHookList(out), res, err
|
|
}
|
|
|
|
// ListStatus returns a list of commit statuses.
|
|
func (s *repositoryService) ListStatus(ctx context.Context, repo, ref string, opts scm.ListOptions) ([]*scm.Status, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s/commit/%s/statuses?%s", repo, ref, encodeListOptions(opts))
|
|
out := new(statuses)
|
|
res, err := s.client.do(ctx, "GET", path, nil, out)
|
|
copyPagination(out.pagination, res)
|
|
return convertStatusList(out), res, err
|
|
}
|
|
|
|
// CreateHook creates a new repository webhook.
|
|
func (s *repositoryService) CreateHook(ctx context.Context, repo string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) {
|
|
target, err := url.Parse(input.Target)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
params := target.Query()
|
|
params.Set("secret", input.Secret)
|
|
target.RawQuery = params.Encode()
|
|
|
|
path := fmt.Sprintf("2.0/repositories/%s/hooks", repo)
|
|
in := new(hookInput)
|
|
in.URL = target.String()
|
|
in.SkipCertVerification = input.SkipVerify
|
|
in.Active = true
|
|
in.Description = input.Name
|
|
in.Events = append(
|
|
input.NativeEvents,
|
|
convertFromHookEvents(input.Events)...,
|
|
)
|
|
out := new(hook)
|
|
res, err := s.client.do(ctx, "POST", path, in, out)
|
|
return convertHook(out), res, err
|
|
}
|
|
|
|
// CreateStatus creates a new commit status.
|
|
func (s *repositoryService) CreateStatus(ctx context.Context, repo, ref string, input *scm.StatusInput) (*scm.Status, *scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s/commit/%s/statuses/build", repo, ref)
|
|
in := &status{
|
|
State: convertFromState(input.State),
|
|
Name: input.Title,
|
|
Desc: input.Desc,
|
|
Key: input.Label,
|
|
URL: input.Target,
|
|
}
|
|
out := new(status)
|
|
res, err := s.client.do(ctx, "POST", path, in, out)
|
|
return convertStatus(out), res, err
|
|
}
|
|
|
|
// UpdateHook updates a repository webhook.
|
|
func (s *repositoryService) UpdateHook(ctx context.Context, repo, id string, input *scm.HookInput) (*scm.Hook, *scm.Response, error) {
|
|
target, err := url.Parse(input.Target)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
params := target.Query()
|
|
params.Set("secret", input.Secret)
|
|
target.RawQuery = params.Encode()
|
|
|
|
path := fmt.Sprintf("2.0/repositories/%s/hooks/%s", repo, id)
|
|
in := new(hookInput)
|
|
in.URL = target.String()
|
|
in.SkipCertVerification = input.SkipVerify
|
|
in.Active = true
|
|
in.Description = input.Name
|
|
in.Events = append(
|
|
input.NativeEvents,
|
|
convertFromHookEvents(input.Events)...,
|
|
)
|
|
out := new(hook)
|
|
res, err := s.client.do(ctx, "PUT", path, in, out)
|
|
return convertHook(out), res, err
|
|
}
|
|
|
|
// DeleteHook deletes a repository webhook.
|
|
func (s *repositoryService) DeleteHook(ctx context.Context, repo string, id string) (*scm.Response, error) {
|
|
path := fmt.Sprintf("2.0/repositories/%s/hooks/%s", repo, id)
|
|
return s.client.do(ctx, "DELETE", path, nil, nil)
|
|
}
|
|
|
|
// helper function to convert from the gogs repository list to
|
|
// the common repository structure.
|
|
func convertRepositoryList(from *repositories) []*scm.Repository {
|
|
to := []*scm.Repository{}
|
|
for _, v := range from.Values {
|
|
to = append(to, convertRepository(v))
|
|
}
|
|
return to
|
|
}
|
|
|
|
// helper function to convert from the gogs repository structure
|
|
// to the common repository structure.
|
|
func convertRepository(from *repository) *scm.Repository {
|
|
namespace, name := scm.Split(from.FullName)
|
|
return &scm.Repository{
|
|
ID: from.UUID,
|
|
Name: name,
|
|
Namespace: namespace,
|
|
Link: from.Links.HTML.Href,
|
|
Branch: from.Mainbranch.Name,
|
|
Private: from.IsPrivate,
|
|
CloneSSH: extractCloneLink(from.Links.Clone, "ssh"),
|
|
Clone: anonymizeLink(extractCloneLink(from.Links.Clone, "https", "http")),
|
|
Created: from.CreatedOn,
|
|
Updated: from.UpdatedOn,
|
|
}
|
|
}
|
|
|
|
func extractCloneLink(links []cloneLink, names ...string) (href string) {
|
|
for _, name := range names {
|
|
for _, link := range links {
|
|
if link.Name == name && link.Href != "" {
|
|
return link.Href
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func anonymizeLink(link string) (href string) {
|
|
parsed, err := url.Parse(link)
|
|
if err != nil {
|
|
return link
|
|
}
|
|
parsed.User = nil
|
|
return parsed.String()
|
|
}
|
|
|
|
func convertPerms(from *perms) *scm.Perm {
|
|
to := new(scm.Perm)
|
|
if len(from.Values) != 1 {
|
|
return to
|
|
}
|
|
switch from.Values[0].Permissions {
|
|
case "admin":
|
|
to.Pull = true
|
|
to.Push = true
|
|
to.Admin = true
|
|
case "write":
|
|
to.Pull = true
|
|
to.Push = true
|
|
default:
|
|
to.Pull = true
|
|
}
|
|
return to
|
|
}
|
|
|
|
func convertHookList(from *hooks) []*scm.Hook {
|
|
to := []*scm.Hook{}
|
|
for _, v := range from.Values {
|
|
to = append(to, convertHook(v))
|
|
}
|
|
return to
|
|
}
|
|
|
|
func convertHook(from *hook) *scm.Hook {
|
|
return &scm.Hook{
|
|
ID: from.UUID,
|
|
Name: from.Description,
|
|
Active: from.Active,
|
|
Target: from.URL,
|
|
Events: from.Events,
|
|
SkipVerify: from.SkipCertVerification,
|
|
}
|
|
}
|
|
|
|
func convertFromHookEvents(from scm.HookEvents) []string {
|
|
var events []string
|
|
if from.Push {
|
|
events = append(events, "repo:push")
|
|
}
|
|
if from.PullRequest {
|
|
events = append(events, "pullrequest:updated")
|
|
events = append(events, "pullrequest:unapproved")
|
|
events = append(events, "pullrequest:approved")
|
|
events = append(events, "pullrequest:rejected")
|
|
events = append(events, "pullrequest:fulfilled")
|
|
events = append(events, "pullrequest:created")
|
|
}
|
|
if from.PullRequestComment {
|
|
events = append(events, "pullrequest:comment_created")
|
|
events = append(events, "pullrequest:comment_updated")
|
|
events = append(events, "pullrequest:comment_deleted")
|
|
}
|
|
if from.Issue {
|
|
events = append(events, "issues")
|
|
events = append(events, "issue:created")
|
|
events = append(events, "issue:updated")
|
|
}
|
|
if from.IssueComment {
|
|
events = append(events, "issue:comment_created")
|
|
}
|
|
return events
|
|
}
|
|
|
|
type repositories struct {
|
|
pagination
|
|
Values []*repository `json:"values"`
|
|
}
|
|
|
|
type statuses struct {
|
|
pagination
|
|
Values []*status `json:"values"`
|
|
}
|
|
|
|
type status struct {
|
|
State string `json:"state"`
|
|
Key string `json:"key"`
|
|
Name string `json:"name,omitempty"`
|
|
URL string `json:"url"`
|
|
Desc string `json:"description,omitempty"`
|
|
}
|
|
|
|
func convertStatusList(from *statuses) []*scm.Status {
|
|
to := []*scm.Status{}
|
|
for _, v := range from.Values {
|
|
to = append(to, convertStatus(v))
|
|
}
|
|
return to
|
|
}
|
|
|
|
func convertStatus(from *status) *scm.Status {
|
|
return &scm.Status{
|
|
State: convertState(from.State),
|
|
Label: from.Key,
|
|
Title: from.Name,
|
|
Desc: from.Desc,
|
|
Target: from.URL,
|
|
}
|
|
}
|
|
|
|
func convertState(from string) scm.State {
|
|
switch from {
|
|
case "FAILED":
|
|
return scm.StateFailure
|
|
case "INPROGRESS":
|
|
return scm.StatePending
|
|
case "SUCCESSFUL":
|
|
return scm.StateSuccess
|
|
default:
|
|
return scm.StateUnknown
|
|
}
|
|
}
|
|
|
|
func convertFromState(from scm.State) string {
|
|
switch from {
|
|
case scm.StatePending, scm.StateRunning:
|
|
return "INPROGRESS"
|
|
case scm.StateSuccess:
|
|
return "SUCCESSFUL"
|
|
default:
|
|
return "FAILED"
|
|
}
|
|
}
|