Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 14 additions & 13 deletions models/migrations/v1_12/v136.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,30 @@ package v1_12
import (
"fmt"
"math"
"path/filepath"
"strings"
"time"

"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/gitrepo"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"

"xorm.io/xorm"
)

func AddCommitDivergenceToPulls(x *xorm.Engine) error {
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`
OwnerName string
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"INDEX NOT NULL"`
}
type Repository struct {
ID int64 `xorm:"pk autoincr"`
OwnerID int64 `xorm:"UNIQUE(s) index"`
OwnerName string
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"INDEX NOT NULL"`
}

func (r *Repository) RelativePath() string {
return fmt.Sprintf("%s/%s.git", strings.ToLower(r.OwnerName), strings.ToLower(r.Name))
}

func AddCommitDivergenceToPulls(x *xorm.Engine) error {
type PullRequest struct {
ID int64 `xorm:"pk autoincr"`
IssueID int64 `xorm:"INDEX"`
Expand Down Expand Up @@ -85,12 +88,10 @@ func AddCommitDivergenceToPulls(x *xorm.Engine) error {
log.Error("Missing base repo with id %d for PR ID %d", pr.BaseRepoID, pr.ID)
continue
}
userPath := filepath.Join(setting.RepoRootPath, strings.ToLower(baseRepo.OwnerName))
repoPath := filepath.Join(userPath, strings.ToLower(baseRepo.Name)+".git")

gitRefName := fmt.Sprintf("refs/pull/%d/head", pr.Index)

divergence, err := git.GetDivergingCommits(graceful.GetManager().HammerContext(), repoPath, pr.BaseBranch, gitRefName)
divergence, err := gitrepo.GetDivergingCommits(graceful.GetManager().HammerContext(), baseRepo, pr.BaseBranch, gitRefName)
if err != nil {
log.Warn("Could not recalculate Divergence for pull: %d", pr.ID)
pr.CommitsAhead = 0
Expand Down
30 changes: 0 additions & 30 deletions modules/git/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,36 +242,6 @@ func GetLatestCommitTime(ctx context.Context, repoPath string) (time.Time, error
return time.Parse("Mon Jan _2 15:04:05 2006 -0700", commitTime)
}

// DivergeObject represents commit count diverging commits
type DivergeObject struct {
Ahead int
Behind int
}

// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
func GetDivergingCommits(ctx context.Context, repoPath, baseBranch, targetBranch string) (do DivergeObject, err error) {
cmd := NewCommand("rev-list", "--count", "--left-right").
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
stdout, _, err := cmd.RunStdString(ctx, &RunOpts{Dir: repoPath})
if err != nil {
return do, err
}
left, right, found := strings.Cut(strings.Trim(stdout, "\n"), "\t")
if !found {
return do, fmt.Errorf("git rev-list output is missing a tab: %q", stdout)
}

do.Behind, err = strconv.Atoi(left)
if err != nil {
return do, err
}
do.Ahead, err = strconv.Atoi(right)
if err != nil {
return do, err
}
return do, nil
}

// CreateBundle create bundle content to the target path
func (repo *Repository) CreateBundle(ctx context.Context, commit string, out io.Writer) error {
tmp, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle")
Expand Down
4 changes: 2 additions & 2 deletions modules/git/repo_commit_gogit.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ func (repo *Repository) SetReference(name, commitID string) error {
return repo.gogitRepo.Storer.SetReference(plumbing.NewReferenceFromStrings(name, commitID))
}

// RemoveReference removes the given reference (e.g. branch or tag).
func (repo *Repository) RemoveReference(name string) error {
// removeReference removes the given reference (e.g. branch or tag).
func (repo *Repository) removeReference(name string) error {
return repo.gogitRepo.Storer.RemoveReference(plumbing.ReferenceName(name))
}

Expand Down
4 changes: 2 additions & 2 deletions modules/git/repo_commit_nogogit.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func (repo *Repository) SetReference(name, commitID string) error {
return err
}

// RemoveReference removes the given reference (e.g. branch or tag).
func (repo *Repository) RemoveReference(name string) error {
// removeReference removes the given reference (e.g. branch or tag).
func (repo *Repository) removeReference(name string) error {
_, _, err := NewCommand("update-ref", "--no-deref", "-d").AddDynamicArguments(name).RunStdString(repo.Ctx, &RunOpts{Dir: repo.Path})
return err
}
Expand Down
2 changes: 1 addition & 1 deletion modules/git/repo_compare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestReadWritePullHead(t *testing.T) {
assert.Equal(t, headContents, newCommit)

// Remove file after the test
err = repo.RemoveReference(PullPrefix + "1/head")
err = repo.removeReference(PullPrefix + "1/head")
assert.NoError(t, err)
}

Expand Down
24 changes: 0 additions & 24 deletions modules/git/repo_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,3 @@ func TestRepoIsEmpty(t *testing.T) {
assert.NoError(t, err)
assert.True(t, isEmpty)
}

func TestRepoGetDivergingCommits(t *testing.T) {
bareRepo1Path := filepath.Join(testReposDir, "repo1_bare")
do, err := GetDivergingCommits(t.Context(), bareRepo1Path, "master", "branch2")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 1,
Behind: 5,
}, do)

do, err = GetDivergingCommits(t.Context(), bareRepo1Path, "master", "master")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 0,
Behind: 0,
}, do)

do, err = GetDivergingCommits(t.Context(), bareRepo1Path, "master", "test")
assert.NoError(t, err)
assert.Equal(t, DivergeObject{
Ahead: 0,
Behind: 2,
}, do)
}
45 changes: 45 additions & 0 deletions modules/gitrepo/diverging.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package gitrepo

import (
"context"
"fmt"
"strconv"
"strings"

"code.gitea.io/gitea/modules/git"
)

// DivergeObject represents commit count diverging commits
type DivergeObject struct {
Ahead int
Behind int
}

// GetDivergingCommits returns the number of commits a targetBranch is ahead or behind a baseBranch
func GetDivergingCommits(ctx context.Context, repo Repository, baseBranch, targetBranch string) (*DivergeObject, error) {
cmd := git.NewCommand("rev-list", "--count", "--left-right").
AddDynamicArguments(baseBranch + "..." + targetBranch).AddArguments("--")
stdout, _, err1 := cmd.RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
if err1 != nil {
return nil, err1
}
left, right, found := strings.Cut(strings.Trim(stdout, "\n"), "\t")
if !found {
return nil, fmt.Errorf("git rev-list output is missing a tab: %q", stdout)
}

var do DivergeObject
var err error
do.Behind, err = strconv.Atoi(left)
if err != nil {
return nil, err
}
do.Ahead, err = strconv.Atoi(right)
if err != nil {
return nil, err
}
return &do, nil
}
17 changes: 17 additions & 0 deletions modules/gitrepo/reference.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright 2025 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package gitrepo

import (
"context"

"code.gitea.io/gitea/modules/git"
)

func RemoveReference(ctx context.Context, repo Repository, refName string) error {
_, _, err := git.NewCommand("update-ref", "--no-deref", "-d").
AddDynamicArguments(refName).
RunStdString(ctx, &git.RunOpts{Dir: repoPath(repo)})
return err
}
2 changes: 1 addition & 1 deletion routers/api/v1/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -979,7 +979,7 @@ func DeleteIssue(ctx *context.APIContext) {
return
}

if err = issue_service.DeleteIssue(ctx, ctx.Doer, ctx.Repo.GitRepo, issue); err != nil {
if err = issue_service.DeleteIssue(ctx, ctx.Doer, issue); err != nil {
ctx.APIErrorInternal(err)
return
}
Expand Down
2 changes: 1 addition & 1 deletion routers/web/repo/issue_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ func BatchDeleteIssues(ctx *context.Context) {
return
}
for _, issue := range issues {
if err := issue_service.DeleteIssue(ctx, ctx.Doer, ctx.Repo.GitRepo, issue); err != nil {
if err := issue_service.DeleteIssue(ctx, ctx.Doer, issue); err != nil {
ctx.ServerError("DeleteIssue", err)
return
}
Expand Down
2 changes: 1 addition & 1 deletion routers/web/repo/issue_new.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func DeleteIssue(ctx *context.Context) {
return
}

if err := issue_service.DeleteIssue(ctx, ctx.Doer, ctx.Repo.GitRepo, issue); err != nil {
if err := issue_service.DeleteIssue(ctx, ctx.Doer, issue); err != nil {
ctx.ServerError("DeleteIssueByID", err)
return
}
Expand Down
37 changes: 16 additions & 21 deletions services/agit/agit.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,35 +214,30 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
}
}

// Store old commit ID for review staleness checking
oldHeadCommitID := pr.HeadCommitID
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line 190 have checked whether the old head commit id is the same as the new one.


pr.HeadCommitID = opts.NewCommitIDs[i]
if err = pull_service.UpdateRef(ctx, pr); err != nil {
if err = pull_service.UpdatePullRequestAgitFlowHead(ctx, pr, pr.HeadCommitID); err != nil {
return nil, fmt.Errorf("failed to update pull ref. Error: %w", err)
}

// Mark existing reviews as stale when PR content changes (same as regular GitHub flow)
if oldHeadCommitID != opts.NewCommitIDs[i] {
if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil {
log.Error("MarkReviewsAsStale: %v", err)
}
if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil {
log.Error("MarkReviewsAsStale: %v", err)
}

// Dismiss all approval reviews if protected branch rule item enabled
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
if err != nil {
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
}
if pb != nil && pb.DismissStaleApprovals {
if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil {
log.Error("DismissApprovalReviews: %v", err)
}
// Dismiss all approval reviews if protected branch rule item enabled
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
if err != nil {
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
}
if pb != nil && pb.DismissStaleApprovals {
if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil {
log.Error("DismissApprovalReviews: %v", err)
}
}

// Mark reviews for the new commit as not stale
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil {
log.Error("MarkReviewsAsNotStale: %v", err)
}
// Mark reviews for the new commit as not stale
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil {
log.Error("MarkReviewsAsNotStale: %v", err)
}

pull_service.StartPullRequestCheckImmediately(ctx, pr)
Expand Down
7 changes: 4 additions & 3 deletions services/issue/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
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/log"
"code.gitea.io/gitea/modules/storage"
notify_service "code.gitea.io/gitea/services/notify"
Expand Down Expand Up @@ -180,7 +181,7 @@ func UpdateAssignees(ctx context.Context, issue *issues_model.Issue, oneAssignee
}

// DeleteIssue deletes an issue
func DeleteIssue(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, issue *issues_model.Issue) error {
func DeleteIssue(ctx context.Context, doer *user_model.User, issue *issues_model.Issue) error {
// load issue before deleting it
if err := issue.LoadAttributes(ctx); err != nil {
return err
Expand All @@ -199,8 +200,8 @@ func DeleteIssue(ctx context.Context, doer *user_model.User, gitRepo *git.Reposi
}

// delete pull request related git data
if issue.IsPull && gitRepo != nil {
if err := gitRepo.RemoveReference(issue.PullRequest.GetGitHeadRefName()); err != nil {
if issue.IsPull {
if err := gitrepo.RemoveReference(ctx, issue.Repo, issue.PullRequest.GetGitHeadRefName()); err != nil {
return err
}
}
Expand Down
5 changes: 5 additions & 0 deletions services/pull/comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package pull

import (
"context"
"fmt"

issues_model "code.gitea.io/gitea/models/issues"
repo_model "code.gitea.io/gitea/models/repo"
Expand Down Expand Up @@ -52,6 +53,10 @@ func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *iss
return nil, nil
}

if err := pr.LoadIssue(ctx); err != nil {
return nil, fmt.Errorf("unable to load issue for PR[%d]: %w", pr.ID, err)
}

opts := &issues_model.CreateCommentOptions{
Type: issues_model.CommentTypePullRequestPush,
Doer: pusher,
Expand Down
Loading
Loading