cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.13.0

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/git/git.go

136lines · modecode

1package git
2
3import (
4 "bufio"
5 "bytes"
6 "fmt"
7 "os/exec"
8 "strconv"
9 "strings"
10
11 "github.com/rs/zerolog/log"
12)
13
14type LineBlame struct {
15 Filename string
16 Line int
17 Commit string
18}
19
20type LineBlames []LineBlame
21
22func (lbs LineBlames) GetCommit(line int) string {
23 for _, lb := range lbs {
24 if lb.Line == line {
25 return lb.Commit
26 }
27 }
28 return ""
29}
30
31type FileBlames map[string]LineBlames
32
33type CommandRunner func(args ...string) ([]byte, error)
34
35func RunGit(args ...string) (content []byte, err error) {
36 log.Debug().Strs("args", args).Msg("Running git command")
37 content, err = exec.Command("git", args...).Output()
38 return content, err
39}
40
41func Blame(path string, cmd CommandRunner) (lines LineBlames, err error) {
42 output, err := cmd("blame", "--line-porcelain", "--", path)
43 if err != nil {
44 return nil, err
45 }
46
47 buf := bytes.NewReader(output)
48 scanner := bufio.NewScanner(buf)
49 var line string
50 var cl LineBlame
51 for scanner.Scan() {
52 line = scanner.Text()
53
54 if strings.HasPrefix(line, "author") {
55 continue
56 } else if strings.HasPrefix(line, "committer") {
57 continue
58 } else if strings.HasPrefix(line, "summary") {
59 continue
60 } else if strings.HasPrefix(line, "filename") {
61 cl.Filename = strings.Split(line, " ")[1]
62 } else if strings.HasPrefix(line, "previous") {
63 continue
64 } else if strings.HasPrefix(line, "boundary") {
65 continue
66 } else if strings.HasPrefix(line, "\t") {
67 if cl.Filename == path {
68 lines = append(lines, cl)
69 }
70 } else {
71 parts := strings.Split(line, " ")
72 if len(parts) < 3 {
73 return nil, fmt.Errorf("failed to parse line number from line: %q", line)
74 }
75 cl.Commit = parts[0]
76 cl.Line, err = strconv.Atoi(parts[2])
77 if err != nil {
78 return nil, fmt.Errorf("failed to parse line number from %q: %w", line, err)
79 }
80 }
81 }
82 if err = scanner.Err(); err != nil {
83 return nil, err
84 }
85
86 return lines, nil
87}
88
89func HeadCommit(cmd CommandRunner) (string, error) {
90 commit, err := cmd("rev-parse", "--verify", "HEAD")
91 if err != nil {
92 return "", err
93 }
94 return strings.Trim(string(commit), "\n"), nil
95}
96
97type CommitRangeResults struct {
98 From string
99 To string
100}
101
102func (gcr CommitRangeResults) String() string {
103 return fmt.Sprintf("%s^..%s", gcr.From, gcr.To)
104}
105
106func CommitRange(cmd CommandRunner, baseBranch string) (cr CommitRangeResults, err error) {
107 out, err := cmd("log", "--format=%H", "--no-abbrev-commit", "--reverse", fmt.Sprintf("%s..HEAD", baseBranch))
108 if err != nil {
109 return cr, err
110 }
111
112 lines := []string{}
113 for _, line := range strings.Split(strings.TrimSuffix(string(out), "\n"), "\n") {
114 if line != "" {
115 lines = append(lines, line)
116 log.Debug().Str("commit", line).Msg("Found commit to scan")
117 }
118 }
119
120 if len(lines) == 0 {
121 return cr, fmt.Errorf("empty commit range")
122 }
123
124 cr.From = lines[0]
125 cr.To = lines[len(lines)-1]
126
127 return
128}
129
130func CurrentBranch(cmd CommandRunner) (string, error) {
131 commit, err := cmd("rev-parse", "--abbrev-ref", "HEAD")
132 if err != nil {
133 return "", err
134 }
135 return strings.Trim(string(commit), "\n"), nil
136}
137