prreview 0.3.0 → 0.5.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: 30200431f3796fe13f702beef779421ce9eb7cbb759bf05a781374d39dc4082b
4
+ data.tar.gz: cc6bbba926af7d7632a97d17551c045ead9b95b5e6682d988de20eef46d1f06b
5
5
  SHA512:
6
- metadata.gz: 197d7fa53eda6c389cc68ff8eb97cb792e1704e4c808a74746bda25274194498a19b90cfbcd5b1dea89b5a7d7b16190790da198fba5571830ef902c0636e5b71
7
- data.tar.gz: 680a13f38effb95f562898efd5b13baad3e6c16334ac2e37f783f4e8dec1ab4b86a3ada77a42b4cbe47c876340a946dd2c379361a36028ef5f2ac52d0bb28e7b
6
+ metadata.gz: 44622bc990c7059044df282588707f489814ab86c6b47eff1d64379809430061de7851d7f6455212a0f5155b76331538d0fc8fe366f9f18a56cf913e2487f9a0
7
+ data.tar.gz: e5281db6c13f7b36532e663cda11eeddc0bd540a598327e7e8e4a256b24addb1879f9758f4b2150c18a86e172a3e28e4c4989c31277c4297a3577dcc40e280bf
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:
@@ -9,14 +11,14 @@ gem install prreview
9
11
  Run this command with a PR URL:
10
12
 
11
13
  ```sh
12
- prreview -u https://github.com/owner/repo/pull/123
14
+ prreview https://github.com/owner/repo/pull/123
13
15
  ```
14
16
 
15
17
  Or use more options:
16
18
 
17
19
  ```
18
20
  prreview --help
19
- prreview --url https://github.com/owner/repo/pull/123 --all-content --prompt "Are there any security issues?"
21
+ prreview https://github.com/owner/repo/pull/123 --all-content --prompt "Are there any security issues?"
20
22
  ```
21
23
 
22
24
  Now, just paste the PR details into ChatGPT, Claude, or any LLM for review.
@@ -48,12 +50,15 @@ 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
 
55
59
  - Ruby
56
- - `GITHUB_TOKEN` environment variable
60
+ - `GITHUB_TOKEN` environment
61
+ variable. [GitHub Docs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)
57
62
 
58
63
  ## License
59
64
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Prreview
4
- VERSION = '0.3.0'
4
+ VERSION = '0.5.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,15 @@ module Prreview
36
36
  end
37
37
 
38
38
  def process
39
- fetch_pull_request
40
- fetch_issues
41
39
  load_optional_files
40
+ begin
41
+ fetch_pull_request
42
+ fetch_linked_issues
43
+ rescue Octokit::Unauthorized
44
+ abort 'Error: Invalid GITHUB_TOKEN.'
45
+ rescue Octokit::NotFound
46
+ abort 'Error: Pull request not found.'
47
+ end
42
48
  build_xml
43
49
  copy_result_to_clipboard
44
50
  end
@@ -48,30 +54,41 @@ module Prreview
48
54
  def parse_options!
49
55
  @prompt = DEFAULT_PROMPT
50
56
  @include_content = false
51
- @issues_limit = DEFAULT_ISSUES_LIMIT
57
+ @linked_issues_limit = DEFAULT_LINKED_ISSUES_LIMIT
52
58
  @optional_files = []
53
59
 
54
- parser = OptionParser.new do |opts|
55
- opts.banner = "Usage: #{File.basename($PROGRAM_NAME)} -u URL [options]"
60
+ ARGV << '--help' if ARGV.empty?
61
+
62
+ OptionParser.new do |parser|
63
+ parser.banner = <<~BAN
64
+ Usage: #{File.basename($PROGRAM_NAME)} URL [options]
65
+
66
+ Pull request URL example: https://github.com/owner/repo/pull/1
67
+
68
+ BAN
56
69
 
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|
70
+ parser.on('-p', '--prompt PROMPT', 'Custom LLM prompt') { |v| @prompt = v }
71
+ parser.on('-a', '--all-content', 'Include full file contents') { @include_content = true }
72
+ parser.on('-l', '--limit LIMIT', Integer, "Limit number of issues fetched (default: #{DEFAULT_LINKED_ISSUES_LIMIT})") { |v| @linked_issues_limit = v }
73
+ parser.on('-o', '--optional PATHS', 'Comma‑separated paths to local files (relative or absolute, e.g. docs/description.md,/etc/hosts)') do |v|
62
74
  @optional_files = v.split(',').map(&:strip)
63
75
  end
64
- opts.on('-h', '--help', 'Show help') do
65
- puts opts
76
+ parser.on_tail('-v', '--version', 'Show version') do
77
+ puts VERSION
66
78
  exit
67
79
  end
80
+ parser.on_tail('-h', '--help', 'Show help') do
81
+ puts parser
82
+ exit
83
+ end
84
+ parser.parse!
68
85
  end
69
86
 
70
- parser.parse!
87
+ @url = ARGV.first
71
88
  end
72
89
 
73
90
  def parse_url!
74
- abort 'Error: Pull-request URL missing. Use -u or --url.' if @url.to_s.empty?
91
+ abort 'Error: Pull request URL missing.' if @url.to_s.empty?
75
92
 
76
93
  match = @url.match(URL_REGEX)
77
94
  abort 'Error: Invalid URL format. See --help for usage.' unless match
@@ -84,11 +101,9 @@ module Prreview
84
101
 
85
102
  def initialize_client
86
103
  access_token = ENV.fetch('GITHUB_TOKEN', nil)
87
- abort 'Error: GITHUB_TOKEN is not set' if access_token.to_s.empty?
104
+ abort 'Error: GITHUB_TOKEN is not set.' if access_token.to_s.empty?
88
105
 
89
106
  @client = Octokit::Client.new(access_token:, auto_paginate: true)
90
- rescue Octokit::Unauthorized
91
- abort 'Error: Invalid GITHUB_TOKEN'
92
107
  end
93
108
 
94
109
  def fetch_pull_request
@@ -107,7 +122,7 @@ module Prreview
107
122
  end
108
123
 
109
124
  def fetch_file_content(path)
110
- puts "Fetching file content for #{path}"
125
+ puts "Fetching #{path}"
111
126
 
112
127
  content = @client.contents(@full_repo, path:, ref: @pull_request.head.sha)
113
128
  decoded = Base64.decode64(content[:content])
@@ -116,45 +131,41 @@ module Prreview
116
131
  '(file content not found)'
117
132
  end
118
133
 
119
- def fetch_issues
120
- @issues = []
134
+ def fetch_linked_issues
135
+ @linked_issues = []
121
136
 
122
137
  text = [@pull_request.body, *@comments].join("\n")
123
138
  queue = extract_refs(text, URL_REGEX)
124
139
  seen = Set.new
125
140
 
126
- until queue.empty? || @issues.length >= @issues_limit
141
+ until queue.empty? || @linked_issues.length >= @linked_issues_limit
127
142
  ref = queue.shift
128
143
  key = ref[:key]
129
144
  next if seen.include?(key)
130
145
 
131
146
  seen << key
132
147
 
133
- issue = fetch_issue(ref)
148
+ issue = fetch_linked_issue(ref)
134
149
  next unless issue
135
150
 
136
- @issues << issue
151
+ @linked_issues << issue
137
152
 
138
153
  new_text = [issue[:description], *issue[:comments]].join("\n")
139
154
  new_refs = extract_refs(new_text, URL_REGEX).reject { |nref| seen.include?(nref[:key]) }
140
155
  queue.concat(new_refs)
141
156
  end
142
157
 
143
- puts "Fetched #{@issues.length} issues (limit: #{@issues_limit})"
158
+ puts "Fetched #{@linked_issues.length} linked issues (limit: #{@linked_issues_limit})"
144
159
  end
145
160
 
146
161
  def load_optional_files
147
162
  @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
163
+ puts "Reading #{path}"
164
+ abort "Optional file #{path} not found." unless File.exist?(path)
165
+ content = File.read(path)
166
+ { filename: path, content: }
155
167
  rescue StandardError => e
156
- warn "Error reading file #{path}: #{e.message}"
157
- nil
168
+ raise "Error reading file #{path}: #{e.message}"
158
169
  end
159
170
  end
160
171
 
@@ -172,11 +183,11 @@ module Prreview
172
183
  end
173
184
  end
174
185
 
175
- def fetch_issue(ref)
186
+ def fetch_linked_issue(ref)
176
187
  full_repo = "#{ref[:owner]}/#{ref[:repo]}"
177
188
  number = ref[:number]
178
189
 
179
- puts "Fetching issue ##{number} for #{full_repo}"
190
+ puts "Fetching linked issue ##{number} for #{full_repo}"
180
191
 
181
192
  issue = @client.issue(full_repo, number)
182
193
  {
@@ -187,7 +198,7 @@ module Prreview
187
198
  comments: @client.issue_comments(full_repo, number).map(&:body)
188
199
  }
189
200
  rescue Octokit::NotFound
190
- puts "Issue #{number} for #{full_repo} not found, skipping"
201
+ warn "Linked issue #{number} for #{full_repo} not found, skipping"
191
202
  nil
192
203
  end
193
204
 
@@ -214,8 +225,8 @@ module Prreview
214
225
  end
215
226
  end
216
227
 
217
- @issues.each do |issue|
218
- x.issue do
228
+ @linked_issues.each do |issue|
229
+ x.linked_issue do
219
230
  x.repo issue[:full_repo]
220
231
  x.number issue[:number]
221
232
  x.title issue[:title]
@@ -249,7 +260,7 @@ module Prreview
249
260
 
250
261
  def copy_result_to_clipboard
251
262
  Clipboard.copy(@xml)
252
- puts 'XML prompt generated and copied to clipboard.'
263
+ puts 'XML prompt generated and copied to your clipboard.'
253
264
  end
254
265
  end
255
266
  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.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evgenii Morozov