stephencelis-ghi 0.0.7 → 0.0.8
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.
- data/History.rdoc +12 -0
- data/README.rdoc +3 -0
- data/lib/ghi/cli.rb +32 -6
- data/lib/ghi.rb +4 -4
- data/spec/ghi/api_spec.rb +183 -0
- data/spec/ghi_spec.rb +82 -3
- metadata +2 -2
data/History.rdoc
CHANGED
data/README.rdoc
CHANGED
@@ -27,6 +27,7 @@ Go:
|
|
27
27
|
-t, --label [number] [label]
|
28
28
|
--claim [number]
|
29
29
|
-d, --unlabel [number] [label]
|
30
|
+
-u, --url [number]
|
30
31
|
-V, --version
|
31
32
|
-h, --help
|
32
33
|
|
@@ -52,6 +53,8 @@ ghi works simply from within a repository. Some short examples:
|
|
52
53
|
ghi -t1 "tag" # Labels issue 1 with "tag"
|
53
54
|
ghi -d1 "tag" # Removes the label, "tag"
|
54
55
|
ghi --claim 1 # Tags issue 1 with your GitHub username
|
56
|
+
open `ghi -u` # Loads issues in your browser.
|
57
|
+
open `ghi -u1` # Loads an issue in your browser.
|
55
58
|
|
56
59
|
|
57
60
|
ghi also works anywhere:
|
data/lib/ghi/cli.rb
CHANGED
@@ -162,6 +162,8 @@ module GHI::CLI #:nodoc:
|
|
162
162
|
when :comment then comment
|
163
163
|
when :label, :claim then add_label
|
164
164
|
when :unlabel then remove_label
|
165
|
+
|
166
|
+
when :url then url
|
165
167
|
end
|
166
168
|
rescue GHI::API::InvalidConnection
|
167
169
|
warn "#{File.basename $0}: not a GitHub repo"
|
@@ -188,13 +190,15 @@ module GHI::CLI #:nodoc:
|
|
188
190
|
opts.on("-l", "--list", "--search", "--show [state|term|number]") do |v|
|
189
191
|
@action = :list
|
190
192
|
case v
|
191
|
-
when nil, /^o
|
193
|
+
when nil, /^o(?:pen)?$/
|
192
194
|
@state = :open
|
193
195
|
when /^\d+$/
|
194
196
|
@action = :show
|
195
197
|
@number = v.to_i
|
196
|
-
when /^c
|
198
|
+
when /^c(?:losed)?$/
|
197
199
|
@state = :closed
|
200
|
+
when /^u$/
|
201
|
+
@action = :url
|
198
202
|
else
|
199
203
|
@action = :search
|
200
204
|
@state ||= :open
|
@@ -213,6 +217,8 @@ module GHI::CLI #:nodoc:
|
|
213
217
|
@state = :open
|
214
218
|
when /^m$/
|
215
219
|
@title = ARGV * " "
|
220
|
+
when /^u$/
|
221
|
+
@action = :url
|
216
222
|
else
|
217
223
|
@title = v
|
218
224
|
end
|
@@ -221,11 +227,14 @@ module GHI::CLI #:nodoc:
|
|
221
227
|
opts.on("-c", "--closed", "--close [number]") do |v|
|
222
228
|
case v
|
223
229
|
when /^\d+$/
|
224
|
-
@action
|
225
|
-
@number = v.to_i
|
226
|
-
when /^l
|
230
|
+
@action ||= :close
|
231
|
+
@number = v.to_i unless v.nil?
|
232
|
+
when /^l$/, nil
|
227
233
|
@action = :list
|
228
234
|
@state = :closed
|
235
|
+
when /^u$/, nil
|
236
|
+
@action = :url
|
237
|
+
@state = :closed
|
229
238
|
when nil
|
230
239
|
raise OptionParser::MissingArgument
|
231
240
|
else
|
@@ -286,6 +295,16 @@ module GHI::CLI #:nodoc:
|
|
286
295
|
end
|
287
296
|
end
|
288
297
|
|
298
|
+
opts.on("-u", "--url [number]") do |v|
|
299
|
+
@action = :url
|
300
|
+
case v
|
301
|
+
when /^\d+$/
|
302
|
+
@number = v.to_i
|
303
|
+
when /^c/
|
304
|
+
@state = :closed
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
289
308
|
opts.on_tail("-V", "--version") do
|
290
309
|
puts "#{File.basename($0)}: v#{GHI::VERSION}"
|
291
310
|
exit
|
@@ -375,7 +394,14 @@ module GHI::CLI #:nodoc:
|
|
375
394
|
body = gets_from_editor api.show(number)
|
376
395
|
comment = api.comment(number, body)
|
377
396
|
delete_message
|
378
|
-
puts "comment #{comment["status"]}"
|
397
|
+
puts "(comment #{comment["status"]})"
|
398
|
+
end
|
399
|
+
|
400
|
+
def url
|
401
|
+
url = "http://github.com/#{user}/#{repo}/issues"
|
402
|
+
url << "/#{state}" unless state.nil?
|
403
|
+
url << "/#{number}/find" unless number.nil?
|
404
|
+
puts url
|
379
405
|
end
|
380
406
|
end
|
381
407
|
end
|
data/lib/ghi.rb
CHANGED
@@ -2,7 +2,7 @@ require "net/http"
|
|
2
2
|
require "yaml"
|
3
3
|
|
4
4
|
module GHI
|
5
|
-
VERSION = "0.0.
|
5
|
+
VERSION = "0.0.8"
|
6
6
|
|
7
7
|
def self.login
|
8
8
|
return @login if defined? @login
|
@@ -39,15 +39,15 @@ module GHI
|
|
39
39
|
def self.user?(username)
|
40
40
|
url = "http://github.com/api/v2/yaml/user/show/#{username}"
|
41
41
|
!YAML.load(Net::HTTP.get(URI.parse(url)))["user"].nil?
|
42
|
-
rescue ArgumentError
|
42
|
+
rescue ArgumentError, URI::InvalidURIError
|
43
43
|
false
|
44
44
|
end
|
45
45
|
|
46
46
|
def self.token?(token)
|
47
47
|
url = "http://github.com/api/v2/yaml/user/show/#{GHI.login}"
|
48
48
|
url += "?login=#{GHI.login}&token=#{token}"
|
49
|
-
!YAML.load(Net::HTTP.get(URI.parse(url)))["user"].nil?
|
50
|
-
rescue ArgumentError, NoMethodError
|
49
|
+
!YAML.load(Net::HTTP.get(URI.parse(url)))["user"]["plan"].nil?
|
50
|
+
rescue ArgumentError, NoMethodError, URI::InvalidURIError
|
51
51
|
false
|
52
52
|
end
|
53
53
|
end
|
data/spec/ghi/api_spec.rb
CHANGED
@@ -1,8 +1,57 @@
|
|
1
1
|
$: << File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
2
|
require "ghi"
|
3
3
|
require "ghi/api"
|
4
|
+
require "ghi/issue"
|
4
5
|
include GHI
|
5
6
|
|
7
|
+
ISSUES_YAML = <<-YAML
|
8
|
+
---
|
9
|
+
issues:
|
10
|
+
- number: 1
|
11
|
+
votes: 0
|
12
|
+
created_at: 2009-04-17 14:55:33 -07:00
|
13
|
+
body: my sweet, sweet issue
|
14
|
+
title: new issue
|
15
|
+
updated_at: 2009-04-17 14:55:33 -07:00
|
16
|
+
user: schacon
|
17
|
+
state: open
|
18
|
+
- number: 2
|
19
|
+
votes: 0
|
20
|
+
created_at: 2009-04-17 15:16:47 -07:00
|
21
|
+
body: the body of a second issue
|
22
|
+
title: another issue
|
23
|
+
updated_at: 2009-04-17 15:16:47 -07:00
|
24
|
+
user: schacon
|
25
|
+
state: open
|
26
|
+
YAML
|
27
|
+
|
28
|
+
ISSUE_YAML = <<-YAML
|
29
|
+
---
|
30
|
+
issue:
|
31
|
+
number: 1
|
32
|
+
votes: 0
|
33
|
+
created_at: 2009-04-17 14:55:33 -07:00
|
34
|
+
body: my sweet, sweet issue
|
35
|
+
title: new issue
|
36
|
+
updated_at: 2009-04-17 14:55:33 -07:00
|
37
|
+
user: schacon
|
38
|
+
state: open
|
39
|
+
YAML
|
40
|
+
|
41
|
+
LABELS_YAML = <<-YAML
|
42
|
+
---
|
43
|
+
labels:
|
44
|
+
- testing
|
45
|
+
- test_label
|
46
|
+
YAML
|
47
|
+
|
48
|
+
COMMENT_YAML = <<-YAML
|
49
|
+
---
|
50
|
+
comment:
|
51
|
+
comment: this is amazing
|
52
|
+
status: saved
|
53
|
+
YAML
|
54
|
+
|
6
55
|
describe GHI::API do
|
7
56
|
it "should require user and repo" do
|
8
57
|
proc { API.new(nil, nil) }.should raise_error(API::InvalidConnection)
|
@@ -10,4 +59,138 @@ describe GHI::API do
|
|
10
59
|
proc { API.new(nil, "r") }.should raise_error(API::InvalidConnection)
|
11
60
|
proc { API.new("u", "r") }.should_not raise_error(API::InvalidConnection)
|
12
61
|
end
|
62
|
+
|
63
|
+
describe "requests" do
|
64
|
+
before :all do
|
65
|
+
@api = API.new "stephencelis", "ghi"
|
66
|
+
GHI.stub!(:login).and_return "stephencelis"
|
67
|
+
GHI.stub!(:token).and_return "token"
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should substitute url tokens" do
|
71
|
+
@api.send(:url, :open).should ==
|
72
|
+
"http://github.com/api/v2/yaml/issues/open/stephencelis/ghi"
|
73
|
+
@api.send(:url, :show, 1).should ==
|
74
|
+
"http://github.com/api/v2/yaml/issues/show/stephencelis/ghi/1"
|
75
|
+
@api.send(:url, :search, :open, "me").should ==
|
76
|
+
"http://github.com/api/v2/yaml/issues/search/stephencelis/ghi/open/me"
|
77
|
+
@api.send(:url, "label/add", "me").should ==
|
78
|
+
"http://github.com/api/v2/yaml/issues/label/add/stephencelis/ghi/me"
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should process gets" do
|
82
|
+
url = "http://github.com/api/v2/yaml/issues/open/stephencelis/ghi"
|
83
|
+
query = "?login=stephencelis&token=d1cd249db48d51c9847cbf2b291f5ae9"
|
84
|
+
@api.stub!(:url).and_return url
|
85
|
+
URI.should_receive(:parse).once.with(url + query).and_return("mock")
|
86
|
+
Net::HTTP.should_receive(:get).once.with("mock").and_return ISSUES_YAML
|
87
|
+
@api.list
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should process posts" do
|
91
|
+
url = "http://github.com/api/v2/yaml/issues/open/stephencelis/ghi"
|
92
|
+
query = { :login => "stephencelis",
|
93
|
+
:token => "d1cd249db48d51c9847cbf2b291f5ae9",
|
94
|
+
:title => "Title",
|
95
|
+
:body => "Body" }
|
96
|
+
@api.stub!(:url).and_return url
|
97
|
+
r = mock(Net::HTTPRequest)
|
98
|
+
r.should_receive(:body).once.and_return ISSUE_YAML
|
99
|
+
URI.should_receive(:parse).once.with(url).and_return "u"
|
100
|
+
Net::HTTP.should_receive(:post_form).once.with("u", query).and_return r
|
101
|
+
@api.open "Title", "Body"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should search open by default" do
|
105
|
+
@api.should_receive(:url).with(:search, :open, "me").and_return "u"
|
106
|
+
Net::HTTP.stub!(:get).and_return ISSUES_YAML
|
107
|
+
issues = @api.search "me"
|
108
|
+
issues.should be_an_instance_of(Array)
|
109
|
+
issues.each { |issue| issue.should be_an_instance_of(Issue) }
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should search closed" do
|
113
|
+
@api.should_receive(:url).with(:search, :closed, "me").and_return "u"
|
114
|
+
Net::HTTP.stub!(:get).and_return ISSUES_YAML
|
115
|
+
@api.search "me", :closed
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should list open by default" do
|
119
|
+
@api.should_receive(:url).with(:list, :open).and_return "u"
|
120
|
+
Net::HTTP.stub!(:get).and_return ISSUES_YAML
|
121
|
+
issues = @api.list
|
122
|
+
issues.should be_an_instance_of(Array)
|
123
|
+
issues.each { |issue| issue.should be_an_instance_of(Issue) }
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should list closed" do
|
127
|
+
@api.should_receive(:url).with(:list, :closed).and_return "u"
|
128
|
+
Net::HTTP.stub!(:get).and_return ISSUES_YAML
|
129
|
+
@api.list :closed
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should show" do
|
133
|
+
@api.should_receive(:url).with(:show, 1).and_return "u"
|
134
|
+
Net::HTTP.stub!(:get).and_return ISSUE_YAML
|
135
|
+
@api.show(1).should be_an_instance_of(Issue)
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should open" do
|
139
|
+
@api.should_receive(:url).with(:open).and_return "u"
|
140
|
+
response = mock(Net::HTTPRequest)
|
141
|
+
response.stub!(:body).and_return ISSUE_YAML
|
142
|
+
Net::HTTP.stub!(:post_form).and_return response
|
143
|
+
@api.open("Title", "Body").should be_an_instance_of(Issue)
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should edit" do
|
147
|
+
@api.should_receive(:url).with(:edit, 1).and_return "u"
|
148
|
+
response = mock(Net::HTTPRequest)
|
149
|
+
response.stub!(:body).and_return ISSUE_YAML
|
150
|
+
Net::HTTP.stub!(:post_form).and_return response
|
151
|
+
@api.edit(1, "Title", "Body").should be_an_instance_of(Issue)
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should close" do
|
155
|
+
@api.should_receive(:url).with(:close, 1).and_return "u"
|
156
|
+
response = mock(Net::HTTPRequest)
|
157
|
+
response.stub!(:body).and_return ISSUE_YAML
|
158
|
+
Net::HTTP.stub!(:post_form).and_return response
|
159
|
+
@api.close(1).should be_an_instance_of(Issue)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should reopen" do
|
163
|
+
@api.should_receive(:url).with(:reopen, 1).and_return "u"
|
164
|
+
response = mock(Net::HTTPRequest)
|
165
|
+
response.stub!(:body).and_return ISSUE_YAML
|
166
|
+
Net::HTTP.stub!(:post_form).and_return response
|
167
|
+
@api.reopen(1).should be_an_instance_of(Issue)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should add labels" do
|
171
|
+
@api.should_receive(:url).with("label/add", 1, "l").and_return "u"
|
172
|
+
response = mock(Net::HTTPRequest)
|
173
|
+
response.stub!(:body).and_return LABELS_YAML
|
174
|
+
Net::HTTP.stub!(:post_form).and_return response
|
175
|
+
@api.add_label(1, "l").should be_an_instance_of(Array)
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should remove labels" do
|
179
|
+
@api.should_receive(:url).with("label/remove", 1, "l").and_return "u"
|
180
|
+
response = mock(Net::HTTPRequest)
|
181
|
+
response.stub!(:body).and_return LABELS_YAML
|
182
|
+
Net::HTTP.stub!(:post_form).and_return response
|
183
|
+
@api.remove_label(1, "l").should be_an_instance_of(Array)
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should comment" do
|
187
|
+
@api.should_receive(:url).with(:comment, 1).and_return "u"
|
188
|
+
URI.stub!(:parse).and_return "u"
|
189
|
+
response = mock(Net::HTTPRequest)
|
190
|
+
response.stub!(:body).and_return COMMENT_YAML
|
191
|
+
Net::HTTP.should_receive(:post_form).with("u",
|
192
|
+
hash_including(:comment => "Comment")).and_return response
|
193
|
+
@api.comment(1, "Comment").should be_an_instance_of(Hash)
|
194
|
+
end
|
195
|
+
end
|
13
196
|
end
|
data/spec/ghi_spec.rb
CHANGED
@@ -1,14 +1,93 @@
|
|
1
|
-
|
1
|
+
$LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
2
|
require "ghi"
|
3
3
|
|
4
|
+
LOGGED_OUT_YAML = <<-YAML
|
5
|
+
---
|
6
|
+
user:
|
7
|
+
id: 23
|
8
|
+
login: defunkt
|
9
|
+
name: Kristopher Walken Wanstrath
|
10
|
+
company: LA
|
11
|
+
location: SF
|
12
|
+
email: me@email.com
|
13
|
+
blog: http://myblog.com
|
14
|
+
following_count: 13
|
15
|
+
followers_count: 63
|
16
|
+
public_gist_count: 0
|
17
|
+
public_repo_count: 2
|
18
|
+
YAML
|
19
|
+
|
20
|
+
LOGGED_IN_YAML = <<-YAML
|
21
|
+
---
|
22
|
+
user:
|
23
|
+
id: 23
|
24
|
+
login: defunkt
|
25
|
+
name: Kristopher Walken Wanstrath
|
26
|
+
company: LA
|
27
|
+
location: SF
|
28
|
+
email: me@email.com
|
29
|
+
blog: http://myblog.com
|
30
|
+
following_count: 13
|
31
|
+
followers_count: 63
|
32
|
+
public_gist_count: 0
|
33
|
+
public_repo_count: 2
|
34
|
+
total_private_repo_count: 1
|
35
|
+
collaborators: 3
|
36
|
+
disk_usage: 50384
|
37
|
+
owned_private_repo_count: 1
|
38
|
+
private_gist_count: 0
|
39
|
+
plan:
|
40
|
+
name: mega
|
41
|
+
collaborators: 60
|
42
|
+
space: 20971520
|
43
|
+
private_repos: 125
|
44
|
+
YAML
|
45
|
+
|
4
46
|
describe GHI do
|
47
|
+
before :each do
|
48
|
+
GHI.instance_eval do
|
49
|
+
remove_instance_variable :@login if instance_variable_defined? :@login
|
50
|
+
remove_instance_variable :@token if instance_variable_defined? :@token
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
5
54
|
it "should return login" do
|
6
|
-
GHI.
|
55
|
+
GHI.should_receive(:`).once.and_return "stephencelis\n"
|
7
56
|
GHI.login.should == "stephencelis"
|
8
57
|
end
|
9
58
|
|
10
59
|
it "should return token" do
|
11
|
-
GHI.
|
60
|
+
GHI.should_receive(:`).once.and_return "da39a3ee5e6b4b0d3255bfef95601890\n"
|
12
61
|
GHI.token.should == "da39a3ee5e6b4b0d3255bfef95601890"
|
13
62
|
end
|
63
|
+
|
64
|
+
it "should approve login input" do
|
65
|
+
GHI.instance_eval { instance_variable_defined?(:@login).should == false }
|
66
|
+
GHI.should_receive(:`).with("git config --get github.user").
|
67
|
+
and_return "\n"
|
68
|
+
GHI.should_receive(:print).twice
|
69
|
+
GHI.should_receive(:gets).twice.and_return "defunct\n", "defunkt\n"
|
70
|
+
Net::HTTP.should_receive(:get).and_return "500: invalid: response",
|
71
|
+
LOGGED_OUT_YAML
|
72
|
+
GHI.should_receive(:warn).once
|
73
|
+
GHI.should_receive(:`).with("git config --global github.user defunkt").
|
74
|
+
and_return "\n"
|
75
|
+
GHI.login.should == "defunkt"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should approve token input" do
|
79
|
+
GHI.instance_eval { instance_variable_defined?(:@token).should == false }
|
80
|
+
GHI.stub!(:login).and_return "defunkt"
|
81
|
+
GHI.should_receive(:`).with("git config --get github.token").
|
82
|
+
and_return "\n"
|
83
|
+
GHI.should_receive(:print).twice
|
84
|
+
token = "da39a3ee5e6b4b0d3255bfef95601890"
|
85
|
+
GHI.should_receive(:gets).and_return "invalid\n", "#{token}\n"
|
86
|
+
Net::HTTP.should_receive(:get).and_return LOGGED_OUT_YAML, LOGGED_IN_YAML
|
87
|
+
GHI.should_receive(:warn).once
|
88
|
+
# FIXME: Passes on its own...but failing for `spec spec`.
|
89
|
+
GHI.should_receive(:`).with("git config --global github.token #{token}").
|
90
|
+
and_return "\n"
|
91
|
+
GHI.token.should == token
|
92
|
+
end
|
14
93
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stephencelis-ghi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Celis
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-04-
|
12
|
+
date: 2009-04-26 00:00:00 -07:00
|
13
13
|
default_executable: ghi
|
14
14
|
dependencies: []
|
15
15
|
|