You've already forked woodpecker
							
							
				mirror of
				https://github.com/woodpecker-ci/woodpecker.git
				synced 2025-10-30 23:27:39 +02:00 
			
		
		
		
	Changed variables to lowercase
Moved to start using conversions and returning "bitbucket server types" Moved the last push type into the internal package. Simplified the types to have values of a repo type
This commit is contained in:
		| @@ -4,12 +4,9 @@ package bitbucketserver | ||||
| // quality or security standards expected of this project. Please use with caution. | ||||
|  | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"crypto/rsa" | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"encoding/hex" | ||||
| 	"encoding/json" | ||||
| 	"encoding/pem" | ||||
| 	"fmt" | ||||
| 	"github.com/drone/drone/model" | ||||
| @@ -98,7 +95,12 @@ func (c *Config) Login(res http.ResponseWriter, req *http.Request) (*model.User, | ||||
|  | ||||
| 	client := internal.NewClientWithToken(c.URL, c.Consumer, accessToken.Token) | ||||
|  | ||||
| 	return client.FindCurrentUser() | ||||
| 	user, err := client.FindCurrentUser() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return convertUser(user, accessToken), nil | ||||
|  | ||||
| } | ||||
|  | ||||
| @@ -114,15 +116,24 @@ func (*Config) Teams(u *model.User) ([]*model.Team, error) { | ||||
| } | ||||
|  | ||||
| func (c *Config) Repo(u *model.User, owner, name string) (*model.Repo, error) { | ||||
| 	client := internal.NewClientWithToken(c.URL, c.Consumer, u.Token) | ||||
|  | ||||
| 	return client.FindRepo(owner, name) | ||||
| 	repo, err := internal.NewClientWithToken(c.URL, c.Consumer, u.Token).FindRepo(owner, name) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return convertRepo(repo), nil | ||||
| } | ||||
|  | ||||
| func (c *Config) Repos(u *model.User) ([]*model.RepoLite, error) { | ||||
| 	client := internal.NewClientWithToken(c.URL, c.Consumer, u.Token) | ||||
| 	repos, err := internal.NewClientWithToken(c.URL, c.Consumer, u.Token).FindRepos() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var all []*model.RepoLite | ||||
| 	for _, repo := range repos { | ||||
| 		all = append(all, convertRepoLite(repo)) | ||||
| 	} | ||||
|  | ||||
| 	return client.FindRepos() | ||||
| 	return all, nil | ||||
| } | ||||
|  | ||||
| func (c *Config) Perm(u *model.User, owner, repo string) (*model.Perm, error) { | ||||
| @@ -173,29 +184,7 @@ func (c *Config) Deactivate(u *model.User, r *model.Repo, link string) error { | ||||
| } | ||||
|  | ||||
| func (c *Config) Hook(r *http.Request) (*model.Repo, *model.Build, error) { | ||||
| 	hook := new(postHook) | ||||
| 	if err := json.NewDecoder(r.Body).Decode(hook); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
|  | ||||
| 	build := &model.Build{ | ||||
| 		Event:  model.EventPush, | ||||
| 		Ref:    hook.RefChanges[0].RefID,                               // TODO check for index Values | ||||
| 		Author: hook.Changesets.Values[0].ToCommit.Author.EmailAddress, // TODO check for index Values | ||||
| 		Commit: hook.RefChanges[0].ToHash,                              // TODO check for index value | ||||
| 		Avatar: avatarLink(hook.Changesets.Values[0].ToCommit.Author.EmailAddress), | ||||
| 		Branch: strings.Split(hook.RefChanges[0].RefID, "refs/heads/")[1], | ||||
| 	} | ||||
|  | ||||
| 	repo := &model.Repo{ | ||||
| 		Name:     hook.Repository.Slug, | ||||
| 		Owner:    hook.Repository.Project.Key, | ||||
| 		FullName: fmt.Sprintf("%s/%s", hook.Repository.Project.Key, hook.Repository.Slug), | ||||
| 		Branch:   "master", | ||||
| 		Kind:     model.RepoGit, | ||||
| 	} | ||||
|  | ||||
| 	return repo, build, nil | ||||
| 	return parseHook(r) | ||||
| } | ||||
|  | ||||
| func CreateConsumer(URL string, ConsumerKey string, PrivateKey *rsa.PrivateKey) *oauth.Consumer { | ||||
| @@ -215,11 +204,3 @@ func CreateConsumer(URL string, ConsumerKey string, PrivateKey *rsa.PrivateKey) | ||||
| 	} | ||||
| 	return consumer | ||||
| } | ||||
|  | ||||
| func avatarLink(email string) (url string) { | ||||
| 	hasher := md5.New() | ||||
| 	hasher.Write([]byte(strings.ToLower(email))) | ||||
| 	emailHash := fmt.Sprintf("%v", hex.EncodeToString(hasher.Sum(nil))) | ||||
| 	avatarURL := fmt.Sprintf("https://www.gravatar.com/avatar/%s.jpg", emailHash) | ||||
| 	return avatarURL | ||||
| } | ||||
|   | ||||
							
								
								
									
										97
									
								
								remote/bitbucketserver/convert.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								remote/bitbucketserver/convert.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| package bitbucketserver | ||||
|  | ||||
| import ( | ||||
| 	"crypto/md5" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/remote/bitbucketserver/internal" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"github.com/mrjones/oauth" | ||||
| ) | ||||
|  | ||||
| // convertRepo is a helper function used to convert a Bitbucket server repository | ||||
| // structure to the common Drone repository structure. | ||||
| func convertRepo(from *internal.Repo) *model.Repo { | ||||
|  | ||||
| 	repo := model.Repo{ | ||||
| 		Name:      from.Slug, | ||||
| 		Owner:     from.Project.Key, | ||||
| 		Branch:    "master", | ||||
| 		Kind:      model.RepoGit, | ||||
| 		IsPrivate: true, // Since we have to use Netrc it has to always be private :/ | ||||
| 		FullName:  fmt.Sprintf("%s/%s", from.Project.Key, from.Slug), | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range from.Links.Clone { | ||||
| 		if item.Name == "http" { | ||||
| 			uri, err := url.Parse(item.Href) | ||||
| 			if err != nil { | ||||
| 				return nil | ||||
| 			} | ||||
| 			uri.User = nil | ||||
| 			repo.Clone = uri.String() | ||||
| 		} | ||||
| 	} | ||||
| 	for _, item := range from.Links.Self { | ||||
| 		if item.Href != "" { | ||||
| 			repo.Link = item.Href | ||||
| 		} | ||||
| 	} | ||||
| 	log.Debug(fmt.Printf("Repo: %+v\n", repo)) | ||||
| 	return &repo | ||||
|  | ||||
| } | ||||
|  | ||||
| // convertRepoLite is a helper function used to convert a Bitbucket repository | ||||
| // structure to the simplified Drone repository structure. | ||||
| func convertRepoLite(from *internal.Repo) *model.RepoLite { | ||||
| 	return &model.RepoLite{ | ||||
| 		Owner:    from.Project.Key, | ||||
| 		Name:     from.Slug, | ||||
| 		FullName: from.Project.Key + "/" + from.Slug, | ||||
| 		//TODO: find the avatar for the repo | ||||
| 		//Avatar: might need another ws call? | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| // convertPushHook is a helper function used to convert a Bitbucket push | ||||
| // hook to the Drone build struct holding commit information. | ||||
| func convertPushHook(hook *internal.PostHook) *model.Build { | ||||
| 	build := &model.Build{ | ||||
| 		Commit: hook.RefChanges[0].ToHash, // TODO check for index value | ||||
| 		//Link: TODO find link | ||||
| 		Branch: strings.Split(hook.RefChanges[0].RefID, "refs/heads/")[1], //TODO figure the correct for tags | ||||
| 		//Message: TODO find the message for the commit | ||||
| 		Avatar: avatarLink(hook.Changesets.Values[0].ToCommit.Author.EmailAddress), | ||||
| 		Author: hook.Changesets.Values[0].ToCommit.Author.EmailAddress, // TODO check for index Values | ||||
| 		//Timestamp: TODO find time parsing | ||||
| 		Event: model.EventPush,          //TODO: do more then PUSH find Tags etc | ||||
| 		Ref:   hook.RefChanges[0].RefID, // TODO check for index Values | ||||
|  | ||||
| 	} | ||||
| 	return build | ||||
| } | ||||
|  | ||||
| // convertUser is a helper function used to convert a Bitbucket user account | ||||
| // structure to the Drone User structure. | ||||
| func convertUser(from *internal.User, token *oauth.AccessToken) *model.User { | ||||
| 	return &model.User{ | ||||
| 		Login:  from.Slug, | ||||
| 		Token:  token.Token, | ||||
| 		Email:  from.EmailAddress, | ||||
| 		Avatar: avatarLink(from.EmailAddress), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func avatarLink(email string) string { | ||||
| 	hasher := md5.New() | ||||
| 	hasher.Write([]byte(strings.ToLower(email))) | ||||
| 	emailHash := fmt.Sprintf("%v", hex.EncodeToString(hasher.Sum(nil))) | ||||
| 	avatarURL := fmt.Sprintf("https://www.gravatar.com/avatar/%s.jpg", emailHash) | ||||
| 	log.Debug(avatarURL) | ||||
| 	return avatarURL | ||||
| } | ||||
| @@ -11,7 +11,6 @@ import ( | ||||
| 	"github.com/mrjones/oauth" | ||||
| 	"io/ioutil" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| @@ -32,10 +31,10 @@ type Client struct { | ||||
| 	accessToken string | ||||
| } | ||||
|  | ||||
| func NewClientWithToken(url string, Consumer *oauth.Consumer, AccessToken string) *Client { | ||||
| func NewClientWithToken(url string, consumer *oauth.Consumer, AccessToken string) *Client { | ||||
| 	var token oauth.AccessToken | ||||
| 	token.Token = AccessToken | ||||
| 	client, err := Consumer.MakeHttpClient(&token) | ||||
| 	client, err := consumer.MakeHttpClient(&token) | ||||
| 	log.Debug(fmt.Printf("Create client: %+v %s\n", token, url)) | ||||
| 	if err != nil { | ||||
| 		log.Error(err) | ||||
| @@ -43,7 +42,7 @@ func NewClientWithToken(url string, Consumer *oauth.Consumer, AccessToken string | ||||
| 	return &Client{client, url, AccessToken} | ||||
| } | ||||
|  | ||||
| func (c *Client) FindCurrentUser() (*model.User, error) { | ||||
| func (c *Client) FindCurrentUser() (*User, error) { | ||||
| 	CurrentUserIdResponse, err := c.client.Get(fmt.Sprintf(currentUserId, c.base)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -72,18 +71,11 @@ func (c *Client) FindCurrentUser() (*model.User, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	ModelUser := &model.User{ | ||||
| 		Login:  login, | ||||
| 		Email:  user.EmailAddress, | ||||
| 		Token:  c.accessToken, | ||||
| 		Avatar: avatarLink(user.EmailAddress), | ||||
| 	} | ||||
| 	log.Debug(fmt.Printf("User information: %+v\n", ModelUser)) | ||||
| 	return ModelUser, nil | ||||
| 	return &user, nil | ||||
|  | ||||
| } | ||||
|  | ||||
| func (c *Client) FindRepo(owner string, name string) (*model.Repo, error) { | ||||
| func (c *Client) FindRepo(owner string, name string) (*Repo, error) { | ||||
| 	urlString := fmt.Sprintf(pathRepo, c.base, owner, name) | ||||
| 	response, err := c.client.Get(urlString) | ||||
| 	if err != nil { | ||||
| @@ -91,40 +83,15 @@ func (c *Client) FindRepo(owner string, name string) (*model.Repo, error) { | ||||
| 	} | ||||
| 	defer response.Body.Close() | ||||
| 	contents, err := ioutil.ReadAll(response.Body) | ||||
| 	bsRepo := BSRepo{} | ||||
| 	err = json.Unmarshal(contents, &bsRepo) | ||||
| 	repo := Repo{} | ||||
| 	err = json.Unmarshal(contents, &repo) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	repo := &model.Repo{ | ||||
| 		Name:      bsRepo.Slug, | ||||
| 		Owner:     bsRepo.Project.Key, | ||||
| 		Branch:    "master", | ||||
| 		Kind:      model.RepoGit, | ||||
| 		IsPrivate: true, // Since we have to use Netrc it has to always be private :/ | ||||
| 		FullName:  fmt.Sprintf("%s/%s", bsRepo.Project.Key, bsRepo.Slug), | ||||
| 	} | ||||
|  | ||||
| 	for _, item := range bsRepo.Links.Clone { | ||||
| 		if item.Name == "http" { | ||||
| 			uri, err := url.Parse(item.Href) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			uri.User = nil | ||||
| 			repo.Clone = uri.String() | ||||
| 		} | ||||
| 	} | ||||
| 	for _, item := range bsRepo.Links.Self { | ||||
| 		if item.Href != "" { | ||||
| 			repo.Link = item.Href | ||||
| 		} | ||||
| 	} | ||||
| 	log.Debug(fmt.Printf("Repo: %+v\n", repo)) | ||||
| 	return repo, nil | ||||
| 	return &repo, nil | ||||
| } | ||||
|  | ||||
| func (c *Client) FindRepos() ([]*model.RepoLite, error) { | ||||
| func (c *Client) FindRepos() ([]*Repo, error) { | ||||
| 	requestUrl := fmt.Sprintf(pathRepos, c.base, "1000") | ||||
| 	log.Debug(fmt.Printf("request :%s", requestUrl)) | ||||
| 	response, err := c.client.Get(requestUrl) | ||||
| @@ -142,16 +109,8 @@ func (c *Client) FindRepos() ([]*model.RepoLite, error) { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	log.Debug(fmt.Printf("repoResponse: %+v\n", repoResponse)) | ||||
| 	var repos = []*model.RepoLite{} | ||||
| 	for _, repo := range repoResponse.Values { | ||||
| 		repos = append(repos, &model.RepoLite{ | ||||
| 			Name:     repo.Slug, | ||||
| 			FullName: repo.Project.Key + "/" + repo.Slug, | ||||
| 			Owner:    repo.Project.Key, | ||||
| 		}) | ||||
| 	} | ||||
| 	log.Debug(fmt.Printf("repos: %+v\n", repos)) | ||||
| 	return repos, nil | ||||
|  | ||||
| 	return repoResponse.Values, nil | ||||
| } | ||||
|  | ||||
| func (c *Client) FindRepoPerms(owner string, repo string) (*model.Perm, error) { | ||||
|   | ||||
| @@ -15,7 +15,7 @@ type User struct { | ||||
| 	Type string `json:"type"` | ||||
| } | ||||
|  | ||||
| type BSRepo struct { | ||||
| type Repo struct { | ||||
| 	Forkable bool `json:"forkable"` | ||||
| 	ID       int  `json:"id"` | ||||
| 	Links    struct { | ||||
| @@ -49,42 +49,11 @@ type BSRepo struct { | ||||
| } | ||||
|  | ||||
| type Repos struct { | ||||
| 	IsLastPage bool `json:"isLastPage"` | ||||
| 	Limit      int  `json:"limit"` | ||||
| 	Size       int  `json:"size"` | ||||
| 	Start      int  `json:"start"` | ||||
| 	Values     []struct { | ||||
| 		Forkable bool `json:"forkable"` | ||||
| 		ID       int  `json:"id"` | ||||
| 		Links    struct { | ||||
| 			Clone []struct { | ||||
| 				Href string `json:"href"` | ||||
| 				Name string `json:"name"` | ||||
| 			} `json:"clone"` | ||||
| 			Self []struct { | ||||
| 				Href string `json:"href"` | ||||
| 			} `json:"self"` | ||||
| 		} `json:"links"` | ||||
| 		Name    string `json:"name"` | ||||
| 		Project struct { | ||||
| 			Description string `json:"description"` | ||||
| 			ID          int    `json:"id"` | ||||
| 			Key         string `json:"key"` | ||||
| 			Links       struct { | ||||
| 				Self []struct { | ||||
| 					Href string `json:"href"` | ||||
| 				} `json:"self"` | ||||
| 			} `json:"links"` | ||||
| 			Name   string `json:"name"` | ||||
| 			Public bool   `json:"public"` | ||||
| 			Type   string `json:"type"` | ||||
| 		} `json:"project"` | ||||
| 		Public        bool   `json:"public"` | ||||
| 		ScmID         string `json:"scmId"` | ||||
| 		Slug          string `json:"slug"` | ||||
| 		State         string `json:"state"` | ||||
| 		StatusMessage string `json:"statusMessage"` | ||||
| 	} `json:"values"` | ||||
| 	IsLastPage bool    `json:"isLastPage"` | ||||
| 	Limit      int     `json:"limit"` | ||||
| 	Size       int     `json:"size"` | ||||
| 	Start      int     `json:"start"` | ||||
| 	Values     []*Repo `json:"values"` | ||||
| } | ||||
|  | ||||
| type Hook struct { | ||||
| @@ -100,3 +69,87 @@ type HookDetail struct { | ||||
| 	Version       string `json:"version"` | ||||
| 	ConfigFormKey string `json:"configFormKey"` | ||||
| } | ||||
|  | ||||
| type PostHook struct { | ||||
| 	Changesets struct { | ||||
| 		Filter     interface{} `json:"filter"` | ||||
| 		IsLastPage bool        `json:"isLastPage"` | ||||
| 		Limit      int         `json:"limit"` | ||||
| 		Size       int         `json:"size"` | ||||
| 		Start      int         `json:"start"` | ||||
| 		Values     []struct { | ||||
| 			Changes struct { | ||||
| 				Filter     interface{} `json:"filter"` | ||||
| 				IsLastPage bool        `json:"isLastPage"` | ||||
| 				Limit      int         `json:"limit"` | ||||
| 				Size       int         `json:"size"` | ||||
| 				Start      int         `json:"start"` | ||||
| 				Values     []struct { | ||||
| 					ContentID  string `json:"contentId"` | ||||
| 					Executable bool   `json:"executable"` | ||||
| 					Link       struct { | ||||
| 						Rel string `json:"rel"` | ||||
| 						URL string `json:"url"` | ||||
| 					} `json:"link"` | ||||
| 					NodeType string `json:"nodeType"` | ||||
| 					Path     struct { | ||||
| 						Components []string `json:"components"` | ||||
| 						Extension  string   `json:"extension"` | ||||
| 						Name       string   `json:"name"` | ||||
| 						Parent     string   `json:"parent"` | ||||
| 						ToString   string   `json:"toString"` | ||||
| 					} `json:"path"` | ||||
| 					PercentUnchanged int    `json:"percentUnchanged"` | ||||
| 					SrcExecutable    bool   `json:"srcExecutable"` | ||||
| 					Type             string `json:"type"` | ||||
| 				} `json:"values"` | ||||
| 			} `json:"changes"` | ||||
| 			FromCommit struct { | ||||
| 				DisplayID string `json:"displayId"` | ||||
| 				ID        string `json:"id"` | ||||
| 			} `json:"fromCommit"` | ||||
| 			Link struct { | ||||
| 				Rel string `json:"rel"` | ||||
| 				URL string `json:"url"` | ||||
| 			} `json:"link"` | ||||
| 			ToCommit struct { | ||||
| 				Author struct { | ||||
| 					EmailAddress string `json:"emailAddress"` | ||||
| 					Name         string `json:"name"` | ||||
| 				} `json:"author"` | ||||
| 				AuthorTimestamp int    `json:"authorTimestamp"` | ||||
| 				DisplayID       string `json:"displayId"` | ||||
| 				ID              string `json:"id"` | ||||
| 				Message         string `json:"message"` | ||||
| 				Parents         []struct { | ||||
| 					DisplayID string `json:"displayId"` | ||||
| 					ID        string `json:"id"` | ||||
| 				} `json:"parents"` | ||||
| 			} `json:"toCommit"` | ||||
| 		} `json:"values"` | ||||
| 	} `json:"changesets"` | ||||
| 	RefChanges []struct { | ||||
| 		FromHash string `json:"fromHash"` | ||||
| 		RefID    string `json:"refId"` | ||||
| 		ToHash   string `json:"toHash"` | ||||
| 		Type     string `json:"type"` | ||||
| 	} `json:"refChanges"` | ||||
| 	Repository struct { | ||||
| 		Forkable bool   `json:"forkable"` | ||||
| 		ID       int    `json:"id"` | ||||
| 		Name     string `json:"name"` | ||||
| 		Project  struct { | ||||
| 			ID         int    `json:"id"` | ||||
| 			IsPersonal bool   `json:"isPersonal"` | ||||
| 			Key        string `json:"key"` | ||||
| 			Name       string `json:"name"` | ||||
| 			Public     bool   `json:"public"` | ||||
| 			Type       string `json:"type"` | ||||
| 		} `json:"project"` | ||||
| 		Public        bool   `json:"public"` | ||||
| 		ScmID         string `json:"scmId"` | ||||
| 		Slug          string `json:"slug"` | ||||
| 		State         string `json:"state"` | ||||
| 		StatusMessage string `json:"statusMessage"` | ||||
| 	} `json:"repository"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										28
									
								
								remote/bitbucketserver/parse.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								remote/bitbucketserver/parse.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| package bitbucketserver | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"github.com/drone/drone/model" | ||||
| 	"github.com/drone/drone/remote/bitbucketserver/internal" | ||||
| 	"net/http" | ||||
| ) | ||||
|  | ||||
| // parseHook parses a Bitbucket hook from an http.Request request and returns | ||||
| // Repo and Build detail. TODO: find a way to support PR hooks | ||||
| func parseHook(r *http.Request) (*model.Repo, *model.Build, error) { | ||||
| 	hook := new(internal.PostHook) | ||||
| 	if err := json.NewDecoder(r.Body).Decode(hook); err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	build := convertPushHook(hook) | ||||
| 	repo := &model.Repo{ | ||||
| 		Name:     hook.Repository.Slug, | ||||
| 		Owner:    hook.Repository.Project.Key, | ||||
| 		FullName: fmt.Sprintf("%s/%s", hook.Repository.Project.Key, hook.Repository.Slug), | ||||
| 		Branch:   "master", | ||||
| 		Kind:     model.RepoGit, | ||||
| 	} | ||||
|  | ||||
| 	return repo, build, nil | ||||
| } | ||||
| @@ -1,87 +0,0 @@ | ||||
| package bitbucketserver | ||||
|  | ||||
| type postHook struct { | ||||
| 	Changesets struct { | ||||
| 		Filter     interface{} `json:"filter"` | ||||
| 		IsLastPage bool        `json:"isLastPage"` | ||||
| 		Limit      int         `json:"limit"` | ||||
| 		Size       int         `json:"size"` | ||||
| 		Start      int         `json:"start"` | ||||
| 		Values     []struct { | ||||
| 			Changes struct { | ||||
| 				Filter     interface{} `json:"filter"` | ||||
| 				IsLastPage bool        `json:"isLastPage"` | ||||
| 				Limit      int         `json:"limit"` | ||||
| 				Size       int         `json:"size"` | ||||
| 				Start      int         `json:"start"` | ||||
| 				Values     []struct { | ||||
| 					ContentID  string `json:"contentId"` | ||||
| 					Executable bool   `json:"executable"` | ||||
| 					Link       struct { | ||||
| 						Rel string `json:"rel"` | ||||
| 						URL string `json:"url"` | ||||
| 					} `json:"link"` | ||||
| 					NodeType string `json:"nodeType"` | ||||
| 					Path     struct { | ||||
| 						Components []string `json:"components"` | ||||
| 						Extension  string   `json:"extension"` | ||||
| 						Name       string   `json:"name"` | ||||
| 						Parent     string   `json:"parent"` | ||||
| 						ToString   string   `json:"toString"` | ||||
| 					} `json:"path"` | ||||
| 					PercentUnchanged int    `json:"percentUnchanged"` | ||||
| 					SrcExecutable    bool   `json:"srcExecutable"` | ||||
| 					Type             string `json:"type"` | ||||
| 				} `json:"values"` | ||||
| 			} `json:"changes"` | ||||
| 			FromCommit struct { | ||||
| 				DisplayID string `json:"displayId"` | ||||
| 				ID        string `json:"id"` | ||||
| 			} `json:"fromCommit"` | ||||
| 			Link struct { | ||||
| 				Rel string `json:"rel"` | ||||
| 				URL string `json:"url"` | ||||
| 			} `json:"link"` | ||||
| 			ToCommit struct { | ||||
| 				Author struct { | ||||
| 					EmailAddress string `json:"emailAddress"` | ||||
| 					Name         string `json:"name"` | ||||
| 				} `json:"author"` | ||||
| 				AuthorTimestamp int    `json:"authorTimestamp"` | ||||
| 				DisplayID       string `json:"displayId"` | ||||
| 				ID              string `json:"id"` | ||||
| 				Message         string `json:"message"` | ||||
| 				Parents         []struct { | ||||
| 					DisplayID string `json:"displayId"` | ||||
| 					ID        string `json:"id"` | ||||
| 				} `json:"parents"` | ||||
| 			} `json:"toCommit"` | ||||
| 		} `json:"values"` | ||||
| 	} `json:"changesets"` | ||||
| 	RefChanges []struct { | ||||
| 		FromHash string `json:"fromHash"` | ||||
| 		RefID    string `json:"refId"` | ||||
| 		ToHash   string `json:"toHash"` | ||||
| 		Type     string `json:"type"` | ||||
| 	} `json:"refChanges"` | ||||
| 	Repository struct { | ||||
| 		Forkable bool   `json:"forkable"` | ||||
| 		ID       int    `json:"id"` | ||||
| 		Name     string `json:"name"` | ||||
| 		Project  struct { | ||||
| 			ID         int    `json:"id"` | ||||
| 			IsPersonal bool   `json:"isPersonal"` | ||||
| 			Key        string `json:"key"` | ||||
| 			Name       string `json:"name"` | ||||
| 			Public     bool   `json:"public"` | ||||
| 			Type       string `json:"type"` | ||||
| 		} `json:"project"` | ||||
| 		Public        bool   `json:"public"` | ||||
| 		ScmID         string `json:"scmId"` | ||||
| 		Slug          string `json:"slug"` | ||||
| 		State         string `json:"state"` | ||||
| 		StatusMessage string `json:"statusMessage"` | ||||
| 	} `json:"repository"` | ||||
| } | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user