mirror of
https://github.com/go-gitea/gitea.git
synced 2026-08-24 12:19:49 +00:00
fix(release): separate publication time from the release date (#36761)
`published_at` was an alias for `created_at`, so a release created from an existing tag reported that tag's commit date as its publication time, and drafts reported one despite never having been published. It is now stored separately, set when a release is published and null for drafts. `created_at` in turn means the date of the commit the release points at, matching what GitHub documents it to be, and the latest release is selected by it again. Publishing a release for an old commit no longer takes over the latest badge, and a tag created in the web UI is dated the same way as one pushed from the CLI. Fixes https://github.com/go-gitea/gitea/issues/11206 Fixes https://github.com/go-gitea/gitea/issues/38714 Fixes https://github.com/go-gitea/gitea/issues/31789 --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -103,7 +103,7 @@ func (p *Parser) parseRef(refBlock string) (map[string]string, error) {
|
||||
return nil, nil //nolint:nilnil // return nil to signal EOF
|
||||
}
|
||||
|
||||
fieldValues := make(map[string]string)
|
||||
fieldValues := make(map[string]string, len(p.format.fieldNames))
|
||||
|
||||
fields := strings.Split(refBlock, p.format.fieldDelimStr)
|
||||
if len(fields) != len(p.format.fieldNames) {
|
||||
|
||||
+12
-1
@@ -7,7 +7,9 @@ package git
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.dev/modules/git/foreachref"
|
||||
"gitea.dev/modules/git/gitcmd"
|
||||
@@ -113,7 +115,7 @@ func (repo *Repository) GetTagWithID(ctx context.Context, idStr, name string) (*
|
||||
func (repo *Repository) GetTagInfos(ctx context.Context, page, pageSize int) ([]*Tag, int, error) {
|
||||
// Generally, refname:short should be equal to refname:lstrip=2 except core.warnAmbiguousRefs is used to select the strict abbreviation mode.
|
||||
// https://git-scm.com/docs/git-for-each-ref#Documentation/git-for-each-ref.txt-refname
|
||||
forEachRefFmt := foreachref.NewFormat("objecttype", "refname:lstrip=2", "object", "objectname", "creator", "contents", "contents:signature")
|
||||
forEachRefFmt := foreachref.NewFormat("objecttype", "refname:lstrip=2", "object", "objectname", "creator", "contents", "contents:signature", "committerdate:unix", "*committerdate:unix")
|
||||
|
||||
var tags []*Tag
|
||||
var tagsTotal int
|
||||
@@ -179,6 +181,15 @@ func parseTagRef(ref map[string]string) (tag *Tag, err error) {
|
||||
tag.Tagger = parseSignatureFromCommitLine(ref["creator"])
|
||||
tag.MessageRaw = ref["contents"]
|
||||
|
||||
// a lightweight tag reports the commit date directly, an annotated one only behind the dereferencing "*"
|
||||
if committerDate := util.IfZero(ref["*committerdate:unix"], ref["committerdate:unix"]); committerDate != "" {
|
||||
seconds, err := strconv.ParseInt(committerDate, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse committerdate '%s': %w", committerDate, err)
|
||||
}
|
||||
tag.CommitDate = time.Unix(seconds, 0)
|
||||
}
|
||||
|
||||
// strip any signature if present in contents field
|
||||
_, tag.MessageRaw, _ = parsePayloadSignature(util.UnsafeStringToBytes(tag.MessageRaw), 0)
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ package git
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -33,6 +34,7 @@ func TestRepository_GetTagInfos(t *testing.T) {
|
||||
assert.Equal(t, "test", tags[1].Name)
|
||||
assert.Equal(t, "3ad28a9149a2864384548f3d17ed7f38014c9e8a", tags[1].ID.String())
|
||||
assert.Equal(t, "tag", tags[1].Type)
|
||||
assert.False(t, tags[0].CommitDate.IsZero(), "for-each-ref resolves the tagged commit's date")
|
||||
}
|
||||
|
||||
func TestRepository_GetTag(t *testing.T) {
|
||||
@@ -207,7 +209,9 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
* add changelog of v1.9.1
|
||||
* Update CHANGELOG.md
|
||||
`,
|
||||
"contents:signature": "",
|
||||
"contents:signature": "",
|
||||
"committerdate:unix": "1565789218",
|
||||
"*committerdate:unix": "",
|
||||
},
|
||||
|
||||
want: &Tag{
|
||||
@@ -216,6 +220,7 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
Object: MustIDFromString("ab23e4b7f4cd0caafe0174c0e7ef6d651ba72889"),
|
||||
Type: "commit",
|
||||
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
|
||||
CommitDate: time.Unix(1565789218, 0),
|
||||
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,
|
||||
},
|
||||
@@ -237,6 +242,9 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
* Update CHANGELOG.md
|
||||
`,
|
||||
"contents:signature": "",
|
||||
// an annotated tag can be made long after the commit, so its own date is not the commit date
|
||||
"committerdate:unix": "",
|
||||
"*committerdate:unix": "1565700000",
|
||||
},
|
||||
|
||||
want: &Tag{
|
||||
@@ -245,6 +253,7 @@ func TestRepository_parseTagRef(t *testing.T) {
|
||||
Object: MustIDFromString("3325fd8a973321fd59455492976c042dde3fd1ca"),
|
||||
Type: "tag",
|
||||
Tagger: parseSignatureFromCommitLine("Foo Bar <foo@bar.com> 1565789218 +0300"),
|
||||
CommitDate: time.Unix(1565700000, 0),
|
||||
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,
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"gitea.dev/modules/util"
|
||||
)
|
||||
@@ -21,6 +22,8 @@ type Tag struct {
|
||||
Type string
|
||||
Tagger *Signature
|
||||
Signature *CommitSignature
|
||||
|
||||
CommitDate time.Time // committer date of Object, only GetTagInfos resolves it
|
||||
}
|
||||
|
||||
func parsePayloadSignature(data []byte, messageStart int) (payload, msg, sign string) {
|
||||
|
||||
Reference in New Issue
Block a user