]> source.dussan.org Git - gitea.git/commitdiff
Add tests for all webhooks (#16214)
authorKN4CK3R <admin@oldschoolhack.me>
Mon, 21 Jun 2021 02:12:19 +0000 (04:12 +0200)
committerGitHub <noreply@github.com>
Mon, 21 Jun 2021 02:12:19 +0000 (22:12 -0400)
* Added tests for MS Teams.

* Added tests for Dingtalk.

* Added tests for Telegram.

* Added tests for Feishu.

* Added tests for Discord.

* Added tests for closed issue and pullrequest comment.

* Added tests for Matrix.

* Trim all spaces.

* Added tests for Slack.

* Added JSONPayload tests.

* Added general tests.

* Replaced duplicated code.

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
15 files changed:
services/webhook/dingtalk.go
services/webhook/dingtalk_test.go
services/webhook/discord.go
services/webhook/discord_test.go [new file with mode: 0644]
services/webhook/feishu.go
services/webhook/feishu_test.go [new file with mode: 0644]
services/webhook/general.go
services/webhook/general_test.go
services/webhook/matrix_test.go
services/webhook/msteams.go
services/webhook/msteams_test.go [new file with mode: 0644]
services/webhook/slack.go
services/webhook/slack_test.go
services/webhook/telegram.go
services/webhook/telegram_test.go

index 0401464a448a6c4fdfdcb64ec3e021691d5c8b89..d781b8c87dbf6d386fe9ebfe4a32a81b10f06027 100644 (file)
@@ -44,16 +44,7 @@ func (d *DingtalkPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        title,
-                       Title:       title,
-                       HideAvatar:  "0",
-                       SingleTitle: fmt.Sprintf("view ref %s", refName),
-                       SingleURL:   p.Repo.HTMLURL + "/src/" + refName,
-               },
-       }, nil
+       return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+refName), nil
 }
 
 // Delete implements PayloadConvertor Delete method
@@ -62,32 +53,14 @@ func (d *DingtalkPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        title,
-                       Title:       title,
-                       HideAvatar:  "0",
-                       SingleTitle: fmt.Sprintf("view ref %s", refName),
-                       SingleURL:   p.Repo.HTMLURL + "/src/" + refName,
-               },
-       }, nil
+       return createDingtalkPayload(title, title, fmt.Sprintf("view ref %s", refName), p.Repo.HTMLURL+"/src/"+refName), nil
 }
 
 // Fork implements PayloadConvertor Fork method
 func (d *DingtalkPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
        title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        title,
-                       Title:       title,
-                       HideAvatar:  "0",
-                       SingleTitle: fmt.Sprintf("view forked repo %s", p.Repo.FullName),
-                       SingleURL:   p.Repo.HTMLURL,
-               },
-       }, nil
+       return createDingtalkPayload(title, title, fmt.Sprintf("view forked repo %s", p.Repo.FullName), p.Repo.HTMLURL), nil
 }
 
 // Push implements PayloadConvertor Push method
@@ -124,70 +97,32 @@ func (d *DingtalkPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                        strings.TrimRight(commit.Message, "\r\n")) + authorName
                // add linebreak to each commit but the last
                if i < len(p.Commits)-1 {
-                       text += "\n"
+                       text += "\r\n"
                }
        }
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        text,
-                       Title:       title,
-                       HideAvatar:  "0",
-                       SingleTitle: linkText,
-                       SingleURL:   titleLink,
-               },
-       }, nil
+       return createDingtalkPayload(title, text, linkText, titleLink), nil
 }
 
 // Issue implements PayloadConvertor Issue method
 func (d *DingtalkPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
        text, issueTitle, attachmentText, _ := getIssuesPayloadInfo(p, noneLinkFormatter, true)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text: text + "\r\n\r\n" + attachmentText,
-                       //Markdown:    "# " + title + "\n" + text,
-                       Title:       issueTitle,
-                       HideAvatar:  "0",
-                       SingleTitle: "view issue",
-                       SingleURL:   p.Issue.HTMLURL,
-               },
-       }, nil
+       return createDingtalkPayload(issueTitle, text+"\r\n\r\n"+attachmentText, "view issue", p.Issue.HTMLURL), nil
 }
 
 // IssueComment implements PayloadConvertor IssueComment method
 func (d *DingtalkPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
        text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        text + "\r\n\r\n" + p.Comment.Body,
-                       Title:       issueTitle,
-                       HideAvatar:  "0",
-                       SingleTitle: "view issue comment",
-                       SingleURL:   p.Comment.HTMLURL,
-               },
-       }, nil
+       return createDingtalkPayload(issueTitle, text+"\r\n\r\n"+p.Comment.Body, "view issue comment", p.Comment.HTMLURL), nil
 }
 
 // PullRequest implements PayloadConvertor PullRequest method
 func (d *DingtalkPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
        text, issueTitle, attachmentText, _ := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text: text + "\r\n\r\n" + attachmentText,
-                       //Markdown:    "# " + title + "\n" + text,
-                       Title:       issueTitle,
-                       HideAvatar:  "0",
-                       SingleTitle: "view pull request",
-                       SingleURL:   p.PullRequest.HTMLURL,
-               },
-       }, nil
+       return createDingtalkPayload(issueTitle, text+"\r\n\r\n"+attachmentText, "view pull request", p.PullRequest.HTMLURL), nil
 }
 
 // Review implements PayloadConvertor Review method
@@ -205,37 +140,17 @@ func (d *DingtalkPayload) Review(p *api.PullRequestPayload, event models.HookEve
 
        }
 
-       return &DingtalkPayload{
-               MsgType: "actionCard",
-               ActionCard: dingtalk.ActionCard{
-                       Text:        title + "\r\n\r\n" + text,
-                       Title:       title,
-                       HideAvatar:  "0",
-                       SingleTitle: "view pull request",
-                       SingleURL:   p.PullRequest.HTMLURL,
-               },
-       }, nil
+       return createDingtalkPayload(title, title+"\r\n\r\n"+text, "view pull request", p.PullRequest.HTMLURL), nil
 }
 
 // Repository implements PayloadConvertor Repository method
 func (d *DingtalkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) {
-       var title, url string
        switch p.Action {
        case api.HookRepoCreated:
-               title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
-               url = p.Repository.HTMLURL
-               return &DingtalkPayload{
-                       MsgType: "actionCard",
-                       ActionCard: dingtalk.ActionCard{
-                               Text:        title,
-                               Title:       title,
-                               HideAvatar:  "0",
-                               SingleTitle: "view repository",
-                               SingleURL:   url,
-                       },
-               }, nil
+               title := fmt.Sprintf("[%s] Repository created", p.Repository.FullName)
+               return createDingtalkPayload(title, title, "view repository", p.Repository.HTMLURL), nil
        case api.HookRepoDeleted:
-               title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
+               title := fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
                return &DingtalkPayload{
                        MsgType: "text",
                        Text: struct {
@@ -253,16 +168,20 @@ func (d *DingtalkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e
 func (d *DingtalkPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
        text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true)
 
+       return createDingtalkPayload(text, text, "view release", p.Release.URL), nil
+}
+
+func createDingtalkPayload(title, text, singleTitle, singleURL string) *DingtalkPayload {
        return &DingtalkPayload{
                MsgType: "actionCard",
                ActionCard: dingtalk.ActionCard{
-                       Text:        text,
-                       Title:       text,
+                       Text:        strings.TrimSpace(text),
+                       Title:       strings.TrimSpace(title),
                        HideAvatar:  "0",
-                       SingleTitle: "view release",
-                       SingleURL:   p.Release.URL,
+                       SingleTitle: singleTitle,
+                       SingleURL:   singleURL,
                },
-       }, nil
+       }
 }
 
 // GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload
index e5aa0fca36abe1f448df92697d5b302482d700d2..213ad1a284ec1fbb7ab05eceee8b02b2f681534c 100644 (file)
@@ -7,25 +7,202 @@ package webhook
 import (
        "testing"
 
+       "code.gitea.io/gitea/models"
        api "code.gitea.io/gitea/modules/structs"
+
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 )
 
-func TestGetDingTalkIssuesPayload(t *testing.T) {
-       p := issueTestPayload()
-       d := new(DingtalkPayload)
-       p.Action = api.HookIssueOpened
-       pl, err := d.Issue(p)
+func TestDingTalkPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] branch test created", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo] branch test created", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view ref test", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] branch test deleted", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo] branch test deleted", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view ref test", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "test/repo2 is forked to test/repo", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "test/repo2 is forked to test/repo", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view forked repo test/repo", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1\r\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo:test] 2 new commits", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view commit 2020558...2020558", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(DingtalkPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Issue opened: #2 crash by user1\r\n\r\nissue body", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "#2 crash", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view issue", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*DingtalkPayload).ActionCard.SingleURL)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Issue closed: #2 crash by user1", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "#2 crash", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view issue", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] New comment on issue #2 crash by user1\r\n\r\nmore info needed", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "#2 crash", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view issue comment", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2#issuecomment-4", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request opened: #12 Fix bug by user1\r\n\r\nfixes bug #2", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "#12 Fix bug", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view pull request", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] New comment on pull request #12 Fix bug by user1\r\n\r\nchanges requested", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "#12 Fix bug", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view issue comment", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12#issuecomment-4", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(DingtalkPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request review approved : #12 Fix bug\r\n\r\ngood job", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo] Pull request review approved : #12 Fix bug", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view pull request", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Repository created", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo] Repository created", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view repository", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(DingtalkPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DingtalkPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Text)
+               assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Title)
+               assert.Equal(t, "view release", pl.(*DingtalkPayload).ActionCard.SingleTitle)
+               assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*DingtalkPayload).ActionCard.SingleURL)
+       })
+}
+
+func TestDingTalkJSONPayload(t *testing.T) {
+       p := pushTestPayload()
+
+       pl, err := new(DingtalkPayload).Push(p)
        require.NoError(t, err)
        require.NotNil(t, pl)
-       assert.Equal(t, "#2 crash", pl.(*DingtalkPayload).ActionCard.Title)
-       assert.Equal(t, "[test/repo] Issue opened: #2 crash by user1\r\n\r\n", pl.(*DingtalkPayload).ActionCard.Text)
+       require.IsType(t, &DingtalkPayload{}, pl)
 
-       p.Action = api.HookIssueClosed
-       pl, err = d.Issue(p)
+       json, err := pl.JSONPayload()
        require.NoError(t, err)
-       require.NotNil(t, pl)
-       assert.Equal(t, "#2 crash", pl.(*DingtalkPayload).ActionCard.Title)
-       assert.Equal(t, "[test/repo] Issue closed: #2 crash by user1\r\n\r\n", pl.(*DingtalkPayload).ActionCard.Text)
+       assert.NotEmpty(t, json)
 }
index d28904715f61857ceb39c5bee04c35784541c87e..378d9ff725db6726ac0695f2e13a2cfe36f3a2bb 100644 (file)
@@ -120,22 +120,7 @@ func (d *DiscordPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title: title,
-                               URL:   p.Repo.HTMLURL + "/src/" + refName,
-                               Color: greenColor,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+refName, greenColor), nil
 }
 
 // Delete implements PayloadConvertor Delete method
@@ -144,44 +129,14 @@ func (d *DiscordPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title: title,
-                               URL:   p.Repo.HTMLURL + "/src/" + refName,
-                               Color: redColor,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL+"/src/"+refName, redColor), nil
 }
 
 // Fork implements PayloadConvertor Fork method
 func (d *DiscordPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
        title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title: title,
-                               URL:   p.Repo.HTMLURL,
-                               Color: greenColor,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, "", p.Repo.HTMLURL, greenColor), nil
 }
 
 // Push implements PayloadConvertor Push method
@@ -216,92 +171,28 @@ func (d *DiscordPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                }
        }
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title:       title,
-                               Description: text,
-                               URL:         titleLink,
-                               Color:       greenColor,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, text, titleLink, greenColor), nil
 }
 
 // Issue implements PayloadConvertor Issue method
 func (d *DiscordPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
-       text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
+       title, _, text, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title:       text,
-                               Description: attachmentText,
-                               URL:         p.Issue.HTMLURL,
-                               Color:       color,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, text, p.Issue.HTMLURL, color), nil
 }
 
 // IssueComment implements PayloadConvertor IssueComment method
 func (d *DiscordPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
-       text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
+       title, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title:       text,
-                               Description: p.Comment.Body,
-                               URL:         p.Comment.HTMLURL,
-                               Color:       color,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, p.Comment.Body, p.Comment.HTMLURL, color), nil
 }
 
 // PullRequest implements PayloadConvertor PullRequest method
 func (d *DiscordPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
-       text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
+       title, _, text, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title:       text,
-                               Description: attachmentText,
-                               URL:         p.PullRequest.HTMLURL,
-                               Color:       color,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, text, p.PullRequest.HTMLURL, color), nil
 }
 
 // Review implements PayloadConvertor Review method
@@ -330,23 +221,7 @@ func (d *DiscordPayload) Review(p *api.PullRequestPayload, event models.HookEven
                }
        }
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               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
+       return d.createPayload(p.Sender, title, text, p.PullRequest.HTMLURL, color), nil
 }
 
 // Repository implements PayloadConvertor Repository method
@@ -363,45 +238,14 @@ func (d *DiscordPayload) Repository(p *api.RepositoryPayload) (api.Payloader, er
                color = redColor
        }
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title: title,
-                               URL:   url,
-                               Color: color,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, title, "", url, color), nil
 }
 
 // Release implements PayloadConvertor Release method
 func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
        text, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
 
-       return &DiscordPayload{
-               Username:  d.Username,
-               AvatarURL: d.AvatarURL,
-               Embeds: []DiscordEmbed{
-                       {
-                               Title:       text,
-                               Description: p.Release.Note,
-                               URL:         p.Release.URL,
-                               Color:       color,
-                               Author: DiscordEmbedAuthor{
-                                       Name:    p.Sender.UserName,
-                                       URL:     setting.AppURL + p.Sender.UserName,
-                                       IconURL: p.Sender.AvatarURL,
-                               },
-                       },
-               },
-       }, nil
+       return d.createPayload(p.Sender, text, p.Release.Note, p.Release.URL, color), nil
 }
 
 // GetDiscordPayload converts a discord webhook into a DiscordPayload
@@ -433,3 +277,23 @@ func parseHookPullRequestEventType(event models.HookEventType) (string, error) {
                return "", errors.New("unknown event type")
        }
 }
+
+func (d *DiscordPayload) createPayload(s *api.User, title, text, url string, color int) *DiscordPayload {
+       return &DiscordPayload{
+               Username:  d.Username,
+               AvatarURL: d.AvatarURL,
+               Embeds: []DiscordEmbed{
+                       {
+                               Title:       title,
+                               Description: text,
+                               URL:         url,
+                               Color:       color,
+                               Author: DiscordEmbedAuthor{
+                                       Name:    s.UserName,
+                                       URL:     setting.AppURL + s.UserName,
+                                       IconURL: s.AvatarURL,
+                               },
+                       },
+               },
+       }
+}
diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go
new file mode 100644 (file)
index 0000000..fd7d285
--- /dev/null
@@ -0,0 +1,245 @@
+// Copyright 2021 The Gitea 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 webhook
+
+import (
+       "testing"
+
+       "code.gitea.io/gitea/models"
+       "code.gitea.io/gitea/modules/setting"
+       api "code.gitea.io/gitea/modules/structs"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestDiscordPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] branch test created", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] branch test deleted", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "test/repo2 is forked to test/repo", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo:test] 2 new commits", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(DiscordPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Issue opened: #2 crash", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "issue body", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Issue closed: #2 crash", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] New comment on issue #2 crash", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "more info needed", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2#issuecomment-4", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Pull request opened: #12 Fix bug", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "fixes bug #2", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] New comment on pull request #12 Fix bug", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "changes requested", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12#issuecomment-4", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(DiscordPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Pull request review approved: #12 Fix bug", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "good job", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Repository created", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(DiscordPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &DiscordPayload{}, pl)
+
+               assert.Len(t, pl.(*DiscordPayload).Embeds, 1)
+               assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*DiscordPayload).Embeds[0].Title)
+               assert.Equal(t, "Note of first stable release", pl.(*DiscordPayload).Embeds[0].Description)
+               assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*DiscordPayload).Embeds[0].URL)
+               assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name)
+               assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL)
+               assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL)
+       })
+}
+
+func TestDiscordJSONPayload(t *testing.T) {
+       p := pushTestPayload()
+
+       pl, err := new(DiscordPayload).Push(p)
+       require.NoError(t, err)
+       require.NotNil(t, pl)
+       require.IsType(t, &DiscordPayload{}, pl)
+
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
+}
index 847a991f366c3d3af4ebc94121d90655b3b4a39a..5c80efb820db7af29214fb6bf78f5b48ad2e368c 100644 (file)
@@ -30,7 +30,7 @@ func newFeishuTextPayload(text string) *FeishuPayload {
                Content: struct {
                        Text string `json:"text"`
                }{
-                       Text: text,
+                       Text: strings.TrimSpace(text),
                },
        }
 }
@@ -84,7 +84,7 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                commitDesc string
        )
 
-       var text = fmt.Sprintf("[%s:%s] %s\n", p.Repo.FullName, branchName, commitDesc)
+       var text = fmt.Sprintf("[%s:%s] %s\r\n", p.Repo.FullName, branchName, commitDesc)
        // for each commit, generate attachment text
        for i, commit := range p.Commits {
                var authorName string
@@ -95,7 +95,7 @@ func (f *FeishuPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                        strings.TrimRight(commit.Message, "\r\n")) + authorName
                // add linebreak to each commit but the last
                if i < len(p.Commits)-1 {
-                       text += "\n"
+                       text += "\r\n"
                }
        }
 
@@ -125,19 +125,14 @@ func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e
 
 // Review implements PayloadConvertor Review method
 func (f *FeishuPayload) Review(p *api.PullRequestPayload, event models.HookEventType) (api.Payloader, error) {
-       var text, title string
-       switch p.Action {
-       case api.HookIssueSynchronized:
-               action, err := parseHookPullRequestEventType(event)
-               if err != nil {
-                       return nil, err
-               }
-
-               title = fmt.Sprintf("[%s] Pull request review %s : #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title)
-               text = p.Review.Content
-
+       action, err := parseHookPullRequestEventType(event)
+       if err != nil {
+               return nil, err
        }
 
+       title := fmt.Sprintf("[%s] Pull request review %s : #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title)
+       text := p.Review.Content
+
        return newFeishuTextPayload(title + "\r\n\r\n" + text), nil
 }
 
diff --git a/services/webhook/feishu_test.go b/services/webhook/feishu_test.go
new file mode 100644 (file)
index 0000000..7f3508c
--- /dev/null
@@ -0,0 +1,172 @@
+// Copyright 2021 The Gitea 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 webhook
+
+import (
+       "testing"
+
+       "code.gitea.io/gitea/models"
+       api "code.gitea.io/gitea/modules/structs"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestFeishuPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, `[test/repo] branch test created`, pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, `[test/repo] branch test deleted`, pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, `test/repo2 is forked to test/repo`, pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "[test/repo:test] \r\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1\r\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(FeishuPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "#2 crash\r\n[test/repo] Issue opened: #2 crash by user1\r\n\r\nissue body", pl.(*FeishuPayload).Content.Text)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "#2 crash\r\n[test/repo] Issue closed: #2 crash by user1", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "#2 crash\r\n[test/repo] New comment on issue #2 crash by user1\r\n\r\nmore info needed", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "#12 Fix bug\r\n[test/repo] Pull request opened: #12 Fix bug by user1\r\n\r\nfixes bug #2", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "#12 Fix bug\r\n[test/repo] New comment on pull request #12 Fix bug by user1\r\n\r\nchanges requested", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(FeishuPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request review approved : #12 Fix bug\r\n\r\ngood job", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Repository created", pl.(*FeishuPayload).Content.Text)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(FeishuPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &FeishuPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*FeishuPayload).Content.Text)
+       })
+}
+
+func TestFeishuJSONPayload(t *testing.T) {
+       p := pushTestPayload()
+
+       pl, err := new(FeishuPayload).Push(p)
+       require.NoError(t, err)
+       require.NotNil(t, pl)
+       require.IsType(t, &FeishuPayload{}, pl)
+
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
+}
index ec247a24109be577cbea6e5048c28648b31a2718..777ae086b5e966fc1343ed92ccf829e7dd89b8fe 100644 (file)
@@ -44,8 +44,11 @@ func getIssuesPayloadInfo(p *api.IssuePayload, linkFormatter linkFormatter, with
        case api.HookIssueEdited:
                text = fmt.Sprintf("[%s] Issue edited: %s", repoLink, titleLink)
        case api.HookIssueAssigned:
-               text = fmt.Sprintf("[%s] Issue assigned to %s: %s", repoLink,
-                       linkFormatter(setting.AppURL+p.Issue.Assignee.UserName, p.Issue.Assignee.UserName), titleLink)
+               list := make([]string, len(p.Issue.Assignees))
+               for i, user := range p.Issue.Assignees {
+                       list[i] = linkFormatter(setting.AppURL+user.UserName, user.UserName)
+               }
+               text = fmt.Sprintf("[%s] Issue assigned to %s: %s", repoLink, strings.Join(list, ", "), titleLink)
                color = greenColor
        case api.HookIssueUnassigned:
                text = fmt.Sprintf("[%s] Issue unassigned: %s", repoLink, titleLink)
@@ -102,7 +105,7 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm
                for i, user := range p.PullRequest.Assignees {
                        list[i] = linkFormatter(setting.AppURL+user.UserName, user.UserName)
                }
-               text = fmt.Sprintf("[%s] Pull request assigned: %s to %s", repoLink,
+               text = fmt.Sprintf("[%s] Pull request assigned to %s: %s", repoLink,
                        strings.Join(list, ", "), titleLink)
                color = greenColor
        case api.HookIssueUnassigned:
@@ -115,7 +118,7 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm
                text = fmt.Sprintf("[%s] Pull request synchronized: %s", repoLink, titleLink)
        case api.HookIssueMilestoned:
                mileStoneLink := fmt.Sprintf("%s/milestone/%d", p.Repository.HTMLURL, p.PullRequest.Milestone.ID)
-               text = fmt.Sprintf("[%s] Pull request milestoned: %s to %s", repoLink,
+               text = fmt.Sprintf("[%s] Pull request milestoned to %s: %s", repoLink,
                        linkFormatter(mileStoneLink, p.PullRequest.Milestone.Title), titleLink)
        case api.HookIssueDemilestoned:
                text = fmt.Sprintf("[%s] Pull request milestone cleared: %s", repoLink, titleLink)
index 3033b578805b67bb126065e9280e0d14e6b69d6a..4d73afe060a6818f63cd6bc99867d3c0c4956f48 100644 (file)
 package webhook
 
 import (
+       "testing"
+
        api "code.gitea.io/gitea/modules/structs"
+
+       "github.com/stretchr/testify/assert"
 )
 
+func createTestPayload() *api.CreatePayload {
+       return &api.CreatePayload{
+               Sha:     "2020558fe2e34debb818a514715839cabd25e777",
+               Ref:     "refs/heads/test",
+               RefType: "branch",
+               Repo: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo",
+                       Name:     "repo",
+                       FullName: "test/repo",
+               },
+               Sender: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
+               },
+       }
+}
+
+func deleteTestPayload() *api.DeletePayload {
+       return &api.DeletePayload{
+               Ref:     "refs/heads/test",
+               RefType: "branch",
+               Repo: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo",
+                       Name:     "repo",
+                       FullName: "test/repo",
+               },
+               Sender: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
+               },
+       }
+}
+
+func forkTestPayload() *api.ForkPayload {
+       return &api.ForkPayload{
+               Forkee: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo2",
+                       Name:     "repo2",
+                       FullName: "test/repo2",
+               },
+               Repo: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo",
+                       Name:     "repo",
+                       FullName: "test/repo",
+               },
+               Sender: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
+               },
+       }
+}
+
+func pushTestPayload() *api.PushPayload {
+       commit := &api.PayloadCommit{
+               ID:      "2020558fe2e34debb818a514715839cabd25e778",
+               Message: "commit message",
+               URL:     "http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778",
+               Author: &api.PayloadUser{
+                       Name:     "user1",
+                       Email:    "user1@localhost",
+                       UserName: "user1",
+               },
+               Committer: &api.PayloadUser{
+                       Name:     "user1",
+                       Email:    "user1@localhost",
+                       UserName: "user1",
+               },
+       }
+
+       return &api.PushPayload{
+               Ref:        "refs/heads/test",
+               Before:     "2020558fe2e34debb818a514715839cabd25e777",
+               After:      "2020558fe2e34debb818a514715839cabd25e778",
+               CompareURL: "",
+               HeadCommit: commit,
+               Commits:    []*api.PayloadCommit{commit, commit},
+               Repo: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo",
+                       Name:     "repo",
+                       FullName: "test/repo",
+               },
+               Pusher: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
+               },
+               Sender: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
+               },
+       }
+}
+
 func issueTestPayload() *api.IssuePayload {
        return &api.IssuePayload{
                Index: 2,
                Sender: &api.User{
-                       UserName: "user1",
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
                Repository: &api.Repository{
                        HTMLURL:  "http://localhost:3000/test/repo",
@@ -20,10 +117,23 @@ func issueTestPayload() *api.IssuePayload {
                        FullName: "test/repo",
                },
                Issue: &api.Issue{
-                       ID:    2,
-                       Index: 2,
-                       URL:   "http://localhost:3000/api/v1/repos/test/repo/issues/2",
-                       Title: "crash",
+                       ID:      2,
+                       Index:   2,
+                       URL:     "http://localhost:3000/api/v1/repos/test/repo/issues/2",
+                       HTMLURL: "http://localhost:3000/test/repo/issues/2",
+                       Title:   "crash",
+                       Body:    "issue body",
+                       Assignees: []*api.User{
+                               {
+                                       UserName:  "user1",
+                                       AvatarURL: "http://localhost:3000/user1/avatar",
+                               },
+                       },
+                       Milestone: &api.Milestone{
+                               ID:          1,
+                               Title:       "Milestone Title",
+                               Description: "Milestone Description",
+                       },
                },
        }
 }
@@ -32,7 +142,8 @@ func issueCommentTestPayload() *api.IssueCommentPayload {
        return &api.IssueCommentPayload{
                Action: api.HookIssueCommentCreated,
                Sender: &api.User{
-                       UserName: "user1",
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
                Repository: &api.Repository{
                        HTMLURL:  "http://localhost:3000/test/repo",
@@ -45,11 +156,12 @@ func issueCommentTestPayload() *api.IssueCommentPayload {
                        Body:     "more info needed",
                },
                Issue: &api.Issue{
-                       ID:    2,
-                       Index: 2,
-                       URL:   "http://localhost:3000/api/v1/repos/test/repo/issues/2",
-                       Title: "crash",
-                       Body:  "this happened",
+                       ID:      2,
+                       Index:   2,
+                       URL:     "http://localhost:3000/api/v1/repos/test/repo/issues/2",
+                       HTMLURL: "http://localhost:3000/test/repo/issues/2",
+                       Title:   "crash",
+                       Body:    "this happened",
                },
        }
 }
@@ -58,7 +170,8 @@ func pullRequestCommentTestPayload() *api.IssueCommentPayload {
        return &api.IssueCommentPayload{
                Action: api.HookIssueCommentCreated,
                Sender: &api.User{
-                       UserName: "user1",
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
                Repository: &api.Repository{
                        HTMLURL:  "http://localhost:3000/test/repo",
@@ -66,16 +179,17 @@ func pullRequestCommentTestPayload() *api.IssueCommentPayload {
                        FullName: "test/repo",
                },
                Comment: &api.Comment{
-                       HTMLURL: "http://localhost:3000/test/repo/pulls/2#issuecomment-4",
-                       PRURL:   "http://localhost:3000/test/repo/pulls/2",
+                       HTMLURL: "http://localhost:3000/test/repo/pulls/12#issuecomment-4",
+                       PRURL:   "http://localhost:3000/test/repo/pulls/12",
                        Body:    "changes requested",
                },
                Issue: &api.Issue{
-                       ID:    2,
-                       Index: 2,
-                       URL:   "http://localhost:3000/api/v1/repos/test/repo/issues/2",
-                       Title: "Fix bug",
-                       Body:  "fixes bug #2",
+                       ID:      12,
+                       Index:   12,
+                       URL:     "http://localhost:3000/api/v1/repos/test/repo/pulls/12",
+                       HTMLURL: "http://localhost:3000/test/repo/pulls/12",
+                       Title:   "Fix bug",
+                       Body:    "fixes bug #2",
                },
                IsPull: true,
        }
@@ -85,7 +199,8 @@ func pullReleaseTestPayload() *api.ReleasePayload {
        return &api.ReleasePayload{
                Action: api.HookReleasePublished,
                Sender: &api.User{
-                       UserName: "user1",
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
                Repository: &api.Repository{
                        HTMLURL:  "http://localhost:3000/test/repo",
@@ -96,6 +211,7 @@ func pullReleaseTestPayload() *api.ReleasePayload {
                        TagName: "v1.0",
                        Target:  "master",
                        Title:   "First stable release",
+                       Note:    "Note of first stable release",
                        URL:     "http://localhost:3000/api/v1/repos/test/repo/releases/2",
                },
        }
@@ -104,9 +220,10 @@ func pullReleaseTestPayload() *api.ReleasePayload {
 func pullRequestTestPayload() *api.PullRequestPayload {
        return &api.PullRequestPayload{
                Action: api.HookIssueOpened,
-               Index:  2,
+               Index:  12,
                Sender: &api.User{
-                       UserName: "user1",
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
                Repository: &api.Repository{
                        HTMLURL:  "http://localhost:3000/test/repo",
@@ -114,12 +231,311 @@ func pullRequestTestPayload() *api.PullRequestPayload {
                        FullName: "test/repo",
                },
                PullRequest: &api.PullRequest{
-                       ID:        2,
-                       Index:     2,
+                       ID:        12,
+                       Index:     12,
                        URL:       "http://localhost:3000/test/repo/pulls/12",
+                       HTMLURL:   "http://localhost:3000/test/repo/pulls/12",
                        Title:     "Fix bug",
                        Body:      "fixes bug #2",
                        Mergeable: true,
+                       Assignees: []*api.User{
+                               {
+                                       UserName:  "user1",
+                                       AvatarURL: "http://localhost:3000/user1/avatar",
+                               },
+                       },
+                       Milestone: &api.Milestone{
+                               ID:          1,
+                               Title:       "Milestone Title",
+                               Description: "Milestone Description",
+                       },
+               },
+               Review: &api.ReviewPayload{
+                       Content: "good job",
+               },
+       }
+}
+
+func repositoryTestPayload() *api.RepositoryPayload {
+       return &api.RepositoryPayload{
+               Action: api.HookRepoCreated,
+               Sender: &api.User{
+                       UserName:  "user1",
+                       AvatarURL: "http://localhost:3000/user1/avatar",
                },
+               Repository: &api.Repository{
+                       HTMLURL:  "http://localhost:3000/test/repo",
+                       Name:     "repo",
+                       FullName: "test/repo",
+               },
+       }
+}
+
+func TestGetIssuesPayloadInfo(t *testing.T) {
+       p := issueTestPayload()
+
+       cases := []struct {
+               action         api.HookIssueAction
+               text           string
+               issueTitle     string
+               attachmentText string
+               color          int
+       }{
+               {
+                       api.HookIssueOpened,
+                       "[test/repo] Issue opened: #2 crash by user1",
+                       "#2 crash",
+                       "issue body",
+                       orangeColor,
+               },
+               {
+                       api.HookIssueClosed,
+                       "[test/repo] Issue closed: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       redColor,
+               },
+               {
+                       api.HookIssueReOpened,
+                       "[test/repo] Issue re-opened: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueEdited,
+                       "[test/repo] Issue edited: #2 crash by user1",
+                       "#2 crash",
+                       "issue body",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueAssigned,
+                       "[test/repo] Issue assigned to user1: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       greenColor,
+               },
+               {
+                       api.HookIssueUnassigned,
+                       "[test/repo] Issue unassigned: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueLabelUpdated,
+                       "[test/repo] Issue labels updated: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueLabelCleared,
+                       "[test/repo] Issue labels cleared: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueSynchronized,
+                       "[test/repo] Issue synchronized: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueMilestoned,
+                       "[test/repo] Issue milestoned to Milestone Title: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueDemilestoned,
+                       "[test/repo] Issue milestone cleared: #2 crash by user1",
+                       "#2 crash",
+                       "",
+                       yellowColor,
+               },
+       }
+
+       for i, c := range cases {
+               p.Action = c.action
+               text, issueTitle, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, true)
+               assert.Equal(t, c.text, text, "case %d", i)
+               assert.Equal(t, c.issueTitle, issueTitle, "case %d", i)
+               assert.Equal(t, c.attachmentText, attachmentText, "case %d", i)
+               assert.Equal(t, c.color, color, "case %d", i)
+       }
+}
+
+func TestGetPullRequestPayloadInfo(t *testing.T) {
+       p := pullRequestTestPayload()
+
+       cases := []struct {
+               action         api.HookIssueAction
+               text           string
+               issueTitle     string
+               attachmentText string
+               color          int
+       }{
+               {
+                       api.HookIssueOpened,
+                       "[test/repo] Pull request opened: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "fixes bug #2",
+                       greenColor,
+               },
+               {
+                       api.HookIssueClosed,
+                       "[test/repo] Pull request closed: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       redColor,
+               },
+               {
+                       api.HookIssueReOpened,
+                       "[test/repo] Pull request re-opened: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueEdited,
+                       "[test/repo] Pull request edited: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "fixes bug #2",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueAssigned,
+                       "[test/repo] Pull request assigned to user1: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       greenColor,
+               },
+               {
+                       api.HookIssueUnassigned,
+                       "[test/repo] Pull request unassigned: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueLabelUpdated,
+                       "[test/repo] Pull request labels updated: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueLabelCleared,
+                       "[test/repo] Pull request labels cleared: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueSynchronized,
+                       "[test/repo] Pull request synchronized: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueMilestoned,
+                       "[test/repo] Pull request milestoned to Milestone Title: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueDemilestoned,
+                       "[test/repo] Pull request milestone cleared: #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       "",
+                       yellowColor,
+               },
+       }
+
+       for i, c := range cases {
+               p.Action = c.action
+               text, issueTitle, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, true)
+               assert.Equal(t, c.text, text, "case %d", i)
+               assert.Equal(t, c.issueTitle, issueTitle, "case %d", i)
+               assert.Equal(t, c.attachmentText, attachmentText, "case %d", i)
+               assert.Equal(t, c.color, color, "case %d", i)
+       }
+}
+
+func TestGetReleasePayloadInfo(t *testing.T) {
+       p := pullReleaseTestPayload()
+
+       cases := []struct {
+               action api.HookReleaseAction
+               text   string
+               color  int
+       }{
+               {
+                       api.HookReleasePublished,
+                       "[test/repo] Release created: v1.0 by user1",
+                       greenColor,
+               },
+               {
+                       api.HookReleaseUpdated,
+                       "[test/repo] Release updated: v1.0 by user1",
+                       yellowColor,
+               },
+               {
+                       api.HookReleaseDeleted,
+                       "[test/repo] Release deleted: v1.0 by user1",
+                       redColor,
+               },
+       }
+
+       for i, c := range cases {
+               p.Action = c.action
+               text, color := getReleasePayloadInfo(p, noneLinkFormatter, true)
+               assert.Equal(t, c.text, text, "case %d", i)
+               assert.Equal(t, c.color, color, "case %d", i)
+       }
+}
+
+func TestGetIssueCommentPayloadInfo(t *testing.T) {
+       p := pullRequestCommentTestPayload()
+
+       cases := []struct {
+               action     api.HookIssueCommentAction
+               text       string
+               issueTitle string
+               color      int
+       }{
+               {
+                       api.HookIssueCommentCreated,
+                       "[test/repo] New comment on pull request #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       greenColorLight,
+               },
+               {
+                       api.HookIssueCommentEdited,
+                       "[test/repo] Comment edited on pull request #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       yellowColor,
+               },
+               {
+                       api.HookIssueCommentDeleted,
+                       "[test/repo] Comment deleted on pull request #12 Fix bug by user1",
+                       "#12 Fix bug",
+                       redColor,
+               },
+       }
+
+       for i, c := range cases {
+               p.Action = c.action
+               text, issueTitle, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, true)
+               assert.Equal(t, c.text, text, "case %d", i)
+               assert.Equal(t, c.issueTitle, issueTitle, "case %d", i)
+               assert.Equal(t, c.color, color, "case %d", i)
        }
 }
index 771146f2f30fee1840854f584cda74b6bc2593e0..7b10e21cfa4a32d1829907c8cdc560e790aa8ea9 100644 (file)
@@ -14,71 +14,173 @@ import (
        "github.com/stretchr/testify/require"
 )
 
-func TestMatrixIssuesPayloadOpened(t *testing.T) {
-       p := issueTestPayload()
-       m := new(MatrixPayloadUnsafe)
+func TestMatrixPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
 
-       p.Action = api.HookIssueOpened
-       pl, err := m.Issue(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Issue opened: [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Issue opened: <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
 
-       p.Action = api.HookIssueClosed
-       pl, err = m.Issue(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Issue closed: [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Issue closed: <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
-}
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo):[test](http://localhost:3000/test/repo/src/branch/test)] branch created by user1", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>:<a href="http://localhost:3000/test/repo/src/branch/test">test</a>] branch created by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
 
-func TestMatrixIssueCommentPayload(t *testing.T) {
-       p := issueCommentTestPayload()
-       m := new(MatrixPayloadUnsafe)
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
 
-       pl, err := m.IssueComment(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
 
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] New comment on issue [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] New comment on issue <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
-}
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo):test] branch deleted by user1", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>:test] branch deleted by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
 
-func TestMatrixPullRequestCommentPayload(t *testing.T) {
-       p := pullRequestCommentTestPayload()
-       m := new(MatrixPayloadUnsafe)
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
 
-       pl, err := m.IssueComment(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
 
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] New comment on pull request [#2 Fix bug](http://localhost:3000/test/repo/pulls/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] New comment on pull request <a href=\"http://localhost:3000/test/repo/pulls/2\">#2 Fix bug</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
-}
+               assert.Equal(t, "[test/repo2](http://localhost:3000/test/repo2) is forked to [test/repo](http://localhost:3000/test/repo)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `<a href="http://localhost:3000/test/repo2">test/repo2</a> is forked to <a href="http://localhost:3000/test/repo">test/repo</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
 
-func TestMatrixReleasePayload(t *testing.T) {
-       p := pullReleaseTestPayload()
-       m := new(MatrixPayloadUnsafe)
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
 
-       pl, err := m.Release(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] user1 pushed 2 commits to [test](http://localhost:3000/test/repo/src/branch/test):\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778): commit message - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778): commit message - user1", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] user1 pushed 2 commits to <a href="http://localhost:3000/test/repo/src/branch/test">test</a>:<br><a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778">2020558</a>: commit message - user1<br><a href="http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778">2020558</a>: commit message - user1`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Issue opened: [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Issue opened: <a href="http://localhost:3000/test/repo/issues/2">#2 crash</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Issue closed: [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Issue closed: <a href="http://localhost:3000/test/repo/issues/2">#2 crash</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
 
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Release created: [v1.0](http://localhost:3000/test/repo/src/v1.0) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Release created: <a href=\"http://localhost:3000/test/repo/src/v1.0\">v1.0</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] New comment on issue [#2 crash](http://localhost:3000/test/repo/issues/2) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] New comment on issue <a href="http://localhost:3000/test/repo/issues/2">#2 crash</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Pull request opened: [#12 Fix bug](http://localhost:3000/test/repo/pulls/12) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Pull request opened: <a href="http://localhost:3000/test/repo/pulls/12">#12 Fix bug</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] New comment on pull request [#12 Fix bug](http://localhost:3000/test/repo/pulls/12) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] New comment on pull request <a href="http://localhost:3000/test/repo/pulls/12">#12 Fix bug</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Pull request review approved: [#12 Fix bug](http://localhost:3000/test/repo/pulls/12) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Pull request review approved: [#12 Fix bug](http://localhost:3000/test/repo/pulls/12) by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, `[[test/repo](http://localhost:3000/test/repo)] Repository created by [user1](https://try.gitea.io/user1)`, pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Repository created by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(MatrixPayloadUnsafe)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MatrixPayloadUnsafe{}, pl)
+
+               assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Release created: [v1.0](http://localhost:3000/test/repo/src/v1.0) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Release created: <a href="http://localhost:3000/test/repo/src/v1.0">v1.0</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*MatrixPayloadUnsafe).FormattedBody)
+       })
 }
 
-func TestMatrixPullRequestPayload(t *testing.T) {
-       p := pullRequestTestPayload()
-       m := new(MatrixPayloadUnsafe)
+func TestMatrixJSONPayload(t *testing.T) {
+       p := pushTestPayload()
 
-       pl, err := m.PullRequest(p)
+       pl, err := new(MatrixPayloadUnsafe).Push(p)
        require.NoError(t, err)
        require.NotNil(t, pl)
+       require.IsType(t, &MatrixPayloadUnsafe{}, pl)
 
-       assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Pull request opened: [#2 Fix bug](http://localhost:3000/test/repo/pulls/12) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body)
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Pull request opened: <a href=\"http://localhost:3000/test/repo/pulls/12\">#2 Fix bug</a> by <a href=\"https://try.gitea.io/user1\">user1</a>", pl.(*MatrixPayloadUnsafe).FormattedBody)
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
 }
 
 func TestMatrixHookRequest(t *testing.T) {
index dc83a47c8d8016f962d775e3fa03c0033825bfec..51bb28a36181d9472debba14c285319c4a925a69 100644 (file)
@@ -78,42 +78,15 @@ func (m *MSTeamsPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName)
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", greenColor),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repo.FullName,
-                                       },
-                                       {
-                                               Name:  fmt.Sprintf("%s:", p.RefType),
-                                               Value: refName,
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.Repo.HTMLURL + "/src/" + refName,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repo,
+               p.Sender,
+               title,
+               "",
+               p.Repo.HTMLURL+"/src/"+refName,
+               greenColor,
+               &MSTeamsFact{fmt.Sprintf("%s:", p.RefType), refName},
+       ), nil
 }
 
 // Delete implements PayloadConvertor Delete method
@@ -122,84 +95,30 @@ func (m *MSTeamsPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName)
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", yellowColor),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repo.FullName,
-                                       },
-                                       {
-                                               Name:  fmt.Sprintf("%s:", p.RefType),
-                                               Value: refName,
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.Repo.HTMLURL + "/src/" + refName,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repo,
+               p.Sender,
+               title,
+               "",
+               p.Repo.HTMLURL+"/src/"+refName,
+               yellowColor,
+               &MSTeamsFact{fmt.Sprintf("%s:", p.RefType), refName},
+       ), nil
 }
 
 // Fork implements PayloadConvertor Fork method
 func (m *MSTeamsPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
        title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName)
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", greenColor),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Forkee:",
-                                               Value: p.Forkee.FullName,
-                                       },
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repo.FullName,
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.Repo.HTMLURL,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repo,
+               p.Sender,
+               title,
+               "",
+               p.Repo.HTMLURL,
+               greenColor,
+               &MSTeamsFact{"Forkee:", p.Forkee.FullName},
+       ), nil
 }
 
 // Push implements PayloadConvertor Push method
@@ -234,172 +153,60 @@ func (m *MSTeamsPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                }
        }
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", greenColor),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             text,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repo.FullName,
-                                       },
-                                       {
-                                               Name:  "Commit count:",
-                                               Value: fmt.Sprintf("%d", len(p.Commits)),
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: titleLink,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repo,
+               p.Sender,
+               title,
+               text,
+               titleLink,
+               greenColor,
+               &MSTeamsFact{"Commit count:", fmt.Sprintf("%d", len(p.Commits))},
+       ), nil
 }
 
 // Issue implements PayloadConvertor Issue method
 func (m *MSTeamsPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
-       text, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
-
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", color),
-               Title:      text,
-               Summary:    text,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             attachmentText,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                                       {
-                                               Name:  "Issue #:",
-                                               Value: fmt.Sprintf("%d", p.Issue.ID),
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.Issue.HTMLURL,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       title, _, attachmentText, color := getIssuesPayloadInfo(p, noneLinkFormatter, false)
+
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               attachmentText,
+               p.Issue.HTMLURL,
+               color,
+               &MSTeamsFact{"Issue #:", fmt.Sprintf("%d", p.Issue.ID)},
+       ), nil
 }
 
 // IssueComment implements PayloadConvertor IssueComment method
 func (m *MSTeamsPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
-       text, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
-
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", color),
-               Title:      text,
-               Summary:    text,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             p.Comment.Body,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                                       {
-                                               Name:  "Issue #:",
-                                               Value: fmt.Sprintf("%d", p.Issue.ID),
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.Comment.HTMLURL,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       title, _, color := getIssueCommentPayloadInfo(p, noneLinkFormatter, false)
+
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               p.Comment.Body,
+               p.Comment.HTMLURL,
+               color,
+               &MSTeamsFact{"Issue #:", fmt.Sprintf("%d", p.Issue.ID)},
+       ), nil
 }
 
 // PullRequest implements PayloadConvertor PullRequest method
 func (m *MSTeamsPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
-       text, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
-
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", color),
-               Title:      text,
-               Summary:    text,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             attachmentText,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                                       {
-                                               Name:  "Pull request #:",
-                                               Value: fmt.Sprintf("%d", p.PullRequest.ID),
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.PullRequest.HTMLURL,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       title, _, attachmentText, color := getPullRequestPayloadInfo(p, noneLinkFormatter, false)
+
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               attachmentText,
+               p.PullRequest.HTMLURL,
+               color,
+               &MSTeamsFact{"Pull request #:", fmt.Sprintf("%d", p.PullRequest.ID)},
+       ), nil
 }
 
 // Review implements PayloadConvertor Review method
@@ -428,43 +235,15 @@ func (m *MSTeamsPayload) Review(p *api.PullRequestPayload, event models.HookEven
                }
        }
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", color),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             text,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                                       {
-                                               Name:  "Pull request #:",
-                                               Value: fmt.Sprintf("%d", p.PullRequest.ID),
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: p.PullRequest.HTMLURL,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               text,
+               p.PullRequest.HTMLURL,
+               color,
+               &MSTeamsFact{"Pull request #:", fmt.Sprintf("%d", p.PullRequest.ID)},
+       ), nil
 }
 
 // Repository implements PayloadConvertor Repository method
@@ -481,66 +260,61 @@ func (m *MSTeamsPayload) Repository(p *api.RepositoryPayload) (api.Payloader, er
                color = yellowColor
        }
 
-       return &MSTeamsPayload{
-               Type:       "MessageCard",
-               Context:    "https://schema.org/extensions",
-               ThemeColor: fmt.Sprintf("%x", color),
-               Title:      title,
-               Summary:    title,
-               Sections: []MSTeamsSection{
-                       {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                               },
-                       },
-               },
-               PotentialAction: []MSTeamsAction{
-                       {
-                               Type: "OpenUri",
-                               Name: "View in Gitea",
-                               Targets: []MSTeamsActionTarget{
-                                       {
-                                               Os:  "default",
-                                               URI: url,
-                                       },
-                               },
-                       },
-               },
-       }, nil
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               "",
+               url,
+               color,
+               nil,
+       ), nil
 }
 
 // Release implements PayloadConvertor Release method
 func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
-       text, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
+       title, color := getReleasePayloadInfo(p, noneLinkFormatter, false)
+
+       return createMSTeamsPayload(
+               p.Repository,
+               p.Sender,
+               title,
+               "",
+               p.Release.URL,
+               color,
+               &MSTeamsFact{"Tag:", p.Release.TagName},
+       ), nil
+}
+
+// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
+func GetMSTeamsPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
+       return convertPayloader(new(MSTeamsPayload), p, event)
+}
+
+func createMSTeamsPayload(r *api.Repository, s *api.User, title, text, actionTarget string, color int, fact *MSTeamsFact) *MSTeamsPayload {
+       facts := []MSTeamsFact{
+               {
+                       Name:  "Repository:",
+                       Value: r.FullName,
+               },
+       }
+       if fact != nil {
+               facts = append(facts, *fact)
+       }
 
        return &MSTeamsPayload{
                Type:       "MessageCard",
                Context:    "https://schema.org/extensions",
                ThemeColor: fmt.Sprintf("%x", color),
-               Title:      text,
-               Summary:    text,
+               Title:      title,
+               Summary:    title,
                Sections: []MSTeamsSection{
                        {
-                               ActivityTitle:    p.Sender.FullName,
-                               ActivitySubtitle: p.Sender.UserName,
-                               ActivityImage:    p.Sender.AvatarURL,
-                               Text:             p.Release.Note,
-                               Facts: []MSTeamsFact{
-                                       {
-                                               Name:  "Repository:",
-                                               Value: p.Repository.FullName,
-                                       },
-                                       {
-                                               Name:  "Tag:",
-                                               Value: p.Release.TagName,
-                                       },
-                               },
+                               ActivityTitle:    s.FullName,
+                               ActivitySubtitle: s.UserName,
+                               ActivityImage:    s.AvatarURL,
+                               Text:             text,
+                               Facts:            facts,
                        },
                },
                PotentialAction: []MSTeamsAction{
@@ -550,15 +324,10 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
                                Targets: []MSTeamsActionTarget{
                                        {
                                                Os:  "default",
-                                               URI: p.Release.URL,
+                                               URI: actionTarget,
                                        },
                                },
                        },
                },
-       }, nil
-}
-
-// GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload
-func GetMSTeamsPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
-       return convertPayloader(new(MSTeamsPayload), p, event)
+       }
 }
diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go
new file mode 100644 (file)
index 0000000..2f54c39
--- /dev/null
@@ -0,0 +1,374 @@
+// Copyright 2021 The Gitea 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 webhook
+
+import (
+       "testing"
+
+       "code.gitea.io/gitea/models"
+       api "code.gitea.io/gitea/modules/structs"
+
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
+)
+
+func TestMSTeamsPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] branch test created", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] branch test created", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repo.FullName, fact.Value)
+                       } else if fact.Name == "branch:" {
+                               assert.Equal(t, "test", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] branch test deleted", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] branch test deleted", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repo.FullName, fact.Value)
+                       } else if fact.Name == "branch:" {
+                               assert.Equal(t, "test", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "test/repo2 is forked to test/repo", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "test/repo2 is forked to test/repo", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repo.FullName, fact.Value)
+                       } else if fact.Name == "Forkee:" {
+                               assert.Equal(t, p.Forkee.FullName, fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo:test] 2 new commits", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo:test] 2 new commits", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1\n\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) commit message - user1", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repo.FullName, fact.Value)
+                       } else if fact.Name == "Commit count:" {
+                               assert.Equal(t, "2", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/src/test", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(MSTeamsPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Issue opened: #2 crash", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Issue opened: #2 crash", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "issue body", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Issue #:" {
+                               assert.Equal(t, "2", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Issue closed: #2 crash", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Issue closed: #2 crash", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Issue #:" {
+                               assert.Equal(t, "2", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] New comment on issue #2 crash", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] New comment on issue #2 crash", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "more info needed", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Issue #:" {
+                               assert.Equal(t, "2", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/issues/2#issuecomment-4", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request opened: #12 Fix bug", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Pull request opened: #12 Fix bug", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "fixes bug #2", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Pull request #:" {
+                               assert.Equal(t, "12", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] New comment on pull request #12 Fix bug", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] New comment on pull request #12 Fix bug", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "changes requested", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Issue #:" {
+                               assert.Equal(t, "12", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12#issuecomment-4", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request review approved: #12 Fix bug", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Pull request review approved: #12 Fix bug", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Equal(t, "good job", pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Pull request #:" {
+                               assert.Equal(t, "12", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo/pulls/12", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Repository created", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Repository created", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 1)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/test/repo", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(MSTeamsPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &MSTeamsPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*MSTeamsPayload).Title)
+               assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*MSTeamsPayload).Summary)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections, 1)
+               assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle)
+               assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text)
+               assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2)
+               for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts {
+                       if fact.Name == "Repository:" {
+                               assert.Equal(t, p.Repository.FullName, fact.Value)
+                       } else if fact.Name == "Tag:" {
+                               assert.Equal(t, "v1.0", fact.Value)
+                       } else {
+                               t.Fail()
+                       }
+               }
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1)
+               assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1)
+               assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI)
+       })
+}
+
+func TestMSTeamsJSONPayload(t *testing.T) {
+       p := pushTestPayload()
+
+       pl, err := new(MSTeamsPayload).Push(p)
+       require.NoError(t, err)
+       require.NotNil(t, pl)
+       require.IsType(t, &MSTeamsPayload{}, pl)
+
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
+}
index f5c857f2a961483d166fd3fda726070dec45a141..1de9c9c37c70cb356593b77332c04f75a1170406 100644 (file)
@@ -111,12 +111,7 @@ func (s *SlackPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
        refLink := SlackLinkToRef(p.Repo.HTMLURL, p.Ref)
        text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
 
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+       return s.createPayload(text, nil), nil
 }
 
 // Delete composes Slack payload for delete a branch or tag.
@@ -124,12 +119,8 @@ func (s *SlackPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
        refName := git.RefEndName(p.Ref)
        repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName)
        text := fmt.Sprintf("[%s:%s] %s deleted by %s", repoLink, refName, p.RefType, p.Sender.UserName)
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+
+       return s.createPayload(text, nil), nil
 }
 
 // Fork composes Slack payload for forked by a repository.
@@ -137,66 +128,46 @@ func (s *SlackPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
        baseLink := SlackLinkFormatter(p.Forkee.HTMLURL, p.Forkee.FullName)
        forkLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.FullName)
        text := fmt.Sprintf("%s is forked to %s", baseLink, forkLink)
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+
+       return s.createPayload(text, nil), nil
 }
 
 // Issue implements PayloadConvertor Issue method
 func (s *SlackPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
        text, issueTitle, attachmentText, color := getIssuesPayloadInfo(p, SlackLinkFormatter, true)
 
-       pl := &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }
+       var attachments []SlackAttachment
        if attachmentText != "" {
                attachmentText = SlackTextFormatter(attachmentText)
                issueTitle = SlackTextFormatter(issueTitle)
-               pl.Attachments = []SlackAttachment{{
+               attachments = append(attachments, SlackAttachment{
                        Color:     fmt.Sprintf("%x", color),
                        Title:     issueTitle,
                        TitleLink: p.Issue.HTMLURL,
                        Text:      attachmentText,
-               }}
+               })
        }
 
-       return pl, nil
+       return s.createPayload(text, attachments), nil
 }
 
 // IssueComment implements PayloadConvertor IssueComment method
 func (s *SlackPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
        text, issueTitle, color := getIssueCommentPayloadInfo(p, SlackLinkFormatter, true)
 
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-               Attachments: []SlackAttachment{{
-                       Color:     fmt.Sprintf("%x", color),
-                       Title:     issueTitle,
-                       TitleLink: p.Comment.HTMLURL,
-                       Text:      SlackTextFormatter(p.Comment.Body),
-               }},
-       }, nil
+       return s.createPayload(text, []SlackAttachment{{
+               Color:     fmt.Sprintf("%x", color),
+               Title:     issueTitle,
+               TitleLink: p.Comment.HTMLURL,
+               Text:      SlackTextFormatter(p.Comment.Body),
+       }}), nil
 }
 
 // Release implements PayloadConvertor Release method
 func (s *SlackPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
        text, _ := getReleasePayloadInfo(p, SlackLinkFormatter, true)
 
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+       return s.createPayload(text, nil), nil
 }
 
 // Push implements PayloadConvertor Push method
@@ -232,42 +203,31 @@ func (s *SlackPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                }
        }
 
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-               Attachments: []SlackAttachment{{
-                       Color:     s.Color,
-                       Title:     p.Repo.HTMLURL,
-                       TitleLink: p.Repo.HTMLURL,
-                       Text:      attachmentText,
-               }},
-       }, nil
+       return s.createPayload(text, []SlackAttachment{{
+               Color:     s.Color,
+               Title:     p.Repo.HTMLURL,
+               TitleLink: p.Repo.HTMLURL,
+               Text:      attachmentText,
+       }}), nil
 }
 
 // PullRequest implements PayloadConvertor PullRequest method
 func (s *SlackPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
        text, issueTitle, attachmentText, color := getPullRequestPayloadInfo(p, SlackLinkFormatter, true)
 
-       pl := &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }
+       var attachments []SlackAttachment
        if attachmentText != "" {
                attachmentText = SlackTextFormatter(p.PullRequest.Body)
                issueTitle = SlackTextFormatter(issueTitle)
-               pl.Attachments = []SlackAttachment{{
+               attachments = append(attachments, SlackAttachment{
                        Color:     fmt.Sprintf("%x", color),
                        Title:     issueTitle,
                        TitleLink: p.PullRequest.URL,
                        Text:      attachmentText,
-               }}
+               })
        }
 
-       return pl, nil
+       return s.createPayload(text, attachments), nil
 }
 
 // Review implements PayloadConvertor Review method
@@ -288,12 +248,7 @@ func (s *SlackPayload) Review(p *api.PullRequestPayload, event models.HookEventT
                text = fmt.Sprintf("[%s] Pull request review %s: [%s](%s) by %s", repoLink, action, title, titleLink, senderLink)
        }
 
-       return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+       return s.createPayload(text, nil), nil
 }
 
 // Repository implements PayloadConvertor Repository method
@@ -309,12 +264,17 @@ func (s *SlackPayload) Repository(p *api.RepositoryPayload) (api.Payloader, erro
                text = fmt.Sprintf("[%s] Repository deleted by %s", repoLink, senderLink)
        }
 
+       return s.createPayload(text, nil), nil
+}
+
+func (s *SlackPayload) createPayload(text string, attachments []SlackAttachment) *SlackPayload {
        return &SlackPayload{
-               Channel:  s.Channel,
-               Text:     text,
-               Username: s.Username,
-               IconURL:  s.IconURL,
-       }, nil
+               Channel:     s.Channel,
+               Text:        text,
+               Username:    s.Username,
+               IconURL:     s.IconURL,
+               Attachments: attachments,
+       }
 }
 
 // GetSlackPayload converts a slack webhook into a SlackPayload
index 20de80bd656d8327bb66622d9795a11ba8d3e1ba..3f279810c98af73cfb633f3b026611bf66397806 100644 (file)
@@ -7,74 +7,166 @@ package webhook
 import (
        "testing"
 
+       "code.gitea.io/gitea/models"
        api "code.gitea.io/gitea/modules/structs"
+
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 )
 
-func TestSlackIssuesPayloadOpened(t *testing.T) {
-       p := issueTestPayload()
-       p.Action = api.HookIssueOpened
+func TestSlackPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
 
-       s := new(SlackPayload)
-       s.Username = p.Sender.UserName
+               d := new(SlackPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
 
-       pl, err := s.Issue(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Issue opened: <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>:<http://localhost:3000/test/repo/src/branch/test|test>] branch created by user1", pl.(*SlackPayload).Text)
+       })
 
-       p.Action = api.HookIssueClosed
-       pl, err = s.Issue(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Issue closed: <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
-}
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
 
-func TestSlackIssueCommentPayload(t *testing.T) {
-       p := issueCommentTestPayload()
-       s := new(SlackPayload)
-       s.Username = p.Sender.UserName
+               d := new(SlackPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
 
-       pl, err := s.IssueComment(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>:test] branch deleted by user1", pl.(*SlackPayload).Text)
+       })
 
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] New comment on issue <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
-}
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
 
-func TestSlackPullRequestCommentPayload(t *testing.T) {
-       p := pullRequestCommentTestPayload()
-       s := new(SlackPayload)
-       s.Username = p.Sender.UserName
+               d := new(SlackPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
 
-       pl, err := s.IssueComment(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               assert.Equal(t, "<http://localhost:3000/test/repo2|test/repo2> is forked to <http://localhost:3000/test/repo|test/repo>", pl.(*SlackPayload).Text)
+       })
 
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] New comment on pull request <http://localhost:3000/test/repo/pulls/2|#2 Fix bug> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
-}
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
 
-func TestSlackReleasePayload(t *testing.T) {
-       p := pullReleaseTestPayload()
-       s := new(SlackPayload)
-       s.Username = p.Sender.UserName
+               d := new(SlackPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
 
-       pl, err := s.Release(p)
-       require.NoError(t, err)
-       require.NotNil(t, pl)
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>:<http://localhost:3000/test/repo/src/branch/test|test>] 2 new commits pushed by user1", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(SlackPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Issue opened: <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
 
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Release created: <http://localhost:3000/test/repo/src/v1.0|v1.0> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Issue closed: <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(SlackPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] New comment on issue <http://localhost:3000/test/repo/issues/2|#2 crash> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(SlackPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Pull request opened: <http://localhost:3000/test/repo/pulls/12|#12 Fix bug> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(SlackPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] New comment on pull request <http://localhost:3000/test/repo/pulls/12|#12 Fix bug> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(SlackPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Pull request review approved: [#12 Fix bug](http://localhost:3000/test/repo/pulls/12) by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(SlackPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Repository created by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(SlackPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &SlackPayload{}, pl)
+
+               assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Release created: <http://localhost:3000/test/repo/src/v1.0|v1.0> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       })
 }
 
-func TestSlackPullRequestPayload(t *testing.T) {
-       p := pullRequestTestPayload()
-       s := new(SlackPayload)
-       s.Username = p.Sender.UserName
+func TestSlackJSONPayload(t *testing.T) {
+       p := pushTestPayload()
 
-       pl, err := s.PullRequest(p)
+       pl, err := new(SlackPayload).Push(p)
        require.NoError(t, err)
        require.NotNil(t, pl)
+       require.IsType(t, &SlackPayload{}, pl)
 
-       assert.Equal(t, "[<http://localhost:3000/test/repo|test/repo>] Pull request opened: <http://localhost:3000/test/repo/pulls/12|#2 Fix bug> by <https://try.gitea.io/user1|user1>", pl.(*SlackPayload).Text)
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
 }
index 5b78b46f8ec02ab67506b4377ed2b6928af97e5d..f71352141dee292c62a8e5385ae5a71d2078823b 100644 (file)
@@ -68,9 +68,7 @@ func (t *TelegramPayload) Create(p *api.CreatePayload) (api.Payloader, error) {
        title := fmt.Sprintf(`[<a href="%s">%s</a>] %s <a href="%s">%s</a> created`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType,
                p.Repo.HTMLURL+"/src/"+refName, refName)
 
-       return &TelegramPayload{
-               Message: title,
-       }, nil
+       return createTelegramPayload(title), nil
 }
 
 // Delete implements PayloadConvertor Delete method
@@ -80,18 +78,14 @@ func (t *TelegramPayload) Delete(p *api.DeletePayload) (api.Payloader, error) {
        title := fmt.Sprintf(`[<a href="%s">%s</a>] %s <a href="%s">%s</a> deleted`, p.Repo.HTMLURL, p.Repo.FullName, p.RefType,
                p.Repo.HTMLURL+"/src/"+refName, refName)
 
-       return &TelegramPayload{
-               Message: title,
-       }, nil
+       return createTelegramPayload(title), nil
 }
 
 // Fork implements PayloadConvertor Fork method
 func (t *TelegramPayload) Fork(p *api.ForkPayload) (api.Payloader, error) {
        title := fmt.Sprintf(`%s is forked to <a href="%s">%s</a>`, p.Forkee.FullName, p.Repo.HTMLURL, p.Repo.FullName)
 
-       return &TelegramPayload{
-               Message: title,
-       }, nil
+       return createTelegramPayload(title), nil
 }
 
 // Push implements PayloadConvertor Push method
@@ -129,36 +123,28 @@ func (t *TelegramPayload) Push(p *api.PushPayload) (api.Payloader, error) {
                }
        }
 
-       return &TelegramPayload{
-               Message: title + "\n" + text,
-       }, nil
+       return createTelegramPayload(title + "\n" + text), nil
 }
 
 // Issue implements PayloadConvertor Issue method
 func (t *TelegramPayload) Issue(p *api.IssuePayload) (api.Payloader, error) {
        text, _, attachmentText, _ := getIssuesPayloadInfo(p, htmlLinkFormatter, true)
 
-       return &TelegramPayload{
-               Message: text + "\n\n" + attachmentText,
-       }, nil
+       return createTelegramPayload(text + "\n\n" + attachmentText), nil
 }
 
 // IssueComment implements PayloadConvertor IssueComment method
 func (t *TelegramPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) {
        text, _, _ := getIssueCommentPayloadInfo(p, htmlLinkFormatter, true)
 
-       return &TelegramPayload{
-               Message: text + "\n" + p.Comment.Body,
-       }, nil
+       return createTelegramPayload(text + "\n" + p.Comment.Body), nil
 }
 
 // PullRequest implements PayloadConvertor PullRequest method
 func (t *TelegramPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) {
        text, _, attachmentText, _ := getPullRequestPayloadInfo(p, htmlLinkFormatter, true)
 
-       return &TelegramPayload{
-               Message: text + "\n" + attachmentText,
-       }, nil
+       return createTelegramPayload(text + "\n" + attachmentText), nil
 }
 
 // Review implements PayloadConvertor Review method
@@ -173,12 +159,9 @@ func (t *TelegramPayload) Review(p *api.PullRequestPayload, event models.HookEve
 
                text = fmt.Sprintf("[%s] Pull request review %s: #%d %s", p.Repository.FullName, action, p.Index, p.PullRequest.Title)
                attachmentText = p.Review.Content
-
        }
 
-       return &TelegramPayload{
-               Message: text + "\n" + attachmentText,
-       }, nil
+       return createTelegramPayload(text + "\n" + attachmentText), nil
 }
 
 // Repository implements PayloadConvertor Repository method
@@ -187,14 +170,10 @@ func (t *TelegramPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e
        switch p.Action {
        case api.HookRepoCreated:
                title = fmt.Sprintf(`[<a href="%s">%s</a>] Repository created`, p.Repository.HTMLURL, p.Repository.FullName)
-               return &TelegramPayload{
-                       Message: title,
-               }, nil
+               return createTelegramPayload(title), nil
        case api.HookRepoDeleted:
                title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName)
-               return &TelegramPayload{
-                       Message: title,
-               }, nil
+               return createTelegramPayload(title), nil
        }
        return nil, nil
 }
@@ -203,12 +182,16 @@ func (t *TelegramPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e
 func (t *TelegramPayload) Release(p *api.ReleasePayload) (api.Payloader, error) {
        text, _ := getReleasePayloadInfo(p, htmlLinkFormatter, true)
 
-       return &TelegramPayload{
-               Message: text + "\n",
-       }, nil
+       return createTelegramPayload(text), nil
 }
 
 // GetTelegramPayload converts a telegram webhook into a TelegramPayload
 func GetTelegramPayload(p api.Payloader, event models.HookEventType, meta string) (api.Payloader, error) {
        return convertPayloader(new(TelegramPayload), p, event)
 }
+
+func createTelegramPayload(message string) *TelegramPayload {
+       return &TelegramPayload{
+               Message: strings.TrimSpace(message),
+       }
+}
index 0e909343a86c6279e2816deb727989cafb58e305..037a2481d6df246aacdb51b2e867ebefe79ca292 100644 (file)
@@ -7,18 +7,166 @@ package webhook
 import (
        "testing"
 
+       "code.gitea.io/gitea/models"
        api "code.gitea.io/gitea/modules/structs"
+
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
 )
 
-func TestGetTelegramIssuesPayload(t *testing.T) {
-       p := issueTestPayload()
-       p.Action = api.HookIssueClosed
+func TestTelegramPayload(t *testing.T) {
+       t.Run("Create", func(t *testing.T) {
+               p := createTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Create(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] branch <a href="http://localhost:3000/test/repo/src/test">test</a> created`, pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Delete", func(t *testing.T) {
+               p := deleteTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Delete(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] branch <a href="http://localhost:3000/test/repo/src/test">test</a> deleted`, pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Fork", func(t *testing.T) {
+               p := forkTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Fork(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `test/repo2 is forked to <a href="http://localhost:3000/test/repo">test/repo</a>`, pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Push", func(t *testing.T) {
+               p := pushTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Push(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>:<a href=\"http://localhost:3000/test/repo/src/test\">test</a>] 2 new commits\n[<a href=\"http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778\">2020558</a>] commit message - user1\n[<a href=\"http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778\">2020558</a>] commit message - user1", pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Issue", func(t *testing.T) {
+               p := issueTestPayload()
+
+               d := new(TelegramPayload)
+               p.Action = api.HookIssueOpened
+               pl, err := d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Issue opened: <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>\n\nissue body", pl.(*TelegramPayload).Message)
+
+               p.Action = api.HookIssueClosed
+               pl, err = d.Issue(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Issue closed: <a href="http://localhost:3000/test/repo/issues/2">#2 crash</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("IssueComment", func(t *testing.T) {
+               p := issueCommentTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
 
-       pl, err := new(TelegramPayload).Issue(p)
+               assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] New comment on issue <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>\nmore info needed", pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("PullRequest", func(t *testing.T) {
+               p := pullRequestTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.PullRequest(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Pull request opened: <a href=\"http://localhost:3000/test/repo/pulls/12\">#12 Fix bug</a> by <a href=\"https://try.gitea.io/user1\">user1</a>\nfixes bug #2", pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("PullRequestComment", func(t *testing.T) {
+               p := pullRequestCommentTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.IssueComment(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] New comment on pull request <a href=\"http://localhost:3000/test/repo/pulls/12\">#12 Fix bug</a> by <a href=\"https://try.gitea.io/user1\">user1</a>\nchanges requested", pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Review", func(t *testing.T) {
+               p := pullRequestTestPayload()
+               p.Action = api.HookIssueReviewed
+
+               d := new(TelegramPayload)
+               pl, err := d.Review(p, models.HookEventPullRequestReviewApproved)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, "[test/repo] Pull request review approved: #12 Fix bug\ngood job", pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Repository", func(t *testing.T) {
+               p := repositoryTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Repository(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Repository created`, pl.(*TelegramPayload).Message)
+       })
+
+       t.Run("Release", func(t *testing.T) {
+               p := pullReleaseTestPayload()
+
+               d := new(TelegramPayload)
+               pl, err := d.Release(p)
+               require.NoError(t, err)
+               require.NotNil(t, pl)
+               require.IsType(t, &TelegramPayload{}, pl)
+
+               assert.Equal(t, `[<a href="http://localhost:3000/test/repo">test/repo</a>] Release created: <a href="http://localhost:3000/test/repo/src/v1.0">v1.0</a> by <a href="https://try.gitea.io/user1">user1</a>`, pl.(*TelegramPayload).Message)
+       })
+}
+
+func TestTelegramJSONPayload(t *testing.T) {
+       p := pushTestPayload()
+
+       pl, err := new(TelegramPayload).Push(p)
        require.NoError(t, err)
        require.NotNil(t, pl)
+       require.IsType(t, &TelegramPayload{}, pl)
 
-       assert.Equal(t, "[<a href=\"http://localhost:3000/test/repo\">test/repo</a>] Issue closed: <a href=\"http://localhost:3000/test/repo/issues/2\">#2 crash</a> by <a href=\"https://try.gitea.io/user1\">user1</a>\n\n", pl.(*TelegramPayload).Message)
+       json, err := pl.JSONPayload()
+       require.NoError(t, err)
+       assert.NotEmpty(t, json)
 }