chore: two small refactors in git module (#10109)
Move the function to the repository struct. There is no need to have it as a separate function, move it to the Repository struct. Add extra unit tests. --- Remove a field from a struct. It has nothing to do with git, it is not the right place to have that field in the git `Tag` struct. Get this value when it's converted to the API struct. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10109 Reviewed-by: Michael Kriese <michael.kriese@gmx.de> Co-authored-by: Gusted <postmaster@gusted.xyz> Co-committed-by: Gusted <postmaster@gusted.xyz>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
// Copyright 2017 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
|
||||
@@ -326,17 +326,6 @@ func Push(ctx context.Context, repoPath string, opts PushOptions) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
|
||||
func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error) {
|
||||
cmd := NewCommand(ctx, "for-each-ref", "--sort=-committerdate", BranchPrefix, "--count", "1", "--format=%(committerdate)")
|
||||
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repoPath})
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
commitTime := strings.TrimSpace(stdout)
|
||||
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
|
||||
}
|
||||
|
||||
// DivergeObject represents commit count diverging commits
|
||||
type DivergeObject struct {
|
||||
Ahead int
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"forgejo.org/modules/cache"
|
||||
"forgejo.org/modules/log"
|
||||
@@ -670,3 +671,14 @@ func (repo *Repository) ConvertToGitID(commitID string) (ObjectID, error) {
|
||||
|
||||
return MustIDFromString(string(sha)), nil
|
||||
}
|
||||
|
||||
// GetLatestCommitTime returns time for latest commit in repository (across all branches)
|
||||
func (repo *Repository) GetLatestCommitTime() (time.Time, error) {
|
||||
cmd := NewCommand(repo.Ctx, "for-each-ref", "--sort=-committerdate", "--count=1", "--format=%(committerdate)", BranchPrefix)
|
||||
stdout, _, err := cmd.RunStdString(&RunOpts{Dir: repo.Path})
|
||||
if err != nil {
|
||||
return time.Time{}, err
|
||||
}
|
||||
commitTime := strings.TrimSpace(stdout)
|
||||
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
|
||||
}
|
||||
|
||||
@@ -236,3 +236,41 @@ func TestGetCommitsFromIDs(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetLatestCommitTime(t *testing.T) {
|
||||
t.Run("repo1", func(t *testing.T) {
|
||||
repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare"))
|
||||
require.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
lct, err := repo.GetLatestCommitTime()
|
||||
require.NoError(t, err)
|
||||
// Time is Sun Nov 13 16:40:14 2022 +0100
|
||||
// which is the time of commit
|
||||
// ce064814f4a0d337b333e646ece456cd39fab612 (refs/heads/master)
|
||||
assert.EqualValues(t, 1668354014, lct.Unix())
|
||||
})
|
||||
|
||||
t.Run("repo1_sha256", func(t *testing.T) {
|
||||
skipIfSHA256NotSupported(t)
|
||||
|
||||
repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo1_bare_sha256"))
|
||||
require.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
lct, err := repo.GetLatestCommitTime()
|
||||
require.NoError(t, err)
|
||||
assert.EqualValues(t, 1698676906, lct.Unix())
|
||||
})
|
||||
|
||||
t.Run("repo3_notes", func(t *testing.T) {
|
||||
repo, err := openRepositoryWithDefaultContext(filepath.Join(testReposDir, "repo3_notes"))
|
||||
require.NoError(t, err)
|
||||
defer repo.Close()
|
||||
|
||||
lct, err := repo.GetLatestCommitTime()
|
||||
require.NoError(t, err)
|
||||
// Time is of refs/heads/master and not of refs/notes/commits
|
||||
assert.EqualValues(t, 1567767909, lct.Unix())
|
||||
})
|
||||
}
|
||||
|
||||
@@ -19,16 +19,6 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestGetLatestCommitTime(t *testing.T) {
|
||||
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
|
||||
lct, err := GetLatestCommitTime(DefaultContext, bareRepo1Path)
|
||||
require.NoError(t, err)
|
||||
// Time is Sun Nov 13 16:40:14 2022 +0100
|
||||
// which is the time of commit
|
||||
// ce064814f4a0d337b333e646ece456cd39fab612 (refs/heads/master)
|
||||
assert.EqualValues(t, 1668354014, lct.Unix())
|
||||
}
|
||||
|
||||
func TestRepoIsEmpty(t *testing.T) {
|
||||
emptyRepo2Path := filepath.Join(testReposDir, "repo2_empty")
|
||||
repo, err := openRepositoryWithDefaultContext(emptyRepo2Path)
|
||||
|
||||
+8
-9
@@ -1,4 +1,5 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package git
|
||||
@@ -7,7 +8,6 @@ import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
api "forgejo.org/modules/structs"
|
||||
"forgejo.org/modules/util"
|
||||
)
|
||||
|
||||
@@ -20,14 +20,13 @@ const (
|
||||
|
||||
// Tag represents a Git tag.
|
||||
type Tag struct {
|
||||
Name string
|
||||
ID ObjectID
|
||||
Object ObjectID // The id of this commit object
|
||||
Type string
|
||||
Tagger *Signature
|
||||
Message string
|
||||
Signature *ObjectSignature
|
||||
ArchiveDownloadCount *api.TagArchiveDownloadCount
|
||||
Name string
|
||||
ID ObjectID
|
||||
Object ObjectID // The id of this commit object
|
||||
Type string
|
||||
Tagger *Signature
|
||||
Message string
|
||||
Signature *ObjectSignature
|
||||
}
|
||||
|
||||
// Commit return the commit of the tag reference
|
||||
|
||||
+12
-13
@@ -65,13 +65,12 @@ func ListTags(ctx *context.APIContext) {
|
||||
|
||||
apiTags := make([]*api.Tag, len(tags))
|
||||
for i := range tags {
|
||||
tags[i].ArchiveDownloadCount, err = repo_model.GetArchiveDownloadCountForTagName(ctx, ctx.Repo.Repository.ID, tags[i].Name)
|
||||
convertedTag, err := convert.ToTag(ctx, ctx.Repo.Repository, tags[i])
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTagArchiveDownloadCountForName", err)
|
||||
ctx.Error(http.StatusInternalServerError, "ToTag", err)
|
||||
return
|
||||
}
|
||||
|
||||
apiTags[i] = convert.ToTag(ctx.Repo.Repository, tags[i])
|
||||
apiTags[i] = convertedTag
|
||||
}
|
||||
ctx.SetLinkHeader(total, listOpts.PageSize)
|
||||
ctx.SetTotalCountHeader(int64(total))
|
||||
@@ -123,13 +122,13 @@ func GetAnnotatedTag(ctx *context.APIContext) {
|
||||
ctx.Error(http.StatusBadRequest, "GetAnnotatedTag", err)
|
||||
}
|
||||
|
||||
tag.ArchiveDownloadCount, err = repo_model.GetArchiveDownloadCountForTagName(ctx, ctx.Repo.Repository.ID, tag.Name)
|
||||
convertedAnnotatedTag, err := convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, tag, commit)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTagArchiveDownloadCountForName", err)
|
||||
ctx.Error(http.StatusInternalServerError, "ToAnnotatedTag", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, convert.ToAnnotatedTag(ctx, ctx.Repo.Repository, tag, commit))
|
||||
ctx.JSON(http.StatusOK, convertedAnnotatedTag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,13 +168,13 @@ func GetTag(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
tag.ArchiveDownloadCount, err = repo_model.GetArchiveDownloadCountForTagName(ctx, ctx.Repo.Repository.ID, tag.Name)
|
||||
convertedTag, err := convert.ToTag(ctx, ctx.Repo.Repository, tag)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTagArchiveDownloadCountForName", err)
|
||||
ctx.Error(http.StatusInternalServerError, "ToTag", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, convert.ToTag(ctx.Repo.Repository, tag))
|
||||
ctx.JSON(http.StatusOK, convertedTag)
|
||||
}
|
||||
|
||||
// CreateTag create a new git tag in a repository
|
||||
@@ -248,13 +247,13 @@ func CreateTag(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
tag.ArchiveDownloadCount, err = repo_model.GetArchiveDownloadCountForTagName(ctx, ctx.Repo.Repository.ID, tag.Name)
|
||||
convertedTag, err := convert.ToTag(ctx, ctx.Repo.Repository, tag)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetTagArchiveDownloadCountForName", err)
|
||||
ctx.Error(http.StatusInternalServerError, "ToTag", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, convert.ToTag(ctx.Repo.Repository, tag))
|
||||
ctx.JSON(http.StatusCreated, convertedTag)
|
||||
}
|
||||
|
||||
// DeleteTag delete a specific tag of in a repository by name
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Copyright 2018 The Gitea Authors. All rights
|
||||
// Copyright 2025 The Forgejo Authors. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package convert
|
||||
@@ -187,7 +188,12 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo
|
||||
}
|
||||
|
||||
// ToTag convert a git.Tag to an api.Tag
|
||||
func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
|
||||
func ToTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag) (*api.Tag, error) {
|
||||
archiveDownloadCount, err := repo_model.GetArchiveDownloadCountForTagName(ctx, repo.ID, t.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.Tag{
|
||||
Name: t.Name,
|
||||
Message: strings.TrimSpace(t.Message),
|
||||
@@ -195,8 +201,8 @@ func ToTag(repo *repo_model.Repository, t *git.Tag) *api.Tag {
|
||||
Commit: ToCommitMeta(repo, t),
|
||||
ZipballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".zip"),
|
||||
TarballURL: util.URLJoin(repo.HTMLURL(), "archive", t.Name+".tar.gz"),
|
||||
ArchiveDownloadCount: t.ArchiveDownloadCount,
|
||||
}
|
||||
ArchiveDownloadCount: archiveDownloadCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToActionTask convert a actions_model.ActionTask to an api.ActionTask
|
||||
@@ -391,7 +397,12 @@ func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([]
|
||||
}
|
||||
|
||||
// ToAnnotatedTag convert git.Tag to api.AnnotatedTag
|
||||
func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag, c *git.Commit) *api.AnnotatedTag {
|
||||
func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag, c *git.Commit) (*api.AnnotatedTag, error) {
|
||||
archiveDownloadCount, err := repo_model.GetArchiveDownloadCountForTagName(ctx, repo.ID, t.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &api.AnnotatedTag{
|
||||
Tag: t.Name,
|
||||
SHA: t.ID.String(),
|
||||
@@ -400,8 +411,8 @@ func ToAnnotatedTag(ctx context.Context, repo *repo_model.Repository, t *git.Tag
|
||||
URL: util.URLJoin(repo.APIURL(), "git/tags", t.ID.String()),
|
||||
Tagger: ToCommitUser(t.Tagger),
|
||||
Verification: ToVerification(ctx, c),
|
||||
ArchiveDownloadCount: t.ArchiveDownloadCount,
|
||||
}
|
||||
ArchiveDownloadCount: archiveDownloadCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ToAnnotatedTagObject convert a git.Commit to an api.AnnotatedTagObject
|
||||
|
||||
@@ -587,7 +587,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
}
|
||||
if !isEmpty {
|
||||
// Get latest commit date and update to current repository updated time
|
||||
commitDate, err := git.GetLatestCommitTime(ctx, m.Repo.RepoPath())
|
||||
commitDate, err := gitRepo.GetLatestCommitTime()
|
||||
if err != nil {
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user