feat: vendor gitea 1.16.2

This commit is contained in:
2026-06-02 08:36:01 +00:00
parent 247cd60f69
commit 54798b4615
2145 changed files with 162965 additions and 126447 deletions
+142 -58
View File
@@ -5,82 +5,166 @@ package pull
import (
"context"
"slices"
"code.gitea.io/gitea/models/db"
issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
)
// getCommitIDsFromRepo get commit IDs from repo in between oldCommitID and newCommitID
// Commit on baseBranch will skip
func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, err error) {
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, repo)
const maxPushCommitsInCommentCount = 1000
func preparePushPullCommentPushActionContent(ctx context.Context, pr *issues_model.PullRequest, oldCommitID, newCommitID string, isForcePush bool) (data issues_model.PushActionContent, shouldCreate bool, err error) {
if isForcePush {
// if it's a force push, we need to get the whole pull request commits
// the force-push timeline comment should always be created, so all errors are ignored and logged only.
mergeBase, err := gitrepo.MergeBase(ctx, pr.BaseRepo, pr.BaseBranch, newCommitID)
if err != nil {
log.Debug("MergeBase %q..%q failed: %v", pr.BaseBranch, newCommitID, err)
} else {
data.CommitIDs, err = gitrepo.GetCommitIDsBetweenReverse(ctx, pr.BaseRepo, mergeBase, newCommitID, "", maxPushCommitsInCommentCount)
if err != nil {
log.Debug("GetCommitIDsBetweenReverse %q..%q failed: %v", mergeBase, newCommitID, err)
}
}
return data, true, nil
}
// for a normal push, it maybe an empty pull request, only non-empty pull request need to create push comment
data.CommitIDs, err = gitrepo.GetCommitIDsBetweenReverse(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch, maxPushCommitsInCommentCount)
return data, len(data.CommitIDs) > 0, err
}
func reconcileOldCommitCommentsForForcePush(ctx context.Context, oldCommitComments []*issues_model.Comment, newData *issues_model.PushActionContent) (needDeleteCommentIDs []int64) {
newPushCommitIDMaps := container.SetOf(newData.CommitIDs...)
for _, oldCommitComment := range oldCommitComments {
oldData, err := oldCommitComment.GetPushActionContent()
if err != nil {
continue
}
if oldData.IsForcePush {
// old comment is for force push, it should be kept
continue
}
// remove the old comment's commit IDs which are not in the new "force" push
oldData.CommitIDs = slices.DeleteFunc(oldData.CommitIDs, func(oldCommitID string) bool { return !newPushCommitIDMaps.Contains(oldCommitID) })
// if old comment doesn't contain any commit ID after the force push, then it can be deleted
if len(oldData.CommitIDs) == 0 {
needDeleteCommentIDs = append(needDeleteCommentIDs, oldCommitComment.ID)
continue
}
// remove new comment's commit IDs which are already in old comment
for _, oldCommitID := range oldData.CommitIDs {
newData.CommitIDs = slices.DeleteFunc(newData.CommitIDs, func(newCommitID string) bool { return newCommitID == oldCommitID })
}
// update the old comment's content (the commit IDs have been changed)
updatedOldContent, _ := json.Marshal(oldData)
_, err = db.GetEngine(ctx).ID(oldCommitComment.ID).Cols("content").NoAutoTime().Update(&issues_model.Comment{Content: string(updatedOldContent)})
if err != nil {
log.Error("Update Comment content failed: %v", err)
}
}
return needDeleteCommentIDs
}
func cleanUpOldCommitCommentsForNewForcePush(ctx context.Context, pr *issues_model.PullRequest, data *issues_model.PushActionContent) error {
// All old non-force-push commit comments will be deleted if they are not in the new commit list.
var oldCommitComments []*issues_model.Comment
err := db.GetEngine(ctx).Table("comment").
Where("issue_id = ?", pr.IssueID).And("type = ?", issues_model.CommentTypePullRequestPush).
Find(&oldCommitComments)
if err != nil {
return nil, err
}
defer closer.Close()
oldCommit, err := gitRepo.GetCommit(oldCommitID)
if err != nil {
return nil, err
return err
}
newCommit, err := gitRepo.GetCommit(newCommitID)
if err != nil {
return nil, err
needDeleteCommentIDs := reconcileOldCommitCommentsForForcePush(ctx, oldCommitComments, data)
if len(needDeleteCommentIDs) == 0 {
return nil
}
// Find commits between new and old commit excluding base branch commits
commits, err := gitRepo.CommitsBetweenNotBase(newCommit, oldCommit, baseBranch)
if err != nil {
return nil, err
}
commitIDs = make([]string, 0, len(commits))
for i := len(commits) - 1; i >= 0; i-- {
commitIDs = append(commitIDs, commits[i].ID.String())
}
return commitIDs, err
_, err = db.GetEngine(ctx).In("id", needDeleteCommentIDs).Delete(&issues_model.Comment{})
return err
}
// CreatePushPullComment create push code to pull base comment
func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *issues_model.PullRequest, oldCommitID, newCommitID string, isForcePush bool) (comment *issues_model.Comment, err error) {
if pr.HasMerged || oldCommitID == "" || newCommitID == "" {
return nil, nil
func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *issues_model.PullRequest, oldRef, newRef string, isForcePush bool) (comment *issues_model.Comment, created bool, err error) {
if pr.HasMerged || oldRef == "" || newRef == "" {
return nil, false, nil
}
opts := &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypePullRequestPush,
Doer: pusher,
Repo: pr.BaseRepo,
IsForcePush: isForcePush,
Issue: pr.Issue,
}
var data issues_model.PushActionContent
if opts.IsForcePush {
data.CommitIDs = []string{oldCommitID, newCommitID}
data.IsForcePush = true
} else {
data.CommitIDs, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch)
if err != nil {
return nil, err
}
if len(data.CommitIDs) == 0 {
return nil, nil
}
}
dataJSON, err := json.Marshal(data)
gitRepo, closer, err := gitrepo.RepositoryFromContextOrOpen(ctx, pr.BaseRepo)
if err != nil {
return nil, err
return nil, false, err
}
defer closer.Close()
oldCommitID := oldRef
if !git.IsEmptyCommitID(oldRef) {
oldCommitID, err = gitRepo.GetRefCommitID(oldRef)
if err != nil {
return nil, false, err
}
}
newCommitID, err := gitRepo.GetRefCommitID(newRef)
if err != nil {
return nil, false, err
}
opts.Content = string(dataJSON)
comment, err = issues_model.CreateComment(ctx, opts)
data, shouldCreate, err := preparePushPullCommentPushActionContent(ctx, pr, oldCommitID, newCommitID, isForcePush)
if !shouldCreate {
return nil, false, err
}
return comment, err
comment, err = db.WithTx2(ctx, func(ctx context.Context) (comment *issues_model.Comment, err error) {
if isForcePush {
err := cleanUpOldCommitCommentsForNewForcePush(ctx, pr, &data)
if err != nil {
log.Error("CleanUpOldCommitComments failed: %v", err)
}
}
if len(data.CommitIDs) > 0 {
// if the push has commit IDs, add a "normal push" commit comment
dataJSON, _ := json.Marshal(data)
opts := &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypePullRequestPush,
Doer: pusher,
Repo: pr.BaseRepo,
Issue: pr.Issue,
Content: string(dataJSON),
}
comment, err = issues_model.CreateComment(ctx, opts)
if err != nil {
return nil, err
}
}
if isForcePush {
// if it's a force push, we need to add a force push comment
forcePushDataJSON, _ := json.Marshal(&issues_model.PushActionContent{IsForcePush: true, CommitIDs: []string{oldCommitID, newCommitID}})
opts := &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypePullRequestPush,
Doer: pusher,
Repo: pr.BaseRepo,
Issue: pr.Issue,
Content: string(forcePushDataJSON),
// It seems the field is unnecessary anymore because PushActionContent includes IsForcePush field.
// However, it can't be simply removed.
IsForcePush: true, // See the comment of "Comment.IsForcePush"
}
comment, err = issues_model.CreateComment(ctx, opts)
if err != nil {
return nil, err
}
}
return comment, nil
})
return comment, comment != nil, err
}