gh-issues-inspector 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 +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/.rubocop.yml +120 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/README.md +85 -0
- data/Rakefile +52 -0
- data/bin/console +10 -0
- data/bin/setup +8 -0
- data/gh-issues-inspector.gemspec +25 -0
- data/lib/evidence.rb +85 -0
- data/lib/exception_hound.rb +45 -0
- data/lib/inspector.rb +73 -0
- data/lib/inspector/version.rb +3 -0
- data/lib/sidekick.rb +101 -0
- metadata +131 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 3fd9721c6b868db5ec4786787fcc9ffd2e8522a7
|
4
|
+
data.tar.gz: 531b0f5e2b0b5ae52c8597dbe2483f7ceef06011
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3e4f9986e0e09d55122852a3eab9104caf82227228ccc97b8693969c19893f2f79c82f3c41e69ac1b4b0bfea14778a9ca8ad80ed8ec1397c193e3db98ec6c412
|
7
|
+
data.tar.gz: e3e04cd2a582ddb4df0f6033a63673757f2c3198335889b47f20749051182fdfcd3ed21cc97d13436f676d1a6fec940328a06262d5b24aa69d6f87a59ff511f9
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
Style/ClassVars:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Style/ClassCheck:
|
5
|
+
EnforcedStyle: kind_of?
|
6
|
+
|
7
|
+
# Cop supports --auto-correct.
|
8
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
9
|
+
Style/BracesAroundHashParameters:
|
10
|
+
Enabled: false
|
11
|
+
|
12
|
+
Lint/UselessAssignment:
|
13
|
+
Exclude:
|
14
|
+
- 'spec/**/*'
|
15
|
+
|
16
|
+
# Cop supports --auto-correct.
|
17
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
18
|
+
Style/IndentHash:
|
19
|
+
Enabled: false
|
20
|
+
|
21
|
+
Style/RaiseArgs:
|
22
|
+
EnforcedStyle: exploded
|
23
|
+
|
24
|
+
Style/DoubleNegation:
|
25
|
+
Enabled: false
|
26
|
+
|
27
|
+
Lint/HandleExceptions:
|
28
|
+
Enabled: false
|
29
|
+
|
30
|
+
# Cop supports --auto-correct.
|
31
|
+
Lint/UnusedBlockArgument:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
# Needed for $verbose
|
35
|
+
Style/GlobalVars:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/FileName:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
# $? Exit
|
42
|
+
Style/SpecialGlobalVars:
|
43
|
+
Enabled: false
|
44
|
+
|
45
|
+
# the let(:key) { ... } should be allowed in tests
|
46
|
+
Lint/ParenthesesAsGroupedExpression:
|
47
|
+
Exclude:
|
48
|
+
- 'spec/**/*'
|
49
|
+
|
50
|
+
# options.rb might be large, we know that
|
51
|
+
Metrics/MethodLength:
|
52
|
+
Max: 60
|
53
|
+
Exclude:
|
54
|
+
- 'lib/*/options.rb'
|
55
|
+
|
56
|
+
# Both string notations are okay
|
57
|
+
Style/StringLiterals:
|
58
|
+
Enabled: false
|
59
|
+
|
60
|
+
# The %w might be confusing for new users
|
61
|
+
Style/WordArray:
|
62
|
+
MinSize: 19
|
63
|
+
|
64
|
+
# Not a good thing
|
65
|
+
Style/RedundantSelf:
|
66
|
+
Enabled: false
|
67
|
+
|
68
|
+
# raise and fail are both okay
|
69
|
+
Style/SignalException:
|
70
|
+
Enabled: false
|
71
|
+
|
72
|
+
# Better too much 'return' than one missing
|
73
|
+
Style/RedundantReturn:
|
74
|
+
Enabled: false
|
75
|
+
|
76
|
+
# Having if in the same line might not always be good
|
77
|
+
Style/IfUnlessModifier:
|
78
|
+
Enabled: false
|
79
|
+
|
80
|
+
# That looks wrong
|
81
|
+
Style/AlignHash:
|
82
|
+
Enabled: false
|
83
|
+
|
84
|
+
# and and or is okay
|
85
|
+
Style/AndOr:
|
86
|
+
Enabled: false
|
87
|
+
|
88
|
+
# Offense count: 20
|
89
|
+
Metrics/AbcSize:
|
90
|
+
Max: 60
|
91
|
+
|
92
|
+
# Configuration parameters: CountComments.
|
93
|
+
Metrics/ClassLength:
|
94
|
+
Max: 320
|
95
|
+
|
96
|
+
Metrics/CyclomaticComplexity:
|
97
|
+
Max: 17
|
98
|
+
|
99
|
+
# Configuration parameters: AllowURI, URISchemes.
|
100
|
+
Metrics/LineLength:
|
101
|
+
Max: 370
|
102
|
+
|
103
|
+
# Configuration parameters: CountKeywordArgs.
|
104
|
+
Metrics/ParameterLists:
|
105
|
+
Max: 17
|
106
|
+
|
107
|
+
Metrics/PerceivedComplexity:
|
108
|
+
Max: 18
|
109
|
+
|
110
|
+
Style/DotPosition:
|
111
|
+
Enabled: false
|
112
|
+
|
113
|
+
Style/GuardClause:
|
114
|
+
Enabled: false
|
115
|
+
|
116
|
+
Style/Documentation:
|
117
|
+
Enabled: false
|
118
|
+
|
119
|
+
Style/ZeroLengthPredicate:
|
120
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
# The Issues Inspector
|
2
|
+
|
3
|
+
## Installation
|
4
|
+
|
5
|
+
Add this line to your application's Gemfile:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
gem 'gh-issues-inspector'
|
9
|
+
```
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
#### The Inspector
|
18
|
+
|
19
|
+
To get started using The Issues Inspector, you will need to
|
20
|
+
create an inspector instance. This class is main public API for querying issues.
|
21
|
+
|
22
|
+
#### Getting Started
|
23
|
+
|
24
|
+
Create an instance of `Inspector::Inspector`, you can then ask it to search
|
25
|
+
based on your raised exception, or as a direct query yourself.
|
26
|
+
|
27
|
+
``` ruby
|
28
|
+
require 'inspector'
|
29
|
+
inspector = Inspector::Inspector.new "orta", "eigen"
|
30
|
+
inspector.search_query "Someone set us up the bomb"
|
31
|
+
```
|
32
|
+
|
33
|
+
By default this would output:
|
34
|
+
|
35
|
+
```
|
36
|
+
Looking for related issues on CocoaPods/CocoaPods...
|
37
|
+
|
38
|
+
- undefined method `to_ary' for #<Pod::Specification name="iVersion">Did you mean? to_query
|
39
|
+
https://github.com/CocoaPods/CocoaPods/issues/4748 [closed] [1 comment]
|
40
|
+
|
41
|
+
- NoMethodError - undefined method `to_ary' for Pod EAIntroView
|
42
|
+
https://github.com/CocoaPods/CocoaPods/issues/4391 [closed] [15 comments]
|
43
|
+
|
44
|
+
- Do a search on GitHub for issues relating to a crash?
|
45
|
+
https://github.com/CocoaPods/CocoaPods/issues/4391 [open] [3 comments]
|
46
|
+
|
47
|
+
and 10 more at:
|
48
|
+
https://github.com/CocoaPods/CocoaPods/search?q=undefined+method+%60to_ary%27&type=Issues
|
49
|
+
```
|
50
|
+
#### Presenting Your Report
|
51
|
+
|
52
|
+
The default user interface for the inspector, its public API should be
|
53
|
+
considered the protocol for other classes wanting to provide a user interface.
|
54
|
+
|
55
|
+
Your custom objects will be verified at runtime that they conform to the protocol.
|
56
|
+
|
57
|
+
You can see the default implmentation at
|
58
|
+
[lib/evidence.rb](/orta/gh-issues-inspector/tree/master/lib/evidence.rb).
|
59
|
+
|
60
|
+
Both `search_query` and `search_exception` take your custom delegate as a 2nd optional parameter.
|
61
|
+
|
62
|
+
``` ruby
|
63
|
+
require 'inspector'
|
64
|
+
inspector = Inspector::Inspector.new "orta", "eigen"
|
65
|
+
inspector.search_query "Someone set us up the bomb", ArtsyUI.new
|
66
|
+
```
|
67
|
+
Protocol for custom objects:
|
68
|
+
|
69
|
+
- `inspector_started_query(_query, inspector)` - Called just as the investigation has begun.
|
70
|
+
- `inspector_successfully_recieved_report(report, _inspector)` - Called once the inspector has recieved a report with more than one issue.
|
71
|
+
- `inspector_recieved_empty_report(_report, inspector)` - Called once the report has been recieved, but when there are no issues found.
|
72
|
+
- `inspector_could_not_create_report(error, query, inspector)` - Called when there have been networking issues in creating the report.
|
73
|
+
|
74
|
+
|
75
|
+
## Development
|
76
|
+
|
77
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
78
|
+
|
79
|
+
The usage section of this README is generated from inline documentation inside the classes, to update it run `rake readme`.
|
80
|
+
|
81
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
82
|
+
|
83
|
+
## Contributing
|
84
|
+
|
85
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/orta/gh-issues-inspector.
|
data/Rakefile
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubocop/rake_task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:specs)
|
6
|
+
|
7
|
+
task default: :spec
|
8
|
+
|
9
|
+
task :spec do
|
10
|
+
Rake::Task['specs'].invoke
|
11
|
+
Rake::Task['rubocop'].invoke
|
12
|
+
end
|
13
|
+
|
14
|
+
desc 'Run RuboCop on the lib/specs directory'
|
15
|
+
RuboCop::RakeTask.new(:rubocop) do |task|
|
16
|
+
task.patterns = ['lib/**/*.rb', 'spec/**/*.rb']
|
17
|
+
end
|
18
|
+
|
19
|
+
task :readme do
|
20
|
+
readme = File.open("README.md", 'rb', &:read)
|
21
|
+
|
22
|
+
start_split = "## Usage"
|
23
|
+
end_split = "## Development"
|
24
|
+
|
25
|
+
start = readme.split(start_split)[0]
|
26
|
+
rest = readme.split(start_split)[1]
|
27
|
+
finale = rest.split(end_split)[1]
|
28
|
+
|
29
|
+
require 'yard'
|
30
|
+
files = ["lib/inspector.rb", "lib/sidekick.rb", "lib/evidence.rb"]
|
31
|
+
docs = YARD::Registry.load(files, true)
|
32
|
+
|
33
|
+
usage = "\n\n"
|
34
|
+
usage << "#### The Inspector\n\n"
|
35
|
+
usage << docs.at("Inspector::Inspector").docstring
|
36
|
+
usage << "\n"
|
37
|
+
|
38
|
+
usage << "#### Presenting Your Report \n\n"
|
39
|
+
evidence = docs.at("Inspector::Evidence")
|
40
|
+
usage << evidence.docstring
|
41
|
+
|
42
|
+
usage << "\nProtocol for custom objects:\n\n"
|
43
|
+
evidence.children.each do |method|
|
44
|
+
next unless method.name.to_s.start_with? "inspector"
|
45
|
+
params = method.parameters.flatten.compact
|
46
|
+
usage << " - `#{method.name}(#{params.join ', '})` - #{method.docstring}\n"
|
47
|
+
end
|
48
|
+
usage << "\n\n"
|
49
|
+
|
50
|
+
new_file = start + start_split + usage + end_split + finale
|
51
|
+
File.open("README.md", 'w') { |f| f.write new_file }
|
52
|
+
end
|
data/bin/console
ADDED
data/bin/setup
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'inspector/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'gh-issues-inspector'
|
8
|
+
spec.version = Inspector::VERSION
|
9
|
+
spec.authors = ['Orta Therox']
|
10
|
+
spec.email = ['orta.therox@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'Search through GitHub issues for your project for existing issues about a Ruby Error.'
|
13
|
+
spec.description = 'Search through GitHub issues for your project for existing issues about a Ruby Error.'
|
14
|
+
spec.homepage = 'https://github.com/orta/gh-issues-inspector'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = 'exe'
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.11'
|
21
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
22
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
23
|
+
spec.add_development_dependency 'pry'
|
24
|
+
spec.add_development_dependency 'rubocop'
|
25
|
+
end
|
data/lib/evidence.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'inspector/version'
|
2
|
+
require 'time'
|
3
|
+
|
4
|
+
module Inspector
|
5
|
+
# The default user interface for the inspector, its public API should be
|
6
|
+
# considered the protocol for other classes wanting to provide a user interface.
|
7
|
+
#
|
8
|
+
# Your custom objects will be verified at runtime that they conform to the protocol.
|
9
|
+
#
|
10
|
+
# You can see the default implmentation at
|
11
|
+
# [lib/evidence.rb](/orta/gh-issues-inspector/tree/master/lib/evidence.rb).
|
12
|
+
#
|
13
|
+
# Both `search_query` and `search_exception` take your custom delegate as a 2nd optional parameter.
|
14
|
+
#
|
15
|
+
# ``` ruby
|
16
|
+
# require 'inspector'
|
17
|
+
# inspector = Inspector::Inspector.new "orta", "eigen"
|
18
|
+
# inspector.search_query "Someone set us up the bomb", ArtsyUI.new
|
19
|
+
# ```
|
20
|
+
#
|
21
|
+
|
22
|
+
class Evidence
|
23
|
+
# Called just as the investigation has begun.
|
24
|
+
def inspector_started_query(_query, inspector)
|
25
|
+
puts "Looking for related issues on #{inspector.repo_owner}/#{inspector.repo_name}..."
|
26
|
+
end
|
27
|
+
|
28
|
+
# Called once the inspector has recieved a report with more than one issue.
|
29
|
+
def inspector_successfully_recieved_report(report, _inspector)
|
30
|
+
report.issues[0..2].each { |issue| print_issue_full(issue) }
|
31
|
+
|
32
|
+
if report.issues.count > 3
|
33
|
+
puts "and #{report.total_results - 3} more at:"
|
34
|
+
puts report.url
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Called once the report has been recieved, but when there are no issues found.
|
39
|
+
def inspector_recieved_empty_report(_report, inspector)
|
40
|
+
puts "Found no similar issues. To create a new issue, please visit:"
|
41
|
+
puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/issues/new"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Called when there have been networking issues in creating the report.
|
45
|
+
def inspector_could_not_create_report(error, query, inspector)
|
46
|
+
puts "Could not access the GitHub API, you may have better luck via the website."
|
47
|
+
puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/search?q=#{query}&type=Issues&utf8=✓"
|
48
|
+
puts "Error: #{error.name}"
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def print_issue_full(issue)
|
54
|
+
puts " - #{issue.title}"
|
55
|
+
puts " #{issue.html_url} [#{issue.state}] [#{issue.comments} comment#{issue.comments == 1 ? '' : 's'}]"
|
56
|
+
puts " #{Time.parse(issue.updated_at).to_pretty}"
|
57
|
+
puts ""
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Taken from http://stackoverflow.com/questions/195740/how-do-you-do-relative-time-in-rails
|
63
|
+
|
64
|
+
module PrettyDate
|
65
|
+
def to_pretty
|
66
|
+
a = (Time.now - self).to_i
|
67
|
+
|
68
|
+
case a
|
69
|
+
when 0 then 'just now'
|
70
|
+
when 1 then 'a second ago'
|
71
|
+
when 2..59 then a.to_s + ' seconds ago'
|
72
|
+
when 60..119 then 'a minute ago' # 120 = 2 minutes
|
73
|
+
when 120..3540 then (a / 60).to_i.to_s + ' minutes ago'
|
74
|
+
when 3541..7100 then 'an hour ago' # 3600 = 1 hour
|
75
|
+
when 7101..82_800 then ((a + 99) / 3600).to_i.to_s + ' hours ago'
|
76
|
+
when 82_801..172_000 then 'a day ago' # 86400 = 1 day
|
77
|
+
when 172_001..518_400 then ((a + 800) / (60 * 60 * 24)).to_i.to_s + ' days ago'
|
78
|
+
when 518_400..1_036_800 then 'a week ago'
|
79
|
+
when 1_036_801..4_147_204 then ((a + 180_000) / (60 * 60 * 24 * 7)).to_i.to_s + ' weeks ago'
|
80
|
+
else strftime("%d %b %Y")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
Time.send :include, PrettyDate
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Inspector
|
2
|
+
class ExceptionHound
|
3
|
+
attr_accessor :message
|
4
|
+
|
5
|
+
def initialize(error)
|
6
|
+
self.message = find_message error
|
7
|
+
end
|
8
|
+
|
9
|
+
def find_message(error)
|
10
|
+
error.to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
def query
|
14
|
+
undefined
|
15
|
+
simple_nil
|
16
|
+
demangle_instances
|
17
|
+
|
18
|
+
message
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def undefined
|
24
|
+
self.message = message.gsub "undefined local variable or method", "undefined"
|
25
|
+
end
|
26
|
+
|
27
|
+
def simple_nil
|
28
|
+
self.message = message.gsub "nil:NilClass", "nil"
|
29
|
+
end
|
30
|
+
|
31
|
+
def demangle_instances
|
32
|
+
self.message = regex_replace(message, /(#<.*>)/, /#<(.*):/)
|
33
|
+
end
|
34
|
+
|
35
|
+
def regex_replace(string, find, replace)
|
36
|
+
if string.match find
|
37
|
+
full = string.match(find)[0]
|
38
|
+
simple = string.match(replace)[1]
|
39
|
+
string.gsub full, simple
|
40
|
+
else
|
41
|
+
string
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/inspector.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'inspector/version'
|
2
|
+
require 'sidekick'
|
3
|
+
require 'evidence'
|
4
|
+
require 'evidence'
|
5
|
+
require 'exception_hound'
|
6
|
+
|
7
|
+
# Note that the README is generated from the class comments, so it's a bit
|
8
|
+
# wider scope than your average class comment.
|
9
|
+
|
10
|
+
module Inspector
|
11
|
+
# To get started using The Issues Inspector, you will need to
|
12
|
+
# create an inspector instance. This class is main public API for querying issues.
|
13
|
+
#
|
14
|
+
# #### Getting Started
|
15
|
+
#
|
16
|
+
# Create an instance of `Inspector::Inspector`, you can then ask it to search
|
17
|
+
# based on your raised exception, or as a direct query yourself.
|
18
|
+
#
|
19
|
+
# ``` ruby
|
20
|
+
# require 'inspector'
|
21
|
+
# inspector = Inspector::Inspector.new "orta", "eigen"
|
22
|
+
# inspector.search_query "Someone set us up the bomb"
|
23
|
+
# ```
|
24
|
+
#
|
25
|
+
# By default this would output:
|
26
|
+
#
|
27
|
+
# ```
|
28
|
+
# Looking for related issues on CocoaPods/CocoaPods...
|
29
|
+
#
|
30
|
+
# - undefined method `to_ary' for #<Pod::Specification name="iVersion">Did you mean? to_query
|
31
|
+
# https://github.com/CocoaPods/CocoaPods/issues/4748 [closed] [1 comment]
|
32
|
+
#
|
33
|
+
# - NoMethodError - undefined method `to_ary' for Pod EAIntroView
|
34
|
+
# https://github.com/CocoaPods/CocoaPods/issues/4391 [closed] [15 comments]
|
35
|
+
#
|
36
|
+
# - Do a search on GitHub for issues relating to a crash?
|
37
|
+
# https://github.com/CocoaPods/CocoaPods/issues/4391 [open] [3 comments]
|
38
|
+
#
|
39
|
+
# and 10 more at:
|
40
|
+
# https://github.com/CocoaPods/CocoaPods/search?q=undefined+method+%60to_ary%27&type=Issues
|
41
|
+
# ```
|
42
|
+
#
|
43
|
+
|
44
|
+
class Inspector
|
45
|
+
attr_accessor :repo_owner, :repo_name, :query, :sidekick
|
46
|
+
|
47
|
+
# Class init function with a "orta/project" style string
|
48
|
+
def self.from_slug(slug)
|
49
|
+
details = slug.split '/'
|
50
|
+
Inspector.new details.first, details.last
|
51
|
+
end
|
52
|
+
|
53
|
+
# Init function with "orta", "project"
|
54
|
+
def initialize(repo_owner, repo_name)
|
55
|
+
self.repo_owner = repo_owner
|
56
|
+
self.repo_name = repo_name
|
57
|
+
self.sidekick = Sidekick.new(self, repo_owner, repo_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Will do some magic to try and pull out a reasonable search query
|
61
|
+
# for an exception, then searches with that
|
62
|
+
def search_exception(exception, delegate = nil)
|
63
|
+
query = ExceptionHound.new(exception).query
|
64
|
+
search_query(query, delegate)
|
65
|
+
end
|
66
|
+
|
67
|
+
# Queries for an specific search string
|
68
|
+
def search_query(query, _delegate = nil)
|
69
|
+
delegate ||= Evidence.new
|
70
|
+
sidekick.search(query, delegate)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/sidekick.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
require "net/http"
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module Inspector
|
5
|
+
# The Sidekick is the one who does all the real work.
|
6
|
+
# They take the query, get the GitHub API results, etc
|
7
|
+
# then pass them back to the inspector who gets the public API credit.
|
8
|
+
|
9
|
+
class Sidekick
|
10
|
+
attr_accessor :repo_owner, :repo_name, :inspector
|
11
|
+
|
12
|
+
def initialize(inspector, repo_owner, repo_name)
|
13
|
+
self.inspector = inspector
|
14
|
+
self.repo_owner = repo_owner
|
15
|
+
self.repo_name = repo_name
|
16
|
+
end
|
17
|
+
|
18
|
+
# Searches for a query, with a UI delegate
|
19
|
+
def search(query, delegate)
|
20
|
+
validate_delegate(delegate)
|
21
|
+
|
22
|
+
delegate.inspector_started_query(query, inspector)
|
23
|
+
url = url_for_request query
|
24
|
+
|
25
|
+
begin
|
26
|
+
results = get_api_results url
|
27
|
+
rescue Timeout::Error, Errno::EINVAL, Errno::ECONNRESET, EOFError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError, Net::ProtocolError => e
|
28
|
+
delegate.inspector_could_not_create_report(e, query, inspector)
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
report = parse_results query, results
|
33
|
+
|
34
|
+
# TODO: progress callback
|
35
|
+
|
36
|
+
if report.issues.any?
|
37
|
+
delegate.inspector_successfully_recieved_report(report, inspector)
|
38
|
+
else
|
39
|
+
delegate.inspector_recieved_empty_report(report, inspector)
|
40
|
+
end
|
41
|
+
|
42
|
+
report
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
require 'json'
|
48
|
+
|
49
|
+
# Generates a URL for the request
|
50
|
+
def url_for_request(query)
|
51
|
+
root = 'https://api.github.com/' \
|
52
|
+
"search/issues?q=#{query}%2Brepo%3A#{repo_owner}%2F#{repo_name}&sort=created&order=asc"
|
53
|
+
URI.escape root
|
54
|
+
end
|
55
|
+
|
56
|
+
# Gets the search results
|
57
|
+
def get_api_results(url)
|
58
|
+
uri = URI.parse url
|
59
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
60
|
+
http.use_ssl = true
|
61
|
+
|
62
|
+
request = Net::HTTP::Get.new uri.request_uri
|
63
|
+
response = http.request request
|
64
|
+
|
65
|
+
JSON.parse response.body
|
66
|
+
end
|
67
|
+
|
68
|
+
# Converts a GitHub search JSON into a InspectionReport
|
69
|
+
def parse_results(query, results)
|
70
|
+
report = InspectionReport.new
|
71
|
+
report.url = "https://github.com/#{repo_owner}/#{repo_name}/search?q=#{query}&type=Issues&utf8=✓"
|
72
|
+
report.query = query
|
73
|
+
report.total_results = results['total_count']
|
74
|
+
report.issues = results['items'].map { |item| Issue.new(item) }
|
75
|
+
report
|
76
|
+
end
|
77
|
+
|
78
|
+
def validate_delegate(delegate)
|
79
|
+
e = Evidence.new
|
80
|
+
protocol = e.public_methods false
|
81
|
+
protocol.each do |m|
|
82
|
+
raise "#{delegate} does not handle #{m}" unless delegate.methods.include? m
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
class InspectionReport
|
88
|
+
attr_accessor :issues, :url, :query, :total_results
|
89
|
+
end
|
90
|
+
|
91
|
+
class Issue
|
92
|
+
attr_accessor :title, :number, :html_url, :state, :body, :comments, :updated_at
|
93
|
+
|
94
|
+
# Hash -> public attributes
|
95
|
+
def initialize(*h)
|
96
|
+
if h.length == 1 && h.first.kind_of?(Hash)
|
97
|
+
h.first.each { |k, v| send("#{k}=", v) if public_methods.include?("#{k}=".to_sym) }
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: gh-issues-inspector
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Orta Therox
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Search through GitHub issues for your project for existing issues about
|
84
|
+
a Ruby Error.
|
85
|
+
email:
|
86
|
+
- orta.therox@gmail.com
|
87
|
+
executables: []
|
88
|
+
extensions: []
|
89
|
+
extra_rdoc_files: []
|
90
|
+
files:
|
91
|
+
- ".gitignore"
|
92
|
+
- ".rspec"
|
93
|
+
- ".rubocop.yml"
|
94
|
+
- ".travis.yml"
|
95
|
+
- Gemfile
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- bin/console
|
99
|
+
- bin/setup
|
100
|
+
- gh-issues-inspector.gemspec
|
101
|
+
- lib/evidence.rb
|
102
|
+
- lib/exception_hound.rb
|
103
|
+
- lib/inspector.rb
|
104
|
+
- lib/inspector/version.rb
|
105
|
+
- lib/sidekick.rb
|
106
|
+
homepage: https://github.com/orta/gh-issues-inspector
|
107
|
+
licenses: []
|
108
|
+
metadata: {}
|
109
|
+
post_install_message:
|
110
|
+
rdoc_options: []
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 2.2.2
|
126
|
+
signing_key:
|
127
|
+
specification_version: 4
|
128
|
+
summary: Search through GitHub issues for your project for existing issues about a
|
129
|
+
Ruby Error.
|
130
|
+
test_files: []
|
131
|
+
has_rdoc:
|