From e68b9d00a6e05b3a941f63ffb696f91e554ac5ec Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 18 Oct 2024 20:33:49 +0200 Subject: Adding upstream version 9.0.3. Signed-off-by: Daniel Baumann --- modules/repository/commits.go | 173 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 modules/repository/commits.go (limited to 'modules/repository/commits.go') diff --git a/modules/repository/commits.go b/modules/repository/commits.go new file mode 100644 index 0000000..ede6042 --- /dev/null +++ b/modules/repository/commits.go @@ -0,0 +1,173 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "context" + "fmt" + "net/url" + "time" + + "code.gitea.io/gitea/models/avatars" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/cache" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" +) + +// PushCommit represents a commit in a push operation. +type PushCommit struct { + Sha1 string + Message string + AuthorEmail string + AuthorName string + CommitterEmail string + CommitterName string + Timestamp time.Time +} + +// PushCommits represents list of commits in a push operation. +type PushCommits struct { + Commits []*PushCommit + HeadCommit *PushCommit + CompareURL string + Len int +} + +// NewPushCommits creates a new PushCommits object. +func NewPushCommits() *PushCommits { + return &PushCommits{} +} + +// toAPIPayloadCommit converts a single PushCommit to an api.PayloadCommit object. +func (pc *PushCommits) toAPIPayloadCommit(ctx context.Context, emailUsers map[string]*user_model.User, repoPath, repoLink string, commit *PushCommit) (*api.PayloadCommit, error) { + var err error + authorUsername := "" + author, ok := emailUsers[commit.AuthorEmail] + if !ok { + author, err = user_model.GetUserByEmail(ctx, commit.AuthorEmail) + if err == nil { + authorUsername = author.Name + emailUsers[commit.AuthorEmail] = author + } + } else { + authorUsername = author.Name + } + + committerUsername := "" + committer, ok := emailUsers[commit.CommitterEmail] + if !ok { + committer, err = user_model.GetUserByEmail(ctx, commit.CommitterEmail) + if err == nil { + // TODO: check errors other than email not found. + committerUsername = committer.Name + emailUsers[commit.CommitterEmail] = committer + } + } else { + committerUsername = committer.Name + } + + fileStatus, err := git.GetCommitFileStatus(ctx, repoPath, commit.Sha1) + if err != nil { + return nil, fmt.Errorf("FileStatus [commit_sha1: %s]: %w", commit.Sha1, err) + } + + return &api.PayloadCommit{ + ID: commit.Sha1, + Message: commit.Message, + URL: fmt.Sprintf("%s/commit/%s", repoLink, url.PathEscape(commit.Sha1)), + Author: &api.PayloadUser{ + Name: commit.AuthorName, + Email: commit.AuthorEmail, + UserName: authorUsername, + }, + Committer: &api.PayloadUser{ + Name: commit.CommitterName, + Email: commit.CommitterEmail, + UserName: committerUsername, + }, + Added: fileStatus.Added, + Removed: fileStatus.Removed, + Modified: fileStatus.Modified, + Timestamp: commit.Timestamp, + }, nil +} + +// ToAPIPayloadCommits converts a PushCommits object to api.PayloadCommit format. +// It returns all converted commits and, if provided, the head commit or an error otherwise. +func (pc *PushCommits) ToAPIPayloadCommits(ctx context.Context, repoPath, repoLink string) ([]*api.PayloadCommit, *api.PayloadCommit, error) { + commits := make([]*api.PayloadCommit, len(pc.Commits)) + var headCommit *api.PayloadCommit + + emailUsers := make(map[string]*user_model.User) + + for i, commit := range pc.Commits { + apiCommit, err := pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, commit) + if err != nil { + return nil, nil, err + } + + commits[i] = apiCommit + if pc.HeadCommit != nil && pc.HeadCommit.Sha1 == commits[i].ID { + headCommit = apiCommit + } + } + if pc.HeadCommit != nil && headCommit == nil { + var err error + headCommit, err = pc.toAPIPayloadCommit(ctx, emailUsers, repoPath, repoLink, pc.HeadCommit) + if err != nil { + return nil, nil, err + } + } + return commits, headCommit, nil +} + +// AvatarLink tries to match user in database with e-mail +// in order to show custom avatar, and falls back to general avatar link. +func (pc *PushCommits) AvatarLink(ctx context.Context, email string) string { + size := avatars.DefaultAvatarPixelSize * setting.Avatar.RenderedSizeFactor + + v, _ := cache.GetWithContextCache(ctx, "push_commits", email, func() (string, error) { + u, err := user_model.GetUserByEmail(ctx, email) + if err != nil { + if !user_model.IsErrUserNotExist(err) { + log.Error("GetUserByEmail: %v", err) + return "", err + } + return avatars.GenerateEmailAvatarFastLink(ctx, email, size), nil + } + return u.AvatarLinkWithSize(ctx, size), nil + }) + + return v +} + +// CommitToPushCommit transforms a git.Commit to PushCommit type. +func CommitToPushCommit(commit *git.Commit) *PushCommit { + return &PushCommit{ + Sha1: commit.ID.String(), + Message: commit.Message(), + AuthorEmail: commit.Author.Email, + AuthorName: commit.Author.Name, + CommitterEmail: commit.Committer.Email, + CommitterName: commit.Committer.Name, + Timestamp: commit.Author.When, + } +} + +// GitToPushCommits transforms a list of git.Commits to PushCommits type. +func GitToPushCommits(gitCommits []*git.Commit) *PushCommits { + commits := make([]*PushCommit, 0, len(gitCommits)) + for _, commit := range gitCommits { + commits = append(commits, CommitToPushCommit(commit)) + } + return &PushCommits{ + Commits: commits, + HeadCommit: nil, + CompareURL: "", + Len: len(commits), + } +} -- cgit v1.2.3