Skip to content

Commit d3317eb

Browse files
GiteaBottclin914wxiaoguang
authored
Always use an empty line to separate the commit message and trailer (#34512) (#34578)
Backport #34512 by tclin914 If the message from form.MergeMessageField is empty, we will miss a "\n" between the title and the "Co-authored-by:" line. The title and message should have a blank line between of them. Co-authored-by: Jim Lin <[email protected]> Co-authored-by: wxiaoguang <[email protected]>
1 parent e9481e1 commit d3317eb

File tree

3 files changed

+63
-5
lines changed

3 files changed

+63
-5
lines changed

services/pull/merge.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"regexp"
1414
"strconv"
1515
"strings"
16+
"unicode"
1617

1718
"code.gitea.io/gitea/models/db"
1819
git_model "code.gitea.io/gitea/models/git"
@@ -161,6 +162,41 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr
161162
return getMergeMessage(ctx, baseGitRepo, pr, mergeStyle, nil)
162163
}
163164

165+
func AddCommitMessageTailer(message, tailerKey, tailerValue string) string {
166+
tailerLine := tailerKey + ": " + tailerValue
167+
message = strings.ReplaceAll(message, "\r\n", "\n")
168+
message = strings.ReplaceAll(message, "\r", "\n")
169+
if strings.Contains(message, "\n"+tailerLine+"\n") || strings.HasSuffix(message, "\n"+tailerLine) {
170+
return message
171+
}
172+
173+
if !strings.HasSuffix(message, "\n") {
174+
message += "\n"
175+
}
176+
pos1 := strings.LastIndexByte(message[:len(message)-1], '\n')
177+
pos2 := -1
178+
if pos1 != -1 {
179+
pos2 = strings.IndexByte(message[pos1:], ':')
180+
if pos2 != -1 {
181+
pos2 += pos1
182+
}
183+
}
184+
var lastLineKey string
185+
if pos1 != -1 && pos2 != -1 {
186+
lastLineKey = message[pos1+1 : pos2]
187+
}
188+
189+
isLikelyTailerLine := lastLineKey != "" && unicode.IsUpper(rune(lastLineKey[0])) && strings.Contains(message, "-")
190+
for i := 0; isLikelyTailerLine && i < len(lastLineKey); i++ {
191+
r := rune(lastLineKey[i])
192+
isLikelyTailerLine = unicode.IsLetter(r) || unicode.IsDigit(r) || r == '-'
193+
}
194+
if !strings.HasSuffix(message, "\n\n") && !isLikelyTailerLine {
195+
message += "\n"
196+
}
197+
return message + tailerLine
198+
}
199+
164200
// ErrInvalidMergeStyle represents an error if merging with disabled merge strategy
165201
type ErrInvalidMergeStyle struct {
166202
ID int64

services/pull/merge_squash.go

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package pull
55

66
import (
77
"fmt"
8-
"strings"
98

109
repo_model "code.gitea.io/gitea/models/repo"
1110
user_model "code.gitea.io/gitea/models/user"
@@ -66,10 +65,8 @@ func doMergeStyleSquash(ctx *mergeContext, message string) error {
6665

6766
if setting.Repository.PullRequest.AddCoCommitterTrailers && ctx.committer.String() != sig.String() {
6867
// add trailer
69-
if !strings.Contains(message, "Co-authored-by: "+sig.String()) {
70-
message += "\nCo-authored-by: " + sig.String()
71-
}
72-
message += fmt.Sprintf("\nCo-committed-by: %s\n", sig.String())
68+
message = AddCommitMessageTailer(message, "Co-authored-by", sig.String())
69+
message = AddCommitMessageTailer(message, "Co-committed-by", sig.String()) // FIXME: this one should be removed, it is not really used or widely used
7370
}
7471
cmdCommit := git.NewCommand("commit").
7572
AddOptionFormat("--author='%s <%s>'", sig.Name, sig.Email).

services/pull/merge_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,28 @@ func Test_expandDefaultMergeMessage(t *testing.T) {
6565
})
6666
}
6767
}
68+
69+
func TestAddCommitMessageTailer(t *testing.T) {
70+
// add tailer for empty message
71+
assert.Equal(t, "\n\nTest-tailer: TestValue", AddCommitMessageTailer("", "Test-tailer", "TestValue"))
72+
73+
// add tailer for message without newlines
74+
assert.Equal(t, "title\n\nTest-tailer: TestValue", AddCommitMessageTailer("title", "Test-tailer", "TestValue"))
75+
assert.Equal(t, "title\n\nNot tailer: xxx\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n\nNot tailer: xxx", "Test-tailer", "TestValue"))
76+
assert.Equal(t, "title\n\nNotTailer: xxx\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n\nNotTailer: xxx", "Test-tailer", "TestValue"))
77+
assert.Equal(t, "title\n\nnot-tailer: xxx\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n\nnot-tailer: xxx", "Test-tailer", "TestValue"))
78+
79+
// add tailer for message with one EOL
80+
assert.Equal(t, "title\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n", "Test-tailer", "TestValue"))
81+
82+
// add tailer for message with two EOLs
83+
assert.Equal(t, "title\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n\n", "Test-tailer", "TestValue"))
84+
85+
// add tailer for message with existing tailer (won't duplicate)
86+
assert.Equal(t, "title\n\nTest-tailer: TestValue", AddCommitMessageTailer("title\n\nTest-tailer: TestValue", "Test-tailer", "TestValue"))
87+
assert.Equal(t, "title\n\nTest-tailer: TestValue\n", AddCommitMessageTailer("title\n\nTest-tailer: TestValue\n", "Test-tailer", "TestValue"))
88+
89+
// add tailer for message with existing tailer and different value (will append)
90+
assert.Equal(t, "title\n\nTest-tailer: v1\nTest-tailer: v2", AddCommitMessageTailer("title\n\nTest-tailer: v1", "Test-tailer", "v2"))
91+
assert.Equal(t, "title\n\nTest-tailer: v1\nTest-tailer: v2", AddCommitMessageTailer("title\n\nTest-tailer: v1\n", "Test-tailer", "v2"))
92+
}

0 commit comments

Comments
 (0)