feat: [CODE-2693]: Add backend support to track time of last push. (#3320)

This commit is contained in:
Johannes Batzill 2025-01-27 22:03:35 +00:00 committed by Harness
parent 7e777093a4
commit cbd889881b
12 changed files with 69 additions and 3 deletions

View File

@ -17,7 +17,9 @@ package githook
import (
"context"
"fmt"
"slices"
"strings"
"time"
"github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth"
@ -61,7 +63,10 @@ func (c *Controller) PostReceive(
// as the branch could be different than the configured default value.
c.handleEmptyRepoPush(ctx, repo, in.PostReceiveInput, &out)
// report ref events if repo is in an active state (best effort)
// always update last git push time - best effort
c.updateLastGITPushTime(ctx, repo, in)
// report ref events if repo is in an active state - best effort
if repo.State == enum.RepoStateActive {
c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput)
}
@ -337,3 +342,29 @@ func (c *Controller) handleEmptyRepoPush(
})
}
}
// updateLastGITPushTime updates the repo's last git push time.
func (c *Controller) updateLastGITPushTime(
ctx context.Context,
repo *types.Repository,
in types.GithookPostReceiveInput,
) {
isNonePRRefFn := func(refUpdate hook.ReferenceUpdate) bool {
return !strings.HasPrefix(refUpdate.Ref, gitReferenceNamePullReq)
}
// ignore push that only contains pr refs for last git push time updates
if !slices.ContainsFunc(in.RefUpdates, isNonePRRefFn) {
return
}
newRepo, err := c.repoStore.UpdateOptLock(ctx, repo, func(r *types.Repository) error {
r.LastGITPush = time.Now().UnixMilli()
return nil
})
if err != nil {
log.Ctx(ctx).Warn().Err(err).Msgf("failed to update last git push time for repo %q", repo.Path)
return
}
*repo = *newRepo
}

View File

@ -113,6 +113,7 @@ func (c *Controller) CreateRepo(
CreatedBy: session.Principal.ID,
Created: now.UnixMilli(),
Updated: now.UnixMilli(),
LastGITPush: now.UnixMilli(), // even in case of an empty repo, the git repo got created.
DefaultBranch: in.DefaultBranch,
IsEmpty: true,
State: enum.RepoStateMigrateGitPush,

View File

@ -116,6 +116,7 @@ func (c *Controller) Create(ctx context.Context, session *auth.Session, in *Crea
CreatedBy: session.Principal.ID,
Created: now,
Updated: now,
LastGITPush: now, // even in case of an empty repo, the git repo got created.
ForkID: in.ForkID,
DefaultBranch: in.DefaultBranch,
IsEmpty: isEmpty,

View File

@ -99,6 +99,7 @@ func (r *RepositoryInfo) ToRepo(
CreatedBy: principal.ID,
Created: now,
Updated: now,
LastGITPush: now, // even in case of an empty repo, the git repo got created.
ForkID: 0,
DefaultBranch: r.DefaultBranch,
State: enum.RepoStateGitImport,

View File

@ -0,0 +1,2 @@
ALTER TABLE repositories
DROP COLUMN repo_last_git_push;

View File

@ -0,0 +1,6 @@
ALTER TABLE repositories
ADD COLUMN repo_last_git_push BIGINT NOT NULL DEFAULT 0;
-- backfill an approximation to ensure roughly correct order at time of introduction of this field.
UPDATE repositories
SET repo_last_git_push = repo_updated;

View File

@ -0,0 +1,2 @@
ALTER TABLE repositories
DROP COLUMN repo_last_git_push;

View File

@ -0,0 +1,6 @@
ALTER TABLE repositories
ADD COLUMN repo_last_git_push BIGINT NOT NULL DEFAULT 0;
-- backfill an approximation to ensure roughly correct order at time of introduction of this field.
UPDATE repositories
SET repo_last_git_push = repo_updated;

View File

@ -69,6 +69,7 @@ type repository struct {
Created int64 `db:"repo_created"`
Updated int64 `db:"repo_updated"`
Deleted null.Int `db:"repo_deleted"`
LastGITPush int64 `db:"repo_last_git_push"`
Size int64 `db:"repo_size"`
SizeUpdated int64 `db:"repo_size_updated"`
@ -99,6 +100,7 @@ const (
,repo_created
,repo_updated
,repo_deleted
,repo_last_git_push
,repo_size
,repo_size_updated
,repo_git_uid
@ -216,6 +218,7 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,repo_created
,repo_updated
,repo_deleted
,repo_last_git_push
,repo_size
,repo_size_updated
,repo_git_uid
@ -238,6 +241,7 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,:repo_created
,:repo_updated
,:repo_deleted
,:repo_last_git_push
,:repo_size
,:repo_size_updated
,:repo_git_uid
@ -281,6 +285,7 @@ func (s *RepoStore) Update(ctx context.Context, repo *types.Repository) error {
repo_version = :repo_version
,repo_updated = :repo_updated
,repo_deleted = :repo_deleted
,repo_last_git_push = :repo_last_git_push
,repo_parent_id = :repo_parent_id
,repo_uid = :repo_uid
,repo_git_uid = :repo_git_uid
@ -754,6 +759,7 @@ func (s *RepoStore) mapToRepo(
CreatedBy: in.CreatedBy,
Updated: in.Updated,
Deleted: in.Deleted.Ptr(),
LastGITPush: in.LastGITPush,
Size: in.Size,
SizeUpdated: in.SizeUpdated,
GitUID: in.GitUID,
@ -837,6 +843,7 @@ func mapToInternalRepo(in *types.Repository) *repository {
CreatedBy: in.CreatedBy,
Updated: in.Updated,
Deleted: null.IntFromPtr(in.Deleted),
LastGITPush: in.LastGITPush,
Size: in.Size,
SizeUpdated: in.SizeUpdated,
GitUID: in.GitUID,
@ -885,6 +892,8 @@ func applySortFilter(stmt squirrel.SelectBuilder, filter *types.RepoFilter) squi
stmt = stmt.OrderBy("repo_updated " + filter.Order.String())
case enum.RepoAttrDeleted:
stmt = stmt.OrderBy("repo_deleted " + filter.Order.String())
case enum.RepoAttrLastGITPush:
stmt = stmt.OrderBy("repo_last_git_push " + filter.Order.String())
}
return stmt

View File

@ -64,6 +64,7 @@ const (
value = "value"
lastUsed = "last_used"
lastActivated = "last_activated"
lastGITPush = "last_git_push"
)
func toInterfaceSlice[T interface{}](vals []T) []interface{} {

View File

@ -30,6 +30,7 @@ const (
RepoAttrCreated
RepoAttrUpdated
RepoAttrDeleted
RepoAttrLastGITPush
)
// ParseRepoAttr parses the repo attribute string
@ -47,6 +48,8 @@ func ParseRepoAttr(s string) RepoAttr {
return RepoAttrUpdated
case deleted, deletedAt:
return RepoAttrDeleted
case lastGITPush:
return RepoAttrLastGITPush
default:
return RepoAttrNone
}
@ -66,6 +69,8 @@ func (a RepoAttr) String() string {
return updated
case RepoAttrDeleted:
return deleted
case RepoAttrLastGITPush:
return lastGITPush
case RepoAttrNone:
return ""
default:

View File

@ -31,6 +31,7 @@ type Repository struct {
Created int64 `json:"created" yaml:"created"`
Updated int64 `json:"updated" yaml:"updated"`
Deleted *int64 `json:"deleted,omitempty" yaml:"deleted"`
LastGITPush int64 `json:"last_git_push" yaml:"last_git_push"`
// Size of the repository in KiB.
Size int64 `json:"size" yaml:"size"`