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.
879 lines
32 KiB
Go
879 lines
32 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 gitlab
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
|
|
"git.awesome-for.me/liuzhiguo/go-scm/scm"
|
|
"git.awesome-for.me/liuzhiguo/go-scm/scm/driver/internal/null"
|
|
)
|
|
|
|
type webhookService struct {
|
|
client *wrapper
|
|
}
|
|
|
|
func (s *webhookService) Parse(req *http.Request, fn scm.SecretFunc) (scm.Webhook, error) {
|
|
data, err := ioutil.ReadAll(
|
|
io.LimitReader(req.Body, 10000000),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var hook scm.Webhook
|
|
switch req.Header.Get("X-Gitlab-Event") {
|
|
case "Push Hook", "Tag Push Hook":
|
|
hook, err = parsePushHook(data)
|
|
case "Issue Hook":
|
|
return nil, scm.ErrUnknownEvent
|
|
case "Merge Request Hook":
|
|
hook, err = parsePullRequestHook(data)
|
|
case "Note Hook":
|
|
hook, err = parseIssueCommentHook(data)
|
|
default:
|
|
return nil, scm.ErrUnknownEvent
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// get the gitlab shared token to verify the payload
|
|
// authenticity. If no key is provided, no validation
|
|
// is performed.
|
|
token, err := fn(hook)
|
|
if err != nil {
|
|
return hook, err
|
|
} else if token == "" {
|
|
return hook, nil
|
|
}
|
|
|
|
if token != req.Header.Get("X-Gitlab-Token") {
|
|
return hook, scm.ErrSignatureInvalid
|
|
}
|
|
|
|
return hook, nil
|
|
}
|
|
|
|
func parseIssueCommentHook(data []byte) (scm.Webhook, error) {
|
|
src := new(commentHook)
|
|
err := json.Unmarshal(data, src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
dst, err := convertCommentHook(src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return dst, nil
|
|
}
|
|
|
|
func parsePushHook(data []byte) (scm.Webhook, error) {
|
|
src := new(pushHook)
|
|
err := json.Unmarshal(data, src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch {
|
|
case src.ObjectKind == "push" && src.Before == "0000000000000000000000000000000000000000":
|
|
// TODO we previously considered returning a
|
|
// branch creation hook, however, the push hook
|
|
// returns more metadata (commit details).
|
|
return convertPushHook(src), nil
|
|
case src.ObjectKind == "push" && src.After == "0000000000000000000000000000000000000000":
|
|
return converBranchHook(src), nil
|
|
case src.ObjectKind == "tag_push" && src.Before == "0000000000000000000000000000000000000000":
|
|
// TODO we previously considered returning a
|
|
// tag creation hook, however, the push hook
|
|
// returns more metadata (commit details).
|
|
return convertPushHook(src), nil
|
|
case src.ObjectKind == "tag_push" && src.After == "0000000000000000000000000000000000000000":
|
|
return convertTagHook(src), nil
|
|
default:
|
|
return convertPushHook(src), nil
|
|
}
|
|
}
|
|
|
|
func parsePullRequestHook(data []byte) (scm.Webhook, error) {
|
|
src := new(pullRequestHook)
|
|
err := json.Unmarshal(data, src)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
switch src.ObjectAttributes.Action {
|
|
case "open", "close", "reopen", "merge", "update":
|
|
// no-op
|
|
default:
|
|
return nil, scm.ErrUnknownEvent
|
|
}
|
|
switch {
|
|
default:
|
|
return convertPullRequestHook(src), nil
|
|
}
|
|
}
|
|
|
|
func convertPushHook(src *pushHook) *scm.PushHook {
|
|
var commits []scm.Commit
|
|
for _, c := range src.Commits {
|
|
commits = append(commits,
|
|
scm.Commit{
|
|
Sha: c.ID,
|
|
Message: c.Message,
|
|
Link: c.URL,
|
|
Author: scm.Signature{
|
|
Name: c.Author.Name,
|
|
Email: c.Author.Email,
|
|
Date: c.Timestamp.ValueOrZero(),
|
|
},
|
|
Committer: scm.Signature{
|
|
Name: c.Author.Name,
|
|
Email: c.Author.Email,
|
|
Date: c.Timestamp.ValueOrZero(),
|
|
},
|
|
})
|
|
}
|
|
namespace, name := scm.Split(src.Project.PathWithNamespace)
|
|
dst := &scm.PushHook{
|
|
Ref: scm.ExpandRef(src.Ref, "refs/heads/"),
|
|
Before: src.Before,
|
|
After: src.After,
|
|
Repo: scm.Repository{
|
|
ID: strconv.Itoa(src.Project.ID),
|
|
Namespace: namespace,
|
|
Name: name,
|
|
Clone: src.Project.GitHTTPURL,
|
|
CloneSSH: src.Project.GitSSHURL,
|
|
Link: src.Project.WebURL,
|
|
Branch: src.Project.DefaultBranch,
|
|
Private: false, // TODO how do we correctly set Private vs Public?
|
|
},
|
|
Commit: scm.Commit{
|
|
Sha: src.CheckoutSha,
|
|
Message: "", // NOTE this is set below
|
|
Author: scm.Signature{
|
|
Login: src.UserUsername,
|
|
Name: src.UserName,
|
|
Email: src.UserEmail,
|
|
Avatar: src.UserAvatar,
|
|
},
|
|
Committer: scm.Signature{
|
|
Login: src.UserUsername,
|
|
Name: src.UserName,
|
|
Email: src.UserEmail,
|
|
Avatar: src.UserAvatar,
|
|
},
|
|
Link: "", // NOTE this is set below
|
|
},
|
|
Sender: scm.User{
|
|
Login: src.UserUsername,
|
|
Name: src.UserName,
|
|
Email: src.UserEmail,
|
|
Avatar: src.UserAvatar,
|
|
},
|
|
Commits: commits,
|
|
}
|
|
if len(src.Commits) > 0 {
|
|
// get the last commit (most recent)
|
|
dst.Commit.Message = src.Commits[len(src.Commits)-1].Message
|
|
dst.Commit.Link = src.Commits[len(src.Commits)-1].URL
|
|
}
|
|
return dst
|
|
}
|
|
|
|
func converBranchHook(src *pushHook) *scm.BranchHook {
|
|
action := scm.ActionCreate
|
|
commit := src.After
|
|
if src.After == "0000000000000000000000000000000000000000" {
|
|
action = scm.ActionDelete
|
|
commit = src.Before
|
|
}
|
|
namespace, name := scm.Split(src.Project.PathWithNamespace)
|
|
return &scm.BranchHook{
|
|
Action: action,
|
|
Ref: scm.Reference{
|
|
Name: scm.TrimRef(src.Ref),
|
|
Sha: commit,
|
|
},
|
|
Repo: scm.Repository{
|
|
ID: strconv.Itoa(src.Project.ID),
|
|
Namespace: namespace,
|
|
Name: name,
|
|
Clone: src.Project.GitHTTPURL,
|
|
CloneSSH: src.Project.GitSSHURL,
|
|
Link: src.Project.WebURL,
|
|
Branch: src.Project.DefaultBranch,
|
|
Private: false, // TODO how do we correctly set Private vs Public?
|
|
},
|
|
Sender: scm.User{
|
|
Login: src.UserUsername,
|
|
Name: src.UserName,
|
|
Email: src.UserEmail,
|
|
Avatar: src.UserAvatar,
|
|
},
|
|
}
|
|
}
|
|
|
|
func convertCommentHook(src *commentHook) (*scm.IssueCommentHook, error) {
|
|
var issue scm.Issue
|
|
var comment scm.Comment
|
|
|
|
switch src.ObjectAttributes.NoteableType {
|
|
case "Commit", "Issue", "Snippet":
|
|
return nil, scm.ErrUnknownEvent
|
|
case "MergeRequest":
|
|
pr := scm.PullRequest{
|
|
Number: src.MergeRequest.Iid,
|
|
Title: src.MergeRequest.Title,
|
|
Body: src.MergeRequest.Description,
|
|
Sha: src.MergeRequest.LastCommit.ID,
|
|
Ref: fmt.Sprintf("refs/merge-requests/%d/head", src.MergeRequest.Iid),
|
|
Source: src.MergeRequest.SourceBranch,
|
|
Target: src.MergeRequest.TargetBranch,
|
|
Link: src.MergeRequest.URL,
|
|
Closed: src.MergeRequest.State != "opened",
|
|
Merged: src.MergeRequest.State == "merged",
|
|
Author: *convertUser(&src.User),
|
|
Created: parseTimeString(src.MergeRequest.CreatedAt),
|
|
Updated: parseTimeString(src.MergeRequest.UpdatedAt),
|
|
}
|
|
for _, l := range src.MergeRequest.Labels {
|
|
label := scm.Label{
|
|
Name: l.Title,
|
|
Color: l.Color,
|
|
}
|
|
pr.Labels = append(pr.Labels, label)
|
|
}
|
|
issue = scm.Issue{
|
|
Number: src.MergeRequest.Iid,
|
|
Title: src.MergeRequest.Title,
|
|
Body: src.MergeRequest.Title,
|
|
Link: src.Project.WebURL,
|
|
Author: *convertUser(&src.User),
|
|
PullRequest: pr,
|
|
Created: parseTimeString(src.ObjectAttributes.CreatedAt),
|
|
Updated: parseTimeString(src.ObjectAttributes.UpdatedAt),
|
|
}
|
|
comment = scm.Comment{
|
|
ID: src.ObjectAttributes.ID,
|
|
Body: src.ObjectAttributes.Note,
|
|
Author: *convertUser(&src.User),
|
|
Created: parseTimeString(src.ObjectAttributes.CreatedAt),
|
|
Updated: parseTimeString(src.ObjectAttributes.UpdatedAt),
|
|
}
|
|
default:
|
|
return nil, scm.ErrUnknownEvent
|
|
}
|
|
|
|
namespace, _ := scm.Split(src.Project.PathWithNamespace)
|
|
dst := scm.IssueCommentHook{
|
|
Action: scm.ActionCreate,
|
|
Repo: scm.Repository{
|
|
ID: strconv.Itoa(src.Project.ID),
|
|
Namespace: namespace,
|
|
Name: src.Repository.Name,
|
|
Clone: src.Project.GitHTTPURL,
|
|
CloneSSH: src.Project.GitSSHURL,
|
|
Link: src.Project.WebURL,
|
|
Branch: src.Project.DefaultBranch,
|
|
Private: false, // TODO how do we correctly set Private vs Public?
|
|
},
|
|
Issue: issue,
|
|
Comment: comment,
|
|
Sender: *convertUser(&src.User),
|
|
}
|
|
return &dst, nil
|
|
}
|
|
|
|
func convertTagHook(src *pushHook) *scm.TagHook {
|
|
action := scm.ActionCreate
|
|
commit := src.After
|
|
if src.After == "0000000000000000000000000000000000000000" {
|
|
action = scm.ActionDelete
|
|
commit = src.Before
|
|
}
|
|
namespace, name := scm.Split(src.Project.PathWithNamespace)
|
|
return &scm.TagHook{
|
|
Action: action,
|
|
Ref: scm.Reference{
|
|
Name: scm.TrimRef(src.Ref),
|
|
Sha: commit,
|
|
},
|
|
Repo: scm.Repository{
|
|
ID: strconv.Itoa(src.Project.ID),
|
|
Namespace: namespace,
|
|
Name: name,
|
|
Clone: src.Project.GitHTTPURL,
|
|
CloneSSH: src.Project.GitSSHURL,
|
|
Link: src.Project.WebURL,
|
|
Branch: src.Project.DefaultBranch,
|
|
Private: false, // TODO how do we correctly set Private vs Public?
|
|
},
|
|
Sender: scm.User{
|
|
Login: src.UserUsername,
|
|
Name: src.UserName,
|
|
Email: src.UserEmail,
|
|
Avatar: src.UserAvatar,
|
|
},
|
|
}
|
|
}
|
|
|
|
func convertPullRequestHook(src *pullRequestHook) *scm.PullRequestHook {
|
|
action := scm.ActionSync
|
|
switch src.ObjectAttributes.Action {
|
|
case "open":
|
|
action = scm.ActionOpen
|
|
case "close":
|
|
action = scm.ActionClose
|
|
case "reopen":
|
|
action = scm.ActionReopen
|
|
case "merge":
|
|
action = scm.ActionMerge
|
|
case "update":
|
|
action = scm.ActionSync
|
|
if src.Changes.Draft.Previous.Bool == false && src.Changes.Draft.Current.Bool == true {
|
|
action = scm.ActionReviewReady
|
|
}
|
|
}
|
|
fork := scm.Join(
|
|
src.ObjectAttributes.Source.Namespace,
|
|
src.ObjectAttributes.Source.Name,
|
|
)
|
|
namespace, name := scm.Split(src.Project.PathWithNamespace)
|
|
return &scm.PullRequestHook{
|
|
Action: action,
|
|
PullRequest: scm.PullRequest{
|
|
Number: src.ObjectAttributes.Iid,
|
|
Title: src.ObjectAttributes.Title,
|
|
Body: src.ObjectAttributes.Description,
|
|
Sha: src.ObjectAttributes.LastCommit.ID,
|
|
Ref: fmt.Sprintf("refs/merge-requests/%d/head", src.ObjectAttributes.Iid),
|
|
Source: src.ObjectAttributes.SourceBranch,
|
|
Target: src.ObjectAttributes.TargetBranch,
|
|
Fork: fork,
|
|
Link: src.ObjectAttributes.URL,
|
|
Closed: src.ObjectAttributes.State != "opened",
|
|
Merged: src.ObjectAttributes.State == "merged",
|
|
// Created : src.ObjectAttributes.CreatedAt,
|
|
// Updated : src.ObjectAttributes.UpdatedAt, // 2017-12-10 17:01:11 UTC
|
|
Author: scm.User{
|
|
Login: src.User.Username,
|
|
Name: src.User.Name,
|
|
Email: "", // TODO how do we get the pull request author email?
|
|
Avatar: src.User.AvatarURL,
|
|
},
|
|
},
|
|
Repo: scm.Repository{
|
|
ID: strconv.Itoa(src.Project.ID),
|
|
Namespace: namespace,
|
|
Name: name,
|
|
Clone: src.Project.GitHTTPURL,
|
|
CloneSSH: src.Project.GitSSHURL,
|
|
Link: src.Project.WebURL,
|
|
Branch: src.Project.DefaultBranch,
|
|
Private: false, // TODO how do we correctly set Private vs Public?
|
|
},
|
|
Sender: scm.User{
|
|
Login: src.User.Username,
|
|
Name: src.User.Name,
|
|
Email: "", // TODO how do we get the pull request author email?
|
|
Avatar: src.User.AvatarURL,
|
|
},
|
|
}
|
|
}
|
|
|
|
func parseTimeString(timeString string) time.Time {
|
|
layout := "2006-01-02 15:04:05 UTC"
|
|
// Returns zero value of time in case of an error 0001-01-01 00:00:00 +0000 UTC
|
|
t, _ := time.Parse(layout, timeString)
|
|
return t
|
|
}
|
|
|
|
type (
|
|
pushHook struct {
|
|
ObjectKind string `json:"object_kind"`
|
|
EventName string `json:"event_name"`
|
|
Before string `json:"before"`
|
|
After string `json:"after"`
|
|
Ref string `json:"ref"`
|
|
CheckoutSha string `json:"checkout_sha"`
|
|
Message interface{} `json:"message"`
|
|
UserID int `json:"user_id"`
|
|
UserName string `json:"user_name"`
|
|
UserUsername string `json:"user_username"`
|
|
UserEmail string `json:"user_email"`
|
|
UserAvatar string `json:"user_avatar"`
|
|
ProjectID int `json:"project_id"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"project"`
|
|
Commits []struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Timestamp null.Time `json:"timestamp"`
|
|
URL string `json:"url"`
|
|
Author struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
} `json:"author"`
|
|
Added []string `json:"added"`
|
|
Modified []interface{} `json:"modified"`
|
|
Removed []interface{} `json:"removed"`
|
|
} `json:"commits"`
|
|
TotalCommitsCount int `json:"total_commits_count"`
|
|
Repository struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Description string `json:"description"`
|
|
Homepage string `json:"homepage"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
} `json:"repository"`
|
|
}
|
|
|
|
commentHook struct {
|
|
ObjectKind string `json:"object_kind"`
|
|
EventType string `json:"event_type"`
|
|
User user `json:"user"`
|
|
ProjectID int `json:"project_id"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"project"`
|
|
ObjectAttributes struct {
|
|
ID int `json:"id"`
|
|
Note string `json:"note"`
|
|
NoteableType string `json:"noteable_type"`
|
|
AuthorID int `json:"author_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
ProjectID int `json:"project_id"`
|
|
Attachment interface{} `json:"attachment"`
|
|
LineCode string `json:"line_code"`
|
|
CommitID string `json:"commit_id"`
|
|
NoteableID int `json:"noteable_id"`
|
|
StDiff interface{} `json:"st_diff"`
|
|
System bool `json:"system"`
|
|
ResolvedAt interface{} `json:"resolved_at"`
|
|
ResolvedByID interface{} `json:"resolved_by_id"`
|
|
ResolvedByPush interface{} `json:"resolved_by_push"`
|
|
DiscussionID string `json:"discussion_id"`
|
|
URL string `json:"url"`
|
|
Position interface{} `json:"position"`
|
|
OriginalPosition interface{} `json:"original_position"`
|
|
ChangePosition interface{} `json:"change_position"`
|
|
Type interface{} `json:"type"`
|
|
Description string `json:"description"`
|
|
} `json:"object_attributes"`
|
|
Repository struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Description string `json:"description"`
|
|
Homepage string `json:"homepage"`
|
|
} `json:"repository"`
|
|
MergeRequest struct {
|
|
AssigneeID interface{} `json:"assignee_id"`
|
|
AuthorID int `json:"author_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
DeletedAt interface{} `json:"deleted_at"`
|
|
Description string `json:"description"`
|
|
HeadPipelineID interface{} `json:"head_pipeline_id"`
|
|
ID int `json:"id"`
|
|
Iid int `json:"iid"`
|
|
LastEditedAt interface{} `json:"last_edited_at"`
|
|
LastEditedByID interface{} `json:"last_edited_by_id"`
|
|
MergeCommitSha interface{} `json:"merge_commit_sha"`
|
|
MergeError interface{} `json:"merge_error"`
|
|
MergeParams interface{} `json:"-"`
|
|
MergeStatus string `json:"merge_status"`
|
|
MergeUserID interface{} `json:"merge_user_id"`
|
|
MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"`
|
|
MilestoneID interface{} `json:"milestone_id"`
|
|
SourceBranch string `json:"source_branch"`
|
|
SourceProjectID int `json:"source_project_id"`
|
|
StateID int `json:"state_id"`
|
|
State string `json:"state"`
|
|
TargetBranch string `json:"target_branch"`
|
|
TargetProjectID int `json:"target_project_id"`
|
|
TimeEstimate int `json:"time_estimate"`
|
|
Title string `json:"title"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
UpdatedByID interface{} `json:"updated_by_id"`
|
|
URL string `json:"url"`
|
|
WorkInProgress bool `json:"work_in_progress"`
|
|
TimeChange int `json:"time_change"`
|
|
HumanTimeChange int `json:"human_time_change"`
|
|
TotalTimeSpent int `json:"total_time_spent"`
|
|
HumanTotalTimeSpent interface{} `json:"human_total_time_spent"`
|
|
HumanTimeEstimate interface{} `json:"human_time_estimate"`
|
|
Action string `json:"action"`
|
|
AssigneeIDs interface{} `json:"assignee_ids"`
|
|
BlockingDiscussionResolved bool `json:"blocking_discussions_resolved"`
|
|
Source struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"source"`
|
|
Target struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"target"`
|
|
LastCommit struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Timestamp string `json:"timestamp"`
|
|
URL string `json:"url"`
|
|
Author struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
} `json:"author"`
|
|
} `json:"last_commit"`
|
|
Labels []struct {
|
|
ID int `json:"id"`
|
|
Title string `json:"title"`
|
|
Color string `json:"color"`
|
|
ProjectID int `json:"project_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
Template bool `json:"template"`
|
|
Description string `json:"description"`
|
|
Type string `json:"type"`
|
|
GroupID interface{} `json:"group_id"`
|
|
} `json:"labels"`
|
|
} `json:"merge_request"`
|
|
}
|
|
|
|
tagHook struct {
|
|
ObjectKind string `json:"object_kind"`
|
|
EventName string `json:"event_name"`
|
|
Before string `json:"before"`
|
|
After string `json:"after"`
|
|
Ref string `json:"ref"`
|
|
CheckoutSha string `json:"checkout_sha"`
|
|
Message interface{} `json:"message"`
|
|
UserID int `json:"user_id"`
|
|
UserName string `json:"user_name"`
|
|
UserUsername string `json:"user_username"`
|
|
UserEmail string `json:"user_email"`
|
|
UserAvatar string `json:"user_avatar"`
|
|
ProjectID int `json:"project_id"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"project"`
|
|
Commits []struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Timestamp string `json:"timestamp"`
|
|
URL string `json:"url"`
|
|
Author struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
} `json:"author"`
|
|
Added []string `json:"added"`
|
|
Modified []interface{} `json:"modified"`
|
|
Removed []interface{} `json:"removed"`
|
|
} `json:"commits"`
|
|
TotalCommitsCount int `json:"total_commits_count"`
|
|
Repository struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Description string `json:"description"`
|
|
Homepage string `json:"homepage"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
} `json:"repository"`
|
|
}
|
|
|
|
issueHook struct {
|
|
ObjectKind string `json:"object_kind"`
|
|
User struct {
|
|
Name string `json:"name"`
|
|
Username string `json:"username"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
} `json:"user"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"project"`
|
|
ObjectAttributes struct {
|
|
AssigneeID interface{} `json:"assignee_id"`
|
|
AuthorID int `json:"author_id"`
|
|
BranchName interface{} `json:"branch_name"`
|
|
ClosedAt interface{} `json:"closed_at"`
|
|
Confidential bool `json:"confidential"`
|
|
CreatedAt string `json:"created_at"`
|
|
DeletedAt interface{} `json:"deleted_at"`
|
|
Description string `json:"description"`
|
|
DueDate interface{} `json:"due_date"`
|
|
ID int `json:"id"`
|
|
Iid int `json:"iid"`
|
|
LastEditedAt string `json:"last_edited_at"`
|
|
LastEditedByID int `json:"last_edited_by_id"`
|
|
MilestoneID interface{} `json:"milestone_id"`
|
|
MovedToID interface{} `json:"moved_to_id"`
|
|
ProjectID int `json:"project_id"`
|
|
RelativePosition int `json:"relative_position"`
|
|
State string `json:"state"`
|
|
TimeEstimate int `json:"time_estimate"`
|
|
Title string `json:"title"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
UpdatedByID int `json:"updated_by_id"`
|
|
URL string `json:"url"`
|
|
TotalTimeSpent int `json:"total_time_spent"`
|
|
HumanTotalTimeSpent interface{} `json:"human_total_time_spent"`
|
|
HumanTimeEstimate interface{} `json:"human_time_estimate"`
|
|
AssigneeIds []interface{} `json:"assignee_ids"`
|
|
Action string `json:"action"`
|
|
} `json:"object_attributes"`
|
|
Labels []struct {
|
|
ID int `json:"id"`
|
|
Title string `json:"title"`
|
|
Color string `json:"color"`
|
|
ProjectID int `json:"project_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
Template bool `json:"template"`
|
|
Description string `json:"description"`
|
|
Type string `json:"type"`
|
|
GroupID interface{} `json:"group_id"`
|
|
} `json:"labels"`
|
|
Changes struct {
|
|
Labels struct {
|
|
Previous []interface{} `json:"previous"`
|
|
Current []struct {
|
|
ID int `json:"id"`
|
|
Title string `json:"title"`
|
|
Color string `json:"color"`
|
|
ProjectID int `json:"project_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
Template bool `json:"template"`
|
|
Description string `json:"description"`
|
|
Type string `json:"type"`
|
|
GroupID interface{} `json:"group_id"`
|
|
} `json:"current"`
|
|
} `json:"labels"`
|
|
} `json:"changes"`
|
|
Repository struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Description string `json:"description"`
|
|
Homepage string `json:"homepage"`
|
|
} `json:"repository"`
|
|
}
|
|
|
|
pullRequestHook struct {
|
|
ObjectKind string `json:"object_kind"`
|
|
User struct {
|
|
Name string `json:"name"`
|
|
Username string `json:"username"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
} `json:"user"`
|
|
Project struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"project"`
|
|
ObjectAttributes struct {
|
|
AssigneeID interface{} `json:"assignee_id"`
|
|
AuthorID int `json:"author_id"`
|
|
CreatedAt string `json:"created_at"`
|
|
DeletedAt interface{} `json:"deleted_at"`
|
|
Description string `json:"description"`
|
|
HeadPipelineID interface{} `json:"head_pipeline_id"`
|
|
ID int `json:"id"`
|
|
Iid int `json:"iid"`
|
|
LastEditedAt interface{} `json:"last_edited_at"`
|
|
LastEditedByID interface{} `json:"last_edited_by_id"`
|
|
MergeCommitSha interface{} `json:"merge_commit_sha"`
|
|
MergeError interface{} `json:"merge_error"`
|
|
MergeParams interface{} `json:"-"`
|
|
MergeStatus string `json:"merge_status"`
|
|
MergeUserID interface{} `json:"merge_user_id"`
|
|
MergeWhenPipelineSucceeds bool `json:"merge_when_pipeline_succeeds"`
|
|
MilestoneID interface{} `json:"milestone_id"`
|
|
SourceBranch string `json:"source_branch"`
|
|
SourceProjectID int `json:"source_project_id"`
|
|
State string `json:"state"`
|
|
TargetBranch string `json:"target_branch"`
|
|
TargetProjectID int `json:"target_project_id"`
|
|
TimeEstimate int `json:"time_estimate"`
|
|
Title string `json:"title"`
|
|
UpdatedAt string `json:"updated_at"`
|
|
UpdatedByID interface{} `json:"updated_by_id"`
|
|
URL string `json:"url"`
|
|
Source struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"source"`
|
|
Target struct {
|
|
ID int `json:"id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
WebURL string `json:"web_url"`
|
|
AvatarURL interface{} `json:"avatar_url"`
|
|
GitSSHURL string `json:"git_ssh_url"`
|
|
GitHTTPURL string `json:"git_http_url"`
|
|
Namespace string `json:"namespace"`
|
|
VisibilityLevel int `json:"visibility_level"`
|
|
PathWithNamespace string `json:"path_with_namespace"`
|
|
DefaultBranch string `json:"default_branch"`
|
|
CiConfigPath interface{} `json:"ci_config_path"`
|
|
Homepage string `json:"homepage"`
|
|
URL string `json:"url"`
|
|
SSHURL string `json:"ssh_url"`
|
|
HTTPURL string `json:"http_url"`
|
|
} `json:"target"`
|
|
LastCommit struct {
|
|
ID string `json:"id"`
|
|
Message string `json:"message"`
|
|
Timestamp string `json:"timestamp"`
|
|
URL string `json:"url"`
|
|
Author struct {
|
|
Name string `json:"name"`
|
|
Email string `json:"email"`
|
|
} `json:"author"`
|
|
} `json:"last_commit"`
|
|
WorkInProgress bool `json:"work_in_progress"`
|
|
TotalTimeSpent int `json:"total_time_spent"`
|
|
HumanTotalTimeSpent interface{} `json:"human_total_time_spent"`
|
|
HumanTimeEstimate interface{} `json:"human_time_estimate"`
|
|
Action string `json:"action"`
|
|
} `json:"object_attributes"`
|
|
Labels []interface{} `json:"labels"`
|
|
Changes struct {
|
|
Draft struct {
|
|
Previous null.Bool `json:"previous"`
|
|
Current null.Bool `json:"current"`
|
|
} `json:"draft"`
|
|
} `json:"changes"`
|
|
Repository struct {
|
|
Name string `json:"name"`
|
|
URL string `json:"url"`
|
|
Description string `json:"description"`
|
|
Homepage string `json:"homepage"`
|
|
} `json:"repository"`
|
|
}
|
|
)
|