aboutsummaryrefslogtreecommitdiff
path: root/models
diff options
context:
space:
mode:
Diffstat (limited to 'models')
-rw-r--r--models/action.go26
-rw-r--r--models/webhook.go14
-rw-r--r--models/webhook_discord.go213
-rw-r--r--models/webhook_slack.go57
4 files changed, 261 insertions, 49 deletions
diff --git a/models/action.go b/models/action.go
index e4c73f3a..a88968d3 100644
--- a/models/action.go
+++ b/models/action.go
@@ -505,26 +505,30 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
apiRepo := repo.APIFormat(nil)
switch opType {
case ACTION_COMMIT_REPO: // Push
+ compareURL := setting.AppUrl + opts.Commits.CompareURL
+ if isNewBranch {
+ compareURL = ""
+ if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
+ Ref: refName,
+ RefType: "branch",
+ Repo: apiRepo,
+ Sender: apiPusher,
+ }); err != nil {
+ return fmt.Errorf("PrepareWebhooks (new branch): %v", err)
+ }
+ }
+
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, &api.PushPayload{
Ref: opts.RefFullName,
Before: opts.OldCommitID,
After: opts.NewCommitID,
- CompareURL: setting.AppUrl + opts.Commits.CompareURL,
+ CompareURL: compareURL,
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
Repo: apiRepo,
Pusher: apiPusher,
Sender: apiPusher,
}); err != nil {
- return fmt.Errorf("PrepareWebhooks: %v", err)
- }
-
- if isNewBranch {
- return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
- Ref: refName,
- RefType: "branch",
- Repo: apiRepo,
- Sender: apiPusher,
- })
+ return fmt.Errorf("PrepareWebhooks (new commit): %v", err)
}
case ACTION_PUSH_TAG: // Create
diff --git a/models/webhook.go b/models/webhook.go
index c8e0559e..c68c82bd 100644
--- a/models/webhook.go
+++ b/models/webhook.go
@@ -292,6 +292,7 @@ type HookTaskType int
const (
GOGS HookTaskType = iota + 1
SLACK
+ DISCORD
)
var hookTaskTypes = map[string]HookTaskType{
@@ -458,6 +459,10 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
var payloader api.Payloader
for _, w := range ws {
+ if !w.IsActive {
+ continue
+ }
+
switch event {
case HOOK_EVENT_CREATE:
if !w.HasCreateEvent() {
@@ -476,12 +481,15 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
switch w.HookTaskType {
case SLACK:
- // FIXME: dirty fix for buggy support of Discord for Slack-type webhook.
- // Should remove this if we want to support Discord fully as its own.
- payloader, err = GetSlackPayload(strings.Contains(w.URL, ".discordapp.com/"), p, event, w.Meta)
+ payloader, err = GetSlackPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetSlackPayload: %v", err)
}
+ case DISCORD:
+ payloader, err = GetDiscordPayload(p, event, w.Meta)
+ if err != nil {
+ return fmt.Errorf("GetDiscordPayload: %v", err)
+ }
default:
p.SetSecret(w.Secret)
payloader = p
diff --git a/models/webhook_discord.go b/models/webhook_discord.go
new file mode 100644
index 00000000..097c6f89
--- /dev/null
+++ b/models/webhook_discord.go
@@ -0,0 +1,213 @@
+// Copyright 2017 The Gogs Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package models
+
+import (
+ "encoding/json"
+ "fmt"
+ "strings"
+
+ "github.com/gogits/git-module"
+ api "github.com/gogits/go-gogs-client"
+)
+
+type DiscordEmbedFooterObject struct {
+ Text string `json:"text"`
+}
+
+type DiscordEmbedAuthorObject struct {
+ Name string `json:"name"`
+ URL string `json:"url"`
+ IconURL string `json:"icon_url"`
+}
+
+type DiscordEmbedFieldObject struct {
+ Name string `json:"name"`
+ Value string `json:"value"`
+}
+
+type DiscordEmbedObject struct {
+ Title string `json:"title"`
+ Description string `json:"description"`
+ URL string `json:"url"`
+ Footer *DiscordEmbedFooterObject `json:"footer"`
+ Author *DiscordEmbedAuthorObject `json:"author"`
+ Fields []*DiscordEmbedFieldObject `json:"fields"`
+}
+
+type DiscordPayload struct {
+ Content string `json:"content"`
+ Username string `json:"username"`
+ AvatarURL string `json:"avatar_url"`
+ Embeds []*DiscordEmbedObject `json:"embeds"`
+}
+
+func (p *DiscordPayload) SetSecret(_ string) {}
+
+func (p *DiscordPayload) JSONPayload() ([]byte, error) {
+ data, err := json.MarshalIndent(p, "", " ")
+ if err != nil {
+ return []byte{}, err
+ }
+ return data, nil
+}
+
+func DiscordLinkFormatter(url string, text string) string {
+ return fmt.Sprintf("[%s](%s)", text, url)
+}
+
+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
+ 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)
+
+ return &DiscordPayload{
+ Username: slack.Username,
+ AvatarURL: slack.IconURL,
+ Embeds: []*DiscordEmbedObject{{
+ Description: content,
+ Author: &DiscordEmbedAuthorObject{
+ Name: p.Sender.UserName,
+ IconURL: p.Sender.AvatarUrl,
+ },
+ }},
+ }, nil
+}
+
+func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayload, error) {
+ // n new commits
+ var (
+ branchName = git.RefEndName(p.Ref)
+ commitDesc string
+ commitString string
+ )
+
+ if len(p.Commits) == 1 {
+ commitDesc = "1 new commit"
+ } else {
+ commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
+ }
+
+ if len(p.CompareURL) > 0 {
+ commitString = DiscordLinkFormatter(p.CompareURL, commitDesc)
+ } else {
+ commitString = commitDesc
+ }
+
+ repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
+ branchLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
+ content := fmt.Sprintf("Pushed %s to %s/%s:\n", commitString, repoLink, branchLink)
+
+ // for each commit, generate attachment text
+ for i, commit := range p.Commits {
+ content += fmt.Sprintf("%s %s - %s", DiscordSHALinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), commit.Author.Name)
+ // add linebreak to each commit but the last
+ if i < len(p.Commits)-1 {
+ content += "\n"
+ }
+ }
+
+ return &DiscordPayload{
+ Username: slack.Username,
+ AvatarURL: slack.IconURL,
+ Embeds: []*DiscordEmbedObject{{
+ Description: content,
+ Author: &DiscordEmbedAuthorObject{
+ Name: p.Sender.UserName,
+ IconURL: p.Sender.AvatarUrl,
+ },
+ }},
+ }, nil
+}
+
+func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*DiscordPayload, error) {
+ title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)
+ url := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index)
+ content := ""
+ fields := make([]*DiscordEmbedFieldObject, 0, 1)
+ switch p.Action {
+ case api.HOOK_ISSUE_OPENED:
+ title = "New pull request: " + title
+ content = p.PullRequest.Body
+ case api.HOOK_ISSUE_CLOSED:
+ if p.PullRequest.HasMerged {
+ title = "Pull request merged: " + title
+ } else {
+ title = "Pull request closed: " + title
+ }
+ case api.HOOK_ISSUE_REOPENED:
+ title = "Pull request re-opened: " + title
+ case api.HOOK_ISSUE_EDITED:
+ title = "Pull request edited: " + title
+ content = p.PullRequest.Body
+ case api.HOOK_ISSUE_ASSIGNED:
+ title = "Pull request assigned: " + title
+ fields = []*DiscordEmbedFieldObject{{
+ Name: "New Assignee",
+ Value: p.PullRequest.Assignee.UserName,
+ }}
+ case api.HOOK_ISSUE_UNASSIGNED:
+ title = "Pull request unassigned: " + title
+ case api.HOOK_ISSUE_LABEL_UPDATED:
+ title = "Pull request labels updated: " + title
+ labels := make([]string, len(p.PullRequest.Labels))
+ for i := range p.PullRequest.Labels {
+ labels[i] = p.PullRequest.Labels[i].Name
+ }
+ fields = []*DiscordEmbedFieldObject{{
+ Name: "Labels",
+ Value: strings.Join(labels, ", "),
+ }}
+ case api.HOOK_ISSUE_LABEL_CLEARED:
+ title = "Pull request labels cleared: " + title
+ case api.HOOK_ISSUE_SYNCHRONIZED:
+ title = "Pull request synchronized: " + title
+ }
+
+ return &DiscordPayload{
+ Username: slack.Username,
+ AvatarURL: slack.IconURL,
+ Embeds: []*DiscordEmbedObject{{
+ Title: title,
+ Description: content,
+ URL: url,
+ Footer: &DiscordEmbedFooterObject{
+ Text: p.Repository.FullName,
+ },
+ Author: &DiscordEmbedAuthorObject{
+ Name: p.Sender.UserName,
+ IconURL: p.Sender.AvatarUrl,
+ },
+ Fields: fields,
+ }},
+ }, nil
+}
+
+func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
+ d := new(DiscordPayload)
+
+ slack := &SlackMeta{}
+ if err := json.Unmarshal([]byte(meta), &slack); err != nil {
+ return d, fmt.Errorf("GetDiscordPayload meta json: %v", err)
+ }
+
+ switch event {
+ case HOOK_EVENT_CREATE:
+ return getDiscordCreatePayload(p.(*api.CreatePayload), slack)
+ case HOOK_EVENT_PUSH:
+ return getDiscordPushPayload(p.(*api.PushPayload), slack)
+ case HOOK_EVENT_PULL_REQUEST:
+ return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
+ }
+
+ return d, nil
+}
diff --git a/models/webhook_slack.go b/models/webhook_slack.go
index 6e4b9408..213421a5 100644
--- a/models/webhook_slack.go
+++ b/models/webhook_slack.go
@@ -6,7 +6,6 @@ package models
import (
"encoding/json"
- "errors"
"fmt"
"strings"
@@ -23,16 +22,6 @@ type SlackMeta struct {
Color string `json:"color"`
}
-type SlackPayload struct {
- Channel string `json:"channel"`
- Text string `json:"text"`
- Username string `json:"username"`
- IconURL string `json:"icon_url"`
- UnfurlLinks int `json:"unfurl_links"`
- LinkNames int `json:"link_names"`
- Attachments []SlackAttachment `json:"attachments"`
-}
-
type SlackAttachment struct {
Fallback string `json:"fallback"`
Color string `json:"color"`
@@ -40,6 +29,16 @@ type SlackAttachment struct {
Text string `json:"text"`
}
+type SlackPayload struct {
+ Channel string `json:"channel"`
+ Text string `json:"text"`
+ Username string `json:"username"`
+ IconURL string `json:"icon_url"`
+ UnfurlLinks int `json:"unfurl_links"`
+ LinkNames int `json:"link_names"`
+ Attachments []*SlackAttachment `json:"attachments"`
+}
+
func (p *SlackPayload) SetSecret(_ string) {}
func (p *SlackPayload) JSONPayload() ([]byte, error) {
@@ -72,21 +71,13 @@ func SlackLinkFormatter(url string, text string) string {
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
}
-func replaceBadCharsForDiscord(in string) string {
- return strings.NewReplacer("[", "", "]", ":", ":", "/").Replace(in)
-}
-
-func getSlackCreatePayload(isDiscord bool, p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
+func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
// Created tag/branch
refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
- format := "[%s:%s] %s created by %s"
- if isDiscord {
- format = replaceBadCharsForDiscord(format)
- }
- text := fmt.Sprintf(format, repoLink, refLink, p.RefType, p.Sender.UserName)
+ text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
return &SlackPayload{
Channel: slack.Channel,
@@ -96,7 +87,7 @@ func getSlackCreatePayload(isDiscord bool, p *api.CreatePayload, slack *SlackMet
}, nil
}
-func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
+func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
// n new commits
var (
branchName = git.RefEndName(p.Ref)
@@ -117,11 +108,7 @@ func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
- format := "[%s:%s] %s pushed by %s"
- if isDiscord {
- format = replaceBadCharsForDiscord(format)
- }
- text := fmt.Sprintf(format, repoLink, branchLink, commitString, p.Pusher.UserName)
+ text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
var attachmentText string
// for each commit, generate attachment text
@@ -138,14 +125,14 @@ func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
- Attachments: []SlackAttachment{{
+ Attachments: []*SlackAttachment{{
Color: slack.Color,
Text: attachmentText,
}},
}, nil
}
-func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
+func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
@@ -185,7 +172,7 @@ func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
- Attachments: []SlackAttachment{{
+ Attachments: []*SlackAttachment{{
Color: slack.Color,
Title: title,
Text: attachmentText,
@@ -193,21 +180,21 @@ func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack
}, nil
}
-func GetSlackPayload(isDiscord bool, p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
+func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
s := new(SlackPayload)
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
- return s, errors.New("GetSlackPayload meta json:" + err.Error())
+ return s, fmt.Errorf("GetSlackPayload meta json: %v", err)
}
switch event {
case HOOK_EVENT_CREATE:
- return getSlackCreatePayload(isDiscord, p.(*api.CreatePayload), slack)
+ return getSlackCreatePayload(p.(*api.CreatePayload), slack)
case HOOK_EVENT_PUSH:
- return getSlackPushPayload(isDiscord, p.(*api.PushPayload), slack)
+ return getSlackPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
- return getSlackPullRequestPayload(isDiscord, p.(*api.PullRequestPayload), slack)
+ return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
return s, nil