@@ -14,14 +14,6 @@ import (
1414 "github.com/rs/zerolog/log"
1515)
1616
17- type GitCloneError struct {
18- msg string
19- }
20-
21- func (e * GitCloneError ) Error () string {
22- return e .msg
23- }
24-
2517type GitClient struct {
2618 Command GitCommand
2719}
@@ -38,19 +30,100 @@ type GitCommand interface {
3830 ReadFile (path string ) ([]byte , error )
3931}
4032
33+ type GitError interface {
34+ error
35+ Command () string
36+ }
37+
38+ type GitCommandError struct {
39+ CommandStr string
40+ Err error
41+ }
42+
43+ func (e * GitCommandError ) Error () string {
44+ return fmt .Sprintf ("error running command `%s`: %v" , e .CommandStr , e .Err )
45+ }
46+
47+ func (e * GitCommandError ) Unwrap () error {
48+ return e .Err
49+ }
50+
51+ func (e * GitCommandError ) Command () string {
52+ return e .CommandStr
53+ }
54+
55+ type GitExitError struct {
56+ CommandStr string
57+ Stderr string
58+ ExitCode int
59+ Err error
60+ }
61+
62+ func (e * GitExitError ) Error () string {
63+ return fmt .Sprintf ("command `%s` failed with exit code %d: %v, stderr: %s" , e .CommandStr , e .ExitCode , e .Err , e .Stderr )
64+ }
65+
66+ func (e * GitExitError ) Unwrap () error {
67+ return e .Err
68+ }
69+
70+ func (e * GitExitError ) Command () string {
71+ return e .CommandStr
72+ }
73+
74+ type GitNotFoundError struct {
75+ CommandStr string
76+ }
77+
78+ func (e * GitNotFoundError ) Error () string {
79+ return fmt .Sprintf ("git binary not found for command `%s`. Please ensure Git is installed and available in your PATH." , e .CommandStr )
80+ }
81+
82+ func (e * GitNotFoundError ) Command () string {
83+ return e .CommandStr
84+ }
85+
4186type ExecGitCommand struct {}
4287
4388func (g * ExecGitCommand ) Run (ctx context.Context , cmd string , args []string , dir string ) ([]byte , error ) {
4489 command := exec .CommandContext (ctx , cmd , args ... )
4590 command .Dir = dir
46- stdout , err := command .Output ()
91+ var stdout , stderr strings.Builder
92+ command .Stdout = & stdout
93+ command .Stderr = & stderr
94+
95+ err := command .Run ()
4796 if err != nil {
48- if exitErr , ok := err .(* exec.ExitError ); ok {
49- return nil , fmt .Errorf ("command `%s` returned an error: %w stderr: %s" , command .String (), err , string (bytes .TrimSpace (exitErr .Stderr )))
97+ var execErr * exec.Error
98+ if errors .As (err , & execErr ) && errors .Is (execErr .Err , exec .ErrNotFound ) {
99+ return nil , & GitNotFoundError {
100+ CommandStr : command .String (),
101+ }
102+ }
103+
104+ var exitErr * exec.ExitError
105+ if errors .As (err , & exitErr ) {
106+ exitCode := exitErr .ExitCode ()
107+ stderrMsg := strings .TrimSpace (stderr .String ())
108+
109+ if stderrMsg == "" {
110+ stderrMsg = exitErr .Error ()
111+ }
112+
113+ return nil , & GitExitError {
114+ CommandStr : command .String (),
115+ Stderr : stderrMsg ,
116+ ExitCode : exitCode ,
117+ Err : exitErr ,
118+ }
119+ }
120+ return nil , & GitCommandError {
121+ CommandStr : command .String (),
122+ Err : err ,
50123 }
51- return nil , fmt .Errorf ("error running command: %w" , err )
52124 }
53- return stdout , nil
125+
126+ return []byte (stdout .String ()), nil
54127}
55128
56129func (g * ExecGitCommand ) ReadFile (path string ) ([]byte , error ) {
@@ -160,15 +233,42 @@ type LocalGitClient struct {
160233}
161234
162235func (g * LocalGitClient ) GetRemoteOriginURL (ctx context.Context , repoPath string ) (string , error ) {
163- return g .GitClient .GetRemoteOriginURL (ctx , repoPath )
236+ remoteOriginURL , err := g .GitClient .GetRemoteOriginURL (ctx , repoPath )
237+ if err != nil {
238+ var gitErr GitError
239+ if errors .As (err , & gitErr ) {
240+ log .Debug ().Err (err ).Msg ("failed to get remote origin URL for local repo" )
241+ return repoPath , nil
242+ }
243+ return "" , err
244+ }
245+ return remoteOriginURL , nil
164246}
165247
166248func (g * LocalGitClient ) LastCommitDate (ctx context.Context , clonePath string ) (time.Time , error ) {
167- return g .GitClient .LastCommitDate (ctx , clonePath )
249+ lastCommitDate , err := g .GitClient .LastCommitDate (ctx , clonePath )
250+ if err != nil {
251+ var gitErr GitError
252+ if errors .As (err , & gitErr ) {
253+ log .Debug ().Err (err ).Msg ("failed to get last commit date for local repo" )
254+ return time .Now (), nil
255+ }
256+ return time.Time {}, err
257+ }
258+ return lastCommitDate , nil
168259}
169260
170261func (g * LocalGitClient ) CommitSHA (clonePath string ) (string , error ) {
171- return g .GitClient .CommitSHA (clonePath )
262+ commitSHA , err := g .GitClient .CommitSHA (clonePath )
263+ if err != nil {
264+ var gitErr GitError
265+ if errors .As (err , & gitErr ) {
266+ log .Debug ().Err (err ).Msg ("failed to get commit SHA for local repo" )
267+ return "" , nil
268+ }
269+ return "" , err
270+ }
271+ return commitSHA , nil
172272}
173273
174274func (g * LocalGitClient ) Clone (ctx context.Context , clonePath string , url string , token string , ref string ) error {
@@ -182,6 +282,11 @@ func (g *LocalGitClient) GetRepoHeadBranchName(ctx context.Context, repoPath str
182282
183283 output , err := g .GitClient .Command .Run (ctx , cmd , args , repoPath )
184284 if err != nil {
285+ var gitErr GitError
286+ if errors .As (err , & gitErr ) {
287+ log .Debug ().Err (err ).Msg ("failed to get repo head branch name for local repo" )
288+ return "local" , nil
289+ }
185290 return "" , err
186291 }
187292
0 commit comments