@@ -2,19 +2,21 @@ package github
2
2
3
3
import (
4
4
"context"
5
- "errors"
6
5
"fmt"
7
6
"os"
8
7
"path/filepath"
9
8
"strings"
9
+ "time"
10
10
11
+ "github.com/cenkalti/backoff/v4"
11
12
"github.com/go-git/go-git/v5"
12
13
"github.com/go-git/go-git/v5/plumbing"
13
14
"github.com/go-git/go-git/v5/plumbing/protocol/packp/sideband"
14
15
githttp "github.com/go-git/go-git/v5/plumbing/transport/http"
15
16
gogithub "github.com/google/go-github/v49/github"
16
17
"github.com/rs/zerolog/log"
17
18
zgit "github.com/zapier/tfbuddy/pkg/git"
19
+ "github.com/zapier/tfbuddy/pkg/utils"
18
20
"github.com/zapier/tfbuddy/pkg/vcs"
19
21
"golang.org/x/oauth2"
20
22
)
@@ -28,6 +30,14 @@ type Client struct {
28
30
token string
29
31
}
30
32
33
+ const DefaultMaxRetries = 3
34
+
35
+ func createBackOffWithRetries () backoff.BackOff {
36
+ exp := backoff .NewExponentialBackOff ()
37
+ exp .MaxElapsedTime = 30 * time .Second
38
+ return backoff .WithMaxRetries (exp , DefaultMaxRetries )
39
+
40
+ }
31
41
func NewGithubClient () * Client {
32
42
token := os .Getenv ("GITHUB_TOKEN" )
33
43
ctx := context .Background ()
@@ -78,17 +88,19 @@ func (c *Client) GetRepoFile(fullName string, file string, ref string) ([]byte,
78
88
if err != nil {
79
89
return nil , err
80
90
}
81
- fileContent , _ , _ , err := c .client .Repositories .GetContents (c .ctx , parts [0 ], parts [1 ], file , & gogithub.RepositoryContentGetOptions {Ref : ref })
82
- if err != nil {
83
- return nil , err
84
- }
91
+ return backoff .RetryWithData (func () ([]byte , error ) {
92
+ fileContent , _ , _ , err := c .client .Repositories .GetContents (c .ctx , parts [0 ], parts [1 ], file , & gogithub.RepositoryContentGetOptions {Ref : ref })
93
+ if err != nil {
94
+ return nil , utils .CreatePermanentError (err )
95
+ }
85
96
86
- contents , err := fileContent .GetContent ()
87
- if err != nil {
88
- return nil , err
89
- }
97
+ contents , err := fileContent .GetContent ()
98
+ if err != nil {
99
+ return nil , utils . CreatePermanentError ( err )
100
+ }
90
101
91
- return []byte (contents ), nil
102
+ return []byte (contents ), nil
103
+ }, createBackOffWithRetries ())
92
104
}
93
105
94
106
func (c * Client ) GetMergeRequestModifiedFiles (prID int , fullName string ) ([]string , error ) {
@@ -102,19 +114,21 @@ func (c *Client) GetMergeRequestModifiedFiles(prID int, fullName string) ([]stri
102
114
}
103
115
104
116
if pr .GetChangedFiles () > 0 {
105
- parts , err := splitFullName (fullName )
106
- if err != nil {
107
- return nil , err
108
- }
109
- files , _ , err := c .client .PullRequests .ListFiles (c .ctx , parts [0 ], parts [1 ], prID , & opts )
110
- if err != nil {
111
- return nil , err
112
- }
113
- modifiedFiles := make ([]string , len (files ))
114
- for i , file := range files {
115
- modifiedFiles [i ] = file .GetFilename ()
116
- }
117
- return modifiedFiles , nil
117
+ return backoff .RetryWithData (func () ([]string , error ) {
118
+ parts , err := splitFullName (fullName )
119
+ if err != nil {
120
+ return nil , utils .CreatePermanentError (err )
121
+ }
122
+ files , _ , err := c .client .PullRequests .ListFiles (c .ctx , parts [0 ], parts [1 ], prID , & opts )
123
+ if err != nil {
124
+ return nil , utils .CreatePermanentError (err )
125
+ }
126
+ modifiedFiles := make ([]string , len (files ))
127
+ for i , file := range files {
128
+ modifiedFiles [i ] = file .GetFilename ()
129
+ }
130
+ return modifiedFiles , nil
131
+ }, createBackOffWithRetries ())
118
132
}
119
133
return []string {}, nil
120
134
}
@@ -129,7 +143,7 @@ func (c *Client) CloneMergeRequest(project string, mr vcs.MR, dest string) (vcs.
129
143
130
144
repo , _ , err := c .client .Repositories .Get (context .Background (), parts [0 ], parts [1 ])
131
145
if err != nil {
132
- return nil , err
146
+ return nil , utils . CreatePermanentError ( err )
133
147
}
134
148
log .Debug ().Msg (* repo .CloneURL )
135
149
ref := plumbing .NewBranchReferenceName (mr .GetSourceBranch ())
@@ -208,50 +222,58 @@ func (c *Client) GetPipelinesForCommit(projectWithNS string, commitSHA string) (
208
222
func (c * Client ) GetIssue (owner * gogithub.User , repo string , issueId int ) (* gogithub.Issue , error ) {
209
223
owName , err := ResolveOwnerName (owner )
210
224
if err != nil {
211
- return nil , err
225
+ return nil , utils . CreatePermanentError ( err )
212
226
}
213
- iss , _ , err := c .client .Issues .Get (context .Background (), owName , repo , issueId )
214
- return iss , err
227
+ return backoff .RetryWithData (func () (* gogithub.Issue , error ) {
228
+ iss , _ , err := c .client .Issues .Get (context .Background (), owName , repo , issueId )
229
+ return iss , utils .CreatePermanentError (err )
230
+ }, createBackOffWithRetries ())
215
231
}
216
232
217
233
func (c * Client ) GetPullRequest (fullName string , prID int ) (* GithubPR , error ) {
218
234
parts , err := splitFullName (fullName )
219
235
if err != nil {
220
236
return nil , err
221
237
}
222
- pr , _ , err := c .client .PullRequests .Get (c .ctx , parts [0 ], parts [1 ], prID )
223
- return & GithubPR {pr }, err
238
+ return backoff .RetryWithData (func () (* GithubPR , error ) {
239
+ pr , _ , err := c .client .PullRequests .Get (c .ctx , parts [0 ], parts [1 ], prID )
240
+ return & GithubPR {pr }, utils .CreatePermanentError (err )
241
+ }, createBackOffWithRetries ())
224
242
}
225
243
226
244
// PostIssueComment adds a comment to an existing Pull Request
227
245
func (c * Client ) PostIssueComment (prId int , fullName string , body string ) (* gogithub.IssueComment , error ) {
228
246
projectParts , err := splitFullName (fullName )
229
247
if err != nil {
230
- return nil , err
231
- }
232
- comment := & gogithub.IssueComment {
233
- Body : String (body ),
234
- }
235
- iss , _ , err := c .client .Issues .CreateComment (context .Background (), projectParts [0 ], projectParts [1 ], prId , comment )
236
- if err != nil {
237
- log .Error ().Err (err ).Msg ("github client: could not post issue comment" )
248
+ return nil , utils .CreatePermanentError (err )
238
249
}
250
+ return backoff .RetryWithData (func () (* gogithub.IssueComment , error ) {
251
+ comment := & gogithub.IssueComment {
252
+ Body : String (body ),
253
+ }
254
+ iss , _ , err := c .client .Issues .CreateComment (context .Background (), projectParts [0 ], projectParts [1 ], prId , comment )
255
+ if err != nil {
256
+ log .Error ().Err (err ).Msg ("github client: could not post issue comment" )
257
+ }
239
258
240
- return iss , err
259
+ return iss , utils .CreatePermanentError (err )
260
+ }, createBackOffWithRetries ())
241
261
}
242
262
243
263
// PostPullRequestComment adds a review comment to an existing PullRequest
244
264
func (c * Client ) PostPullRequestComment (owner , repo string , prId int , body string ) error {
245
265
// TODO: this is broken
246
- comment := & gogithub.PullRequestComment {
247
- //InReplyTo: nil,
248
- Body : String (body ),
249
- }
250
- _ , _ , err := c .client .PullRequests .CreateComment (c .ctx , owner , repo , int (prId ), comment )
251
- if err != nil {
252
- log .Error ().Err (err ).Msg ("could not post pull request comment" )
253
- }
254
- return err
266
+ return backoff .Retry (func () error {
267
+ comment := & gogithub.PullRequestComment {
268
+ //InReplyTo: nil,
269
+ Body : String (body ),
270
+ }
271
+ _ , _ , err := c .client .PullRequests .CreateComment (c .ctx , owner , repo , int (prId ), comment )
272
+ if err != nil {
273
+ log .Error ().Err (err ).Msg ("could not post pull request comment" )
274
+ }
275
+ return utils .CreatePermanentError (err )
276
+ }, createBackOffWithRetries ())
255
277
}
256
278
257
279
func String (str string ) * string {
@@ -266,7 +288,7 @@ func ResolveOwnerName(owner *gogithub.User) (string, error) {
266
288
name = owner .Login
267
289
if name == nil {
268
290
log .Error ().Msg ("owner name/login is nil" )
269
- return "" , errors . New ("owner name/login is nil" )
291
+ return "" , fmt . Errorf ("owner name/login is nil. %w" , utils . ErrPermanent )
270
292
}
271
293
}
272
294
return * name , nil
@@ -275,7 +297,7 @@ func ResolveOwnerName(owner *gogithub.User) (string, error) {
275
297
func splitFullName (fullName string ) ([]string , error ) {
276
298
parts := strings .Split (fullName , "/" )
277
299
if len (parts ) != 2 {
278
- return nil , fmt .Errorf ("github client: invalid repo format" )
300
+ return nil , fmt .Errorf ("github client: invalid repo format. %w" , utils . ErrPermanent )
279
301
}
280
302
return parts , nil
281
303
}
0 commit comments