Skip to content

Commit 2f7097f

Browse files
committed
Mark old reviews as stale on agit pr updates
Fixes: #34134
1 parent d6d643f commit 2f7097f

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

services/agit/agit.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"strings"
1111

12+
git_model "code.gitea.io/gitea/models/git"
1213
issues_model "code.gitea.io/gitea/models/issues"
1314
repo_model "code.gitea.io/gitea/models/repo"
1415
user_model "code.gitea.io/gitea/models/user"
@@ -199,11 +200,37 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git.
199200
}
200201
}
201202

203+
// Store old commit ID for review staleness checking
204+
oldHeadCommitID := pr.HeadCommitID
205+
202206
pr.HeadCommitID = opts.NewCommitIDs[i]
203207
if err = pull_service.UpdateRef(ctx, pr); err != nil {
204208
return nil, fmt.Errorf("failed to update pull ref. Error: %w", err)
205209
}
206210

211+
// Mark existing reviews as stale when PR content changes (same as regular GitHub flow)
212+
if oldHeadCommitID != opts.NewCommitIDs[i] {
213+
if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil {
214+
log.Error("MarkReviewsAsStale: %v", err)
215+
}
216+
217+
// Dismiss all approval reviews if protected branch rule item enabled
218+
pb, err := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch)
219+
if err != nil {
220+
log.Error("GetFirstMatchProtectedBranchRule: %v", err)
221+
}
222+
if pb != nil && pb.DismissStaleApprovals {
223+
if err := pull_service.DismissApprovalReviews(ctx, pusher, pr); err != nil {
224+
log.Error("DismissApprovalReviews: %v", err)
225+
}
226+
}
227+
228+
// Mark reviews for the new commit as not stale
229+
if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, opts.NewCommitIDs[i]); err != nil {
230+
log.Error("MarkReviewsAsNotStale: %v", err)
231+
}
232+
}
233+
207234
pull_service.StartPullRequestCheckImmediately(ctx, pr)
208235
err = pr.LoadIssue(ctx)
209236
if err != nil {

tests/integration/git_misc_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,3 +135,97 @@ func TestAgitPullPush(t *testing.T) {
135135
assert.NoError(t, err)
136136
})
137137
}
138+
139+
func TestAgitReviewStaleness(t *testing.T) {
140+
onGiteaRun(t, func(t *testing.T, u *url.URL) {
141+
baseAPITestContext := NewAPITestContext(t, "user2", "repo1", auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeWriteUser)
142+
143+
u.Path = baseAPITestContext.GitPath()
144+
u.User = url.UserPassword("user2", userPassword)
145+
146+
dstPath := t.TempDir()
147+
doGitClone(dstPath, u)(t)
148+
149+
gitRepo, err := git.OpenRepository(t.Context(), dstPath)
150+
assert.NoError(t, err)
151+
defer gitRepo.Close()
152+
153+
doGitCreateBranch(dstPath, "test-agit-review")
154+
155+
// Create initial commit
156+
_, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "[email protected]", "User Two", "initial-")
157+
assert.NoError(t, err)
158+
159+
// create PR via agit
160+
err = git.NewCommand("push", "origin",
161+
"-o", "title=Test agit Review Staleness", "-o", "description=Testing review staleness",
162+
"HEAD:refs/for/master/test-agit-review",
163+
).Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
164+
assert.NoError(t, err)
165+
166+
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
167+
BaseRepoID: 1,
168+
Flow: issues_model.PullRequestFlowAGit,
169+
HeadBranch: "user2/test-agit-review",
170+
})
171+
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
172+
173+
// Get initial commit ID for the review
174+
initialCommitID := pr.HeadCommitID
175+
t.Logf("Initial commit ID: %s", initialCommitID)
176+
177+
// Create a review on the PR (as user1 reviewing user2's PR)
178+
reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
179+
review, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{
180+
Type: issues_model.ReviewTypeApprove,
181+
Reviewer: reviewer,
182+
Issue: pr.Issue,
183+
CommitID: initialCommitID,
184+
Content: "LGTM! Looks good to merge.",
185+
Official: false,
186+
})
187+
assert.NoError(t, err)
188+
assert.False(t, review.Stale, "New review should not be stale")
189+
190+
// Verify review exists and is not stale
191+
reviews, err := issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
192+
IssueID: pr.IssueID,
193+
})
194+
assert.NoError(t, err)
195+
assert.Len(t, reviews, 1)
196+
assert.Equal(t, initialCommitID, reviews[0].CommitID)
197+
assert.False(t, reviews[0].Stale, "Review should not be stale initially")
198+
199+
// Create a new commit and update the agit PR
200+
_, err = generateCommitWithNewData(testFileSizeSmall, dstPath, "[email protected]", "User Two", "updated-")
201+
assert.NoError(t, err)
202+
203+
err = git.NewCommand("push", "origin", "HEAD:refs/for/master/test-agit-review").Run(git.DefaultContext, &git.RunOpts{Dir: dstPath})
204+
assert.NoError(t, err)
205+
206+
// Reload PR to get updated commit ID
207+
pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{
208+
BaseRepoID: 1,
209+
Flow: issues_model.PullRequestFlowAGit,
210+
HeadBranch: "user2/test-agit-review",
211+
})
212+
assert.NoError(t, pr.LoadIssue(db.DefaultContext))
213+
updatedCommitID := pr.HeadCommitID
214+
t.Logf("Updated commit ID: %s", updatedCommitID)
215+
216+
// Verify the PR was updated with new commit
217+
assert.NotEqual(t, initialCommitID, updatedCommitID, "PR should have new commit ID after update")
218+
219+
// Check that the review is now marked as stale
220+
reviews, err = issues_model.FindReviews(db.DefaultContext, issues_model.FindReviewOptions{
221+
IssueID: pr.IssueID,
222+
})
223+
assert.NoError(t, err)
224+
assert.Len(t, reviews, 1)
225+
226+
assert.True(t, reviews[0].Stale, "Review should be marked as stale after AGit PR update")
227+
228+
// The review commit ID should remain the same (pointing to the original commit)
229+
assert.Equal(t, initialCommitID, reviews[0].CommitID, "Review commit ID should remain unchanged and point to original commit")
230+
})
231+
}

0 commit comments

Comments
 (0)