prreview 0.3.0 → 0.4.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: af7fe1f1ccb8ef35c2eeec1252123861705106dc5439725923915ee20aa21fc6
4
- data.tar.gz: 97c37aa978ee7df44aff01eaa890acc5bb2a60eacd17fceb7ad5cc4319f8aa1a
3
+ metadata.gz: 714f7802004de97bfd9e4defb9f447ad5b445ea77e12b8f04123218a6684549b
4
+ data.tar.gz: ce62752c1d1d11c13f432e0c74df032873088d75018a13dec4dfc658b5ed6c73
5
5
  SHA512:
6
- metadata.gz: 197d7fa53eda6c389cc68ff8eb97cb792e1704e4c808a74746bda25274194498a19b90cfbcd5b1dea89b5a7d7b16190790da198fba5571830ef902c0636e5b71
7
- data.tar.gz: 680a13f38effb95f562898efd5b13baad3e6c16334ac2e37f783f4e8dec1ab4b86a3ada77a42b4cbe47c876340a946dd2c379361a36028ef5f2ac52d0bb28e7b
6
+ metadata.gz: 7526eaadf9570e7ad2967a2e003989b3126bff0ae2d0907d4d4056f92b90f8e2e7dff91a17cef9cd8a6cd81625d20a0cf27dcb378a348f6e1f7708124952011f
7
+ data.tar.gz: b9a446c787e170bb3998211173e198d5cb67480512446ddbb9f0a7620a8233ec692f8493bed7c1e1b4a181968c8e6b1ee07f1a4838ddd515c300ef60ef18bddf
data/.rubocop.yml CHANGED
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
2
  NewCops: enable
3
+ SuggestExtensions: false
3
4
 
4
5
  Metrics/AbcSize:
5
6
  Enabled: false
data/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ [![Gem Version](https://badge.fury.io/rb/prreview.svg)](https://badge.fury.io/rb/prreview)
2
+
1
3
  ## How to use
2
4
 
3
5
  Install:
@@ -48,7 +50,9 @@ However, in the future we might add some optional integrations.
48
50
  - Run `prreview` after you've thoroughly reviewed the PR. It works best when you understand the changes well.
49
51
  - Don't hesitate to try different LLMs or refresh the response to see if something new comes up.
50
52
  - Use `--all-content` and other extra options — they can significantly improve results for some PRs.
51
- - After the LLM responds, ask "Anything else?" to potentially uncover more issues.
53
+ - After the LLM responds, to potentially uncover more issues:
54
+ - Ask "Anything else?".
55
+ - If the response has a list of problems, try responding to each of them, giving the LLM more context.
52
56
 
53
57
  ## Requirements
54
58
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prreview
4
- VERSION = '0.3.0'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/prreview.rb CHANGED
@@ -11,7 +11,7 @@ require 'optparse'
11
11
  module Prreview
12
12
  class CLI
13
13
  DEFAULT_PROMPT = 'Your task is to review this pull request. Do you see any problems there?'
14
- DEFAULT_ISSUES_LIMIT = 10
14
+ DEFAULT_LINKED_ISSUES_LIMIT = 5
15
15
 
16
16
  # url or owner/repo#123 or #123
17
17
  URL_REGEX = %r{
@@ -36,9 +36,9 @@ module Prreview
36
36
  end
37
37
 
38
38
  def process
39
- fetch_pull_request
40
- fetch_issues
41
39
  load_optional_files
40
+ fetch_pull_request
41
+ fetch_linked_issues
42
42
  build_xml
43
43
  copy_result_to_clipboard
44
44
  end
@@ -48,26 +48,31 @@ module Prreview
48
48
  def parse_options!
49
49
  @prompt = DEFAULT_PROMPT
50
50
  @include_content = false
51
- @issues_limit = DEFAULT_ISSUES_LIMIT
51
+ @linked_issues_limit = DEFAULT_LINKED_ISSUES_LIMIT
52
52
  @optional_files = []
53
53
 
54
- parser = OptionParser.new do |opts|
55
- opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} -u URL [options]"
54
+ ARGV << '--help' if ARGV.empty?
56
55
 
57
- opts.on('-u', '--url URL', 'Pull‑request URL (https://github.com/owner/repo/pull/1)') { |v| @url = v }
58
- opts.on('-p', '--prompt PROMPT', 'Custom LLM prompt') { |v| @prompt = v }
59
- opts.on('-a', '--all-content', 'Include full file contents') { @include_content = true }
60
- opts.on('-l', '--limit LIMIT', Integer, "Limit number of issues fetched (default: #{DEFAULT_ISSUES_LIMIT})") { |v| @issues_limit = v }
61
- opts.on('-o', '--optional PATHS', 'Comma‑separated paths to local files (relative or absolute, e.g. docs/description.md,/etc/hosts)') do |v|
56
+ OptionParser.new do |parser|
57
+ parser.banner = "Usage: #{File.basename($PROGRAM_NAME)} -u URL [options]"
58
+
59
+ parser.on('-u', '--url URL', 'Pull‑request URL (https://github.com/owner/repo/pull/1)') { |v| @url = v }
60
+ parser.on('-p', '--prompt PROMPT', 'Custom LLM prompt') { |v| @prompt = v }
61
+ parser.on('-a', '--all-content', 'Include full file contents') { @include_content = true }
62
+ parser.on('-l', '--limit LIMIT', Integer, "Limit number of issues fetched (default: #{DEFAULT_LINKED_ISSUES_LIMIT})") { |v| @linked_issues_limit = v }
63
+ parser.on('-o', '--optional PATHS', 'Comma‑separated paths to local files (relative or absolute, e.g. docs/description.md,/etc/hosts)') do |v|
62
64
  @optional_files = v.split(',').map(&:strip)
63
65
  end
64
- opts.on('-h', '--help', 'Show help') do
65
- puts opts
66
+ parser.on_tail('-v', '--version', 'Show version') do
67
+ puts VERSION
66
68
  exit
67
69
  end
70
+ parser.on_tail('-h', '--help', 'Show help') do
71
+ puts parser
72
+ exit
73
+ end
74
+ parser.parse!
68
75
  end
69
-
70
- parser.parse!
71
76
  end
72
77
 
73
78
  def parse_url!
@@ -84,11 +89,11 @@ module Prreview
84
89
 
85
90
  def initialize_client
86
91
  access_token = ENV.fetch('GITHUB_TOKEN', nil)
87
- abort 'Error: GITHUB_TOKEN is not set' if access_token.to_s.empty?
92
+ abort 'Error: GITHUB_TOKEN is not set.' if access_token.to_s.empty?
88
93
 
89
94
  @client = Octokit::Client.new(access_token:, auto_paginate: true)
90
95
  rescue Octokit::Unauthorized
91
- abort 'Error: Invalid GITHUB_TOKEN'
96
+ abort 'Error: Invalid GITHUB_TOKEN.'
92
97
  end
93
98
 
94
99
  def fetch_pull_request
@@ -107,7 +112,7 @@ module Prreview
107
112
  end
108
113
 
109
114
  def fetch_file_content(path)
110
- puts "Fetching file content for #{path}"
115
+ puts "Fetching #{path}"
111
116
 
112
117
  content = @client.contents(@full_repo, path:, ref: @pull_request.head.sha)
113
118
  decoded = Base64.decode64(content[:content])
@@ -116,45 +121,41 @@ module Prreview
116
121
  '(file content not found)'
117
122
  end
118
123
 
119
- def fetch_issues
120
- @issues = []
124
+ def fetch_linked_issues
125
+ @linked_issues = []
121
126
 
122
127
  text = [@pull_request.body, *@comments].join("\n")
123
128
  queue = extract_refs(text, URL_REGEX)
124
129
  seen = Set.new
125
130
 
126
- until queue.empty? || @issues.length >= @issues_limit
131
+ until queue.empty? || @linked_issues.length >= @linked_issues_limit
127
132
  ref = queue.shift
128
133
  key = ref[:key]
129
134
  next if seen.include?(key)
130
135
 
131
136
  seen << key
132
137
 
133
- issue = fetch_issue(ref)
138
+ issue = fetch_linked_issue(ref)
134
139
  next unless issue
135
140
 
136
- @issues << issue
141
+ @linked_issues << issue
137
142
 
138
143
  new_text = [issue[:description], *issue[:comments]].join("\n")
139
144
  new_refs = extract_refs(new_text, URL_REGEX).reject { |nref| seen.include?(nref[:key]) }
140
145
  queue.concat(new_refs)
141
146
  end
142
147
 
143
- puts "Fetched #{@issues.length} issues (limit: #{@issues_limit})"
148
+ puts "Fetched #{@linked_issues.length} linked issues (limit: #{@linked_issues_limit})"
144
149
  end
145
150
 
146
151
  def load_optional_files
147
152
  @optional_file_contents = @optional_files.filter_map do |path|
148
- if File.exist?(path)
149
- content = File.read(path)
150
- { filename: path, content: content }
151
- else
152
- warn "File #{path} not found, skipping"
153
- nil
154
- end
153
+ puts "Reading #{path}"
154
+ abort "Optional file #{path} not found." unless File.exist?(path)
155
+ content = File.read(path)
156
+ { filename: path, content: }
155
157
  rescue StandardError => e
156
- warn "Error reading file #{path}: #{e.message}"
157
- nil
158
+ raise "Error reading file #{path}: #{e.message}"
158
159
  end
159
160
  end
160
161
 
@@ -172,11 +173,11 @@ module Prreview
172
173
  end
173
174
  end
174
175
 
175
- def fetch_issue(ref)
176
+ def fetch_linked_issue(ref)
176
177
  full_repo = "#{ref[:owner]}/#{ref[:repo]}"
177
178
  number = ref[:number]
178
179
 
179
- puts "Fetching issue ##{number} for #{full_repo}"
180
+ puts "Fetching linked issue ##{number} for #{full_repo}"
180
181
 
181
182
  issue = @client.issue(full_repo, number)
182
183
  {
@@ -187,7 +188,7 @@ module Prreview
187
188
  comments: @client.issue_comments(full_repo, number).map(&:body)
188
189
  }
189
190
  rescue Octokit::NotFound
190
- puts "Issue #{number} for #{full_repo} not found, skipping"
191
+ warn "Linked issue #{number} for #{full_repo} not found, skipping"
191
192
  nil
192
193
  end
193
194
 
@@ -214,8 +215,8 @@ module Prreview
214
215
  end
215
216
  end
216
217
 
217
- @issues.each do |issue|
218
- x.issue do
218
+ @linked_issues.each do |issue|
219
+ x.linked_issue do
219
220
  x.repo issue[:full_repo]
220
221
  x.number issue[:number]
221
222
  x.title issue[:title]
@@ -249,7 +250,7 @@ module Prreview
249
250
 
250
251
  def copy_result_to_clipboard
251
252
  Clipboard.copy(@xml)
252
- puts 'XML prompt generated and copied to clipboard.'
253
+ puts 'XML prompt generated and copied to your clipboard.'
253
254
  end
254
255
  end
255
256
  end
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.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov