Browse Source

webhook: able to detect delete branch or tag (#2315)

pull/4240/head
Unknwon 8 years ago
parent
commit
f0086e66ae
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
  1. 4
      conf/locale/locale_en-US.ini
  2. 74
      models/action.go
  3. 45
      models/update.go
  4. 12
      models/webhook.go
  5. 53
      models/webhook_discord.go
  6. 45
      models/webhook_slack.go
  7. 4
      modules/bindata/bindata.go
  8. 1
      modules/form/repo.go
  9. 1
      routers/repo/webhook.go
  10. 10
      templates/repo/settings/webhook_settings.tmpl
  11. 2
      vendor/github.com/gogits/go-gogs-client/gogs.go
  12. 35
      vendor/github.com/gogits/go-gogs-client/repo_hook.go
  13. 6
      vendor/vendor.json

4
conf/locale/locale_en-US.ini

@ -755,7 +755,9 @@ settings.event_push_only = Just the <code>push</code> event.
settings.event_send_everything = I need <strong>everything</strong>.
settings.event_choose = Let me choose what I need.
settings.event_create = Create
settings.event_create_desc = Branch, or tag created
settings.event_create_desc = Branch or tag created
settings.event_delete = Delete
settings.event_delete_desc = Branch or tag deleted
settings.event_pull_request = Pull Request
settings.event_pull_request_desc = Pull request opened, closed, reopened, edited, assigned, unassigned, label updated, label cleared, or synchronized.
settings.event_push = Push

74
models/action.go

@ -458,18 +458,16 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
return fmt.Errorf("UpdateRepository: %v", err)
}
isNewBranch := false
isNewRef := opts.OldCommitID == git.EMPTY_SHA
isDelRef := opts.NewCommitID == git.EMPTY_SHA
opType := ACTION_COMMIT_REPO
// Check it's tag push or branch.
// Check if it's tag push or branch.
if strings.HasPrefix(opts.RefFullName, git.TAG_PREFIX) {
opType = ACTION_PUSH_TAG
opts.Commits = &PushCommits{}
} else {
// TODO: detect branch deletion
// if not the first commit, set the compare URL.
if opts.OldCommitID == git.EMPTY_SHA {
isNewBranch = true
} else {
if !isNewRef && !isDelRef {
opts.Commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
}
@ -506,20 +504,36 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
go HookQueue.Add(repo.ID)
}()
apiPusher := pusher.APIFormat()
apiRepo := repo.APIFormat(nil)
apiPusher := pusher.APIFormat()
switch opType {
case ACTION_COMMIT_REPO: // Push
if isDelRef {
if err = PrepareWebhooks(repo, HOOK_EVENT_DELETE, &api.DeletePayload{
Ref: refName,
RefType: "branch",
PusherType: api.PUSHER_TYPE_USER,
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks.(delete branch): %v", err)
}
// Delete branch doesn't have anything to push or compare
return nil
}
compareURL := setting.AppUrl + opts.Commits.CompareURL
if isNewBranch {
if isNewRef {
compareURL = ""
if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
Ref: refName,
RefType: "branch",
DefaultBranch: repo.DefaultBranch,
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks (new branch): %v", err)
return fmt.Errorf("PrepareWebhooks.(new branch): %v", err)
}
}
@ -533,16 +547,32 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
Pusher: apiPusher,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks (new commit): %v", err)
return fmt.Errorf("PrepareWebhooks.(new commit): %v", err)
}
case ACTION_PUSH_TAG: // Create
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "tag",
Repo: apiRepo,
Sender: apiPusher,
})
case ACTION_PUSH_TAG: // Tag
if isDelRef {
if err = PrepareWebhooks(repo, HOOK_EVENT_DELETE, &api.DeletePayload{
Ref: refName,
RefType: "tag",
PusherType: api.PUSHER_TYPE_USER,
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks.(delete tag): %v", err)
}
return nil
}
if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "tag",
DefaultBranch: repo.DefaultBranch,
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks.(new tag): %v", err)
}
}
return nil

45
models/update.go

@ -10,8 +10,6 @@ import (
"os/exec"
"strings"
log "gopkg.in/clog.v1"
git "github.com/gogits/git-module"
)
@ -29,6 +27,10 @@ func CommitToPushCommit(commit *git.Commit) *PushCommit {
}
func ListToPushCommits(l *list.List) *PushCommits {
if l == nil {
return &PushCommits{}
}
commits := make([]*PushCommit, 0)
var actEmail string
for e := l.Front(); e != nil; e = e.Next() {
@ -68,12 +70,6 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
return fmt.Errorf("Fail to call 'git update-server-info': %v", err)
}
if isDelRef {
log.Trace("Reference '%s' has been deleted from '%s/%s' by %s",
opts.RefFullName, opts.RepoUserName, opts.RepoName, opts.PusherName)
return nil
}
gitRepo, err := git.OpenRepository(repoPath)
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
@ -100,27 +96,30 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
NewCommitID: opts.NewCommitID,
Commits: &PushCommits{},
}); err != nil {
return fmt.Errorf("CommitRepoAction (tag): %v", err)
return fmt.Errorf("CommitRepoAction.(tag): %v", err)
}
return nil
}
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
if err != nil {
return fmt.Errorf("gitRepo.GetCommit: %v", err)
}
// Push new branch.
var l *list.List
if isNewRef {
l, err = newCommit.CommitsBeforeLimit(10)
// Skip read parent commits when delete branch
if !isDelRef {
// Push new branch.
newCommit, err := gitRepo.GetCommit(opts.NewCommitID)
if err != nil {
return fmt.Errorf("newCommit.CommitsBeforeLimit: %v", err)
return fmt.Errorf("GetCommit [commit_id: %s]: %v", opts.NewCommitID, err)
}
} else {
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
if err != nil {
return fmt.Errorf("newCommit.CommitsBeforeUntil: %v", err)
if isNewRef {
l, err = newCommit.CommitsBeforeLimit(10)
if err != nil {
return fmt.Errorf("CommitsBeforeLimit [commit_id: %s]: %v", newCommit.ID, err)
}
} else {
l, err = newCommit.CommitsBeforeUntil(opts.OldCommitID)
if err != nil {
return fmt.Errorf("CommitsBeforeUntil [commit_id: %s]: %v", opts.OldCommitID, err)
}
}
}
@ -133,7 +132,7 @@ func PushUpdate(opts PushUpdateOptions) (err error) {
NewCommitID: opts.NewCommitID,
Commits: ListToPushCommits(l),
}); err != nil {
return fmt.Errorf("CommitRepoAction (branch): %v", err)
return fmt.Errorf("CommitRepoAction.(branch): %v", err)
}
return nil
}

12
models/webhook.go

@ -63,6 +63,7 @@ func IsValidHookContentType(name string) bool {
type HookEvents struct {
Create bool `json:"create"`
Delete bool `json:"delete"`
Push bool `json:"push"`
PullRequest bool `json:"pull_request"`
}
@ -156,6 +157,12 @@ func (w *Webhook) HasCreateEvent() bool {
(w.ChooseEvents && w.HookEvents.Create)
}
// HasDeleteEvent returns true if hook enabled delete event.
func (w *Webhook) HasDeleteEvent() bool {
return w.SendEverything ||
(w.ChooseEvents && w.HookEvents.Delete)
}
// HasPushEvent returns true if hook enabled push event.
func (w *Webhook) HasPushEvent() bool {
return w.PushOnly || w.SendEverything ||
@ -337,6 +344,7 @@ type HookEventType string
const (
HOOK_EVENT_CREATE HookEventType = "create"
HOOK_EVENT_DELETE HookEventType = "delete"
HOOK_EVENT_PUSH HookEventType = "push"
HOOK_EVENT_PULL_REQUEST HookEventType = "pull_request"
)
@ -462,6 +470,10 @@ func prepareWebhooks(repo *Repository, event HookEventType, p api.Payloader, web
if !w.HasCreateEvent() {
continue
}
case HOOK_EVENT_DELETE:
if !w.HasDeleteEvent() {
continue
}
case HOOK_EVENT_PUSH:
if !w.HasPushEvent() {
continue

53
models/webhook_discord.go

@ -68,22 +68,35 @@ func DiscordSHALinkFormatter(url string, text string) string {
return fmt.Sprintf("[`%s`](%s)", text, url)
}
func getDiscordCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*DiscordPayload, error) {
// Created tag/branch
// getDiscordCreatePayload composes Discord payload for create new branch or tag.
func getDiscordCreatePayload(p *api.CreatePayload) (*DiscordPayload, error) {
refName := git.RefEndName(p.Ref)
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
content := fmt.Sprintf("Created new %s: %s/%s", p.RefType, repoLink, refLink)
color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
return &DiscordPayload{
Username: slack.Username,
AvatarURL: slack.IconURL,
Embeds: []*DiscordEmbedObject{{
Description: content,
URL: setting.AppUrl + p.Sender.UserName,
Color: int(color),
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
},
}},
}, nil
}
// getDiscordDeletePayload composes Discord payload for delete a branch or tag.
func getDiscordDeletePayload(p *api.DeletePayload) (*DiscordPayload, error) {
refName := git.RefEndName(p.Ref)
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
content := fmt.Sprintf("Deleted %s: %s/%s", p.RefType, repoLink, refName)
return &DiscordPayload{
Embeds: []*DiscordEmbedObject{{
Description: content,
URL: setting.AppUrl + p.Sender.UserName,
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
@ -206,22 +219,32 @@ func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (
}, nil
}
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
d := new(DiscordPayload)
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (payload *DiscordPayload, err error) {
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
return d, fmt.Errorf("GetDiscordPayload meta json: %v", err)
return nil, fmt.Errorf("json.Unmarshal: %v", err)
}
switch event {
case HOOK_EVENT_CREATE:
return getDiscordCreatePayload(p.(*api.CreatePayload), slack)
payload, err = getDiscordCreatePayload(p.(*api.CreatePayload))
case HOOK_EVENT_DELETE:
payload, err = getDiscordDeletePayload(p.(*api.DeletePayload))
case HOOK_EVENT_PUSH:
return getDiscordPushPayload(p.(*api.PushPayload), slack)
payload, err = getDiscordPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
payload, err = getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
if err != nil {
return nil, fmt.Errorf("event '%s': %v", event, err)
}
payload.Username = slack.Username
payload.AvatarURL = slack.IconURL
if len(payload.Embeds) > 0 {
color, _ := strconv.ParseInt(strings.TrimLeft(slack.Color, "#"), 16, 32)
payload.Embeds[0].Color = int(color)
}
return d, nil
return payload, nil
}

45
models/webhook_slack.go

@ -69,19 +69,24 @@ func SlackLinkFormatter(url string, text string) string {
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
}
func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
// Created tag/branch
// getSlackCreatePayload composes Slack payload for create new branch or tag.
func getSlackCreatePayload(p *api.CreatePayload) (*SlackPayload, error) {
refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
return &SlackPayload{
Text: text,
}, nil
}
// getSlackDeletePayload composes Slack payload for delete a branch or tag.
func getSlackDeletePayload(p *api.DeletePayload) (*SlackPayload, error) {
refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
return &SlackPayload{
Channel: slack.Channel,
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Text: text,
}, nil
}
@ -178,22 +183,32 @@ func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*S
}, nil
}
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
s := new(SlackPayload)
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (payload *SlackPayload, err error) {
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
return s, fmt.Errorf("GetSlackPayload meta json: %v", err)
return nil, fmt.Errorf("json.Unmarshal: %v", err)
}
switch event {
case HOOK_EVENT_CREATE:
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
payload, err = getSlackCreatePayload(p.(*api.CreatePayload))
case HOOK_EVENT_DELETE:
payload, err = getSlackDeletePayload(p.(*api.DeletePayload))
case HOOK_EVENT_PUSH:
return getSlackPushPayload(p.(*api.PushPayload), slack)
payload, err = getSlackPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
payload, err = getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
if err != nil {
return nil, fmt.Errorf("event '%s': %v", event, err)
}
payload.Channel = slack.Channel
payload.Username = slack.Username
payload.IconURL = slack.IconURL
if len(payload.Attachments) > 0 {
payload.Attachments[0].Color = slack.Color
}
return s, nil
return payload, nil
}

4
modules/bindata/bindata.go

File diff suppressed because one or more lines are too long

1
modules/form/repo.go

@ -135,6 +135,7 @@ func (f *ProtectBranch) Validate(ctx *macaron.Context, errs binding.Errors) bind
type Webhook struct {
Events string
Create bool
Delete bool
Push bool
PullRequest bool
Active bool

1
routers/repo/webhook.go

@ -110,6 +110,7 @@ func ParseHookEvent(f form.Webhook) *models.HookEvent {
ChooseEvents: f.ChooseEvents(),
HookEvents: models.HookEvents{
Create: f.Create,
Delete: f.Delete,
Push: f.Push,
PullRequest: f.PullRequest,
},

10
templates/repo/settings/webhook_settings.tmpl

@ -32,6 +32,16 @@
</div>
</div>
</div>
<!-- Delete -->
<div class="seven wide column">
<div class="field">
<div class="ui checkbox">
<input class="hidden" name="delete" type="checkbox" tabindex="0" {{if .Webhook.Delete}}checked{{end}}>
<label>{{.i18n.Tr "repo.settings.event_delete"}}</label>
<span class="help">{{.i18n.Tr "repo.settings.event_delete_desc"}}</span>
</div>
</div>
</div>
<!-- Push -->
<div class="seven wide column">
<div class="field">

2
vendor/github.com/gogits/go-gogs-client/gogs.go generated vendored

@ -14,7 +14,7 @@ import (
)
func Version() string {
return "0.12.6"
return "0.12.7"
}
// Client represents a Gogs API client.

35
vendor/github.com/gogits/go-gogs-client/repo_hook.go generated vendored

@ -91,6 +91,7 @@ type PayloadCommit struct {
var (
_ Payloader = &CreatePayload{}
_ Payloader = &DeletePayload{}
_ Payloader = &PushPayload{}
_ Payloader = &PullRequestPayload{}
)
@ -103,10 +104,11 @@ var (
// \/ \/ \/ \/
type CreatePayload struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
Ref string `json:"ref"`
RefType string `json:"ref_type"`
DefaultBranch string `json:"default_branch"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *CreatePayload) JSONPayload() ([]byte, error) {
@ -133,6 +135,31 @@ func ParseCreateHook(raw []byte) (*CreatePayload, error) {
return hook, nil
}
// ________ .__ __
// \______ \ ____ | | _____/ |_ ____
// | | \_/ __ \| | _/ __ \ __\/ __ \
// | ` \ ___/| |_\ ___/| | \ ___/
// /_______ /\___ >____/\___ >__| \___ >
// \/ \/ \/ \/
type PusherType string
const (
PUSHER_TYPE_USER PusherType = "user"
)
type DeletePayload struct {
Ref string `json:"ref"`
RefType string `json:"ref_type"`
PusherType PusherType `json:"pusher_type"`
Repo *Repository `json:"repository"`
Sender *User `json:"sender"`
}
func (p *DeletePayload) JSONPayload() ([]byte, error) {
return json.MarshalIndent(p, "", " ")
}
// __________ .__
// \______ \__ __ _____| |__
// | ___/ | \/ ___/ | \

6
vendor/vendor.json vendored

@ -165,10 +165,10 @@
"revisionTime": "2017-02-19T18:16:29Z"
},
{
"checksumSHA1": "exKX51W/Hieq7OOmYK2gYn+Huuw=",
"checksumSHA1": "rtJ+nZ9VHh2X2Zon7wLczPAAc/s=",
"path": "github.com/gogits/go-gogs-client",
"revision": "f12fbacb5495120dc62dae7cfdf140d39bf6f715",
"revisionTime": "2017-02-24T06:16:35Z"
"revision": "ba630f557c8349952183305373fa89b155202bac",
"revisionTime": "2017-02-24T20:25:47Z"
},
{
"checksumSHA1": "p4yoFWgDiTfpu1JYgh26t6+VDTk=",

Loading…
Cancel
Save