diff options
author | zeripath <art27@cantab.net> | 2021-07-02 20:23:37 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-07-02 21:23:37 +0200 |
commit | 62c278e4ab66090f48b7937717b28a657cab8688 (patch) | |
tree | 240da3c53d43d306f68ed2fe69d59c11dd6f32a7 /modules/git/commit.go | |
parent | 836884429ae6d08909f4f96fbe0f1ea288e7af12 (diff) | |
download | gitea-62c278e4ab66090f48b7937717b28a657cab8688.tar.gz gitea-62c278e4ab66090f48b7937717b28a657cab8688.zip |
Fix modified files list in webhooks when there is a space (#16288)
* Fix modified files list in webhooks when there is a space
There is an unfortunate bug with GetCommitFileStatus where files with
spaces are misparsed and split at the space.
There is a second bug because modern gits detect renames meaning that
this function no longer works correctly.
There is a third bug in that merge commits don't have their modified
files detected correctly.
Fix #15865
Signed-off-by: Andrew Thornton <art27@cantab.net>
Diffstat (limited to 'modules/git/commit.go')
-rw-r--r-- | modules/git/commit.go | 64 |
1 files changed, 46 insertions, 18 deletions
diff --git a/modules/git/commit.go b/modules/git/commit.go index f4d6075fe2..3ce2b03886 100644 --- a/modules/git/commit.go +++ b/modules/git/commit.go @@ -15,6 +15,8 @@ import ( "os/exec" "strconv" "strings" + + "code.gitea.io/gitea/modules/log" ) // Commit represents a git commit. @@ -432,33 +434,59 @@ func NewCommitFileStatus() *CommitFileStatus { } } +func parseCommitFileStatus(fileStatus *CommitFileStatus, stdout io.Reader) { + rd := bufio.NewReader(stdout) + peek, err := rd.Peek(1) + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + if peek[0] == '\n' || peek[0] == '\x00' { + _, _ = rd.Discard(1) + } + for { + modifier, err := rd.ReadSlice('\x00') + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + file, err := rd.ReadString('\x00') + if err != nil { + if err != io.EOF { + log.Error("Unexpected error whilst reading from git log --name-status. Error: %v", err) + } + return + } + file = file[:len(file)-1] + switch modifier[0] { + case 'A': + fileStatus.Added = append(fileStatus.Added, file) + case 'D': + fileStatus.Removed = append(fileStatus.Removed, file) + case 'M': + fileStatus.Modified = append(fileStatus.Modified, file) + } + } +} + // GetCommitFileStatus returns file status of commit in given repository. func GetCommitFileStatus(repoPath, commitID string) (*CommitFileStatus, error) { stdout, w := io.Pipe() done := make(chan struct{}) fileStatus := NewCommitFileStatus() go func() { - scanner := bufio.NewScanner(stdout) - for scanner.Scan() { - fields := strings.Fields(scanner.Text()) - if len(fields) < 2 { - continue - } - - switch fields[0][0] { - case 'A': - fileStatus.Added = append(fileStatus.Added, fields[1]) - case 'D': - fileStatus.Removed = append(fileStatus.Removed, fields[1]) - case 'M': - fileStatus.Modified = append(fileStatus.Modified, fields[1]) - } - } - done <- struct{}{} + parseCommitFileStatus(fileStatus, stdout) + close(done) }() stderr := new(bytes.Buffer) - err := NewCommand("show", "--name-status", "--pretty=format:''", commitID).RunInDirPipeline(repoPath, w, stderr) + args := []string{"log", "--name-status", "-c", "--pretty=format:", "--parents", "--no-renames", "-z", "-1", commitID} + + err := NewCommand(args...).RunInDirPipeline(repoPath, w, stderr) w.Close() // Close writer to exit parsing goroutine if err != nil { return nil, ConcatenateError(err, stderr.String()) |