diff options
author | KN4CK3R <admin@oldschoolhack.me> | 2023-09-16 19:42:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-16 17:42:34 +0000 |
commit | ed64f1c2b835bf9332bf8347be9675ef29c8274b (patch) | |
tree | d549801f35652496808d7307403f86e2f3f1ff39 /routers/web/repo/blame.go | |
parent | c766140dad3408048ad843d0e7b4ab5d9f5777c6 (diff) | |
download | gitea-ed64f1c2b835bf9332bf8347be9675ef29c8274b.tar.gz gitea-ed64f1c2b835bf9332bf8347be9675ef29c8274b.zip |
Support `.git-blame-ignore-revs` file (#26395)
Closes #26329
This PR adds the ability to ignore revisions specified in the
`.git-blame-ignore-revs` file in the root of the repository.

The banner is displayed in this case. I intentionally did not add a UI
way to bypass the ignore file (same behaviour as Github) but you can add
`?bypass-blame-ignore=true` to the url manually.
---------
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Diffstat (limited to 'routers/web/repo/blame.go')
-rw-r--r-- | routers/web/repo/blame.go | 91 |
1 files changed, 69 insertions, 22 deletions
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index b1cb42297c..e4506a857e 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -8,9 +8,9 @@ import ( gotemplate "html/template" "net/http" "net/url" + "strconv" "strings" - repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/context" @@ -45,10 +45,6 @@ func RefBlame(ctx *context.Context) { return } - userName := ctx.Repo.Owner.Name - repoName := ctx.Repo.Repository.Name - commitID := ctx.Repo.CommitID - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL() treeLink := branchLink rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL() @@ -101,26 +97,16 @@ func RefBlame(ctx *context.Context) { return } - blameReader, err := git.CreateBlameReader(ctx, repo_model.RepoPath(userName, repoName), commitID, fileName) + bypassBlameIgnore, _ := strconv.ParseBool(ctx.FormString("bypass-blame-ignore")) + + result, err := performBlame(ctx, ctx.Repo.Repository.RepoPath(), ctx.Repo.Commit, fileName, bypassBlameIgnore) if err != nil { ctx.NotFound("CreateBlameReader", err) return } - defer blameReader.Close() - - blameParts := make([]git.BlamePart, 0) - for { - blamePart, err := blameReader.NextPart() - if err != nil { - ctx.NotFound("NextPart", err) - return - } - if blamePart == nil { - break - } - blameParts = append(blameParts, *blamePart) - } + ctx.Data["UsesIgnoreRevs"] = result.UsesIgnoreRevs + ctx.Data["FaultyIgnoreRevsFile"] = result.FaultyIgnoreRevsFile // Get Topics of this repo renderRepoTopics(ctx) @@ -128,16 +114,77 @@ func RefBlame(ctx *context.Context) { return } - commitNames, previousCommits := processBlameParts(ctx, blameParts) + commitNames, previousCommits := processBlameParts(ctx, result.Parts) if ctx.Written() { return } - renderBlame(ctx, blameParts, commitNames, previousCommits) + renderBlame(ctx, result.Parts, commitNames, previousCommits) ctx.HTML(http.StatusOK, tplRepoHome) } +type blameResult struct { + Parts []git.BlamePart + UsesIgnoreRevs bool + FaultyIgnoreRevsFile bool +} + +func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) { + blameReader, err := git.CreateBlameReader(ctx, repoPath, commit, file, bypassBlameIgnore) + if err != nil { + return nil, err + } + + r := &blameResult{} + if err := fillBlameResult(blameReader, r); err != nil { + _ = blameReader.Close() + return nil, err + } + + err = blameReader.Close() + if err != nil { + if len(r.Parts) == 0 && r.UsesIgnoreRevs { + // try again without ignored revs + + blameReader, err = git.CreateBlameReader(ctx, repoPath, commit, file, true) + if err != nil { + return nil, err + } + + r := &blameResult{ + FaultyIgnoreRevsFile: true, + } + if err := fillBlameResult(blameReader, r); err != nil { + _ = blameReader.Close() + return nil, err + } + + return r, blameReader.Close() + } + return nil, err + } + return r, nil +} + +func fillBlameResult(br *git.BlameReader, r *blameResult) error { + r.UsesIgnoreRevs = br.UsesIgnoreRevs() + + r.Parts = make([]git.BlamePart, 0, 5) + for { + blamePart, err := br.NextPart() + if err != nil { + return fmt.Errorf("BlameReader.NextPart failed: %w", err) + } + if blamePart == nil { + break + } + r.Parts = append(r.Parts, *blamePart) + } + + return nil +} + func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]*user_model.UserCommit, map[string]string) { // store commit data by SHA to look up avatar info etc commitNames := make(map[string]*user_model.UserCommit) |