diff --git a/modules/git/signature_gogit.go b/modules/git/signature_gogit.go index c984ad6e20ddc..1f3c18e517d8c 100644 --- a/modules/git/signature_gogit.go +++ b/modules/git/signature_gogit.go @@ -21,19 +21,21 @@ type Signature = object.Signature // Helper to get a signature from the commit line, which looks like these: // // author Patrick Gundlach 1378823654 +0200 -// author Patrick Gundlach Thu, 07 Apr 2005 22:13:13 +0200 +// author Patrick Gundlach Thu Apr 07 22:13:13 2005 +0200 // // but without the "author " at the beginning (this method should) // be used for author and committer. -// -// FIXME: include timezone for timestamp! func newSignatureFromCommitline(line []byte) (_ *Signature, err error) { sig := new(Signature) emailStart := bytes.IndexByte(line, '<') + emailEnd := bytes.IndexByte(line, '>') + if emailStart == -1 || emailEnd == -1 || emailEnd < emailStart { + return sig, err + } + if emailStart > 0 { // Empty name has already occurred, even if it shouldn't sig.Name = strings.TrimSpace(string(line[:emailStart-1])) } - emailEnd := bytes.IndexByte(line, '>') sig.Email = string(line[emailStart+1 : emailEnd]) // Check date format. @@ -41,18 +43,37 @@ func newSignatureFromCommitline(line []byte) (_ *Signature, err error) { firstChar := line[emailEnd+2] if firstChar >= 48 && firstChar <= 57 { timestop := bytes.IndexByte(line[emailEnd+2:], ' ') + if timestop < 0 { + return sig, nil + } + timestring := string(line[emailEnd+2 : emailEnd+2+timestop]) seconds, _ := strconv.ParseInt(timestring, 10, 64) sig.When = time.Unix(seconds, 0) + + timestop += emailEnd + 3 + if timestop >= len(line) || timestop+5 > len(line) { + return sig, nil + } + + timezone := string(line[timestop : timestop+5]) + tzhours, err1 := strconv.ParseInt(timezone[0:3], 10, 64) + tzmins, err2 := strconv.ParseInt(timezone[3:], 10, 64) + if err1 != nil || err2 != nil { + return sig, err + } + if tzhours < 0 { + tzmins *= -1 + } + tz := time.FixedZone("", int(tzhours*60*60+tzmins*60)) + sig.When = sig.When.In(tz) + } else { sig.When, err = time.Parse(GitTimeLayout, string(line[emailEnd+2:])) if err != nil { return nil, err } } - } else { - // Fall back to unix 0 time - sig.When = time.Unix(0, 0) } return sig, nil } diff --git a/modules/git/signature_test.go b/modules/git/signature_test.go new file mode 100644 index 0000000000000..45451049cc4c8 --- /dev/null +++ b/modules/git/signature_test.go @@ -0,0 +1,41 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestNewNewSignatureFromCommitline(t *testing.T) { + tz := time.FixedZone("", 2*60*60) + + kases := map[string]Signature{ + "": {}, + "author gitea test ": { + Name: "author gitea test", + Email: "test@gitea.com", + }, + "author gitea test 1705912028 +0200": { + Name: "author gitea test", + Email: "test@gitea.com", + When: time.Unix(1705912028, 0).In(tz), + }, + "author gitea test Mon Jan 22 10:27:08 2024 +0200": { + Name: "author gitea test", + Email: "test@gitea.com", + When: time.Unix(1705912028, 0).In(tz), + }, + } + + for text, sign := range kases { + newSign, err := newSignatureFromCommitline([]byte(text)) + assert.NoError(t, err) + assert.Equal(t, sign.Name, newSign.Name) + assert.Equal(t, sign.Email, newSign.Email) + assert.Equal(t, sign.When, newSign.When) + } +}