Code monitors: truncate long Slack blocks (#50083)

Slack requires that text blocks be no longer than 3000 characters. We
already limit the number of lines in the match blocks, but if the lines
are long then the block can still exceed the character limit. With this
change, we also truncate lines if they will push the block over the
character limit.

Fixes #49979.
This commit is contained in:
Julie Tibshirani 2023-04-03 08:43:42 -07:00 committed by GitHub
parent 1f98538819
commit 4edebd80d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 123 additions and 19 deletions

View File

@ -211,13 +211,7 @@ func toDisplayResult(result *searchresult.CommitMatch, externalURL *url.URL) *Di
resultType = "Diff"
}
var content string
if result.DiffPreview != nil {
content = truncateString(result.DiffPreview.Content)
} else {
content = truncateString(result.MessagePreview.Content)
}
content := truncateMatchContent(result)
return &DisplayResult{
ResultType: resultType,
CommitURL: getCommitURL(externalURL, string(result.Repo.Name), string(result.Commit.ID), utmSourceEmail),

View File

@ -49,12 +49,8 @@ func slackPayload(args actionArgs) *slack.WebhookMessage {
result.Repo.Name,
result.Commit.ID.Short(),
)))
var contentRaw string
if result.DiffPreview != nil {
contentRaw = truncateString(result.DiffPreview.Content)
} else {
contentRaw = truncateString(result.MessagePreview.Content)
}
contentRaw := truncateMatchContent(result)
blocks = append(blocks, newMarkdownSection(formatCodeBlock(contentRaw)))
}
if truncatedCount > 0 {
@ -85,13 +81,42 @@ func formatCodeBlock(s string) string {
return fmt.Sprintf("```%s```", strings.ReplaceAll(s, "```", "\\`\\`\\`"))
}
// truncateString truncates the input to 10 lines.
func truncateString(input string) string {
const lines = 10
// truncateMatchContent truncates the match to at most 10 lines, and also
// truncates lines once the content length exceeds 2500 bytes.
//
// We limit the bytes to ensure we don't hit Slack's max block size of 3000
// characters. To be conservative, we truncate to 2500 bytes. We also limit
// the number of lines to 10 to ensure the content is easy to read.
func truncateMatchContent(result *searchresult.CommitMatch) string {
const maxBytes = 2500
const maxLines = 10
splitLines := strings.SplitAfter(input, "\n")
if len(splitLines) > lines {
splitLines = splitLines[:lines]
var matchedString *searchresult.MatchedString
switch {
case result.DiffPreview != nil:
matchedString = result.DiffPreview
case result.MessagePreview != nil:
matchedString = result.MessagePreview
default:
panic("exactly one of DiffPreview or MessagePreview must be set")
}
splitLines := strings.SplitAfter(matchedString.Content, "\n")
limit := len(splitLines)
if limit > maxLines {
limit = maxLines
}
chars, index := 0, 0
for ; index < limit; index++ {
chars += len(splitLines[index])
if chars > maxBytes {
break
}
}
if len(splitLines) > index {
splitLines = splitLines[:index]
splitLines = append(splitLines, "...\n")
}
return strings.Join(splitLines, "")

View File

@ -80,6 +80,14 @@ func TestSlackWebhook(t *testing.T) {
autogold.ExpectFile(t, jsonSlackPayload(actionCopy))
})
t.Run("golden with truncated matches", func(t *testing.T) {
actionCopy := action
actionCopy.IncludeResults = true
// add a commit result with very long lines that exceeds the character limit
actionCopy.Results = append(actionCopy.Results, &longCommitResultMock)
autogold.ExpectFile(t, jsonSlackPayload(actionCopy))
})
t.Run("golden without results", func(t *testing.T) {
autogold.ExpectFile(t, jsonSlackPayload(action))
})

View File

@ -50,3 +50,20 @@ var commitResultMock = result.CommitMatch{
}
var commitDisplayResultMock = toDisplayResult(&commitResultMock, externalURLMock)
var longCommitResultMock = result.CommitMatch{
Commit: gitdomain.Commit{
ID: api.CommitID("9cb4a43a052f8178566"),
Parents: []api.CommitID{},
},
Repo: types.MinimalRepo{
Name: api.RepoName("github.com/test/test"),
},
MessagePreview: &result.MatchedString{
Content: "summary line\nnext line\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong",
MatchedRanges: result.Ranges{{
Start: result.Location{Line: 2, Offset: 15, Column: 0},
End: result.Location{Line: 2, Offset: 19, Column: 4},
}},
},
}

View File

@ -0,0 +1,60 @@
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Camden Cheek's Sourcegraph Code monitor, *My test monitor*, detected *4* new matches."
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Diff match: \u003chttps://sourcegraph.com/github.com/test/test/-/commit/7815187511872asbasdfgasd?utm_source=|github.com/test/test@7815187\u003e"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "```file1.go file2.go\n@@ -97,5 +97,5 @@ func Test() {\n leading context\n+matched added\n-matched removed\n trailing context\n```"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Message match: \u003chttps://sourcegraph.com/github.com/test/test/-/commit/7815187511872asbasdfgasd?utm_source=|github.com/test/test@7815187\u003e"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "```summary line\n\nvery\nlong\nmessage\nbody\nwith\nmore\nthan\nten\n...\n```"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "Message match: \u003chttps://sourcegraph.com/github.com/test/test/-/commit/9cb4a43a052f8178566?utm_source=|github.com/test/test@9cb4a43\u003e"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "```summary line\nnext line\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n longlonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglonglong\n...\n```"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "If you are Camden Cheek, you can \u003chttps://sourcegraph.com/code-monitoring/Q29kZU1vbml0b3I6MA==?utm_source=|edit your code monitor\u003e"
}
}
]
}