cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.7.2

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/git/git.go

136lines · modeblame

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