* Add whitespace handling to PR-comparsion In a PR we have to keep an eye on a lot of different things. But sometimes the bare code is the key-thing we want to care about and just don't want to care about fixed indention on some places. Especially if we follow the pathfinder rule we face a lot of these situations because these changes don't break the code in many languages but improve the readability a lot. So this change introduce a fine graned button to adjust the way how the reviewer want to see whitespace-changes within the code. The possibilities reflect the possibilities from git itself except of the `--ignore-blank-lines` flag because that one is also handled by `-b` and is really rare. Signed-off-by: Felix Nehrke <felix@nehrke.info>master
@@ -633,6 +633,13 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D | |||||
// passing the empty string as beforeCommitID returns a diff from the | // passing the empty string as beforeCommitID returns a diff from the | ||||
// parent commit. | // parent commit. | ||||
func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) { | func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int) (*Diff, error) { | ||||
return GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID, maxLines, maxLineCharacters, maxFiles, "") | |||||
} | |||||
// GetDiffRangeWithWhitespaceBehavior builds a Diff between two commits of a repository. | |||||
// Passing the empty string as beforeCommitID returns a diff from the parent commit. | |||||
// The whitespaceBehavior is either an empty string or a git flag | |||||
func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID string, maxLines, maxLineCharacters, maxFiles int, whitespaceBehavior string) (*Diff, error) { | |||||
gitRepo, err := git.OpenRepository(repoPath) | gitRepo, err := git.OpenRepository(repoPath) | ||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
@@ -644,17 +651,21 @@ func GetDiffRange(repoPath, beforeCommitID, afterCommitID string, maxLines, maxL | |||||
} | } | ||||
var cmd *exec.Cmd | var cmd *exec.Cmd | ||||
// if "after" commit given | |||||
if len(beforeCommitID) == 0 { | |||||
// First commit of repository. | |||||
if commit.ParentCount() == 0 { | |||||
cmd = exec.Command("git", "show", afterCommitID) | |||||
} else { | |||||
c, _ := commit.Parent(0) | |||||
cmd = exec.Command("git", "diff", "-M", c.ID.String(), afterCommitID) | |||||
} | |||||
if len(beforeCommitID) == 0 && commit.ParentCount() == 0 { | |||||
cmd = exec.Command("git", "show", afterCommitID) | |||||
} else { | } else { | ||||
cmd = exec.Command("git", "diff", "-M", beforeCommitID, afterCommitID) | |||||
actualBeforeCommitID := beforeCommitID | |||||
if len(actualBeforeCommitID) == 0 { | |||||
parentCommit, _ := commit.Parent(0) | |||||
actualBeforeCommitID = parentCommit.ID.String() | |||||
} | |||||
diffArgs := []string{"diff", "-M"} | |||||
if len(whitespaceBehavior) != 0 { | |||||
diffArgs = append(diffArgs, whitespaceBehavior) | |||||
} | |||||
diffArgs = append(diffArgs, actualBeforeCommitID) | |||||
diffArgs = append(diffArgs, afterCommitID) | |||||
cmd = exec.Command("git", diffArgs...) | |||||
} | } | ||||
cmd.Dir = repoPath | cmd.Dir = repoPath | ||||
cmd.Stderr = os.Stderr | cmd.Stderr = os.Stderr | ||||
@@ -1152,6 +1152,11 @@ diff.data_not_available = Diff Content Not Available | |||||
diff.show_diff_stats = Show Diff Stats | diff.show_diff_stats = Show Diff Stats | ||||
diff.show_split_view = Split View | diff.show_split_view = Split View | ||||
diff.show_unified_view = Unified View | diff.show_unified_view = Unified View | ||||
diff.whitespace_button = Whitespace | |||||
diff.whitespace_show_everything = Show all changes | |||||
diff.whitespace_ignore_all_whitespace = Ignore whitespace when comparing lines | |||||
diff.whitespace_ignore_amount_changes = Ignore changes in amount of whitespace | |||||
diff.whitespace_ignore_at_eol = Ignore changes in whitespace at EOL | |||||
diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</strong> and <strong>%d deletions</strong> | diff.stats_desc = <strong> %d changed files</strong> with <strong>%d additions</strong> and <strong>%d deletions</strong> | ||||
diff.bin = BIN | diff.bin = BIN | ||||
diff.view_file = View File | diff.view_file = View File | ||||
@@ -50,3 +50,14 @@ func SetDiffViewStyle(ctx *context.Context) { | |||||
ctx.ServerError("ErrUpdateDiffViewStyle", err) | ctx.ServerError("ErrUpdateDiffViewStyle", err) | ||||
} | } | ||||
} | } | ||||
// SetWhitespaceBehavior set whitespace behavior as render variable | |||||
func SetWhitespaceBehavior(ctx *context.Context) { | |||||
whitespaceBehavior := ctx.Query("whitespace") | |||||
switch whitespaceBehavior { | |||||
case "ignore-all", "ignore-eol", "ignore-change": | |||||
ctx.Data["WhitespaceBehavior"] = whitespaceBehavior | |||||
default: | |||||
ctx.Data["WhitespaceBehavior"] = "" | |||||
} | |||||
} |
@@ -390,6 +390,12 @@ func ViewPullFiles(ctx *context.Context) { | |||||
} | } | ||||
pull := issue.PullRequest | pull := issue.PullRequest | ||||
whitespaceFlags := map[string]string{ | |||||
"ignore-all": "-w", | |||||
"ignore-change": "-b", | |||||
"ignore-eol": "--ignore-space-at-eol", | |||||
"": ""} | |||||
var ( | var ( | ||||
diffRepoPath string | diffRepoPath string | ||||
startCommitID string | startCommitID string | ||||
@@ -455,11 +461,12 @@ func ViewPullFiles(ctx *context.Context) { | |||||
ctx.Data["Reponame"] = pull.HeadRepo.Name | ctx.Data["Reponame"] = pull.HeadRepo.Name | ||||
} | } | ||||
diff, err := models.GetDiffRange(diffRepoPath, | |||||
diff, err := models.GetDiffRangeWithWhitespaceBehavior(diffRepoPath, | |||||
startCommitID, endCommitID, setting.Git.MaxGitDiffLines, | startCommitID, endCommitID, setting.Git.MaxGitDiffLines, | ||||
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles) | |||||
setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, | |||||
whitespaceFlags[ctx.Data["WhitespaceBehavior"].(string)]) | |||||
if err != nil { | if err != nil { | ||||
ctx.ServerError("GetDiffRange", err) | |||||
ctx.ServerError("GetDiffRangeWithWhitespaceBehavior", err) | |||||
return | return | ||||
} | } | ||||
@@ -674,7 +674,7 @@ func RegisterRoutes(m *macaron.Macaron) { | |||||
m.Post("/merge", reqRepoWriter, bindIgnErr(auth.MergePullRequestForm{}), repo.MergePullRequest) | m.Post("/merge", reqRepoWriter, bindIgnErr(auth.MergePullRequestForm{}), repo.MergePullRequest) | ||||
m.Post("/cleanup", context.RepoRef(), repo.CleanUpPullRequest) | m.Post("/cleanup", context.RepoRef(), repo.CleanUpPullRequest) | ||||
m.Group("/files", func() { | m.Group("/files", func() { | ||||
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ViewPullFiles) | |||||
m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles) | |||||
m.Group("/reviews", func() { | m.Group("/reviews", func() { | ||||
m.Post("/comments", bindIgnErr(auth.CodeCommentForm{}), repo.CreateCodeComment) | m.Post("/comments", bindIgnErr(auth.CodeCommentForm{}), repo.CreateCodeComment) | ||||
m.Post("/submit", bindIgnErr(auth.SubmitReviewForm{}), repo.SubmitReview) | m.Post("/submit", bindIgnErr(auth.SubmitReviewForm{}), repo.SubmitReview) | ||||
@@ -1,4 +1,19 @@ | |||||
{{if .DiffNotAvailable}} | {{if .DiffNotAvailable}} | ||||
<div class="diff-detail-box diff-box ui sticky"> | |||||
<div> | |||||
<div class="ui right"> | |||||
{{if .PageIsPullFiles}} | |||||
{{template "repo/diff/whitespace_dropdown" .}} | |||||
{{else}} | |||||
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a> | |||||
{{end}} | |||||
<a class="ui tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a> | |||||
{{if and .PageIsPullFiles $.SignedUserID}} | |||||
{{template "repo/diff/new_review" .}} | |||||
{{end}} | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4> | <h4>{{.i18n.Tr "repo.diff.data_not_available"}}</h4> | ||||
{{else}} | {{else}} | ||||
<div class="diff-detail-box diff-box ui sticky"> | <div class="diff-detail-box diff-box ui sticky"> | ||||
@@ -6,7 +21,11 @@ | |||||
<i class="fa fa-retweet"></i> | <i class="fa fa-retweet"></i> | ||||
{{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}} | {{.i18n.Tr "repo.diff.stats_desc" .Diff.NumFiles .Diff.TotalAddition .Diff.TotalDeletion | Str2html}} | ||||
<div class="ui right"> | <div class="ui right"> | ||||
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a> | |||||
{{if .PageIsPullFiles}} | |||||
{{template "repo/diff/whitespace_dropdown" .}} | |||||
{{else}} | |||||
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a> | |||||
{{end}} | |||||
<a class="ui tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a> | <a class="ui tiny basic toggle button" data-target="#diff-files">{{.i18n.Tr "repo.diff.show_diff_stats"}}</a> | ||||
{{if and .PageIsPullFiles $.SignedUserID}} | {{if and .PageIsPullFiles $.SignedUserID}} | ||||
{{template "repo/diff/new_review" .}} | {{template "repo/diff/new_review" .}} | ||||
@@ -0,0 +1,23 @@ | |||||
<div class="ui dropdown tiny button"> | |||||
{{.i18n.Tr "repo.diff.whitespace_button"}} | |||||
<i class="dropdown icon"></i> | |||||
<div class="menu"> | |||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace="> | |||||
<i class="circle {{ if eq .WhitespaceBehavior "" }}dot{{else}}outline{{end}} icon"></i> | |||||
{{.i18n.Tr "repo.diff.whitespace_show_everything"}} | |||||
</a> | |||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-all"> | |||||
<i class="circle {{ if eq .WhitespaceBehavior "ignore-all" }}dot{{else}}outline{{end}} icon"></i> | |||||
{{.i18n.Tr "repo.diff.whitespace_ignore_all_whitespace"}} | |||||
</a> | |||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-change"> | |||||
<i class="circle {{ if eq .WhitespaceBehavior "ignore-change" }}dot{{else}}outline{{end}} icon"></i> | |||||
{{.i18n.Tr "repo.diff.whitespace_ignore_amount_changes"}} | |||||
</a> | |||||
<a class="item" href="?style={{if .IsSplitStyle}}split{{else}}unified{{end}}&whitespace=ignore-eol"> | |||||
<i class="circle {{ if eq .WhitespaceBehavior "ignore-eol" }}dot{{else}}outline{{end}} icon"></i> | |||||
{{.i18n.Tr "repo.diff.whitespace_ignore_at_eol"}} | |||||
</a> | |||||
</div> | |||||
</div> | |||||
<a class="ui tiny basic toggle button" href="?style={{if .IsSplitStyle}}unified{{else}}split{{end}}&whitespace={{$.WhitespaceBehavior}}">{{ if .IsSplitStyle }}{{.i18n.Tr "repo.diff.show_unified_view"}}{{else}}{{.i18n.Tr "repo.diff.show_split_view"}}{{end}}</a> |