Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull request review/approval and comment on code #3748

Merged
merged 104 commits into from
Aug 6, 2018
Merged
Show file tree
Hide file tree
Changes from 102 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
85e1ad5
Initial ui components for pull request review
lafriks Apr 2, 2018
623a9f6
Add Review
jonasfranz May 6, 2018
aeb0577
Replace ReviewComment with Content
jonasfranz May 6, 2018
2c18552
Add load functions
jonasfranz May 10, 2018
9544c46
Add create review comment implementation
jonasfranz May 10, 2018
0f772d1
Simplified create and find functions for review
jonasfranz May 10, 2018
4ad563d
Moved "Pending" to first position
jonasfranz May 10, 2018
17af2d1
Add GetCurrentReview to simplify fetching current review
jonasfranz May 10, 2018
75b7d9b
Preview for listing comments
jonasfranz May 11, 2018
e252d3b
Move new comment form to its own file
jonasfranz May 11, 2018
3e5f3c3
Implement Review form
jonasfranz May 11, 2018
61cc134
Add support for single comments
jonasfranz May 11, 2018
36d6631
Add pending tag to pending review comments
jonasfranz May 11, 2018
9c6bb4b
Add unit tests for Review
jonasfranz May 11, 2018
bc93592
Fetch all review ids at once
jonasfranz May 11, 2018
58fb672
gofmt
jonasfranz May 12, 2018
066086c
Improved comment rendering in "Files" view by adding Comments to Diff…
jonasfranz May 12, 2018
7986d6e
Add support for invalidating comments
jonasfranz May 13, 2018
cbdd8c9
Switched back to code.gitea.io/git
jonasfranz May 13, 2018
2f46613
Merge pull request #2 from JonasFranzDEV/feat/approval
lafriks May 13, 2018
6d00c1a
Merge branch 'master' into feat/approval-new
jonasfranz May 13, 2018
7723e15
Moved review migration from v64 to v65
jonasfranz May 13, 2018
90d9dda
Rebuild css
jonasfranz May 13, 2018
5f55ede
gofmt
jonasfranz May 13, 2018
d2b4347
Improve translations
jonasfranz May 13, 2018
ed695c1
Fix unit tests by updating fixtures and updating outdated test
jonasfranz May 14, 2018
de7081c
Comments will be shown at the right place now
jonasfranz May 14, 2018
7c4bf56
Add support for deleting CodeComments
jonasfranz May 14, 2018
6ae32b2
Fix problems caused by files in subdirectories
jonasfranz May 14, 2018
4ea74e5
Add support for showing code comments of reviews in conversation
jonasfranz May 15, 2018
7c1edf9
Merge branch 'master' into feat/approval
jonasfranz May 15, 2018
8bb5113
Add support for "Show/Hide outdated"
jonasfranz May 15, 2018
5c2171e
Update code.gitea.io/git
jonasfranz May 17, 2018
0f64dad
Merge branch 'master' into feat/approval-new
jonasfranz May 17, 2018
6e55557
Add support for new webhooks
jonasfranz May 17, 2018
05df5a7
Update comparison
jonasfranz May 19, 2018
e5bde14
Resolve conflicts
jonasfranz May 19, 2018
a8dc699
Merge branch 'master' into feat/approval-new
jonasfranz May 19, 2018
8ea8209
Minor UI improvements
lafriks May 19, 2018
a550052
Merge branch 'master' into feat/approval
jonasfranz May 21, 2018
0f88cb8
update code.gitea.io/git
jonasfranz May 21, 2018
e60b3f6
Merge branch 'master' into feat/approval
jonasfranz May 22, 2018
a05d052
Merge branch 'master' into feat/approval
jonasfranz May 23, 2018
27c488e
Merge branch 'master' into feat/approval
jonasfranz May 23, 2018
2b6001b
Fix ui bug reported by @lunny causing wrong position of add button
jonasfranz May 24, 2018
d25df5b
Prepare solving conflicts
jonasfranz May 24, 2018
7592f5b
Merge branch 'master' into feat/approval-new
jonasfranz May 24, 2018
4cb3a60
Show add button only if no comments already exist for the line
jonasfranz May 24, 2018
f64f8e0
Add missing vendor files
jonasfranz May 24, 2018
f07b4e1
Merge branch 'master' into feat/approval
jonasfranz May 24, 2018
4ad72de
Check if reviewer is nil
jonasfranz May 25, 2018
e2f60f4
Merge branch 'master' into feat/approval-new
jonasfranz May 25, 2018
229129d
Merge remote-tracking branch 'lafriks/feat/approval' into feat/approv…
jonasfranz May 25, 2018
c083682
Show forms only to users who are logged in
jonasfranz May 25, 2018
c7dffe6
Revert "Show forms only to users who are logged in"
jonasfranz May 29, 2018
4d0abce
Save patch in comment
jonasfranz May 31, 2018
c79e5a1
Merge branch 'master' into feat/approval-new
jonasfranz May 31, 2018
39fcc99
Add link to comment in code
jonasfranz May 31, 2018
9a0c394
Add reply form to comment list
jonasfranz May 31, 2018
c8c1e70
Add 'Reply' as translatable
jonasfranz May 31, 2018
853ed7d
Merge branch 'master' into feat/approval
jonasfranz May 31, 2018
b6d8aea
gofmt
jonasfranz May 31, 2018
e3f87a9
Merge remote-tracking branch 'lafriks/feat/approval' into feat/approv…
jonasfranz May 31, 2018
3f48c7c
Fix problems introduced by checking for singed in user
jonasfranz May 31, 2018
b4e43d6
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 5, 2018
45dabaf
Add v70
jonasfranz Jul 5, 2018
b553556
Update generated stylesheet
jonasfranz Jul 5, 2018
73b325c
Fix preview
jonasfranz Jul 5, 2018
3cd5ee4
Add new algo to generate diff for line range
jonasfranz Jul 6, 2018
7f0eb69
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 6, 2018
8a84f04
Add documentation and example for CutDiffAroundLine
jonasfranz Jul 6, 2018
fbaeb02
Fix example of CutDiffAroundLine
jonasfranz Jul 6, 2018
5dd39d3
Fix some comment UI rendering bugs
jonasfranz Jul 6, 2018
aee593b
Add code comment edit mode
jonasfranz Jul 6, 2018
8f77329
Send notifications / actions to users until review gets published
jonasfranz Jul 6, 2018
d8ddade
Fix vet errors
jonasfranz Jul 6, 2018
dbc7aee
Send notifications also for single comments
jonasfranz Jul 6, 2018
a0d9afd
Fix some notification bugs, fix link
jonasfranz Jul 6, 2018
b2092fe
Fix: add comment icon is only shown on code lines
jonasfranz Jul 6, 2018
3013c0c
Add lint comment
jonasfranz Jul 6, 2018
858345d
Add unit tests for git diff
jonasfranz Jul 7, 2018
e340181
Merge branch 'master' into feat/approval
jonasfranz Jul 7, 2018
3f39e23
Add more error messages
jonasfranz Jul 9, 2018
6de1f38
Merge remote-tracking branch 'lafriks/feat/approval' into feat/approv…
jonasfranz Jul 9, 2018
65d4318
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 20, 2018
e7b2b61
Regenerated css
jonasfranz Jul 20, 2018
8a6e6dc
fmt
jonasfranz Jul 20, 2018
5554ad2
Regenerated CSS with latest less version
jonasfranz Jul 20, 2018
b29e722
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 21, 2018
cb29fdb
Fix test by updating comment type to new ID
jonasfranz Jul 21, 2018
021f028
Introducing CodeComments as type for map[string]map[int64][]*Comment
jonasfranz Jul 24, 2018
5539c96
Fix data-tab issues
jonasfranz Jul 24, 2018
7eec104
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 24, 2018
ce07867
Remove unnecessary change
jonasfranz Jul 24, 2018
dc4a27d
refactored checkForInvalidation
jonasfranz Jul 24, 2018
4c76cf5
Append comments instead of setting
jonasfranz Jul 24, 2018
77caec7
Use HeadRepo instead of BaseRepo
jonasfranz Jul 25, 2018
f1a3e6f
Merge branch 'master' into feat/approval
jonasfranz Jul 25, 2018
a116913
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Jul 27, 2018
64269ef
Update migration
jonasfranz Jul 27, 2018
7888318
Regenerated CSS
jonasfranz Jul 27, 2018
638ea14
Add copyright
jonasfranz Jul 27, 2018
c503a70
Merge branch 'master' of https://github.com/go-gitea/gitea into feat/…
jonasfranz Aug 5, 2018
5f8c9a2
Update index.css
jonasfranz Aug 5, 2018
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
2 changes: 2 additions & 0 deletions custom/conf/app.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ ISSUE_PAGING_NUM = 10
FEED_MAX_COMMIT_NUM = 5
; Number of maximum commits displayed in commit graph.
GRAPH_MAX_COMMIT_NUM = 100
; Number of line of codes shown for a code comment
CODE_COMMENT_LINES = 4
; Value of `theme-color` meta tag, used by Android >= 5.0
; An invalid color like "none" or "disable" will have the default style
; More info: https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
Expand Down
4 changes: 2 additions & 2 deletions docs/content/doc/features/comparison.en-us.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ _Symbols used in table:_
| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Squash merging | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ |
| Rebase merging | ✓ | ✓ | ✓ | ✘ | ⁄ | ✘ | ✓ |
| Pull/Merge request inline comments | | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pull/Merge request approval | | ✘ | ⁄ | ✓ | ✓ | ✓ | ✓ |
| Pull/Merge request inline comments | | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Pull/Merge request approval | | ✘ | ⁄ | ✓ | ✓ | ✓ | ✓ |
| Merge conflict resolution | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ⁄ | ✓ | ✓ | ✓ |
| Revert specific commits or a merge request | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
Expand Down
22 changes: 22 additions & 0 deletions models/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -1344,3 +1344,25 @@ func IsErrUnknownDependencyType(err error) bool {
func (err ErrUnknownDependencyType) Error() string {
return fmt.Sprintf("unknown dependency type [type: %d]", err.Type)
}

// __________ .__
// \______ \ _______ _|__| ______ _ __
// | _// __ \ \/ / |/ __ \ \/ \/ /
// | | \ ___/\ /| \ ___/\ /
// |____|_ /\___ >\_/ |__|\___ >\/\_/
// \/ \/ \/

// ErrReviewNotExist represents a "ReviewNotExist" kind of error.
type ErrReviewNotExist struct {
ID int64
}

// IsErrReviewNotExist checks if an error is a ErrReviewNotExist.
func IsErrReviewNotExist(err error) bool {
_, ok := err.(ErrReviewNotExist)
return ok
}

func (err ErrReviewNotExist) Error() string {
return fmt.Sprintf("review does not exist [id: %d]", err.ID)
}
21 changes: 21 additions & 0 deletions models/fixtures/comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,24 @@
issue_id: 1 # in repo_id 1
content: "meh..."
created_unix: 946684812
-
id: 4
type: 21 # code comment
poster_id: 1
issue_id: 2
content: "meh..."
review_id: 4
line: 4
tree_path: "README.md"
created_unix: 946684812
invalidated: false
-
id: 5
type: 21 # code comment
poster_id: 1
issue_id: 2
content: "meh..."
line: -4
tree_path: "README.md"
created_unix: 946684812
invalidated: false
32 changes: 32 additions & 0 deletions models/fixtures/review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
-
id: 1
type: 1
reviewer_id: 1
issue_id: 2
content: "Demo Review"
updated_unix: 946684810
created_unix: 946684810
-
id: 2
type: 1
reviewer_id: 534543
issue_id: 534543
content: "Invalid Review #1"
updated_unix: 946684810
created_unix: 946684810
-
id: 3
type: 1
reviewer_id: 1
issue_id: 343545
content: "Invalid Review #2"
updated_unix: 946684810
created_unix: 946684810
-
id: 4
type: 0 # Pending review
reviewer_id: 1
issue_id: 2
content: "Pending Review"
updated_unix: 946684810
created_unix: 946684810
206 changes: 195 additions & 11 deletions models/git_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import (
"io/ioutil"
"os"
"os/exec"
"regexp"
"sort"
"strconv"
"strings"

Expand Down Expand Up @@ -57,13 +59,27 @@ type DiffLine struct {
RightIdx int
Type DiffLineType
Content string
Comments []*Comment
}

// GetType returns the type of a DiffLine.
func (d *DiffLine) GetType() int {
return int(d.Type)
}

// CanComment returns whether or not a line can get commented
func (d *DiffLine) CanComment() bool {
return len(d.Comments) == 0 && d.Type != DiffLineSection
}

// GetCommentSide returns the comment side of the first comment, if not set returns empty string
func (d *DiffLine) GetCommentSide() string {
if len(d.Comments) == 0 {
return ""
}
return d.Comments[0].DiffSide()
}

// DiffSection represents a section of a DiffFile.
type DiffSection struct {
Name string
Expand Down Expand Up @@ -225,11 +241,167 @@ type Diff struct {
IsIncomplete bool
}

// LoadComments loads comments into each line
func (diff *Diff) LoadComments(issue *Issue, currentUser *User) error {
allComments, err := FetchCodeComments(issue, currentUser)
if err != nil {
return err
}
for _, file := range diff.Files {
if lineCommits, ok := allComments[file.Name]; ok {
for _, section := range file.Sections {
for _, line := range section.Lines {
if comments, ok := lineCommits[int64(line.LeftIdx*-1)]; ok {
Copy link
Contributor

Choose a reason for hiding this comment

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

I find the next lines a bit confusing, might want to add a comment.

  • Why is LeftIDX multuiplied by -1?
  • Why is the LeftIdx comment replaced an the RightIdx one appended?

Copy link
Member

Choose a reason for hiding this comment

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

Why is LeftIdx multiplied by -1?

Because we differentiate between "previous" and "proposed" lines. "Previous" lines are negative and "proposed" lines are positive. This is documented at the comment model.

Why is the LeftIdx comment replaced an the RightIdx one appended?

Both should be appended. I will fix it.

line.Comments = append(line.Comments, comments...)
}
if comments, ok := lineCommits[int64(line.RightIdx)]; ok {
line.Comments = append(line.Comments, comments...)
}
sort.SliceStable(line.Comments, func(i, j int) bool {
return line.Comments[i].CreatedUnix < line.Comments[j].CreatedUnix
})
}
}
}
}
return nil
}

// NumFiles returns number of files changes in a diff.
func (diff *Diff) NumFiles() int {
return len(diff.Files)
}

// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
var hunkRegex = regexp.MustCompile(`^@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@`)

func isHeader(lof string) bool {
return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++")
}

// CutDiffAroundLine cuts a diff of a file in way that only the given line + numberOfLine above it will be shown
// it also recalculates hunks and adds the appropriate headers to the new diff.
// Warning: Only one-file diffs are allowed.
func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) string {
if line == 0 || numbersOfLine == 0 {
// no line or num of lines => no diff
return ""
}
scanner := bufio.NewScanner(originalDiff)
hunk := make([]string, 0)
// begin is the start of the hunk containing searched line
// end is the end of the hunk ...
// currentLine is the line number on the side of the searched line (differentiated by old)
// otherLine is the line number on the opposite side of the searched line (differentiated by old)
var begin, end, currentLine, otherLine int64
var headerLines int
for scanner.Scan() {
lof := scanner.Text()
// Add header to enable parsing
if isHeader(lof) {
hunk = append(hunk, lof)
headerLines++
}
if currentLine > line {
break
}
// Detect "hunk" with contains commented lof
if strings.HasPrefix(lof, "@@") {
// Already got our hunk. End of hunk detected!
if len(hunk) > headerLines {
break
}
groups := hunkRegex.FindStringSubmatch(lof)
if old {
begin = com.StrTo(groups[1]).MustInt64()
end = com.StrTo(groups[2]).MustInt64()
// init otherLine with begin of opposite side
otherLine = com.StrTo(groups[3]).MustInt64()
} else {
begin = com.StrTo(groups[3]).MustInt64()
end = com.StrTo(groups[4]).MustInt64()
// init otherLine with begin of opposite side
otherLine = com.StrTo(groups[1]).MustInt64()
}
end += begin // end is for real only the number of lines in hunk
// lof is between begin and end
if begin <= line && end >= line {
hunk = append(hunk, lof)
currentLine = begin
continue
}
} else if len(hunk) > headerLines {
hunk = append(hunk, lof)
// Count lines in context
switch lof[0] {
case '+':
if !old {
currentLine++
} else {
otherLine++
}
case '-':
if old {
currentLine++
} else {
otherLine++
}
default:
currentLine++
otherLine++
}
}
}

// No hunk found
if currentLine == 0 {
return ""
}
// headerLines + hunkLine (1) = totalNonCodeLines
if len(hunk)-headerLines-1 <= numbersOfLine {
// No need to cut the hunk => return existing hunk
return strings.Join(hunk, "\n")
}
var oldBegin, oldNumOfLines, newBegin, newNumOfLines int64
if old {
oldBegin = currentLine
newBegin = otherLine
} else {
oldBegin = otherLine
newBegin = currentLine
}
// headers + hunk header
newHunk := make([]string, headerLines)
// transfer existing headers
for idx, lof := range hunk[:headerLines] {
newHunk[idx] = lof
}
// transfer last n lines
for _, lof := range hunk[len(hunk)-numbersOfLine-1:] {
newHunk = append(newHunk, lof)
}
// calculate newBegin, ... by counting lines
for i := len(hunk) - 1; i >= len(hunk)-numbersOfLine; i-- {
switch hunk[i][0] {
case '+':
newBegin--
newNumOfLines++
case '-':
oldBegin--
oldNumOfLines++
default:
oldBegin--
newBegin--
newNumOfLines++
oldNumOfLines++
}
}
// construct the new hunk header
newHunk[headerLines] = fmt.Sprintf("@@ -%d,%d +%d,%d @@",
oldBegin, oldNumOfLines, newBegin, newNumOfLines)
return strings.Join(newHunk, "\n")
}

const cmdDiffHead = "diff --git "

// ParsePatch builds a Diff object from a io.Reader and some
Expand Down Expand Up @@ -307,7 +479,6 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
}

switch {
case line[0] == ' ':
diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
Expand Down Expand Up @@ -524,32 +695,46 @@ const (
// GetRawDiff dumps diff results of repository in given commit ID to io.Writer.
// TODO: move this function to gogits/git-module
func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Writer) error {
return GetRawDiffForFile(repoPath, "", commitID, diffType, "", writer)
}

// GetRawDiffForFile dumps diff results of file in given commit ID to io.Writer.
// TODO: move this function to gogits/git-module
func GetRawDiffForFile(repoPath, startCommit, endCommit string, diffType RawDiffType, file string, writer io.Writer) error {
repo, err := git.OpenRepository(repoPath)
if err != nil {
return fmt.Errorf("OpenRepository: %v", err)
}

commit, err := repo.GetCommit(commitID)
commit, err := repo.GetCommit(endCommit)
if err != nil {
return fmt.Errorf("GetCommit: %v", err)
}

fileArgs := make([]string, 0)
if len(file) > 0 {
fileArgs = append(fileArgs, "--", file)
}
var cmd *exec.Cmd
switch diffType {
case RawDiffNormal:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "show", commitID)
if len(startCommit) != 0 {
cmd = exec.Command("git", append([]string{"diff", "-M", startCommit, endCommit}, fileArgs...)...)
} else if commit.ParentCount() == 0 {
cmd = exec.Command("git", append([]string{"show", endCommit}, fileArgs...)...)
} else {
c, _ := commit.Parent(0)
cmd = exec.Command("git", "diff", "-M", c.ID.String(), commitID)
cmd = exec.Command("git", append([]string{"diff", "-M", c.ID.String(), endCommit}, fileArgs...)...)
}
case RawDiffPatch:
if commit.ParentCount() == 0 {
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", "--root", commitID)
if len(startCommit) != 0 {
query := fmt.Sprintf("%s...%s", endCommit, startCommit)
cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", "--root", query}, fileArgs...)...)
} else if commit.ParentCount() == 0 {
cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", "--root", endCommit}, fileArgs...)...)
} else {
c, _ := commit.Parent(0)
query := fmt.Sprintf("%s...%s", commitID, c.ID.String())
cmd = exec.Command("git", "format-patch", "--no-signature", "--stdout", query)
query := fmt.Sprintf("%s...%s", endCommit, c.ID.String())
cmd = exec.Command("git", append([]string{"format-patch", "--no-signature", "--stdout", query}, fileArgs...)...)
}
default:
return fmt.Errorf("invalid diffType: %s", diffType)
Expand All @@ -560,7 +745,6 @@ func GetRawDiff(repoPath, commitID string, diffType RawDiffType, writer io.Write
cmd.Dir = repoPath
cmd.Stdout = writer
cmd.Stderr = stderr

if err = cmd.Run(); err != nil {
return fmt.Errorf("Run: %v - %s", err, stderr)
}
Expand Down
Loading