fix: Invalid UTF-8 commit messages in JSON API responses (#37542)

This commit is contained in:
Nicolas
2026-05-07 16:19:45 +02:00
committed by GitHub
parent 2200ed7499
commit c9b9e376fb
54 changed files with 221 additions and 215 deletions

View File

@@ -261,7 +261,7 @@ func UpdateBranch(ctx context.Context, repoID, pusherID int64, branchName string
Cols("commit_id, commit_message, pusher_id, commit_time, is_deleted, updated_unix").
Update(&Branch{
CommitID: commit.ID.String(),
CommitMessage: commit.Summary(),
CommitMessage: commit.MessageTitle(),
PusherID: pusherID,
CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
IsDeleted: false,

View File

@@ -36,7 +36,7 @@ func TestAddDeletedBranch(t *testing.T) {
commit := &git.Commit{
ID: git.MustIDFromString(secondBranch.CommitID),
CommitMessage: secondBranch.CommitMessage,
CommitMessage: git.CommitMessage{MessageRaw: secondBranch.CommitMessage},
Committer: &git.Signature{
When: secondBranch.CommitTime.AsLocalTime(),
},

View File

@@ -89,7 +89,10 @@ func ToUTF8(content []byte, opts ConvertOpts) []byte {
encoding, _ := charset.Lookup(charsetLabel)
if encoding == nil {
setting.PanicInDevOrTesting("unsupported detected charset %q, it shouldn't happen", charsetLabel)
return content
if opts.ErrorReturnOrigin {
return content
}
return bytes.ToValidUTF8(content, opts.ErrorReplacement)
}
var decoded []byte

View File

@@ -11,19 +11,28 @@ import (
"os/exec"
"strings"
"code.gitea.io/gitea/modules/charset"
"code.gitea.io/gitea/modules/git/gitcmd"
"code.gitea.io/gitea/modules/util"
)
type CommitMessage struct {
MessageRaw string
messageUTF8 *string
messageTitle *string
messageBody *string
}
// Commit represents a git commit.
type Commit struct {
Tree // FIXME: bad design, this field can be nil if the commit is from "last commit cache"
ID ObjectID
Author *Signature // never nil
Committer *Signature // never nil
CommitMessage string
Signature *CommitSignature
CommitMessage
ID ObjectID
Author *Signature // never nil
Committer *Signature // never nil
Signature *CommitSignature
Parents []ObjectID // ID strings
submoduleCache *ObjectCache[*SubModule]
@@ -35,19 +44,28 @@ type CommitSignature struct {
Payload string
}
// Message returns the commit message. Same as retrieving CommitMessage directly.
func (c *Commit) Message() string {
// FIXME: GIT-COMMIT-MESSAGE-ENCODING: this logic is not right
// * When need to use commit message in templates/database, it should be valid UTF-8
// * When need to get the original commit message, it should just use "c.CommitMessage"
// It's not easy to refactor at the moment, many templates need to be updated and tested
return c.CommitMessage
func (c *CommitMessage) MessageUTF8() string {
if c.messageUTF8 == nil {
bs := charset.ToUTF8(util.UnsafeStringToBytes(c.MessageRaw), charset.ConvertOpts{ErrorReplacement: []byte{'?'}})
c.messageUTF8 = new(util.UnsafeBytesToString(bs))
}
return *c.messageUTF8
}
// Summary returns first line of commit message.
// The string is forced to be valid UTF8
func (c *Commit) Summary() string {
return strings.ToValidUTF8(strings.Split(strings.TrimSpace(c.CommitMessage), "\n")[0], "?")
func (c *CommitMessage) MessageTitle() string {
if c.messageTitle == nil {
s, _, _ := strings.Cut(strings.TrimSpace(c.MessageUTF8()), "\n")
c.messageTitle = new(strings.TrimSpace(s))
}
return *c.messageTitle
}
func (c *CommitMessage) MessageBody() string {
if c.messageBody == nil {
_, s, _ := strings.Cut(strings.TrimSpace(c.MessageUTF8()), "\n")
c.messageBody = new(strings.TrimSpace(s))
}
return *c.messageBody
}
// ParentID returns oid of n-th parent (0-based index).

View File

@@ -66,7 +66,7 @@ func convertPGPSignature(c *object.Commit) *CommitSignature {
func convertCommit(c *object.Commit) *Commit {
return &Commit{
ID: ParseGogitHash(c.Hash),
CommitMessage: c.Message,
CommitMessage: CommitMessage{MessageRaw: c.Message},
Committer: &c.Committer,
Author: &c.Author,
Signature: convertPGPSignature(c),

View File

@@ -92,7 +92,7 @@ func CommitFromReader(gitRepo *Repository, objectID ObjectID, reader io.Reader)
}
}
commit.CommitMessage = messageSB.String()
commit.MessageRaw = messageSB.String()
if commit.Signature != nil {
commit.Signature.Payload = payloadSB.String()
}

View File

@@ -95,7 +95,7 @@ signed commit`, commitFromReader.Signature.Payload)
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
}

View File

@@ -91,7 +91,7 @@ empty commit`, commitFromReader.Signature.Payload)
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
}
@@ -154,11 +154,20 @@ ISO-8859-1`, commitFromReader.Signature.Payload)
commitFromReader2, err := CommitFromReader(gitRepo, sha, strings.NewReader(commitString+"\n\n"))
assert.NoError(t, err)
commitFromReader.CommitMessage += "\n\n"
commitFromReader.CommitMessage.MessageRaw += "\n\n"
commitFromReader.Signature.Payload += "\n\n"
assert.Equal(t, commitFromReader, commitFromReader2)
}
func TestCommitMessageSanitizesInvalidUTF8(t *testing.T) {
commit := &Commit{
CommitMessage: CommitMessage{MessageRaw: "title \xff\n\n\n\nbody \xff\n\n\n"},
}
assert.Equal(t, "title ÿ", commit.MessageTitle())
assert.Equal(t, "body ÿ", commit.MessageBody())
assert.Equal(t, "title ÿ\n\n\n\nbody ÿ\n\n\n", commit.MessageUTF8())
}
func TestHasPreviousCommit(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")

View File

@@ -111,8 +111,6 @@ func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
len(fields), len(p.format.fieldNames))
}
for i, field := range fields {
field = strings.TrimSpace(field)
var fieldKey string
var fieldVal string
before, after, ok := strings.Cut(field, " ")

View File

@@ -116,12 +116,12 @@ func TestParser(t *testing.T) {
},
{
"refname:short": "v0.0.2",
"contents": "Update CI config (#651)",
"contents": "Update CI config (#651)\n\n",
"author": "John Doe <john.doe@foo.com> 1521643174 +0000",
},
{
"refname:short": "v0.0.3",
"contents": "Fixed code sample for bash completion (#687)",
"contents": "Fixed code sample for bash completion (#687)\n\n",
"author": "Foo Baz <foo@baz.com> 1524836750 +0200",
},
},

View File

@@ -10,7 +10,6 @@ import (
"bytes"
"io"
"sort"
"strings"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/git/gitcmd"
@@ -97,7 +96,7 @@ func findLFSFileFunc(repo *git.Repository, objectID git.ObjectID, revListReader
result := LFSResult{
Name: curPath + fname,
SHA: curCommit.ID.String(),
Summary: strings.Split(strings.TrimSpace(curCommit.CommitMessage), "\n")[0],
Summary: curCommit.MessageTitle(),
When: curCommit.Author.When,
ParentHashes: curCommit.Parents,
}

View File

@@ -54,7 +54,7 @@ func TestGetTagCommitWithSignature(t *testing.T) {
assert.NotNil(t, commit)
assert.NotNil(t, commit.Signature)
// test that signature is not in message
assert.Equal(t, "signed-commit\n", commit.CommitMessage)
assert.Equal(t, "signed-commit\n", commit.CommitMessage.MessageRaw)
}
func TestGetCommitWithBadCommitID(t *testing.T) {

View File

@@ -176,15 +176,14 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) {
}
tag.Tagger = parseSignatureFromCommitLine(ref["creator"])
tag.Message = ref["contents"]
tag.MessageRaw = ref["contents"]
// strip any signature if present in contents field
_, tag.Message, _ = parsePayloadSignature(util.UnsafeStringToBytes(tag.Message), 0)
_, tag.MessageRaw, _ = parsePayloadSignature(util.UnsafeStringToBytes(tag.MessageRaw), 0)
// annotated tag with GPG signature
if tag.Type == "tag" && ref["contents:signature"] != "" {
payload := fmt.Sprintf("object %s\ntype commit\ntag %s\ntagger %s\n\n%s\n",
tag.Object, tag.Name, ref["creator"], strings.TrimSpace(tag.Message))
payload := fmt.Sprintf("object %s\ntype commit\ntag %s\ntagger %s\n\n%s", tag.Object, tag.Name, ref["creator"], tag.MessageRaw)
tag.Signature = &CommitSignature{
Signature: ref["contents:signature"],
Payload: payload,

View File

@@ -64,12 +64,12 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
CommitMessage: CommitMessage{MessageRaw: commit.CommitMessage.MessageRaw},
}
repo.tagCache.Set(tagID.String(), tag)
@@ -86,12 +86,12 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID.Type().MustID(gogitTag.Target[:]),
Type: tp,
Tagger: &gogitTag.Tagger,
Message: gogitTag.Message,
Name: name,
ID: tagID,
Object: commitID.Type().MustID(gogitTag.Target[:]),
Type: tp,
Tagger: &gogitTag.Tagger,
CommitMessage: CommitMessage{MessageRaw: gogitTag.Message},
}
repo.tagCache.Set(tagID.String(), tag)

View File

@@ -71,12 +71,12 @@ func (repo *Repository) getTag(tagID ObjectID, name string) (*Tag, error) {
return nil, err
}
tag := &Tag{
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
Message: commit.Message(),
Name: name,
ID: tagID,
Object: commitID,
Type: tp,
Tagger: commit.Committer,
CommitMessage: commit.CommitMessage,
}
repo.tagCache.Set(tagID.String(), tag)

View File

@@ -211,13 +211,13 @@ func TestRepository_parseTagRef(t *testing.T) {
},
want: &Tag{
Name: "v1.9.1",
ID: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Type: "commit",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
Signature: nil,
Name: "v1.9.1",
ID: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
Type: "commit",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
CommitMessage: CommitMessage{MessageRaw: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n"},
Signature: nil,
},
},
@@ -240,13 +240,13 @@ func TestRepository_parseTagRef(t *testing.T) {
},
want: &Tag{
Name: "v0.0.1",
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n",
Signature: nil,
Name: "v0.0.1",
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
CommitMessage: CommitMessage{MessageRaw: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n"},
Signature: nil,
},
},
@@ -263,6 +263,7 @@ func TestRepository_parseTagRef(t *testing.T) {
* add changelog of v1.9.1
* Update CHANGELOG.md
-----BEGIN PGP SIGNATURE-----
aBCGzBAABCgAdFiEEyWRwv/q1Q6IjSv+D4IPOwzt33PoFAmI8jbIACgkQ4IPOwzt3
@@ -298,12 +299,12 @@ qbHDASXl
},
want: &Tag{
Name: "v0.0.1",
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
Message: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md",
Name: "v0.0.1",
ID: MustIDFromString("8c68a1f06fc59c655b7e3905b159d761e91c53c9"),
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
Type: "tag",
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
CommitMessage: CommitMessage{MessageRaw: "Add changelog of v1.9.1 (#7859)\n\n* add changelog of v1.9.1\n* Update CHANGELOG.md\n"},
Signature: &CommitSignature{
Signature: `-----BEGIN PGP SIGNATURE-----

View File

@@ -12,12 +12,13 @@ import (
// Tag represents a Git tag.
type Tag struct {
CommitMessage
Name string
ID ObjectID
Object ObjectID // The id of this commit object
Type string
Tagger *Signature
Message string
Signature *CommitSignature
}
@@ -87,7 +88,7 @@ func parseTagData(objectFormat ObjectFormat, data []byte) (*Tag, error) {
pos += eol + 1
}
payload, msg, sign := parsePayloadSignature(data, pos)
tag.Message = msg
tag.MessageRaw = msg
if len(sign) > 0 {
tag.Signature = &CommitSignature{Signature: sign, Payload: payload}
}

View File

@@ -28,7 +28,6 @@ tagger Lucas Michot <lucas@semalead.com> 1484491741 +0100
Object: MustIDFromString("3b114ab800c6432ad42387ccf6bc8d4388a2885a"),
Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))},
Message: "",
Signature: nil,
},
},
@@ -43,13 +42,13 @@ o
ono`,
expected: Tag{
Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(),
Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc"),
Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0).In(time.FixedZone("", 3600))},
Message: "test message\no\n\nono",
Signature: nil,
Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(),
Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfccc"),
Type: "commit",
Tagger: &Signature{Name: "Lucas Michot", Email: "lucas@semalead.com", When: time.Unix(1484553735, 0).In(time.FixedZone("", 3600))},
CommitMessage: CommitMessage{MessageRaw: "test message\no\n\nono"},
Signature: nil,
},
},
{
@@ -64,12 +63,12 @@ dummy signature
-----END SSH SIGNATURE-----
`,
expected: Tag{
Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(),
Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa"),
Type: "commit",
Tagger: &Signature{Name: "dummy user", Email: "dummy-email@example.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))},
Message: "dummy message",
Name: "",
ID: Sha1ObjectFormat.EmptyObjectID(),
Object: MustIDFromString("7cdf42c0b1cc763ab7e4c33c47a24e27c66bfaaa"),
Type: "commit",
Tagger: &Signature{Name: "dummy user", Email: "dummy-email@example.com", When: time.Unix(1484491741, 0).In(time.FixedZone("", 3600))},
CommitMessage: CommitMessage{MessageRaw: "dummy message"},
Signature: &CommitSignature{
Signature: `-----BEGIN SSH SIGNATURE-----
dummy signature
@@ -93,5 +92,5 @@ dummy message`,
tag, err := parseTagData(Sha1ObjectFormat, []byte("type commit\n\nfoo\n-----BEGIN SSH SIGNATURE-----\ncorrupted..."))
assert.NoError(t, err)
assert.Equal(t, "foo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...", tag.Message)
assert.Equal(t, "foo\n-----BEGIN SSH SIGNATURE-----\ncorrupted...", tag.CommitMessage.MessageRaw)
}

View File

@@ -97,7 +97,7 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
RepoID: repo.ID,
Name: branch,
CommitID: commit.ID.String(),
CommitMessage: commit.Summary(),
CommitMessage: commit.MessageTitle(),
PusherID: doerID,
CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
})
@@ -112,7 +112,7 @@ func SyncRepoBranchesWithRepo(ctx context.Context, repo *repo_model.Repository,
RepoID: repo.ID,
Name: branch,
CommitID: commit.ID.String(),
CommitMessage: commit.Summary(),
CommitMessage: commit.MessageTitle(),
PusherID: doerID,
CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
})

View File

@@ -152,7 +152,7 @@ func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string {
func CommitToPushCommit(commit *git.Commit) *PushCommit {
return &PushCommit{
Sha1: commit.ID.String(),
Message: commit.Message(),
Message: commit.MessageUTF8(),
AuthorEmail: commit.Author.Email,
AuthorName: commit.Author.Name,
CommitterEmail: commit.Committer.Email,

View File

@@ -145,7 +145,7 @@ func TestCommitToPushCommit(t *testing.T) {
ID: sha1,
Author: sig,
Committer: sig,
CommitMessage: "Commit Message",
CommitMessage: git.CommitMessage{MessageRaw: "Commit Message"},
})
assert.Equal(t, hexString, pushCommit.Sha1)
assert.Equal(t, "Commit Message", pushCommit.Message)
@@ -176,13 +176,13 @@ func TestListToPushCommits(t *testing.T) {
ID: hash1,
Author: sig,
Committer: sig,
CommitMessage: "Message1",
CommitMessage: git.CommitMessage{MessageRaw: "Message1"},
},
{
ID: hash2,
Author: sig,
Committer: sig,
CommitMessage: "Message2",
CommitMessage: git.CommitMessage{MessageRaw: "Message2"},
},
}

View File

@@ -132,10 +132,9 @@ func newFuncMapWebPage() template.FuncMap {
// -----------------------------------------------------------------
// misc (TODO: move them to MiscUtils to avoid bloating the main func map)
"ActionContent2Commits": ActionContent2Commits,
"IsMultilineCommitMessage": isMultilineCommitMessage,
"CommentMustAsDiff": gitdiff.CommentMustAsDiff,
"MirrorRemoteAddress": mirrorRemoteAddress,
"ActionContent2Commits": ActionContent2Commits,
"CommentMustAsDiff": gitdiff.CommentMustAsDiff,
"MirrorRemoteAddress": mirrorRemoteAddress,
"FilenameIsImage": filenameIsImage,
"TabSizeClass": tabSizeClass,

View File

@@ -52,11 +52,6 @@ func sortArrow(normSort, revSort, urlSort string, isDefault bool) template.HTML
return ""
}
// isMultilineCommitMessage checks to see if a commit message contains multiple lines.
func isMultilineCommitMessage(msg string) bool {
return strings.Count(strings.TrimSpace(msg), "\n") >= 1
}
// Actioner describes an action
type Actioner interface {
GetOpType() activities_model.ActionType

View File

@@ -79,20 +79,14 @@ func (ut *RenderUtils) RenderCommitMessageLinkSubject(msg, urlDefault string, re
// RenderCommitBody extracts the body of a commit message without its title.
func (ut *RenderUtils) RenderCommitBody(msg string, repo *repo.Repository) template.HTML {
msgLine := strings.TrimSpace(msg)
lineEnd := strings.IndexByte(msgLine, '\n')
if lineEnd > 0 {
msgLine = msgLine[lineEnd+1:]
} else {
return ""
}
msgLine = strings.TrimLeftFunc(msgLine, unicode.IsSpace)
if len(msgLine) == 0 {
_, body, _ := strings.Cut(strings.TrimSpace(msg), "\n")
body = strings.TrimFunc(body, unicode.IsSpace)
if body == "" {
return ""
}
rctx := renderhelper.NewRenderContextRepoComment(ut.ctx, repo)
htmlContent := template.HTML(template.HTMLEscapeString(msgLine))
htmlContent := template.HTML(template.HTMLEscapeString(body))
renderedMessage, err := markup.PostProcessCommitMessage(rctx, htmlContent)
if err != nil {
log.Error("PostProcessCommitMessage: %v", err)

View File

@@ -4,7 +4,6 @@
package feed
import (
"strings"
"time"
"code.gitea.io/gitea/models/repo"
@@ -39,14 +38,14 @@ func ShowBranchFeed(ctx *context.Context, repo *repo.Repository, formatType stri
for _, commit := range commits {
feed.Items = append(feed.Items, &feeds.Item{
Id: commit.ID.String(),
Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]),
Title: commit.MessageTitle(),
Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()},
Author: &feeds.Author{
Name: commit.Author.Name,
Email: commit.Author.Email,
},
Description: commit.Message(),
Content: commit.Message(),
Description: commit.MessageUTF8(), // TODO: description can be shorten content
Content: commit.MessageUTF8(),
Created: commit.Committer.When,
})
}

View File

@@ -4,7 +4,6 @@
package feed
import (
"strings"
"time"
"code.gitea.io/gitea/models/repo"
@@ -46,14 +45,14 @@ func ShowFileFeed(ctx *context.Context, repo *repo.Repository, formatType string
for _, commit := range commits {
feed.Items = append(feed.Items, &feeds.Item{
Id: commit.ID.String(),
Title: strings.TrimSpace(strings.Split(commit.Message(), "\n")[0]),
Title: commit.MessageTitle(),
Link: &feeds.Link{Href: repo.HTMLURL() + "/commit/" + commit.ID.String()},
Author: &feeds.Author{
Name: commit.Author.Name,
Email: commit.Author.Email,
},
Description: commit.Message(),
Content: commit.Message(),
Description: commit.MessageUTF8(), // TODO: description can be shorten content
Content: commit.MessageUTF8(),
Created: commit.Committer.When,
})
}

View File

@@ -231,7 +231,7 @@ func renderBlameFillFirstBlameRow(repoLink string, avatarUtils *templates.Avatar
br.PreviousSha = part.PreviousSha
br.PreviousShaURL = fmt.Sprintf("%s/blame/commit/%s/%s", repoLink, url.PathEscape(part.PreviousSha), util.PathEscapeSegments(part.PreviousPath))
br.CommitURL = fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(part.Sha))
br.CommitMessage = commit.CommitMessage
br.CommitMessage = commit.MessageUTF8()
br.CommitSince = templates.TimeSince(commit.Author.When)
}

View File

@@ -349,7 +349,7 @@ func Diff(ctx *context.Context) {
parentCommitID = parentCommit.ID.String()
}
setCompareContext(ctx, parentCommit, commit, userName, repoName)
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
ctx.Data["Title"] = commit.MessageTitle() + " · " + base.ShortSha(commitID)
ctx.Data["Commit"] = commit
ctx.Data["Diff"] = diff
ctx.Data["DiffBlobExcerptData"] = diffBlobExcerptData

View File

@@ -391,17 +391,14 @@ func prepareNewPullRequestTitleContent(ci *git_service.CompareInfo, commits []*g
if useFirstCommitAsTitle {
// the "commits" are from "ShowPrettyFormatLogToList", which is ordered from newest to oldest, here take the oldest one
c := commits[len(commits)-1]
title = strings.TrimSpace(c.UserCommit.Summary())
title = c.UserCommit.MessageTitle()
} else {
title = autoTitleFromBranchName(ci.HeadRef.ShortName())
}
if len(commits) == 1 {
// FIXME: GIT-COMMIT-MESSAGE-ENCODING: try to convert the encoding for commit message explicitly, ideally it should be done by a git commit struct method
c := commits[0]
_, content, _ = strings.Cut(strings.TrimSpace(c.UserCommit.CommitMessage), "\n")
content = strings.TrimSpace(content)
content = string(charset.ToUTF8([]byte(content), charset.ConvertOpts{}))
content = c.MessageBody()
}
var titleTrailer string

View File

@@ -6,7 +6,6 @@ package repo
import (
"strings"
"testing"
"unicode/utf8"
asymkey_model "code.gitea.io/gitea/models/asymkey"
git_model "code.gitea.io/gitea/models/git"
@@ -55,7 +54,7 @@ func TestNewPullRequestTitleContent(t *testing.T) {
SignCommit: &asymkey_model.SignCommit{
UserCommit: &user_model.UserCommit{
Commit: &git.Commit{
CommitMessage: msg,
CommitMessage: git.CommitMessage{MessageRaw: msg},
},
},
},
@@ -99,9 +98,9 @@ func TestNewPullRequestTitleContent(t *testing.T) {
assert.Equal(t, "title-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa…", title)
assert.Equal(t, "…aaaaaaaaa\n", content)
title, content = prepareNewPullRequestTitleContent(ci, []*git_model.SignCommitWithStatuses{mockCommit("a\xf0\xf0\xf0\nb\xf0\xf0\xf0")}, setting.RepoPRTitleSourceFirstCommit)
assert.Equal(t, "a?", title) // FIXME: GIT-COMMIT-MESSAGE-ENCODING: "title" doesn't use the same charset converting logic as "content"
assert.Equal(t, "b"+string(utf8.RuneError)+string(utf8.RuneError), content)
title, content = prepareNewPullRequestTitleContent(ci, []*git_model.SignCommitWithStatuses{mockCommit("title \xf0\nbody \xf0")}, setting.RepoPRTitleSourceFirstCommit)
assert.Equal(t, "title ð", title)
assert.Equal(t, "body ð", content)
}
func TestAutoTitleFromBranchName(t *testing.T) {

View File

@@ -6,7 +6,6 @@ package repo
import (
"bytes"
"net/http"
"strings"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
@@ -33,10 +32,10 @@ func CherryPick(ctx *context.Context) {
if ctx.FormString("cherry-pick-type") == "revert" {
ctx.Data["CherryPickType"] = "revert"
ctx.Data["commit_summary"] = "revert " + ctx.PathParam("sha")
ctx.Data["commit_message"] = "revert " + cherryPickCommit.Message()
ctx.Data["commit_message"] = "revert " + cherryPickCommit.MessageUTF8()
} else {
ctx.Data["CherryPickType"] = "cherry-pick"
ctx.Data["commit_summary"], ctx.Data["commit_message"], _ = strings.Cut(cherryPickCommit.Message(), "\n")
ctx.Data["commit_summary"], ctx.Data["commit_message"] = cherryPickCommit.MessageTitle(), cherryPickCommit.MessageBody()
}
ctx.HTML(http.StatusOK, tplCherryPick)

View File

@@ -675,7 +675,7 @@ func TestWebhook(ctx *context.Context) {
ID: objectFormat.EmptyObjectID(),
Author: ghost.NewGitSig(),
Committer: ghost.NewGitSig(),
CommitMessage: "This is a fake commit",
CommitMessage: git.CommitMessage{MessageRaw: "This is a fake commit"},
}
}
@@ -683,7 +683,7 @@ func TestWebhook(ctx *context.Context) {
apiCommit := &api.PayloadCommit{
ID: commit.ID.String(),
Message: commit.Message(),
Message: commit.MessageUTF8(),
URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + url.PathEscape(commit.ID.String()),
Author: &api.PayloadUser{
Name: commit.Author.Name,

View File

@@ -256,7 +256,7 @@ func skipWorkflows(ctx context.Context, input *notifyInput, commit *git.Commit)
log.Debug("repo %s: skipped run for pr %v because of %s string", input.Repo.RelativePath(), input.PullRequest.Issue.ID, s)
return true
}
if strings.Contains(commit.CommitMessage, s) {
if strings.Contains(commit.MessageRaw, s) {
log.Debug("repo %s with commit %s: skipped run because of %s string", input.Repo.RelativePath(), commit.ID, s)
return true
}
@@ -320,7 +320,7 @@ func handleWorkflows(
for _, dwf := range detectedWorkflows {
run := &actions_model.ActionRun{
Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0],
Title: commit.MessageTitle(),
RepoID: input.Repo.ID,
Repo: input.Repo,
OwnerID: input.Repo.OwnerID,
@@ -483,7 +483,7 @@ func handleSchedules(
}
run := &actions_model.ActionSchedule{
Title: strings.SplitN(commit.CommitMessage, "\n", 2)[0],
Title: commit.MessageTitle(),
RepoID: input.Repo.ID,
Repo: input.Repo,
OwnerID: input.Repo.OwnerID,

View File

@@ -5,7 +5,6 @@ package actions
import (
"fmt"
"strings"
actions_model "code.gitea.io/gitea/models/actions"
"code.gitea.io/gitea/models/perm"
@@ -98,7 +97,7 @@ func DispatchActionWorkflow(ctx reqctx.RequestContext, doer *user_model.User, re
var entry *git.TreeEntry
run := &actions_model.ActionRun{
Title: strings.SplitN(runTargetCommit.CommitMessage, "\n", 2)[0],
Title: runTargetCommit.MessageTitle(),
RepoID: repo.ID,
Repo: repo,
OwnerID: repo.OwnerID,

View File

@@ -150,17 +150,13 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
if err != nil {
return nil, fmt.Errorf("failed to get commit %s in repository: %s Error: %w", opts.NewCommitIDs[i], repo.FullName(), err)
}
}
// create a new pull request
if title == "" {
title = strings.Split(commit.CommitMessage, "\n")[0]
}
if description == "" {
_, description, _ = strings.Cut(commit.CommitMessage, "\n\n")
}
if description == "" {
description = title
// create a new pull request
if title == "" {
title = commit.MessageTitle()
}
if description == "" {
description = commit.MessageBody()
}
}
prIssue := &issues_model.Issue{

View File

@@ -11,7 +11,6 @@ import (
"net/url"
"path"
"strconv"
"strings"
"time"
actions_model "code.gitea.io/gitea/models/actions"
@@ -215,7 +214,7 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
return &api.Tag{
Name: t.Name,
Message: strings.TrimSpace(t.Message),
Message: t.MessageUTF8(),
ID: t.ID.String(),
Commit: ToCommitMeta(repo, t),
ZipballURL: zipballURL,
@@ -769,7 +768,7 @@ func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag
Tag: t.Name,
SHA: t.ID.String(),
Object: ToAnnotatedTagObject(repo, c),
Message: t.Message,
Message: t.MessageUTF8(),
URL: repo.APIURL() + "/git/tags/" + t.ID.String(),
Tagger: ToCommitUser(t.Tagger),
Verification: ToVerification(ctx, c),

View File

@@ -56,7 +56,7 @@ func ToPayloadCommit(ctx context.Context, repo *repo_model.Repository, c *git.Co
return &api.PayloadCommit{
ID: c.ID.String(),
Message: c.Message(),
Message: c.MessageUTF8(),
URL: repo.HTMLURL() + "/commit/" + c.ID.String(),
Author: &api.PayloadUser{
Name: c.Author.Name,
@@ -171,7 +171,7 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep
},
Date: commit.Committer.When.Format(time.RFC3339),
},
Message: commit.Message(),
Message: commit.MessageUTF8(),
Tree: &api.CommitMeta{
URL: repo.APIURL() + "/git/trees/" + url.PathEscape(commit.ID.String()),
SHA: commit.ID.String(),

View File

@@ -21,12 +21,12 @@ func TestToCommitMeta(t *testing.T) {
sha1 := git.Sha1ObjectFormat
signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)}
tag := &git.Tag{
Name: "Test Tag",
ID: sha1.EmptyObjectID(),
Object: sha1.EmptyObjectID(),
Type: "Test Type",
Tagger: signature,
Message: "Test Message",
Name: "Test Tag",
ID: sha1.EmptyObjectID(),
Object: sha1.EmptyObjectID(),
Type: "Test Type",
Tagger: signature,
CommitMessage: git.CommitMessage{MessageRaw: "Test Message"},
}
commitMeta := ToCommitMeta(headRepo, tag)

View File

@@ -28,7 +28,7 @@ func ToWikiCommit(commit *git.Commit) *api.WikiCommit {
},
Date: commit.Committer.When.UTC().Format(time.RFC3339),
},
Message: commit.CommitMessage,
Message: commit.MessageUTF8(),
}
}

View File

@@ -847,7 +847,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ
maxMsgSize := setting.Repository.PullRequest.DefaultMergeMessageSize
for i := len(commits) - 1; i >= 0; i-- {
commit := commits[i]
msg := strings.TrimSpace(commit.CommitMessage)
msg := strings.TrimSpace(commit.MessageUTF8())
if msg == "" {
continue
}
@@ -1074,7 +1074,7 @@ func GetPullCommits(ctx context.Context, baseGitRepo *git.Repository, doer *user
}
commits = append(commits, CommitInfo{
Summary: commit.Summary(),
Summary: commit.MessageTitle(),
CommitterOrAuthorName: committerOrAuthorName,
ID: commit.ID.String(),
ShortSha: base.ShortSha(commit.ID.String()),

View File

@@ -359,7 +359,7 @@ func SyncBranchesToDB(ctx context.Context, repoID, pusherID int64, branchNames,
RepoID: repoID,
Name: branchName,
CommitID: commit.ID.String(),
CommitMessage: commit.Summary(),
CommitMessage: commit.MessageTitle(),
PusherID: pusherID,
CommitTime: timeutil.TimeStamp(commit.Committer.When.Unix()),
})

View File

@@ -179,7 +179,7 @@ func getFileContentsByEntryInternal(ctx context.Context, repo *repo_model.Reposi
}
}
if opts.IncludeCommitMessage {
contentsResponse.LastCommitMessage = new(lastCommit.Message())
contentsResponse.LastCommitMessage = new(lastCommit.MessageUTF8())
}
}

View File

@@ -110,7 +110,7 @@ func GetFileCommitResponse(repo *repo_model.Repository, commit *git.Commit) (*ap
},
Date: commit.Committer.When.UTC().Format(time.RFC3339),
},
Message: commit.Message(),
Message: commit.MessageUTF8(),
Tree: &api.CommitMeta{
URL: commitTreeURL.String(),
SHA: commit.Tree.ID.String(),

View File

@@ -402,7 +402,7 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo
}
rel, has := relMap[lowerTag]
title, note := git.SplitCommitTitleBody(tag.Message, 255)
title, note := git.SplitCommitTitleBody(tag.MessageUTF8(), 255)
if !has {
rel = &repo_model.Release{
RepoID: repo.ID,

View File

@@ -18,8 +18,7 @@
<meta property="og:title" content="{{.Title}}">
<meta property="og:url" content="{{ctx.AppFullLink $.Link}}">
{{if and .PageIsDiff .Commit}}
{{- $commitMessageParts := StringUtils.Cut .Commit.Message "\n" -}}
{{- $commitMessageBody := index $commitMessageParts 1 -}}
{{- $commitMessageBody := .Commit.MessageBody -}}
{{- if $commitMessageBody -}}
<meta property="og:description" content="{{StringUtils.EllipsisString $commitMessageBody 300}}">
{{- end -}}

View File

@@ -65,11 +65,12 @@
{{end -}}
{{if eq .ActionName "push"}}
<ul>
{{range .Comment.Commits}}
{{$repoURL := $.Comment.Issue.PullRequest.BaseRepo.HTMLURL}}
{{range $commit := $.Comment.Commits}}
<li>
<a href="{{$.Comment.Issue.PullRequest.BaseRepo.HTMLURL}}/commit/{{.ID}}">
{{ShortSha .ID.String}}
</a> - {{.Summary}}
<a href="{{$repoURL}}/commit/{{$commit.ID}}">
{{ShortSha $commit.ID.String}}
</a> - {{$commit.MessageTitle}}
</li>
{{end}}
</ul>

View File

@@ -5,7 +5,7 @@
<div class="ui container fluid padded">
<div class="ui top attached header clearing segment tw-relative commit-header">
<div class="tw-flex tw-mb-4 tw-gap-1">
<h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.Summary}}">{{ctx.RenderUtils.RenderCommitMessage .Commit.Message $.Repository}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses "AdditionalClasses" "tw-inline"}}</h3>
<h3 class="tw-mb-0 tw-flex-1"><span class="commit-summary" title="{{.Commit.MessageTitle}}">{{ctx.RenderUtils.RenderCommitMessage .Commit.MessageUTF8 $.Repository}}</span>{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses "AdditionalClasses" "tw-inline"}}</h3>
{{if not $.PageIsWiki}}
<div class="commit-header-buttons">
<a class="ui primary tiny button" href="{{.SourcePath}}">
@@ -119,8 +119,8 @@
</div>
{{end}}
</div>
{{if IsMultilineCommitMessage .Commit.Message}}
<pre class="commit-body">{{ctx.RenderUtils.RenderCommitBody .Commit.Message $.Repository}}</pre>
{{if .Commit.MessageBody}}
<pre class="commit-body">{{ctx.RenderUtils.RenderCommitBody .Commit.MessageUTF8 $.Repository}}</pre>
{{end}}
{{template "repo/commit_load_branches_and_tags" .}}
</div>

View File

@@ -11,7 +11,7 @@
</thead>
<tbody class="commit-list">
{{$commitRepoLink := $.RepoLink}}{{if $.CommitRepoLink}}{{$commitRepoLink = $.CommitRepoLink}}{{end}}
{{range .Commits}}
{{range $commit := .Commits}}
<tr>
<td class="author">
<span class="author-wrapper">
@@ -38,18 +38,22 @@
<td class="message">
<span class="message-wrapper">
{{if $.PageIsWiki}}
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{.Summary | ctx.RenderUtils.RenderEmoji}}</span>
<span class="commit-summary {{if gt $commit.ParentCount 1}} grey text{{end}}" title="{{$commit.MessageTitle}}">
{{$commit.MessageTitle | ctx.RenderUtils.RenderEmoji}}
</span>
{{else}}
{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape .ID.String)}}
<span class="commit-summary {{if gt .ParentCount 1}} grey text{{end}}" title="{{.Summary}}">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink $.Repository}}</span>
{{$commitLink:= printf "%s/commit/%s" $commitRepoLink (PathEscape $commit.ID.String)}}
<span class="commit-summary {{if gt $commit.ParentCount 1}} grey text{{end}}" title="{{$commit.MessageTitle}}">
{{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.MessageUTF8 $commitLink $.Repository}}
</span>
{{end}}
</span>
{{if IsMultilineCommitMessage .Message}}
{{if $commit.MessageBody}}
<button class="ui button ellipsis-button" aria-expanded="false" data-global-click="onRepoEllipsisButtonClick">...</button>
{{end}}
{{template "repo/commit_statuses" dict "Status" .Status "Statuses" .Statuses}}
{{if IsMultilineCommitMessage .Message}}
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .Message $.Repository}}</pre>
{{if $commit.MessageBody}}
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody $commit.MessageUTF8 $.Repository}}</pre>
{{end}}
{{if $.CommitsTagsMap}}
{{range (index $.CommitsTagsMap .ID.String)}}

View File

@@ -1,6 +1,6 @@
{{$index := 0}}
<div class="timeline-item commits-list">
{{range .comment.Commits}}
{{range $commit := .comment.Commits}}
{{$tag := printf "%s-%d" $.comment.HashTag $index}}
{{$index = Eval $index "+" 1}}
<div class="flex-text-block" id="{{$tag}}">{{/*singular-commit*/}}
@@ -14,11 +14,11 @@
{{$commitBaseLink := printf "%s/commit" $.comment.Issue.PullRequest.BaseRepo.Link}}
{{$commitLink:= printf "%s/%s" $commitBaseLink (PathEscape .ID.String)}}
<span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{.Summary}}">
{{- ctx.RenderUtils.RenderCommitMessageLinkSubject .Message $commitLink $.comment.Issue.PullRequest.BaseRepo -}}
<span class="tw-flex-1 tw-font-mono gt-ellipsis" title="{{$commit.MessageTitle}}">
{{- ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.MessageUTF8 $commitLink $.comment.Issue.PullRequest.BaseRepo -}}
</span>
{{if IsMultilineCommitMessage .Message}}
{{if $commit.MessageBody}}
<button class="ui button ellipsis-button show-panel toggle" data-panel="[data-singular-commit-body-for='{{$tag}}']">...</button>
{{end}}
@@ -27,9 +27,9 @@
{{template "repo/commit_sign_badge" dict "Commit" . "CommitBaseLink" $commitBaseLink "CommitSignVerification" .Verification}}
</span>
</div>
{{if IsMultilineCommitMessage .Message}}
{{if $commit.MessageBody}}
<pre class="commit-body tw-ml-[33px] tw-hidden" data-singular-commit-body-for="{{$tag}}">
{{- ctx.RenderUtils.RenderCommitBody .Message $.comment.Issue.PullRequest.BaseRepo -}}
{{- ctx.RenderUtils.RenderCommitBody $commit.MessageUTF8 $.comment.Issue.PullRequest.BaseRepo -}}
</pre>
{{end}}
{{end}}

View File

@@ -17,10 +17,11 @@
{{template "repo/commit_statuses" dict "Status" .LatestCommitStatus "Statuses" .LatestCommitStatuses}}
{{$commitLink:= printf "%s/commit/%s" .RepoLink (PathEscape .LatestCommit.ID.String)}}
<span class="grey commit-summary" title="{{.LatestCommit.Summary}}"><span class="message-wrapper">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .LatestCommit.Message $commitLink $.Repository}}</span>
{{if IsMultilineCommitMessage .LatestCommit.Message}}
<span class="grey commit-summary" title="{{.LatestCommit.MessageTitle}}">
<span class="message-wrapper">{{ctx.RenderUtils.RenderCommitMessageLinkSubject .LatestCommit.MessageUTF8 $commitLink $.Repository}}</span>
{{if .LatestCommit.MessageBody}}
<button class="ui button ellipsis-button" aria-expanded="false" data-global-click="onRepoEllipsisButtonClick">...</button>
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .LatestCommit.Message $.Repository}}</pre>
<pre class="commit-body tw-hidden">{{ctx.RenderUtils.RenderCommitBody .LatestCommit.MessageUTF8 $.Repository}}</pre>
{{end}}
</span>
{{end}}

View File

@@ -6,7 +6,7 @@
</h4>
<table id="lfs-files-find-table" class="ui attached segment single line table">
<tbody>
{{range .Results}}
{{range $lfsItem := .Results}}
<tr>
<td>
{{svg "octicon-file"}}
@@ -14,8 +14,8 @@
</td>
<td class="message">
<span class="truncate">
<a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{.Summary}}">
{{.Summary | ctx.RenderUtils.RenderEmoji}}
<a href="{{$.RepoLink}}/commit/{{.SHA}}" title="{{$lfsItem.Summary}}">
{{$lfsItem.Summary | ctx.RenderUtils.RenderEmoji}}
</a>
</span>
</td>

View File

@@ -56,7 +56,7 @@
<div class="repo-file-cell message commit-summary {{if not $commit}}notready{{end}}">
{{if $commit}}
{{$commitLink := printf "%s/commit/%s" $.RepoLink (PathEscape $commit.ID.String)}}
{{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.Message $commitLink $.Repository}}
{{ctx.RenderUtils.RenderCommitMessageLinkSubject $commit.MessageUTF8 $commitLink $.Repository}}
{{else}}
{{/* will be loaded again by LastCommitLoaderURL */}}
{{end}}

View File

@@ -88,13 +88,13 @@
{{$repoLink := (.GetRepoLink ctx)}}
{{$repo := .Repo}}
<div class="tw-flex tw-flex-col tw-gap-1">
{{range $push.Commits}}
{{range $pushCommit := $push.Commits}}
{{$commitLink := printf "%s/commit/%s" $repoLink .Sha1}}
<div class="flex-text-block">
<img loading="lazy" alt class="ui avatar" src="{{$push.AvatarLink ctx .AuthorEmail}}" title="{{.AuthorName}}" width="16" height="16">
<a class="ui sha label" href="{{$commitLink}}">{{ShortSha .Sha1}}</a>
<span class="tw-inline-block tw-truncate">
{{ctx.RenderUtils.RenderCommitMessage .Message $repo}}
{{ctx.RenderUtils.RenderCommitMessage $pushCommit.Message $repo}}
</span>
</div>
{{end}}

View File

@@ -16,6 +16,7 @@ import (
"code.gitea.io/gitea/tests"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAPIRepoTags(t *testing.T) {
@@ -35,24 +36,22 @@ func TestAPIRepoTags(t *testing.T) {
assert.Len(t, tags, 1)
assert.Equal(t, "v1.1", tags[0].Name)
assert.Equal(t, "Initial commit", tags[0].Message)
assert.Equal(t, "Initial commit\n", tags[0].Message)
assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.SHA)
assert.Equal(t, setting.AppURL+"api/v1/repos/user2/repo1/git/commits/65f1bf27bc3bf70f64657658635e66094edbcb4d", tags[0].Commit.URL)
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.zip", tags[0].ZipballURL)
assert.Equal(t, setting.AppURL+"user2/repo1/archive/v1.1.tar.gz", tags[0].TarballURL)
newTag := createNewTagUsingAPI(t, token, user.Name, repoName, "gitea/22", "", "nice!\nand some text")
assert.Equal(t, "nice!\nand some text\n", newTag.Message) // git message standard: there will always be a newline at the end of the message
resp = MakeRequest(t, req, http.StatusOK)
tags = DecodeJSON(t, resp, []*api.Tag{})
assert.Len(t, tags, 2)
for _, tag := range tags {
if tag.Name != "v1.1" {
assert.Equal(t, newTag.Name, tag.Name)
assert.Equal(t, newTag.Message, tag.Message)
assert.Equal(t, "nice!\nand some text", tag.Message)
assert.Equal(t, newTag.Commit.SHA, tag.Commit.SHA)
}
}
require.Len(t, tags, 2)
respTag := tags[0]
assert.Equal(t, newTag.Name, respTag.Name)
assert.Equal(t, newTag.Message, respTag.Message)
assert.Equal(t, newTag.Commit.SHA, respTag.Commit.SHA)
// get created tag
req = NewRequestf(t, "GET", "/api/v1/repos/%s/%s/tags/%s", user.Name, repoName, newTag.Name).