phase 3 initial completion
This commit is contained in:
@@ -169,6 +169,31 @@ func (h *RepoHandler) Commits(w http.ResponseWriter, r *http.Request) {
|
||||
jsonOK(w, commits)
|
||||
}
|
||||
|
||||
func (h *RepoHandler) Diff(w http.ResponseWriter, r *http.Request) {
|
||||
repo, ok := h.lookupRepo(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
base := r.URL.Query().Get("base")
|
||||
head := r.URL.Query().Get("head")
|
||||
if base == "" || head == "" {
|
||||
jsonError(w, "base and head query params are required", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
gitdomain.SetRepoRoot(h.cfg.RepoRoot)
|
||||
diffs, err := gitdomain.Diff(repo.DiskPath, base, head)
|
||||
if err != nil {
|
||||
jsonError(w, "could not compute diff", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if diffs == nil {
|
||||
diffs = []gitdomain.FileDiff{}
|
||||
}
|
||||
jsonOK(w, diffs)
|
||||
}
|
||||
|
||||
// lookupRepo resolves {owner}/{repo} URL params to a DB row, enforcing access.
|
||||
func (h *RepoHandler) lookupRepo(w http.ResponseWriter, r *http.Request) (*models.Repository, bool) {
|
||||
ownerName := chi.URLParam(r, "owner")
|
||||
|
||||
@@ -77,6 +77,7 @@ func New(cfg *config.Config, engine *xorm.Engine, store sessions.Store, staticFi
|
||||
r.Get("/tree", repoH.Tree)
|
||||
r.Get("/blob", repoH.Blob)
|
||||
r.Get("/commits", repoH.Commits)
|
||||
r.Get("/diff", repoH.Diff)
|
||||
r.Route("/pulls", func(r chi.Router) {
|
||||
r.Get("/", prH.List)
|
||||
r.With(csrf).Post("/", prH.Create)
|
||||
|
||||
@@ -138,3 +138,67 @@ func TreeLS(repoPath, ref, subPath string) ([]TreeEntry, error) {
|
||||
func BlobCat(repoPath, ref, filePath string) ([]byte, error) {
|
||||
return run(repoPath, "show", ref+":"+filePath)
|
||||
}
|
||||
|
||||
// FileDiff represents a single changed file in a diff.
|
||||
type FileDiff struct {
|
||||
Path string `json:"path"`
|
||||
OldPath string `json:"oldPath,omitempty"` // set on renames
|
||||
Additions int `json:"additions"`
|
||||
Deletions int `json:"deletions"`
|
||||
Patch string `json:"patch"` // unified diff hunk(s) for this file
|
||||
}
|
||||
|
||||
// Diff returns per-file diffs between two refs.
|
||||
func Diff(repoPath, base, head string) ([]FileDiff, error) {
|
||||
out, err := run(repoPath,
|
||||
"diff", "--unified=5", "--no-color",
|
||||
"--diff-filter=ACDMRT", // exclude untracked
|
||||
base+".."+head,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return parseUnifiedDiff(string(out)), nil
|
||||
}
|
||||
|
||||
// parseUnifiedDiff splits a multi-file unified diff into per-file FileDiff entries.
|
||||
func parseUnifiedDiff(raw string) []FileDiff {
|
||||
var files []FileDiff
|
||||
var cur *FileDiff
|
||||
var patchLines []string
|
||||
|
||||
commit := func() {
|
||||
if cur != nil {
|
||||
cur.Patch = strings.Join(patchLines, "\n")
|
||||
files = append(files, *cur)
|
||||
}
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(raw, "\n") {
|
||||
if strings.HasPrefix(line, "diff --git ") {
|
||||
commit()
|
||||
cur = &FileDiff{}
|
||||
patchLines = nil
|
||||
continue
|
||||
}
|
||||
if cur == nil {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case strings.HasPrefix(line, "--- a/"):
|
||||
cur.OldPath = strings.TrimPrefix(line, "--- a/")
|
||||
case strings.HasPrefix(line, "+++ b/"):
|
||||
cur.Path = strings.TrimPrefix(line, "+++ b/")
|
||||
case strings.HasPrefix(line, "+") && !strings.HasPrefix(line, "+++"):
|
||||
cur.Additions++
|
||||
patchLines = append(patchLines, line)
|
||||
case strings.HasPrefix(line, "-") && !strings.HasPrefix(line, "---"):
|
||||
cur.Deletions++
|
||||
patchLines = append(patchLines, line)
|
||||
default:
|
||||
patchLines = append(patchLines, line)
|
||||
}
|
||||
}
|
||||
commit()
|
||||
return files
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user