Co-authored-by: Marco De Araujo <marco.araujo.junior@gmail.com> Co-committed-by: Marco De Araujo <marco.araujo.junior@gmail.com>
This commit is contained in:
		
					parent
					
						
							
								cff7754735
							
						
					
				
			
			
				commit
				
					
						1f4be5baad
					
				
			
		
					 3 changed files with 145 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -10,6 +10,7 @@ import (
 | 
			
		|||
	"html/template"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"unicode/utf8"
 | 
			
		||||
| 
						 | 
				
			
			@ -202,6 +203,9 @@ func (d discordConvertor) Push(p *api.PushPayload) (DiscordPayload, error) {
 | 
			
		|||
		// limit the commit message display to just the summary, otherwise it would be hard to read
 | 
			
		||||
		message := strings.TrimRight(strings.SplitN(commit.Message, "\n", 1)[0], "\r")
 | 
			
		||||
 | 
			
		||||
		// Escaping markdown character
 | 
			
		||||
		message = escapeMarkdown(message)
 | 
			
		||||
 | 
			
		||||
		// a limit of 50 is set because GitHub does the same
 | 
			
		||||
		if utf8.RuneCountInString(message) > 50 {
 | 
			
		||||
			message = fmt.Sprintf("%.47s...", message)
 | 
			
		||||
| 
						 | 
				
			
			@ -365,3 +369,40 @@ func (d discordConvertor) createPayload(s *api.User, title, text, url string, co
 | 
			
		|||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var orderedListPattern = regexp.MustCompile(`(\d+)\.`)
 | 
			
		||||
 | 
			
		||||
var markdownPatterns = map[string]*regexp.Regexp{
 | 
			
		||||
	"~": regexp.MustCompile(`\~(.*?)\~`),
 | 
			
		||||
	"*": regexp.MustCompile(`\*(.*?)\*`),
 | 
			
		||||
	"_": regexp.MustCompile(`\_(.*?)\_`),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var markdownToEscape = strings.NewReplacer(
 | 
			
		||||
	"* ", "\\* ",
 | 
			
		||||
	"`", "\\`",
 | 
			
		||||
	"[", "\\[",
 | 
			
		||||
	"]", "\\]",
 | 
			
		||||
	"(", "\\(",
 | 
			
		||||
	")", "\\)",
 | 
			
		||||
	"#", "\\#",
 | 
			
		||||
	"+ ", "\\+ ",
 | 
			
		||||
	"- ", "\\- ",
 | 
			
		||||
	"---", "\\---",
 | 
			
		||||
	"!", "\\!",
 | 
			
		||||
	"|", "\\|",
 | 
			
		||||
	"<", "\\<",
 | 
			
		||||
	">", "\\>",
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Escape Markdown characters
 | 
			
		||||
func escapeMarkdown(input string) string {
 | 
			
		||||
	// Escaping ordered list
 | 
			
		||||
	output := orderedListPattern.ReplaceAllString(input, "$1\\.")
 | 
			
		||||
 | 
			
		||||
	for char, pattern := range markdownPatterns {
 | 
			
		||||
		output = pattern.ReplaceAllString(output, fmt.Sprintf(`\%s$1\%s`, char, char))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return markdownToEscape.Replace(output)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -94,6 +94,20 @@ func TestDiscordPayload(t *testing.T) {
 | 
			
		|||
		assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("PushWithMarkdownCharactersInCommitMessage", func(t *testing.T) {
 | 
			
		||||
		p := pushTestEscapeCommitMessagePayload()
 | 
			
		||||
 | 
			
		||||
		pl, err := dc.Push(p)
 | 
			
		||||
		require.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
		assert.Len(t, pl.Embeds, 1)
 | 
			
		||||
		assert.Equal(t, "[test/repo:test] 2 new commits", pl.Embeds[0].Title)
 | 
			
		||||
		assert.Equal(t, "[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) \\# conflicts\n\\# \\- some/conflicting/file.txt - user1\n[2020558](http://localhost:3000/test/repo/commit/2020558fe2e34debb818a514715839cabd25e778) \\# conflicts\n\\# \\- some/conflicting/file.txt - user1", pl.Embeds[0].Description)
 | 
			
		||||
		assert.Equal(t, p.Sender.UserName, pl.Embeds[0].Author.Name)
 | 
			
		||||
		assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.Embeds[0].Author.URL)
 | 
			
		||||
		assert.Equal(t, p.Sender.AvatarURL, pl.Embeds[0].Author.IconURL)
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	t.Run("Issue", func(t *testing.T) {
 | 
			
		||||
		p := issueTestPayload()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -346,3 +360,89 @@ func TestDiscordJSONPayload(t *testing.T) {
 | 
			
		|||
	require.NoError(t, err)
 | 
			
		||||
	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", body.Embeds[0].Description)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var escapedMarkdownTests = map[string]struct {
 | 
			
		||||
	input    string
 | 
			
		||||
	expected string
 | 
			
		||||
}{
 | 
			
		||||
	"Escape heading level 1": {
 | 
			
		||||
		input:    "# Heading level 1",
 | 
			
		||||
		expected: "\\# Heading level 1",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape heading level 2": {
 | 
			
		||||
		input:    "## Heading level 2",
 | 
			
		||||
		expected: "\\#\\# Heading level 2",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape heading level 3": {
 | 
			
		||||
		input:    "### Heading level 3",
 | 
			
		||||
		expected: "\\#\\#\\# Heading level 3",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape bold text": {
 | 
			
		||||
		input:    "**bold text**",
 | 
			
		||||
		expected: "\\*\\*bold text\\*\\*",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape italic text": {
 | 
			
		||||
		input:    "*italic text*",
 | 
			
		||||
		expected: "\\*italic text\\*",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape italic text underline": {
 | 
			
		||||
		input:    "_italic text_",
 | 
			
		||||
		expected: "\\_italic text\\_",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape strikethrough": {
 | 
			
		||||
		input:    "~~strikethrough~~",
 | 
			
		||||
		expected: "\\~\\~strikethrough\\~\\~",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape Ordered list item": {
 | 
			
		||||
		input:    "1. Ordered list item\n2. Second ordered list item\n999999999999. 999999999999 ordered list item",
 | 
			
		||||
		expected: "1\\. Ordered list item\n2\\. Second ordered list item\n999999999999\\. 999999999999 ordered list item",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape Unordered list item": {
 | 
			
		||||
		input:    "- Unordered list\n + using plus",
 | 
			
		||||
		expected: "\\- Unordered list\n \\+ using plus",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape bullet list item": {
 | 
			
		||||
		input:    "* Bullet list item",
 | 
			
		||||
		expected: "\\* Bullet list item",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape table": {
 | 
			
		||||
		input:    "| Table | Example |\n|-|-|\n| Lorem | Ipsum |",
 | 
			
		||||
		expected: "\\| Table \\| Example \\|\n\\|-\\|-\\|\n\\| Lorem \\| Ipsum \\|",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape link": {
 | 
			
		||||
		input:    "[Link to Forgejo](https://forgejo.org/)",
 | 
			
		||||
		expected: "\\[Link to Forgejo\\]\\(https://forgejo.org/\\)",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape Alt text for an image": {
 | 
			
		||||
		input:    "",
 | 
			
		||||
		expected: "\\!\\[Alt text for an image\\]\\(https://forgejo.org/\\_astro/mascot-dark.1omhhgvT\\_Zm0N2n.webp\\)",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape URL if it has markdown character": {
 | 
			
		||||
		input:    "https://forgejo.org/_astro/mascot-dark.1omhhgvT_Zm0N2n.webp",
 | 
			
		||||
		expected: "https://forgejo.org/\\_astro/mascot-dark.1omhhgvT\\_Zm0N2n.webp",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape blockquote text": {
 | 
			
		||||
		input:    "> Blockquote text.",
 | 
			
		||||
		expected: "\\> Blockquote text.",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape inline code": {
 | 
			
		||||
		input:    "`Inline code`",
 | 
			
		||||
		expected: "\\`Inline code\\`",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape multiple code": {
 | 
			
		||||
		input:    "```\nCode block\nwith multiple lines\n```\n",
 | 
			
		||||
		expected: "\\`\\`\\`\nCode block\nwith multiple lines\n\\`\\`\\`\n",
 | 
			
		||||
	},
 | 
			
		||||
	"Escape horizontal rule": {
 | 
			
		||||
		input:    "---",
 | 
			
		||||
		expected: "\\---",
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestEscapeMarkdownChar(t *testing.T) {
 | 
			
		||||
	for name, test := range escapedMarkdownTests {
 | 
			
		||||
		t.Run(name, func(t *testing.T) {
 | 
			
		||||
			assert.Equal(t, test.expected, escapeMarkdown(test.input))
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -72,6 +72,10 @@ func pushTestMultilineCommitMessagePayload() *api.PushPayload {
 | 
			
		|||
	return pushTestPayloadWithCommitMessage("This is a commit summary ⚠️⚠️⚠️⚠️ containing 你好 ⚠️⚠️️\n\nThis is the message body.")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pushTestEscapeCommitMessagePayload() *api.PushPayload {
 | 
			
		||||
	return pushTestPayloadWithCommitMessage("# conflicts\n# - some/conflicting/file.txt")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func pushTestPayloadWithCommitMessage(message string) *api.PushPayload {
 | 
			
		||||
	commit := &api.PayloadCommit{
 | 
			
		||||
		ID:      "2020558fe2e34debb818a514715839cabd25e778",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue