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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 28b817e16bf9a5637315d36b0dd477f851a80a03c1aa61988fdb521de6458dae
4
- data.tar.gz: 44da1b71ce4de6cfe5ec280ee5eda07559ba28d2c5e9fcfda8a52fe30f9af899
3
+ metadata.gz: 9b7c0932a902f7945386447266e75f47c548440c6dba6f4df12120a7e1f798d8
4
+ data.tar.gz: 3ce6c0071493576b4a40763193797668206471b87d28a5d08ca74c37a720c0d9
5
5
  SHA512:
6
- metadata.gz: 30d0092f74f555b89c2bc43c3badc141219c66b7f95c36e7084994ad3ed979abd997935454b141feb5ee72b20a0a75949b0260d062f84a04669f088592529369
7
- data.tar.gz: cf0b141c62a2142417a784b42a9c9f323ec10406b378c5dfb998d53bc27a6245e0e8a4556a009e85510ca546a07462629d28d10a136da871f68dfa9336e53c70
6
+ metadata.gz: b549fb10017f52ee23154662ce1f28271f385e8771e607b9c736e2e5295327ff5389792bcdd4f6e55e9d490cc9e7ec2de04781bd4de4dc249865090e4d96d0d9
7
+ data.tar.gz: 8393b54c91c0c81dc8da1c9a7d7f39d864d455dd63b46ff4a7614783da90ff83554fc2a5daeca5aaee24b62ec54ecafb0d7c997ff5611a51db2355574f7596f0
data/.rubocop.yml CHANGED
@@ -26,5 +26,8 @@ Metrics/CyclomaticComplexity:
26
26
  Metrics/ParameterLists:
27
27
  Enabled: false
28
28
 
29
+ Metrics/PerceivedComplexity:
30
+ Enabled: false
31
+
29
32
  Naming/MethodParameterName:
30
33
  Enabled: false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prreview
4
- VERSION = '0.5.1'
4
+ VERSION = '0.7.0'
5
5
  end
data/lib/prreview.rb CHANGED
@@ -10,7 +10,14 @@ require 'optparse'
10
10
 
11
11
  module Prreview
12
12
  class CLI
13
- DEFAULT_PROMPT = 'Your task is to review this pull request. Do you see any problems there?'
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
- fetch_pull_request
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 fetch_pull_request
116
+ def fetch_pr
110
117
  puts "Fetching PR ##{@pr_number} for #{@full_repo}"
111
118
 
112
- @pull_request = @client.pull_request(@full_repo, @pr_number)
113
- @comments = @client.issue_comments(@full_repo, @pr_number).map(&:body)
114
- @commits = @client.pull_request_commits(@full_repo, @pr_number).map { |c| c.commit.message }
115
- @files = @client.pull_request_files(@full_repo, @pr_number).map do |file|
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: @pull_request.head.sha)
128
- decoded = Base64.decode64(content[:content])
129
- binary?(decoded) ? '(binary file)' : 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 = [@pull_request.body, *@comments].join("\n")
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
- issue = fetch_linked_issue(ref)
149
- next unless issue
152
+ linked_issue = fetch_linked_issue(ref)
153
+ next unless linked_issue
150
154
 
151
- @linked_issues << issue
155
+ @linked_issues << linked_issue
152
156
 
153
- new_text = [issue[:description], *issue[:comments]].join("\n")
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
- owner: m[:owner] || @owner,
179
- repo: m[:repo] || @repo,
180
- number: m[:number].to_i,
181
- key: "#{m[:owner]}/#{m[:repo]}##{m[:number]}"
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
- full_repo = "#{ref[:owner]}/#{ref[:repo]}"
191
+ issue_path = "#{ref[:owner]}/#{ref[:repo]}"
188
192
  number = ref[:number]
189
193
 
190
- puts "Fetching linked issue ##{number} for #{full_repo}"
194
+ puts "Fetching linked issue ##{number} for #{issue_path}"
191
195
 
192
- issue = @client.issue(full_repo, number)
193
196
  {
194
- full_repo:,
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 #{full_repo} not found, skipping"
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.task @prompt
208
+ x.your_task @prompt
209
209
  x.current_date DateTime.now
210
210
 
211
211
  x.pull_request do
212
- x.number @pr_number
213
- x.title @pull_request.title
214
- x.description @pull_request.body
215
-
216
- @comments.each { |c| x.comment_ c }
217
- @commits.each { |m| x.commit m }
218
-
219
- @files.each do |file|
220
- x.file do
221
- x.filename file[:filename]
222
- x.content file[:content]
223
- x.patch extract_patch(file)
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
- @linked_issues.each do |issue|
229
- x.linked_issue do
230
- x.repo issue[:full_repo]
231
- x.number issue[:number]
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
- issue[:comments].each { |c| x.comment_ c }
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
- x.task @prompt
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[:filename])
309
+ return if skip_file?(file.filename)
259
310
 
260
- file[:patch]
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.'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prreview
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov