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.
go-scm/scm/driver/azure/webhook.go

791 lines
25 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 azure
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/http"
"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
}
// we need to read the json data then look at the eventType
var unstructuredJSON map[string]interface{}
jsonErr := json.Unmarshal([]byte(data), &unstructuredJSON)
if jsonErr != nil {
return nil, fmt.Errorf("Error parsing JSON from webhook: %s", jsonErr)
}
eventType := unstructuredJSON["eventType"].(string)
switch eventType {
case "git.push":
// https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.push
src := new(pushHook)
err := json.Unmarshal(data, src)
if err != nil {
return nil, err
}
dst := convertPushHook(src)
return dst, nil
case "git.pullrequest.created":
// https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.created
src := new(createPullRequestHook)
err := json.Unmarshal(data, src)
if err != nil {
return nil, err
}
dst := convertCreatePullRequestHook(src)
dst.Action = scm.ActionCreate
return dst, nil
case "git.pullrequest.updated":
// https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.updated
src := new(updatePullRequestHook)
err := json.Unmarshal(data, src)
if err != nil {
return nil, err
}
dst := convertUpdatePullRequestHook(src)
dst.Action = scm.ActionUpdate
return dst, nil
case "git.pullrequest.merged":
// https://docs.microsoft.com/en-us/azure/devops/service-hooks/events?view=azure-devops#git.pullrequest.merged
src := new(mergePullRequestHook)
err := json.Unmarshal(data, src)
if err != nil {
return nil, err
}
dst := convertMergePullRequestHook(src)
dst.Action = scm.ActionMerge
return dst, nil
case "ms.vss-code.git-pullrequest-comment-event":
src := new(issueCommentPullRequestHook)
err := json.Unmarshal(data, src)
if err != nil {
return nil, err
}
dst := convertIssueCommentHook(src)
dst.Action = getIssueCommentAction(src)
return dst, nil
default:
return nil, scm.ErrUnknownEvent
}
}
func getIssueCommentAction(src *issueCommentPullRequestHook) scm.Action {
if src.Resource.Comment.IsDeleted {
return scm.ActionDelete
} else if src.Resource.Comment.PublishedDate.Equal(src.Resource.Comment.LastUpdatedDate) {
return scm.ActionCreate
} else {
return scm.ActionEdit
}
}
func convertPushHook(src *pushHook) *scm.PushHook {
var commits []scm.Commit
for _, c := range src.Resource.Commits {
commits = append(commits,
scm.Commit{
Sha: c.CommitID,
Message: c.Comment,
Link: c.URL,
Author: scm.Signature{
Login: c.Author.Name,
Email: c.Author.Email,
Name: c.Author.Name,
Date: c.Author.Date,
},
Committer: scm.Signature{
Login: c.Committer.Name,
Email: c.Committer.Email,
Name: c.Committer.Name,
Date: c.Committer.Date,
},
})
}
dst := &scm.PushHook{
Commit: scm.Commit{
Sha: src.Resource.RefUpdates[0].NewObjectID,
Message: "",
Author: scm.Signature{
Login: src.Resource.PushedBy.ID,
Name: src.Resource.PushedBy.DisplayName,
Email: src.Resource.PushedBy.UniqueName,
Avatar: src.Resource.PushedBy.ImageURL,
},
Committer: scm.Signature{
Login: src.Resource.PushedBy.ID,
Name: src.Resource.PushedBy.DisplayName,
Email: src.Resource.PushedBy.UniqueName,
Avatar: src.Resource.PushedBy.ImageURL,
},
Link: "",
},
Ref: src.Resource.RefUpdates[0].Name,
Before: src.Resource.RefUpdates[0].OldObjectID,
After: src.Resource.RefUpdates[0].NewObjectID,
Sender: scm.User{
Login: src.Resource.PushedBy.ID,
Name: src.Resource.PushedBy.DisplayName,
Email: src.Resource.PushedBy.UniqueName,
Avatar: src.Resource.PushedBy.ImageURL,
},
Repo: scm.Repository{
ID: src.Resource.Repository.ID,
Branch: scm.TrimRef(src.Resource.Repository.DefaultBranch),
Name: src.Resource.Repository.Name,
Namespace: src.Resource.Repository.Project.Name,
Clone: src.Resource.Repository.RemoteURL,
Link: src.Resource.Repository.RemoteURL,
},
Commits: commits,
}
return dst
}
func convertCreatePullRequestHook(src *createPullRequestHook) (returnVal *scm.PullRequestHook) {
returnVal = &scm.PullRequestHook{
PullRequest: scm.PullRequest{
Number: src.Resource.PullRequestID,
Title: src.Resource.Title,
Body: src.Resource.Description,
Sha: src.Resource.LastMergeSourceCommit.CommitID,
Ref: src.Resource.SourceRefName,
Source: scm.TrimRef(src.Resource.SourceRefName),
Target: scm.TrimRef(src.Resource.TargetRefName),
Link: src.Resource.URL,
Closed: false,
Merged: false,
Author: scm.User{
Login: src.Resource.CreatedBy.DisplayName,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
Created: src.Resource.CreationDate,
},
Repo: scm.Repository{
ID: src.Resource.Repository.ID,
Name: src.Resource.Repository.Name,
Namespace: src.Resource.Repository.Project.Name,
Link: src.Resource.Repository.WebURL,
Clone: src.Resource.Repository.WebURL,
CloneSSH: src.Resource.Repository.SSHURL,
},
Sender: scm.User{
Login: src.Resource.CreatedBy.ID,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
}
return returnVal
}
func convertUpdatePullRequestHook(src *updatePullRequestHook) (returnVal *scm.PullRequestHook) {
returnVal = &scm.PullRequestHook{
PullRequest: scm.PullRequest{
Number: src.Resource.PullRequestID,
Title: src.Resource.Title,
Body: src.Resource.Description,
Sha: src.Resource.LastMergeSourceCommit.CommitID,
Ref: src.Resource.SourceRefName,
Source: scm.TrimRef(src.Resource.SourceRefName),
Target: scm.TrimRef(src.Resource.TargetRefName),
Link: src.Resource.URL,
Closed: src.Resource.ClosedDate.Valid,
Merged: false,
Author: scm.User{
Login: src.Resource.CreatedBy.DisplayName,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
Created: src.Resource.CreationDate,
},
Repo: scm.Repository{
ID: src.Resource.Repository.ID,
Name: src.Resource.Repository.Name,
Namespace: src.Resource.Repository.Project.Name,
Link: src.Resource.Repository.WebURL,
Clone: src.Resource.Repository.WebURL,
CloneSSH: src.Resource.Repository.SSHURL,
},
Sender: scm.User{
Login: src.Resource.CreatedBy.ID,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
}
return returnVal
}
func convertMergePullRequestHook(src *mergePullRequestHook) (returnVal *scm.PullRequestHook) {
returnVal = &scm.PullRequestHook{
PullRequest: scm.PullRequest{
Number: src.Resource.PullRequestID,
Title: src.Resource.Title,
Body: src.Resource.Description,
Sha: src.Resource.LastMergeSourceCommit.CommitID,
Ref: src.Resource.SourceRefName,
Source: scm.TrimRef(src.Resource.SourceRefName),
Target: scm.TrimRef(src.Resource.TargetRefName),
Link: src.Resource.URL,
Closed: false,
Merged: true,
Author: scm.User{
Login: src.Resource.CreatedBy.DisplayName,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
Created: src.Resource.CreationDate,
},
Repo: scm.Repository{
ID: src.Resource.Repository.ID,
Name: src.Resource.Repository.Name,
Namespace: src.Resource.Repository.Project.Name,
Link: src.Resource.Repository.WebURL,
Clone: src.Resource.Repository.WebURL,
CloneSSH: src.Resource.Repository.SSHURL,
},
Sender: scm.User{
Login: src.Resource.CreatedBy.ID,
Name: src.Resource.CreatedBy.DisplayName,
Email: src.Resource.CreatedBy.UniqueName,
Avatar: src.Resource.CreatedBy.ImageURL,
},
}
return returnVal
}
func convertIssueCommentHook(src *issueCommentPullRequestHook) *scm.IssueCommentHook {
dst := &scm.IssueCommentHook{
Repo: scm.Repository{
ID: src.Resource.PullRequest.Repository.ID,
Namespace: src.Resource.PullRequest.Repository.Project.Name,
Name: src.Resource.PullRequest.Repository.Name,
Branch: scm.TrimRef(src.Resource.PullRequest.SourceRefName),
Private: false,
Clone: src.Resource.PullRequest.Repository.WebURL,
CloneSSH: src.Resource.PullRequest.Repository.SSHURL,
Link: src.Resource.PullRequest.Repository.WebURL,
},
Issue: scm.Issue{
Number: src.Resource.PullRequest.PullRequestID,
Title: src.Resource.PullRequest.Title,
Body: src.Resource.PullRequest.Description,
Link: src.Resource.PullRequest.URL,
Author: scm.User{
Login: src.Resource.PullRequest.CreatedBy.DisplayName,
Name: src.Resource.PullRequest.CreatedBy.DisplayName,
Email: src.Resource.PullRequest.CreatedBy.UniqueName,
Avatar: src.Resource.PullRequest.CreatedBy.ImageURL,
},
PullRequest: scm.PullRequest{
Number: src.Resource.PullRequest.PullRequestID,
Title: src.Resource.PullRequest.Title,
Body: src.Resource.PullRequest.Description,
Sha: src.Resource.PullRequest.LastMergeSourceCommit.CommitID,
Ref: src.Resource.PullRequest.SourceRefName,
Source: scm.TrimRef(src.Resource.PullRequest.SourceRefName),
Target: scm.TrimRef(src.Resource.PullRequest.TargetRefName),
Link: src.Resource.PullRequest.URL,
Closed: false,
Merged: false,
Author: scm.User{
Login: src.Resource.PullRequest.CreatedBy.DisplayName,
Name: src.Resource.PullRequest.CreatedBy.DisplayName,
Email: src.Resource.PullRequest.CreatedBy.UniqueName,
Avatar: src.Resource.PullRequest.CreatedBy.ImageURL,
},
Created: src.Resource.PullRequest.CreationDate,
},
Created: src.Resource.PullRequest.CreationDate,
},
Comment: scm.Comment{
ID: src.Resource.Comment.ID,
Body: src.Resource.Comment.Content,
Author: scm.User{
Email: src.Resource.Comment.Author.UniqueName,
Login: src.Resource.Comment.Author.ID,
Name: src.Resource.Comment.Author.DisplayName,
},
Created: src.Resource.Comment.PublishedDate,
Updated: src.Resource.Comment.LastUpdatedDate,
},
Sender: scm.User{
Email: src.Resource.Comment.Author.UniqueName,
Login: src.Resource.Comment.Author.ID,
Name: src.Resource.Comment.Author.DisplayName,
},
}
return dst
}
type pushHook struct {
CreatedDate string `json:"createdDate"`
DetailedMessage struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"detailedMessage"`
EventType string `json:"eventType"`
ID string `json:"id"`
Message struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"message"`
PublisherID string `json:"publisherId"`
Resource struct {
Commits []struct {
Author struct {
Date time.Time `json:"date"`
Email string `json:"email"`
Name string `json:"name"`
} `json:"author"`
Comment string `json:"comment"`
CommitID string `json:"commitId"`
Committer struct {
Date time.Time `json:"date"`
Email string `json:"email"`
Name string `json:"name"`
} `json:"committer"`
URL string `json:"url"`
} `json:"commits"`
Date string `json:"date"`
PushID int64 `json:"pushId"`
PushedBy struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
UniqueName string `json:"uniqueName"`
ImageURL string `json:"imageUrl"`
} `json:"pushedBy"`
RefUpdates []struct {
Name string `json:"name"`
NewObjectID string `json:"newObjectId"`
OldObjectID string `json:"oldObjectId"`
} `json:"refUpdates"`
Repository struct {
DefaultBranch string `json:"defaultBranch"`
ID string `json:"id"`
Name string `json:"name"`
Project struct {
ID string `json:"id"`
Name string `json:"name"`
State string `json:"state"`
URL string `json:"url"`
} `json:"project"`
RemoteURL string `json:"remoteUrl"`
URL string `json:"url"`
} `json:"repository"`
URL string `json:"url"`
} `json:"resource"`
ResourceContainers struct {
Account struct {
ID string `json:"id"`
} `json:"account"`
Collection struct {
ID string `json:"id"`
} `json:"collection"`
Project struct {
ID string `json:"id"`
} `json:"project"`
} `json:"resourceContainers"`
ResourceVersion string `json:"resourceVersion"`
Scope string `json:"scope"`
}
type createPullRequestHook struct {
ID string `json:"id"`
EventType string `json:"eventType"`
PublisherID string `json:"publisherId"`
Scope string `json:"scope"`
Message struct {
Text string `json:"text"`
HTML string `json:"html"`
Markdown string `json:"markdown"`
} `json:"message"`
DetailedMessage struct {
Text string `json:"text"`
HTML string `json:"html"`
Markdown string `json:"markdown"`
} `json:"detailedMessage"`
Resource struct {
Repository struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
WebURL string `json:"webUrl"`
SSHURL string `json:"sshUrl"`
Project struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
State string `json:"state"`
} `json:"project"`
DefaultBranch string `json:"defaultBranch"`
RemoteURL string `json:"remoteUrl"`
} `json:"repository"`
PullRequestID int `json:"pullRequestId"`
Status string `json:"status"`
CreatedBy struct {
ID string `json:"id"`
DisplayName string `json:"displayName"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
ImageURL string `json:"imageUrl"`
} `json:"createdBy"`
CreationDate time.Time `json:"creationDate"`
Title string `json:"title"`
Description string `json:"description"`
SourceRefName string `json:"sourceRefName"`
TargetRefName string `json:"targetRefName"`
MergeStatus string `json:"mergeStatus"`
MergeID string `json:"mergeId"`
LastMergeSourceCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeSourceCommit"`
LastMergeTargetCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeTargetCommit"`
LastMergeCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeCommit"`
Reviewers []struct {
ReviewerURL interface{} `json:"reviewerUrl"`
Vote int `json:"vote"`
ID string `json:"id"`
DisplayName string `json:"displayName"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
ImageURL string `json:"imageUrl"`
IsContainer bool `json:"isContainer"`
} `json:"reviewers"`
URL string `json:"url"`
} `json:"resource"`
ResourceVersion string `json:"resourceVersion"`
ResourceContainers struct {
Collection struct {
ID string `json:"id"`
} `json:"collection"`
Account struct {
ID string `json:"id"`
} `json:"account"`
Project struct {
ID string `json:"id"`
} `json:"project"`
} `json:"resourceContainers"`
CreatedDate time.Time `json:"createdDate"`
}
type updatePullRequestHook struct {
CreatedDate string `json:"createdDate"`
DetailedMessage struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"detailedMessage"`
EventType string `json:"eventType"`
ID string `json:"id"`
Message struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"message"`
PublisherID string `json:"publisherId"`
Resource struct {
ClosedDate null.String `json:"closedDate"`
Commits []struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"commits"`
CreatedBy struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
} `json:"createdBy"`
CreationDate time.Time `json:"creationDate"`
Description string `json:"description"`
LastMergeCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeCommit"`
LastMergeSourceCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeSourceCommit"`
LastMergeTargetCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeTargetCommit"`
MergeID string `json:"mergeId"`
MergeStatus string `json:"mergeStatus"`
PullRequestID int `json:"pullRequestId"`
Repository struct {
DefaultBranch string `json:"defaultBranch"`
ID string `json:"id"`
Name string `json:"name"`
Project struct {
ID string `json:"id"`
Name string `json:"name"`
State string `json:"state"`
URL string `json:"url"`
} `json:"project"`
RemoteURL string `json:"remoteUrl"`
URL string `json:"url"`
WebURL string `json:"webUrl"`
SSHURL string `json:"sshUrl"`
} `json:"repository"`
Reviewers []struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
IsContainer bool `json:"isContainer"`
ReviewerURL interface{} `json:"reviewerUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
Vote int64 `json:"vote"`
} `json:"reviewers"`
SourceRefName string `json:"sourceRefName"`
Status string `json:"status"`
TargetRefName string `json:"targetRefName"`
Title string `json:"title"`
URL string `json:"url"`
} `json:"resource"`
ResourceContainers struct {
Account struct {
ID string `json:"id"`
} `json:"account"`
Collection struct {
ID string `json:"id"`
} `json:"collection"`
Project struct {
ID string `json:"id"`
} `json:"project"`
} `json:"resourceContainers"`
ResourceVersion string `json:"resourceVersion"`
Scope string `json:"scope"`
}
type mergePullRequestHook struct {
CreatedDate string `json:"createdDate"`
DetailedMessage struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"detailedMessage"`
EventType string `json:"eventType"`
ID string `json:"id"`
Message struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"message"`
PublisherID string `json:"publisherId"`
Resource struct {
ClosedDate string `json:"closedDate"`
CreatedBy struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
} `json:"createdBy"`
CreationDate time.Time `json:"creationDate"`
Description string `json:"description"`
LastMergeCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeCommit"`
LastMergeSourceCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeSourceCommit"`
LastMergeTargetCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeTargetCommit"`
MergeID string `json:"mergeId"`
MergeStatus string `json:"mergeStatus"`
PullRequestID int `json:"pullRequestId"`
Repository struct {
DefaultBranch string `json:"defaultBranch"`
ID string `json:"id"`
Name string `json:"name"`
Project struct {
ID string `json:"id"`
Name string `json:"name"`
State string `json:"state"`
URL string `json:"url"`
} `json:"project"`
RemoteURL string `json:"remoteUrl"`
URL string `json:"url"`
WebURL string `json:"webUrl"`
SSHURL string `json:"sshUrl"`
} `json:"repository"`
Reviewers []struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
IsContainer bool `json:"isContainer"`
ReviewerURL interface{} `json:"reviewerUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
Vote int64 `json:"vote"`
} `json:"reviewers"`
SourceRefName string `json:"sourceRefName"`
Status string `json:"status"`
TargetRefName string `json:"targetRefName"`
Title string `json:"title"`
URL string `json:"url"`
} `json:"resource"`
ResourceContainers struct {
Account struct {
ID string `json:"id"`
} `json:"account"`
Collection struct {
ID string `json:"id"`
} `json:"collection"`
Project struct {
ID string `json:"id"`
} `json:"project"`
} `json:"resourceContainers"`
ResourceVersion string `json:"resourceVersion"`
Scope string `json:"scope"`
}
type issueCommentPullRequestHook struct {
CreatedDate string `json:"createdDate"`
DetailedMessage struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"detailedMessage"`
EventType string `json:"eventType"`
ID string `json:"id"`
Message struct {
HTML string `json:"html"`
Markdown string `json:"markdown"`
Text string `json:"text"`
} `json:"message"`
PublisherID string `json:"publisherId"`
Resource struct {
PullRequest struct {
CreatedBy struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
} `json:"createdBy"`
CreationDate time.Time `json:"creationDate"`
Description string `json:"description"`
LastMergeCommit struct {
CommitID string `json:"commitId"`
Author struct {
Date time.Time `json:"date"`
Email string `json:"email"`
Name string `json:"name"`
} `json:"author"`
URL string `json:"url"`
} `json:"lastMergeCommit"`
LastMergeSourceCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeSourceCommit"`
LastMergeTargetCommit struct {
CommitID string `json:"commitId"`
URL string `json:"url"`
} `json:"lastMergeTargetCommit"`
MergeID string `json:"mergeId"`
MergeStatus string `json:"mergeStatus"`
PullRequestID int `json:"pullRequestId"`
Repository struct {
ID string `json:"id"`
Name string `json:"name"`
Project struct {
ID string `json:"id"`
Name string `json:"name"`
State string `json:"state"`
URL string `json:"url"`
} `json:"project"`
RemoteURL string `json:"remoteUrl"`
URL string `json:"url"`
WebURL string `json:"webUrl"`
SSHURL string `json:"sshUrl"`
} `json:"repository"`
Reviewers []struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
IsContainer bool `json:"isContainer"`
ReviewerURL interface{} `json:"reviewerUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
Vote int64 `json:"vote"`
} `json:"reviewers"`
SourceRefName string `json:"sourceRefName"`
Status string `json:"status"`
TargetRefName string `json:"targetRefName"`
Title string `json:"title"`
URL string `json:"url"`
} `json:"pullRequest"`
Comment struct {
ID int `json:"id"`
ParentCommentId int `json:"parentCommentId"`
Content string `json:"content"`
PublishedDate time.Time `json:"publishedDate"`
LastUpdatedDate time.Time `json:"lastUpdatedDate"`
LastContentUpdatedDate time.Time `json:"lastContentUpdatedDate"`
CommentType string `json:"commentType"`
IsDeleted bool `json:"isDeleted"`
Author struct {
DisplayName string `json:"displayName"`
ID string `json:"id"`
ImageURL string `json:"imageUrl"`
UniqueName string `json:"uniqueName"`
URL string `json:"url"`
} `json:"author"`
} `json:"comment"`
} `json:"resource"`
ResourceContainers struct {
Account struct {
ID string `json:"id"`
} `json:"account"`
Collection struct {
ID string `json:"id"`
} `json:"collection"`
Project struct {
ID string `json:"id"`
} `json:"project"`
} `json:"resourceContainers"`
ResourceVersion string `json:"resourceVersion"`
Scope string `json:"scope"`
}