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 ( import (
"context" "context"
"fmt" "fmt"
"slices"
"strings" "strings"
"time"
"github.com/harness/gitness/app/api/usererror" "github.com/harness/gitness/app/api/usererror"
"github.com/harness/gitness/app/auth" "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. // as the branch could be different than the configured default value.
c.handleEmptyRepoPush(ctx, repo, in.PostReceiveInput, &out) 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 { if repo.State == enum.RepoStateActive {
c.reportReferenceEvents(ctx, rgit, repo, in.PrincipalID, in.PostReceiveInput) 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, CreatedBy: session.Principal.ID,
Created: now.UnixMilli(), Created: now.UnixMilli(),
Updated: now.UnixMilli(), Updated: now.UnixMilli(),
LastGITPush: now.UnixMilli(), // even in case of an empty repo, the git repo got created.
DefaultBranch: in.DefaultBranch, DefaultBranch: in.DefaultBranch,
IsEmpty: true, IsEmpty: true,
State: enum.RepoStateMigrateGitPush, 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, CreatedBy: session.Principal.ID,
Created: now, Created: now,
Updated: now, Updated: now,
LastGITPush: now, // even in case of an empty repo, the git repo got created.
ForkID: in.ForkID, ForkID: in.ForkID,
DefaultBranch: in.DefaultBranch, DefaultBranch: in.DefaultBranch,
IsEmpty: isEmpty, IsEmpty: isEmpty,

View File

@ -99,6 +99,7 @@ func (r *RepositoryInfo) ToRepo(
CreatedBy: principal.ID, CreatedBy: principal.ID,
Created: now, Created: now,
Updated: now, Updated: now,
LastGITPush: now, // even in case of an empty repo, the git repo got created.
ForkID: 0, ForkID: 0,
DefaultBranch: r.DefaultBranch, DefaultBranch: r.DefaultBranch,
State: enum.RepoStateGitImport, 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"` Created int64 `db:"repo_created"`
Updated int64 `db:"repo_updated"` Updated int64 `db:"repo_updated"`
Deleted null.Int `db:"repo_deleted"` Deleted null.Int `db:"repo_deleted"`
LastGITPush int64 `db:"repo_last_git_push"`
Size int64 `db:"repo_size"` Size int64 `db:"repo_size"`
SizeUpdated int64 `db:"repo_size_updated"` SizeUpdated int64 `db:"repo_size_updated"`
@ -99,6 +100,7 @@ const (
,repo_created ,repo_created
,repo_updated ,repo_updated
,repo_deleted ,repo_deleted
,repo_last_git_push
,repo_size ,repo_size
,repo_size_updated ,repo_size_updated
,repo_git_uid ,repo_git_uid
@ -208,7 +210,7 @@ func (s *RepoStore) FindDeletedByUID(
func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error { func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
const sqlQuery = ` const sqlQuery = `
INSERT INTO repositories ( INSERT INTO repositories (
repo_version repo_version
,repo_parent_id ,repo_parent_id
,repo_uid ,repo_uid
,repo_description ,repo_description
@ -216,8 +218,9 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,repo_created ,repo_created
,repo_updated ,repo_updated
,repo_deleted ,repo_deleted
,repo_last_git_push
,repo_size ,repo_size
,repo_size_updated ,repo_size_updated
,repo_git_uid ,repo_git_uid
,repo_default_branch ,repo_default_branch
,repo_fork_id ,repo_fork_id
@ -238,6 +241,7 @@ func (s *RepoStore) Create(ctx context.Context, repo *types.Repository) error {
,:repo_created ,:repo_created
,:repo_updated ,:repo_updated
,:repo_deleted ,:repo_deleted
,:repo_last_git_push
,:repo_size ,:repo_size
,:repo_size_updated ,:repo_size_updated
,:repo_git_uid ,:repo_git_uid
@ -281,6 +285,7 @@ func (s *RepoStore) Update(ctx context.Context, repo *types.Repository) error {
repo_version = :repo_version repo_version = :repo_version
,repo_updated = :repo_updated ,repo_updated = :repo_updated
,repo_deleted = :repo_deleted ,repo_deleted = :repo_deleted
,repo_last_git_push = :repo_last_git_push
,repo_parent_id = :repo_parent_id ,repo_parent_id = :repo_parent_id
,repo_uid = :repo_uid ,repo_uid = :repo_uid
,repo_git_uid = :repo_git_uid ,repo_git_uid = :repo_git_uid
@ -754,6 +759,7 @@ func (s *RepoStore) mapToRepo(
CreatedBy: in.CreatedBy, CreatedBy: in.CreatedBy,
Updated: in.Updated, Updated: in.Updated,
Deleted: in.Deleted.Ptr(), Deleted: in.Deleted.Ptr(),
LastGITPush: in.LastGITPush,
Size: in.Size, Size: in.Size,
SizeUpdated: in.SizeUpdated, SizeUpdated: in.SizeUpdated,
GitUID: in.GitUID, GitUID: in.GitUID,
@ -837,6 +843,7 @@ func mapToInternalRepo(in *types.Repository) *repository {
CreatedBy: in.CreatedBy, CreatedBy: in.CreatedBy,
Updated: in.Updated, Updated: in.Updated,
Deleted: null.IntFromPtr(in.Deleted), Deleted: null.IntFromPtr(in.Deleted),
LastGITPush: in.LastGITPush,
Size: in.Size, Size: in.Size,
SizeUpdated: in.SizeUpdated, SizeUpdated: in.SizeUpdated,
GitUID: in.GitUID, GitUID: in.GitUID,
@ -885,6 +892,8 @@ func applySortFilter(stmt squirrel.SelectBuilder, filter *types.RepoFilter) squi
stmt = stmt.OrderBy("repo_updated " + filter.Order.String()) stmt = stmt.OrderBy("repo_updated " + filter.Order.String())
case enum.RepoAttrDeleted: case enum.RepoAttrDeleted:
stmt = stmt.OrderBy("repo_deleted " + filter.Order.String()) stmt = stmt.OrderBy("repo_deleted " + filter.Order.String())
case enum.RepoAttrLastGITPush:
stmt = stmt.OrderBy("repo_last_git_push " + filter.Order.String())
} }
return stmt return stmt

View File

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

View File

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

View File

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