stephencelis-ghi 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|