cloudflare/pint

Public

mirrored fromhttps://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.75.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/git/git.go

115lines · modecode

1package git
2
3import (
4 "bufio"
5 "bytes"
6 "errors"
7 "fmt"
8 "log/slog"
9 "os/exec"
10 "strconv"
11 "strings"
12)
13
14type LineBlame struct {
15 Filename string
16 Commit string
17 PrevLine int
18 Line int
19}
20
21type LineBlames []LineBlame
22
23type FileBlames map[string]LineBlames
24
25type CommandRunner func(args ...string) ([]byte, error)
26
27func RunGit(args ...string) (content []byte, err error) {
28 slog.Debug("Running git command", slog.Any("args", args))
29 cmd := exec.Command("git", args...)
30 var stdout, stderr bytes.Buffer
31 cmd.Stdout = &stdout
32 cmd.Stderr = &stderr
33 if err = cmd.Run(); err != nil {
34 if stderr.Len() > 0 {
35 return nil, errors.New(stderr.String())
36 }
37 return nil, err
38 }
39 return stdout.Bytes(), nil
40}
41
42func Blame(cmd CommandRunner, path, commit string) (lines LineBlames, err error) {
43 slog.Debug("Running git blame", slog.String("path", path))
44 output, err := cmd("blame", "--line-porcelain", commit, "--", path)
45 if err != nil {
46 return nil, err
47 }
48
49 buf := bytes.NewReader(output)
50 scanner := bufio.NewScanner(buf)
51 var line string
52 var cl LineBlame
53 for scanner.Scan() {
54 line = scanner.Text()
55
56 switch {
57 case strings.HasPrefix(line, "author"):
58 continue
59 case strings.HasPrefix(line, "committer"):
60 continue
61 case strings.HasPrefix(line, "summary"):
62 continue
63 case strings.HasPrefix(line, "filename"):
64 cl.Filename = strings.Split(line, " ")[1]
65 case strings.HasPrefix(line, "previous"):
66 continue
67 case strings.HasPrefix(line, "boundary"):
68 continue
69 case strings.HasPrefix(line, "\t"):
70 lines = append(lines, cl)
71 cl.PrevLine = 0
72 default:
73 parts := strings.Split(line, " ")
74 if len(parts) < 3 {
75 return nil, fmt.Errorf("failed to parse line number from line: %q", line)
76 }
77 cl.Commit = parts[0]
78 if cl.PrevLine, err = strconv.Atoi(parts[1]); err != nil {
79 return nil, fmt.Errorf("failed to parse line number from %q: %w", line, err)
80 }
81 if cl.Line, err = strconv.Atoi(parts[2]); err != nil {
82 return nil, fmt.Errorf("failed to parse line number from %q: %w", line, err)
83 }
84 }
85 }
86 if err = scanner.Err(); err != nil {
87 return nil, err
88 }
89
90 return lines, nil
91}
92
93func HeadCommit(cmd CommandRunner) (string, error) {
94 commit, err := cmd("rev-parse", "--verify", "HEAD")
95 if err != nil {
96 return "", err
97 }
98 return strings.Trim(string(commit), "\n"), nil
99}
100
101func CurrentBranch(cmd CommandRunner) (string, error) {
102 commit, err := cmd("rev-parse", "--abbrev-ref", "HEAD")
103 if err != nil {
104 return "", err
105 }
106 return strings.Trim(string(commit), "\n"), nil
107}
108
109func CommitMessage(cmd CommandRunner, sha string) (string, error) {
110 msg, err := cmd("show", "-s", "--format=%B", sha)
111 if err != nil {
112 return "", err
113 }
114 return string(msg), err
115}
116