1
1
package main
2
2
3
3
import (
4
- "bytes"
5
4
"context"
6
- "encoding/json"
7
5
"fmt"
8
- "io"
9
- "net/http"
10
6
"os"
11
7
"strings"
12
8
9
+ "github.com/google/go-github/v51/github"
13
10
"github.com/jessevdk/go-flags"
14
11
"github.com/sashabaranov/go-openai"
15
12
)
@@ -37,116 +34,87 @@ func main() {
37
34
}
38
35
os .Exit (0 )
39
36
}
40
- openaiClient := openai .NewClient (opts .OpenAIToken )
37
+ openaiClient := NewOpenAIClient (opts .OpenAIToken )
38
+ githubClient := NewGithubClient (context .Background (), opts .GithubToken )
41
39
42
- diff , err := getDiffContent ( opts . GithubToken , opts .Owner , opts .Repo , opts .PRNumber )
40
+ diff , err := githubClient . GetPullRequestDiff ( context . Background () , opts .Owner , opts .Repo , opts .PRNumber )
43
41
if err != nil {
44
- fmt .Printf ("Error fetching diff content : %v\n " , err )
42
+ fmt .Printf ("Error getting pull request diff : %v\n " , err )
45
43
return
46
44
}
47
- filesDiff , err := parseGitDiffAndSplitPerFile (diff )
45
+ filesDiff , err := parseGitDiffAndSplitPerFile (diff , strings . Split ( opts . SkipFiles , "," ) )
48
46
if err != nil {
49
47
return
50
48
}
51
49
52
50
var messages []openai.ChatCompletionMessage
53
- prompt := fmt .Sprintf (
54
- "Generate a GitHub pull request description based on the following changes " +
55
- "without basic prefix in markdown format with ###Description and ###Changes blocks:\n " ,
56
- )
51
+ prompt := fmt .Sprintf ("Generate a GitHub pull request description based on the following changes without basic prefix in markdown format with ###Description and ###Changes blocks:\n " )
57
52
messages = append (messages , openai.ChatCompletionMessage {
58
53
Role : openai .ChatMessageRoleUser ,
59
54
Content : prompt ,
60
55
})
61
56
for _ , fileDiff := range filesDiff {
62
57
fileName := getFilenameFromDiffHeader (fileDiff .Header )
63
58
64
- isSkipped := false
65
- for _ , skipFile := range strings .Split (opts .SkipFiles , "," ) {
66
- if strings .Contains (fileName , skipFile ) {
67
- isSkipped = true
68
- break
69
- }
70
- }
71
- if isSkipped {
72
- continue
73
- }
74
-
75
59
prompt := fmt .Sprintf ("File %s:\n %s\n %s\n " , fileName , fileDiff .Header , fileDiff .Diff )
76
60
messages = append (messages , openai.ChatCompletionMessage {
77
61
Role : openai .ChatMessageRoleUser ,
78
62
Content : prompt ,
79
63
})
80
64
}
81
- chatGPTDescription , err := generatePRDescription ( openaiClient , messages )
65
+ chatGPTDescription , err := openaiClient . ChatCompletion ( context . Background () , messages )
82
66
if err != nil {
83
67
fmt .Printf ("Error generating pull request description: %v\n " , err )
84
68
return
85
69
}
86
70
87
- title , err := getPullRequestTitle ( opts . GithubToken , opts .Owner , opts .Repo , opts .PRNumber )
71
+ pr , err := githubClient . GetPullRequest ( context . Background () , opts .Owner , opts .Repo , opts .PRNumber )
88
72
if err != nil {
73
+ fmt .Printf ("Error getting pull request: %v\n " , err )
89
74
return
90
75
}
91
76
92
- jiraLink := generateJiraLinkByTitle (title )
77
+ jiraLink := generateJiraLinkByTitle (* pr . Title )
93
78
94
79
description := fmt .Sprintf ("### Jira\n %s\n %s" , jiraLink , chatGPTDescription )
95
80
if opts .Test {
96
81
fmt .Println (description )
97
82
os .Exit (0 )
98
83
}
99
84
// Update the pull request with the generated description
100
- err = updatePullRequestDescription (opts .GithubToken , opts .Owner , opts .Repo , opts .PRNumber , description )
85
+ _ , err = githubClient .UpdatePullRequest (
86
+ context .Background (), opts .Owner , opts .Repo , opts .PRNumber , & github.PullRequest {Body : & description },
87
+ )
101
88
if err != nil {
102
- fmt .Printf ("Error updating pull request description : %v\n " , err )
89
+ fmt .Printf ("Error updating pull request: %v\n " , err )
103
90
return
104
91
}
105
-
106
- fmt .Println ("Pull request description updated successfully" )
107
- }
108
-
109
- func getDiffContent (token , owner , repo string , prNumber int ) (string , error ) {
110
- url := fmt .Sprintf ("https://api.github.com/repos/%s/%s/pulls/%d" , owner , repo , prNumber )
111
- method := "GET"
112
-
113
- client := & http.Client {}
114
- req , err := http .NewRequest (method , url , nil )
115
-
116
- if err != nil {
117
- fmt .Println (err )
118
- return "" , err
119
- }
120
- req .Header .Add ("Accept" , "application/vnd.github.v3.diff" )
121
- req .Header .Add ("Authorization" , fmt .Sprintf ("token %s" , token ))
122
- //req.Header.Add("Cookie", "logged_in=no")
123
-
124
- res , err := client .Do (req )
125
- if err != nil {
126
- return "" , err
127
- }
128
- defer res .Body .Close ()
129
-
130
- body , err := io .ReadAll (res .Body )
131
- if err != nil {
132
- return "" , err
133
- }
134
-
135
- return string (body ), nil
136
92
}
137
93
138
94
// parseGitDiffAndSplitPerFile parses a git diff and splits it into a slice of FileDiff.
139
- func parseGitDiffAndSplitPerFile (diff string ) ([]FileDiff , error ) {
95
+ func parseGitDiffAndSplitPerFile (diff string , skipFiles [] string ) ([]FileDiff , error ) {
140
96
lines := strings .Split (diff , "\n " )
141
97
var fileDiffs []FileDiff
142
98
143
- inFileDiff := false
99
+ inFileDiff , isSkipFile := false , false
144
100
var currentFileDiff FileDiff
145
101
for _ , line := range lines {
146
102
if strings .HasPrefix (line , "diff --git" ) {
147
103
if inFileDiff {
148
104
fileDiffs = append (fileDiffs , currentFileDiff )
149
105
}
106
+ if len (skipFiles ) > 0 {
107
+ isSkipFile = false
108
+ for _ , skipFile := range skipFiles {
109
+ if strings .Contains (line , skipFile ) {
110
+ isSkipFile = true
111
+ break
112
+ }
113
+ }
114
+ }
115
+ if isSkipFile {
116
+ continue
117
+ }
150
118
currentFileDiff = FileDiff {Header : line }
151
119
inFileDiff = true
152
120
} else if inFileDiff {
@@ -178,57 +146,6 @@ func getFilenameFromDiffHeader(diffHeader string) string {
178
146
}
179
147
}
180
148
181
- func generatePRDescription (client * openai.Client , messages []openai.ChatCompletionMessage ) (string , error ) {
182
- resp , err := client .CreateChatCompletion (
183
- context .Background (),
184
- openai.ChatCompletionRequest {
185
- Model : openai .GPT3Dot5Turbo ,
186
- Messages : messages ,
187
- },
188
- )
189
-
190
- if err != nil {
191
- fmt .Printf ("ChatCompletion error: %v\n " , err )
192
- return "" , err
193
- }
194
-
195
- return resp .Choices [0 ].Message .Content , nil
196
- }
197
-
198
- func getPullRequestTitle (token , owner , repo string , prNumber int ) (string , error ) {
199
- url := fmt .Sprintf ("https://api.github.com/repos/%s/%s/pulls/%d" , owner , repo , prNumber )
200
-
201
- req , err := http .NewRequest ("GET" , url , nil )
202
- if err != nil {
203
- return "" , err
204
- }
205
-
206
- req .Header .Set ("Authorization" , fmt .Sprintf ("token %s" , token ))
207
- req .Header .Set ("Accept" , "application/vnd.github.v3+json" )
208
-
209
- client := & http.Client {}
210
- resp , err := client .Do (req )
211
- if err != nil {
212
- return "" , err
213
- }
214
- defer resp .Body .Close ()
215
-
216
- if resp .StatusCode != http .StatusOK {
217
- return "" , fmt .Errorf ("Failed to fetch pull request details. Status code: %d" , resp .StatusCode )
218
- }
219
-
220
- var pr struct {
221
- Title string `json:"title"`
222
- }
223
-
224
- err = json .NewDecoder (resp .Body ).Decode (& pr )
225
- if err != nil {
226
- return "" , err
227
- }
228
-
229
- return pr .Title , nil
230
- }
231
-
232
149
func generateJiraLinkByTitle (title string ) string {
233
150
//NCR-1234
234
151
issueKey := strings .ToUpper (strings .Split (title , " " )[0 ])
@@ -239,38 +156,3 @@ func generateJiraLinkByTitle(title string) string {
239
156
240
157
return fmt .Sprintf ("[%s](%s%s)" , issueKey , jiraBaseURL , issueKey )
241
158
}
242
-
243
- func updatePullRequestDescription (token string , o string , r string , number int , description string ) error {
244
- url := fmt .Sprintf ("https://api.github.com/repos/%s/%s/pulls/%d" , o , r , number )
245
-
246
- data := map [string ]string {
247
- "body" : description ,
248
- }
249
-
250
- payload , err := json .Marshal (data )
251
- if err != nil {
252
- return err
253
- }
254
-
255
- req , err := http .NewRequest ("PATCH" , url , bytes .NewBuffer (payload ))
256
- if err != nil {
257
- return err
258
- }
259
-
260
- req .Header .Set ("Authorization" , fmt .Sprintf ("token %s" , token ))
261
- req .Header .Set ("Accept" , "application/vnd.github.v3+json" )
262
- req .Header .Set ("Content-Type" , "application/json" )
263
-
264
- client := & http.Client {}
265
- resp , err := client .Do (req )
266
- if err != nil {
267
- return err
268
- }
269
- defer resp .Body .Close ()
270
-
271
- if resp .StatusCode != http .StatusOK {
272
- return fmt .Errorf ("failed to update pull request description. Status code: %d" , resp .StatusCode )
273
- }
274
-
275
- return nil
276
- }
0 commit comments