-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implementation of discord webhook (#2402)
* implementation of discord webhook * fix webhooks * fix typo and unnecessary color values * fix typo * fix imports and revert changes to webhook_slack.go
- Loading branch information
Showing
11 changed files
with
427 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
package models | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"code.gitea.io/git" | ||
"code.gitea.io/gitea/modules/setting" | ||
api "code.gitea.io/sdk/gitea" | ||
) | ||
|
||
type ( | ||
// DiscordEmbedFooter for Embed Footer Structure. | ||
DiscordEmbedFooter struct { | ||
Text string `json:"text"` | ||
} | ||
|
||
// DiscordEmbedAuthor for Embed Author Structure | ||
DiscordEmbedAuthor struct { | ||
Name string `json:"name"` | ||
URL string `json:"url"` | ||
IconURL string `json:"icon_url"` | ||
} | ||
|
||
// DiscordEmbedField for Embed Field Structure | ||
DiscordEmbedField struct { | ||
Name string `json:"name"` | ||
Value string `json:"value"` | ||
} | ||
|
||
// DiscordEmbed is for Embed Structure | ||
DiscordEmbed struct { | ||
Title string `json:"title"` | ||
Description string `json:"description"` | ||
URL string `json:"url"` | ||
Color int `json:"color"` | ||
Footer DiscordEmbedFooter `json:"footer"` | ||
Author DiscordEmbedAuthor `json:"author"` | ||
Fields []DiscordEmbedField `json:"fields"` | ||
} | ||
|
||
// DiscordPayload represents | ||
DiscordPayload struct { | ||
Wait bool `json:"wait"` | ||
Content string `json:"content"` | ||
Username string `json:"username"` | ||
AvatarURL string `json:"avatar_url"` | ||
TTS bool `json:"tts"` | ||
Embeds []DiscordEmbed `json:"embeds"` | ||
} | ||
|
||
// DiscordMeta contains the discord metadata | ||
DiscordMeta struct { | ||
Username string `json:"username"` | ||
IconURL string `json:"icon_url"` | ||
} | ||
) | ||
|
||
func color(clr string) int { | ||
if clr != "" { | ||
clr = strings.TrimLeft(clr, "#") | ||
if s, err := strconv.ParseInt(clr, 16, 32); err == nil { | ||
return int(s) | ||
} | ||
} | ||
|
||
return 0 | ||
} | ||
|
||
var ( | ||
successColor = color("1ac600") | ||
warnColor = color("ffd930") | ||
failedColor = color("ff3232") | ||
) | ||
|
||
// SetSecret sets the discord secret | ||
func (p *DiscordPayload) SetSecret(_ string) {} | ||
|
||
// JSONPayload Marshals the DiscordPayload to json | ||
func (p *DiscordPayload) JSONPayload() ([]byte, error) { | ||
data, err := json.MarshalIndent(p, "", " ") | ||
if err != nil { | ||
return []byte{}, err | ||
} | ||
return data, nil | ||
} | ||
|
||
func getDiscordCreatePayload(p *api.CreatePayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||
// created tag/branch | ||
refName := git.RefEndName(p.Ref) | ||
title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) | ||
|
||
return &DiscordPayload{ | ||
Username: meta.Username, | ||
AvatarURL: meta.IconURL, | ||
Embeds: []DiscordEmbed{ | ||
{ | ||
Title: title, | ||
URL: p.Repo.HTMLURL + "/src/" + refName, | ||
Color: successColor, | ||
Author: DiscordEmbedAuthor{ | ||
Name: p.Sender.UserName, | ||
URL: setting.AppURL + p.Sender.UserName, | ||
IconURL: p.Sender.AvatarURL, | ||
}, | ||
}, | ||
}, | ||
}, nil | ||
} | ||
|
||
func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||
var ( | ||
branchName = git.RefEndName(p.Ref) | ||
commitDesc string | ||
) | ||
|
||
var titleLink string | ||
if len(p.Commits) == 1 { | ||
commitDesc = "1 new commit" | ||
titleLink = p.Commits[0].URL | ||
} else { | ||
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits)) | ||
titleLink = p.CompareURL | ||
} | ||
if titleLink == "" { | ||
titleLink = p.Repo.HTMLURL + "/src/" + branchName | ||
} | ||
|
||
title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) | ||
|
||
var text string | ||
// for each commit, generate attachment text | ||
for i, commit := range p.Commits { | ||
text += fmt.Sprintf("[%s](%s) %s - %s", commit.ID[:7], commit.URL, | ||
strings.TrimRight(commit.Message, "\r\n"), commit.Author.Name) | ||
// add linebreak to each commit but the last | ||
if i < len(p.Commits)-1 { | ||
text += "\n" | ||
} | ||
} | ||
|
||
fmt.Println(text) | ||
|
||
return &DiscordPayload{ | ||
Username: meta.Username, | ||
AvatarURL: meta.IconURL, | ||
Embeds: []DiscordEmbed{ | ||
{ | ||
Title: title, | ||
Description: text, | ||
URL: titleLink, | ||
Color: successColor, | ||
Author: DiscordEmbedAuthor{ | ||
Name: p.Sender.UserName, | ||
URL: setting.AppURL + p.Sender.UserName, | ||
IconURL: p.Sender.AvatarURL, | ||
}, | ||
}, | ||
}, | ||
}, nil | ||
} | ||
|
||
func getDiscordPullRequestPayload(p *api.PullRequestPayload, meta *DiscordMeta) (*DiscordPayload, error) { | ||
var text, title string | ||
var color int | ||
switch p.Action { | ||
case api.HookIssueOpened: | ||
title = fmt.Sprintf("[%s] Pull request opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueClosed: | ||
if p.PullRequest.HasMerged { | ||
title = fmt.Sprintf("[%s] Pull request merged: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
color = successColor | ||
} else { | ||
title = fmt.Sprintf("[%s] Pull request closed: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
color = failedColor | ||
} | ||
text = p.PullRequest.Body | ||
case api.HookIssueReOpened: | ||
title = fmt.Sprintf("[%s] Pull request re-opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueEdited: | ||
title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueAssigned: | ||
title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, | ||
p.PullRequest.Assignee.UserName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = successColor | ||
case api.HookIssueUnassigned: | ||
title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueLabelUpdated: | ||
title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueLabelCleared: | ||
title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
case api.HookIssueSynchronized: | ||
title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) | ||
text = p.PullRequest.Body | ||
color = warnColor | ||
} | ||
|
||
return &DiscordPayload{ | ||
Username: meta.Username, | ||
AvatarURL: meta.IconURL, | ||
Embeds: []DiscordEmbed{ | ||
{ | ||
Title: title, | ||
Description: text, | ||
URL: p.PullRequest.HTMLURL, | ||
Color: color, | ||
Author: DiscordEmbedAuthor{ | ||
Name: p.Sender.UserName, | ||
URL: setting.AppURL + p.Sender.UserName, | ||
IconURL: p.Sender.AvatarURL, | ||
}, | ||
}, | ||
}, | ||
}, nil | ||
} | ||
|
||
// GetDiscordPayload converts a discord webhook into a DiscordPayload | ||
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) { | ||
s := new(DiscordPayload) | ||
|
||
discord := &DiscordMeta{} | ||
if err := json.Unmarshal([]byte(meta), &discord); err != nil { | ||
return s, errors.New("GetDiscordPayload meta json:" + err.Error()) | ||
} | ||
|
||
switch event { | ||
case HookEventCreate: | ||
return getDiscordCreatePayload(p.(*api.CreatePayload), discord) | ||
case HookEventPush: | ||
return getDiscordPushPayload(p.(*api.PushPayload), discord) | ||
case HookEventPullRequest: | ||
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord) | ||
} | ||
|
||
return s, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.