summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
authordelvh <leon@kske.dev>2022-05-07 20:28:10 +0200
committerGitHub <noreply@github.com>2022-05-07 20:28:10 +0200
commit5ca224a789394d00cc1efb5afcae7b87aa7d1e49 (patch)
treed88bddc7a08449a2c8f2b4e5ae47d3ef067a1cc0 /services
parent59b30f060a840cde305952ef7bc344fa4101c0d5 (diff)
downloadgitea-5ca224a789394d00cc1efb5afcae7b87aa7d1e49.tar.gz
gitea-5ca224a789394d00cc1efb5afcae7b87aa7d1e49.zip
Allow to mark files in a PR as viewed (#19007)
Users can now mark files in PRs as viewed, resulting in them not being shown again by default when they reopen the PR again.
Diffstat (limited to 'services')
-rw-r--r--services/gitdiff/gitdiff.go127
1 files changed, 104 insertions, 23 deletions
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 1df16e5016..7fe056a481 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/models/db"
+ pull_model "code.gitea.io/gitea/models/pull"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/analyze"
"code.gitea.io/gitea/modules/charset"
@@ -602,25 +603,27 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif
// DiffFile represents a file diff.
type DiffFile struct {
- Name string
- OldName string
- Index int
- Addition, Deletion int
- Type DiffFileType
- IsCreated bool
- IsDeleted bool
- IsBin bool
- IsLFSFile bool
- IsRenamed bool
- IsAmbiguous bool
- IsSubmodule bool
- Sections []*DiffSection
- IsIncomplete bool
- IsIncompleteLineTooLong bool
- IsProtected bool
- IsGenerated bool
- IsVendored bool
- Language string
+ Name string
+ OldName string
+ Index int
+ Addition, Deletion int
+ Type DiffFileType
+ IsCreated bool
+ IsDeleted bool
+ IsBin bool
+ IsLFSFile bool
+ IsRenamed bool
+ IsAmbiguous bool
+ IsSubmodule bool
+ Sections []*DiffSection
+ IsIncomplete bool
+ IsIncompleteLineTooLong bool
+ IsProtected bool
+ IsGenerated bool
+ IsVendored bool
+ IsViewed bool // User specific
+ HasChangedSinceLastReview bool // User specific
+ Language string
}
// GetType returns type of diff file.
@@ -663,6 +666,18 @@ func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID,
return tailSection
}
+// GetDiffFileName returns the name of the diff file, or its old name in case it was deleted
+func (diffFile *DiffFile) GetDiffFileName() string {
+ if diffFile.Name == "" {
+ return diffFile.OldName
+ }
+ return diffFile.Name
+}
+
+func (diffFile *DiffFile) ShouldBeHidden() bool {
+ return diffFile.IsGenerated || diffFile.IsViewed
+}
+
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
blob, err := commit.GetBlobByPath(filePath)
if err != nil {
@@ -677,10 +692,12 @@ func getCommitFileLineCount(commit *git.Commit, filePath string) int {
// Diff represents a difference between two git trees.
type Diff struct {
- Start, End string
- NumFiles, TotalAddition, TotalDeletion int
- Files []*DiffFile
- IsIncomplete bool
+ Start, End string
+ NumFiles int
+ TotalAddition, TotalDeletion int
+ Files []*DiffFile
+ IsIncomplete bool
+ NumViewedFiles int // user-specific
}
// LoadComments loads comments into each line
@@ -1497,6 +1514,70 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
return diff, nil
}
+// SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set
+// Additionally, the database asynchronously is updated if files have changed since the last review
+func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *models.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) {
+ diff, err := GetDiff(gitRepo, opts, files...)
+ if err != nil {
+ return nil, err
+ }
+ review, err := pull_model.GetNewestReviewState(ctx, userID, pull.ID)
+ if err != nil || review == nil || review.UpdatedFiles == nil {
+ return diff, err
+ }
+
+ latestCommit := opts.AfterCommitID
+ if latestCommit == "" {
+ latestCommit = pull.HeadBranch // opts.AfterCommitID is preferred because it handles PRs from forks correctly and the branch name doesn't
+ }
+
+ changedFiles, err := gitRepo.GetFilesChangedBetween(review.CommitSHA, latestCommit)
+ if err != nil {
+ return diff, err
+ }
+
+ filesChangedSinceLastDiff := make(map[string]pull_model.ViewedState)
+outer:
+ for _, diffFile := range diff.Files {
+ fileViewedState := review.UpdatedFiles[diffFile.GetDiffFileName()]
+
+ // Check whether it was previously detected that the file has changed since the last review
+ if fileViewedState == pull_model.HasChanged {
+ diffFile.HasChangedSinceLastReview = true
+ continue
+ }
+
+ filename := diffFile.GetDiffFileName()
+
+ // Check explicitly whether the file has changed since the last review
+ for _, changedFile := range changedFiles {
+ diffFile.HasChangedSinceLastReview = filename == changedFile
+ if diffFile.HasChangedSinceLastReview {
+ filesChangedSinceLastDiff[filename] = pull_model.HasChanged
+ continue outer // We don't want to check if the file is viewed here as that would fold the file, which is in this case unwanted
+ }
+ }
+ // Check whether the file has already been viewed
+ if fileViewedState == pull_model.Viewed {
+ diffFile.IsViewed = true
+ diff.NumViewedFiles++
+ }
+ }
+
+ // Explicitly store files that have changed in the database, if any is present at all.
+ // This has the benefit that the "Has Changed" attribute will be present as long as the user does not explicitly mark this file as viewed, so it will even survive a page reload after marking another file as viewed.
+ // On the other hand, this means that even if a commit reverting an unseen change is committed, the file will still be seen as changed.
+ if len(filesChangedSinceLastDiff) > 0 {
+ err := pull_model.UpdateReviewState(ctx, review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff)
+ if err != nil {
+ log.Warn("Could not update review for user %d, pull %d, commit %s and the changed files %v: %v", review.UserID, review.PullID, review.CommitSHA, filesChangedSinceLastDiff, err)
+ return nil, err
+ }
+ }
+
+ return diff, err
+}
+
// CommentAsDiff returns c.Patch as *Diff
func CommentAsDiff(c *models.Comment) (*Diff, error) {
diff, err := ParsePatch(setting.Git.MaxGitDiffLines,