163 lines
3.4 KiB
Go
163 lines
3.4 KiB
Go
package gitcmd
|
|
|
|
import (
|
|
"bytes"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type Commit struct {
|
|
ID string `json:"id"`
|
|
ShortSHA string `json:"short_sha"`
|
|
Message string `json:"message"`
|
|
Author string `json:"author"`
|
|
AuthorEmail string `json:"author_email"`
|
|
When time.Time `json:"when"`
|
|
Parents []string `json:"parents"`
|
|
}
|
|
|
|
type CommitDetail struct {
|
|
Commit
|
|
Stats DiffStats `json:"stats"`
|
|
Files []FileDiff `json:"files"`
|
|
}
|
|
|
|
type DiffStats struct {
|
|
Additions int `json:"additions"`
|
|
Deletions int `json:"deletions"`
|
|
Total int `json:"total"`
|
|
Files int `json:"files"`
|
|
}
|
|
|
|
type FileDiff struct {
|
|
Path string `json:"path"`
|
|
Additions int `json:"additions"`
|
|
Deletions int `json:"deletions"`
|
|
Status string `json:"status"`
|
|
}
|
|
|
|
func (r *Repository) GetCommit(ref string) (*Commit, error) {
|
|
out, _, err := NewCommand("show", "-s").
|
|
Add("--format=%H%x1f%h%x1f%s%x1f%an%x1f%ae%x1f%aI%x1f%P").
|
|
AddDynamicArguments(ref).
|
|
WithDir(r.Path).
|
|
RunStdString(r.ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return parseCommitLine(strings.TrimSpace(out)), nil
|
|
}
|
|
|
|
func (r *Repository) ListCommits(ref string, limit int) ([]Commit, error) {
|
|
|
|
if empty, err := r.IsEmpty(); err != nil {
|
|
return nil, err
|
|
} else if empty {
|
|
return []Commit{}, nil
|
|
}
|
|
|
|
cmd := NewCommand("log").
|
|
Add("--format=%H%x1f%h%x1f%s%x1f%an%x1f%ae%x1f%aI%x1f%P").
|
|
WithDir(r.Path)
|
|
if limit > 0 {
|
|
cmd.Add("-n", strconv.Itoa(limit))
|
|
}
|
|
cmd.AddDynamicArguments(ref)
|
|
|
|
out, _, err := cmd.RunStdString(r.ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var commits []Commit
|
|
for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
commits = append(commits, *parseCommitLine(line))
|
|
}
|
|
return commits, nil
|
|
}
|
|
|
|
func (r *Repository) GetCommitDetail(sha string) (*CommitDetail, error) {
|
|
commit, err := r.GetCommit(sha)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
out, _, err := NewCommand("show", "--numstat", "--format=").
|
|
AddDynamicArguments(sha).
|
|
WithDir(r.Path).
|
|
RunStdString(r.ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var files []FileDiff
|
|
var totalAdd, totalDel int
|
|
|
|
for _, line := range strings.Split(strings.TrimSpace(out), "\n") {
|
|
if line == "" {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(line, "\t", 3)
|
|
if len(parts) < 3 {
|
|
continue
|
|
}
|
|
add, _ := strconv.Atoi(parts[0])
|
|
del, _ := strconv.Atoi(parts[1])
|
|
path := parts[2]
|
|
|
|
status := "M"
|
|
if add == 0 && del > 0 {
|
|
status = "D"
|
|
} else if del == 0 && add > 0 {
|
|
status = "A"
|
|
}
|
|
|
|
files = append(files, FileDiff{
|
|
Path: path,
|
|
Additions: add,
|
|
Deletions: del,
|
|
Status: status,
|
|
})
|
|
totalAdd += add
|
|
totalDel += del
|
|
}
|
|
|
|
return &CommitDetail{
|
|
Commit: *commit,
|
|
Stats: DiffStats{
|
|
Additions: totalAdd,
|
|
Deletions: totalDel,
|
|
Total: totalAdd + totalDel,
|
|
Files: len(files),
|
|
},
|
|
Files: files,
|
|
}, nil
|
|
}
|
|
|
|
func parseCommitLine(line string) *Commit {
|
|
fields := bytes.SplitN([]byte(line), []byte{0x1f}, 7)
|
|
if len(fields) < 6 {
|
|
return &Commit{Message: line}
|
|
}
|
|
|
|
when, _ := time.Parse(time.RFC3339, string(fields[5]))
|
|
parents := []string{}
|
|
if len(fields) >= 7 && len(fields[6]) > 0 {
|
|
parents = strings.Fields(string(fields[6]))
|
|
}
|
|
|
|
return &Commit{
|
|
ID: string(fields[0]),
|
|
ShortSHA: string(fields[1]),
|
|
Message: string(fields[2]),
|
|
Author: string(fields[3]),
|
|
AuthorEmail: string(fields[4]),
|
|
When: when,
|
|
Parents: parents,
|
|
}
|
|
}
|