0
0
mirror of https://github.com/go-gitea/gitea.git synced 2025-11-08 01:10:48 +01:00

Add inline diff in repos/pulls/files api

Add the inline diff on a per file basis to be compatible with GitHub

Example:

```
curl http://localhost:3000/api/v1/repos/cedstrom/test/pulls/1/files?token=[redacted]
```

```
[
    {
        "filename": ".gitignore",
        "status": "added",
        "additions": 2,
        "deletions": 0,
        "changes": 2,
        "html_url": "ce2c532233/.gitignore",
        "contents_url": "http://localhost:3000/api/v1/repos/cedstrom/test/contents/.gitignore?ref=ce2c53223388eaaa026c25156b807e30acc05a56",
        "raw_url": "ce2c532233/.gitignore",
        "patch": "diff --git a/.gitignore b/.gitignore\n--- a/.gitignore\n+++ b/.gitignore\n@@ -0,1 +1,2 @@\n @@ -0,0 +1,2 @@\n++.env\n++.env.local\n\n"
    },
    {
        "filename": "README.md",
        "status": "changed",
        "additions": 1,
        "deletions": 0,
        "changes": 1,
        "html_url": "ce2c532233/README.md",
        "contents_url": "http://localhost:3000/api/v1/repos/cedstrom/test/contents/README.md?ref=ce2c53223388eaaa026c25156b807e30acc05a56",
        "raw_url": "ce2c532233/README.md",
        "patch": "diff --git a/README.md b/README.md\n--- a/README.md\n+++ b/README.md\n@@ -1,2 +1,3 @@\n @@ -1,2 +1,3 @@\n  # test\n  \n++This is my first PR.\n\n"
    }
]
```
This commit is contained in:
Chris Edstrom 2025-10-10 17:22:08 +00:00
parent 165a3ead52
commit b906cd6381
4 changed files with 90 additions and 0 deletions

View File

@ -188,4 +188,6 @@ type ChangedFile struct {
ContentsURL string `json:"contents_url,omitempty"`
// The raw URL to download the file
RawURL string `json:"raw_url,omitempty"`
// The patch text for the file changes
Patch string `json:"patch,omitempty"`
}

View File

@ -812,6 +812,7 @@ func ToChangedFile(f *gitdiff.DiffFile, repo *repo_model.Repository, commit stri
HTMLURL: fmt.Sprint(repo.HTMLURL(), "/src/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
ContentsURL: fmt.Sprint(repo.APIURL(), "/contents/", util.PathEscapeSegments(f.GetDiffFileName()), "?ref=", commit),
RawURL: fmt.Sprint(repo.HTMLURL(), "/raw/commit/", commit, "/", util.PathEscapeSegments(f.GetDiffFileName())),
Patch: gitdiff.RenderUnifiedDiff(f),
}
return file

View File

@ -1058,6 +1058,88 @@ func createDiffFile(line string) *DiffFile {
return curFile
}
func RenderUnifiedDiff(file *DiffFile) string {
var sb strings.Builder
oldPath := file.OldName
if oldPath == "" {
oldPath = file.Name
}
newPath := file.Name
// File header
fmt.Fprintf(&sb, "diff --git a/%s b/%s\n", oldPath, newPath)
fmt.Fprintf(&sb, "--- a/%s\n", oldPath)
fmt.Fprintf(&sb, "+++ b/%s\n", newPath)
if file.IsBin {
return ("Binary files differ\n\n")
}
for _, section := range file.Sections {
// Compute hunk header
leftStart, leftCount := hunkRange(section, true)
rightStart, rightCount := hunkRange(section, false)
fmt.Fprintf(&sb, "@@ -%d,%d +%d,%d @@\n", leftStart, leftCount, rightStart, rightCount)
for _, line := range section.Lines {
prefix := " "
switch line.Type {
case DiffLineAdd:
prefix = "+"
case DiffLineDel:
prefix = "-"
}
sb.WriteString(prefix + line.Content)
if !strings.HasSuffix(line.Content, "\n") {
sb.WriteString("\n")
}
}
}
sb.WriteString("\n")
return sb.String()
}
// hunkRange calculates the start and length for either old or new file in a section
func hunkRange(section *DiffSection, left bool) (start, count int) {
lines := section.Lines
if len(lines) == 0 {
return 0, 0
}
if left {
for _, l := range lines {
if l.LeftIdx > 0 {
start = l.LeftIdx
break
}
}
for _, l := range lines {
if l.LeftIdx > 0 {
count++
}
}
} else {
for _, l := range lines {
if l.RightIdx > 0 {
start = l.RightIdx
break
}
}
for _, l := range lines {
if l.RightIdx > 0 {
count++
}
}
}
if count == 0 {
count = 1
}
return start, count
}
func readFileName(rd *strings.Reader) (string, bool) {
ambiguity := false
var name string

View File

@ -22121,6 +22121,11 @@
"type": "string",
"x-go-name": "HTMLURL"
},
"patch": {
"description": "The patch text for the file changes",
"type": "string",
"x-go-name": "Patch"
},
"previous_filename": {
"description": "The previous filename if the file was renamed",
"type": "string",