prreview 0.5.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/lib/prreview/version.rb +1 -1
- data/lib/prreview.rb +122 -60
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b7c0932a902f7945386447266e75f47c548440c6dba6f4df12120a7e1f798d8
|
4
|
+
data.tar.gz: 3ce6c0071493576b4a40763193797668206471b87d28a5d08ca74c37a720c0d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b549fb10017f52ee23154662ce1f28271f385e8771e607b9c736e2e5295327ff5389792bcdd4f6e55e9d490cc9e7ec2de04781bd4de4dc249865090e4d96d0d9
|
7
|
+
data.tar.gz: 8393b54c91c0c81dc8da1c9a7d7f39d864d455dd63b46ff4a7614783da90ff83554fc2a5daeca5aaee24b62ec54ecafb0d7c997ff5611a51db2355574f7596f0
|
data/.rubocop.yml
CHANGED
data/lib/prreview/version.rb
CHANGED
data/lib/prreview.rb
CHANGED
@@ -10,7 +10,14 @@ require 'optparse'
|
|
10
10
|
|
11
11
|
module Prreview
|
12
12
|
class CLI
|
13
|
-
DEFAULT_PROMPT =
|
13
|
+
DEFAULT_PROMPT = <<~PROMPT
|
14
|
+
Your task is to review this pull request.
|
15
|
+
Patch lines starting with `-` are deleted.
|
16
|
+
Patch lines starting with `+` are added.
|
17
|
+
Focus on new problems, not ones that were already there.
|
18
|
+
Do you see any problems?
|
19
|
+
PROMPT
|
20
|
+
|
14
21
|
DEFAULT_LINKED_ISSUES_LIMIT = 5
|
15
22
|
|
16
23
|
# url or owner/repo#123 or #123
|
@@ -38,7 +45,7 @@ module Prreview
|
|
38
45
|
def process
|
39
46
|
load_optional_files
|
40
47
|
begin
|
41
|
-
|
48
|
+
fetch_pr
|
42
49
|
fetch_linked_issues
|
43
50
|
rescue Octokit::Unauthorized
|
44
51
|
abort 'Error: Invalid GITHUB_TOKEN.'
|
@@ -106,27 +113,24 @@ module Prreview
|
|
106
113
|
@client = Octokit::Client.new(access_token:, auto_paginate: true)
|
107
114
|
end
|
108
115
|
|
109
|
-
def
|
116
|
+
def fetch_pr
|
110
117
|
puts "Fetching PR ##{@pr_number} for #{@full_repo}"
|
111
118
|
|
112
|
-
@
|
113
|
-
@
|
114
|
-
@
|
115
|
-
@
|
116
|
-
|
117
|
-
filename: file.filename,
|
118
|
-
patch: file.patch || '(no patch data)',
|
119
|
-
content: @include_content && !skip_file?(file.filename) ? fetch_file_content(file.filename) : '(no content)'
|
120
|
-
}
|
121
|
-
end
|
119
|
+
@pr = @client.pull_request(@full_repo, @pr_number)
|
120
|
+
@pr_comments = @client.issue_comments(@full_repo, @pr_number)
|
121
|
+
@pr_code_comments = @client.pull_request_comments(@full_repo, @pr_number)
|
122
|
+
@pr_commits = @client.pull_request_commits(@full_repo, @pr_number)
|
123
|
+
@pr_files = @client.pull_request_files(@full_repo, @pr_number)
|
122
124
|
end
|
123
125
|
|
124
126
|
def fetch_file_content(path)
|
125
127
|
puts "Fetching #{path}"
|
126
128
|
|
127
|
-
content = @client.contents(@full_repo, path:, ref: @
|
128
|
-
decoded = Base64.decode64(content
|
129
|
-
binary?(decoded)
|
129
|
+
content = @client.contents(@full_repo, path:, ref: @pr.head.sha)
|
130
|
+
decoded = Base64.decode64(content.content)
|
131
|
+
return if binary?(decoded)
|
132
|
+
|
133
|
+
decoded
|
130
134
|
rescue Octokit::NotFound
|
131
135
|
'(file content not found)'
|
132
136
|
end
|
@@ -134,7 +138,7 @@ module Prreview
|
|
134
138
|
def fetch_linked_issues
|
135
139
|
@linked_issues = []
|
136
140
|
|
137
|
-
text = [@
|
141
|
+
text = [@pr.body, *@pr_comments.map(&:body), *@pr_code_comments.map(&:body)].join("\n")
|
138
142
|
queue = extract_refs(text, URL_REGEX)
|
139
143
|
seen = Set.new
|
140
144
|
|
@@ -145,12 +149,12 @@ module Prreview
|
|
145
149
|
|
146
150
|
seen << key
|
147
151
|
|
148
|
-
|
149
|
-
next unless
|
152
|
+
linked_issue = fetch_linked_issue(ref)
|
153
|
+
next unless linked_issue
|
150
154
|
|
151
|
-
@linked_issues <<
|
155
|
+
@linked_issues << linked_issue
|
152
156
|
|
153
|
-
new_text = [
|
157
|
+
new_text = [linked_issue[:issue].body, *linked_issue[:comments].map(&:body)].join("\n")
|
154
158
|
new_refs = extract_refs(new_text, URL_REGEX).reject { |nref| seen.include?(nref[:key]) }
|
155
159
|
queue.concat(new_refs)
|
156
160
|
end
|
@@ -174,65 +178,97 @@ module Prreview
|
|
174
178
|
m = Regexp.last_match
|
175
179
|
next unless m[:number]
|
176
180
|
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
}
|
181
|
+
owner = m[:owner] || @owner
|
182
|
+
repo = m[:repo] || @repo
|
183
|
+
number = m[:number].to_i
|
184
|
+
key = "#{owner}/#{repo}##{number}"
|
185
|
+
|
186
|
+
{ owner:, repo:, number:, key: }
|
183
187
|
end
|
184
188
|
end
|
185
189
|
|
186
190
|
def fetch_linked_issue(ref)
|
187
|
-
|
191
|
+
issue_path = "#{ref[:owner]}/#{ref[:repo]}"
|
188
192
|
number = ref[:number]
|
189
193
|
|
190
|
-
puts "Fetching linked issue ##{number} for #{
|
194
|
+
puts "Fetching linked issue ##{number} for #{issue_path}"
|
191
195
|
|
192
|
-
issue = @client.issue(full_repo, number)
|
193
196
|
{
|
194
|
-
|
195
|
-
number
|
196
|
-
title: issue.title,
|
197
|
-
description: issue.body,
|
198
|
-
comments: @client.issue_comments(full_repo, number).map(&:body)
|
197
|
+
issue: @client.issue(issue_path, number),
|
198
|
+
comments: @client.issue_comments(issue_path, number)
|
199
199
|
}
|
200
200
|
rescue Octokit::NotFound
|
201
|
-
warn "Linked issue #{number} for #{
|
201
|
+
warn "Linked issue #{number} for #{issue_path} not found, skipping"
|
202
202
|
nil
|
203
203
|
end
|
204
204
|
|
205
205
|
def build_xml
|
206
206
|
builder = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |x|
|
207
207
|
x.prompt do
|
208
|
-
x.
|
208
|
+
x.your_task @prompt
|
209
209
|
x.current_date DateTime.now
|
210
210
|
|
211
211
|
x.pull_request do
|
212
|
-
x
|
213
|
-
|
214
|
-
x.
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
212
|
+
build_issue!(x, @pr)
|
213
|
+
|
214
|
+
x.commits do
|
215
|
+
@pr_commits.each do |c|
|
216
|
+
x.commit do
|
217
|
+
x.commiter c.committer&.login
|
218
|
+
x.message c.commit.message
|
219
|
+
x.date c.commit.committer&.date
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
x.comments do
|
225
|
+
@pr_comments.each do |c|
|
226
|
+
x.comment_ do
|
227
|
+
build_comment!(x, c)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
x.code_comments do
|
233
|
+
@pr_code_comments.each do |c|
|
234
|
+
x.code_comment do
|
235
|
+
build_comment!(x, c)
|
236
|
+
x.path c.path
|
237
|
+
x.line c.line
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
x.pull_request_files do
|
243
|
+
@pr_files.each do |f|
|
244
|
+
content = fetch_file_content(f.filename) if @include_content && !skip_file?(f.filename)
|
245
|
+
patch = extract_patch(f)
|
246
|
+
|
247
|
+
x.file do
|
248
|
+
x.filename f.filename
|
249
|
+
x.content { cdata!(x, content) } if content
|
250
|
+
x.patch { cdata!(x, patch) } if patch
|
251
|
+
end
|
224
252
|
end
|
225
253
|
end
|
226
254
|
end
|
227
255
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
x.title issue[:title]
|
233
|
-
x.description issue[:description]
|
256
|
+
x.linked_issues do
|
257
|
+
@linked_issues.each do |linked_issue|
|
258
|
+
issue = linked_issue[:issue]
|
259
|
+
comments = linked_issue[:comments]
|
234
260
|
|
235
|
-
|
261
|
+
x.linked_issue do
|
262
|
+
build_issue!(x, issue)
|
263
|
+
|
264
|
+
x.comments do
|
265
|
+
comments.each do |c|
|
266
|
+
x.comment_ do
|
267
|
+
build_comment!(x, c)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
236
272
|
end
|
237
273
|
end
|
238
274
|
|
@@ -241,23 +277,38 @@ module Prreview
|
|
241
277
|
@optional_file_contents.each do |file|
|
242
278
|
x.file do
|
243
279
|
x.filename file[:filename]
|
244
|
-
x.content file[:content]
|
280
|
+
x.content { cdata!(x, file[:content]) }
|
245
281
|
end
|
246
282
|
end
|
247
283
|
end
|
248
284
|
end
|
249
285
|
|
250
|
-
|
286
|
+
# Intentionally duplicate the prompt to remind LLM about the task
|
287
|
+
x.your_task @prompt
|
251
288
|
end
|
252
289
|
end
|
253
290
|
|
254
291
|
@xml = builder.doc.root.to_xml
|
255
292
|
end
|
256
293
|
|
294
|
+
def build_issue!(xml, issue)
|
295
|
+
xml.url issue.html_url
|
296
|
+
xml.user issue.user.login
|
297
|
+
xml.title issue.title
|
298
|
+
xml.body issue.body
|
299
|
+
xml.created_at issue.created_at
|
300
|
+
end
|
301
|
+
|
302
|
+
def build_comment!(xml, comment)
|
303
|
+
xml.user comment.user.login
|
304
|
+
xml.body comment.body
|
305
|
+
xml.created_at comment.created_at
|
306
|
+
end
|
307
|
+
|
257
308
|
def extract_patch(file)
|
258
|
-
return if skip_file?(file
|
309
|
+
return if skip_file?(file.filename)
|
259
310
|
|
260
|
-
file
|
311
|
+
file.patch
|
261
312
|
end
|
262
313
|
|
263
314
|
def skip_file?(filename)
|
@@ -268,6 +319,17 @@ module Prreview
|
|
268
319
|
string.include?("\x00")
|
269
320
|
end
|
270
321
|
|
322
|
+
def cdata!(x, str)
|
323
|
+
return unless str
|
324
|
+
|
325
|
+
parts = str.to_s.split(']]>')
|
326
|
+
x.cdata(parts.first || '')
|
327
|
+
parts.drop(1).each do |rest|
|
328
|
+
x.text(']]>')
|
329
|
+
x.cdata rest
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
271
333
|
def copy_result_to_clipboard
|
272
334
|
Clipboard.copy(@xml)
|
273
335
|
puts 'XML prompt generated and copied to your clipboard.'
|