stephencelis-ghi 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +8 -0
- data/lib/ghi.rb +1 -1
- data/lib/ghi/api.rb +35 -23
- data/lib/ghi/cli.rb +70 -47
- metadata +2 -2
data/History.rdoc
CHANGED
data/lib/ghi.rb
CHANGED
data/lib/ghi/api.rb
CHANGED
@@ -17,54 +17,66 @@ class GHI::API
|
|
17
17
|
@user, @repo = user, repo
|
18
18
|
end
|
19
19
|
|
20
|
+
def search(term, state = :open)
|
21
|
+
get(:search, state, term)["issues"].map { |attrs| GHI::Issue.new(attrs) }
|
22
|
+
end
|
23
|
+
|
20
24
|
def list(state = :open)
|
21
|
-
|
22
|
-
raise ResponseError, res if res["issues"].nil?
|
23
|
-
res["issues"].map { |attrs| GHI::Issue.new(attrs) }
|
25
|
+
get(:list, state)["issues"].map { |attrs| GHI::Issue.new(attrs) }
|
24
26
|
end
|
25
27
|
|
26
28
|
def show(number)
|
27
|
-
|
28
|
-
raise ResponseError, res if res["issue"].nil?
|
29
|
-
GHI::Issue.new res["issue"]
|
29
|
+
GHI::Issue.new get(:show, number)["issue"]
|
30
30
|
end
|
31
31
|
|
32
32
|
def open(title, body)
|
33
|
-
|
34
|
-
raise ResponseError, res if res["issue"].nil?
|
35
|
-
GHI::Issue.new res["issue"]
|
33
|
+
GHI::Issue.new post(:open, :title => title, :body => body)["issue"]
|
36
34
|
end
|
37
35
|
|
38
36
|
def edit(number, title, body)
|
39
|
-
res = post
|
40
|
-
raise ResponseError, res if res["issue"].nil?
|
37
|
+
res = post :edit, number, :title => title, :body => body
|
41
38
|
GHI::Issue.new res["issue"]
|
42
39
|
end
|
43
40
|
|
44
41
|
def close(number)
|
45
|
-
|
46
|
-
raise ResponseError, res if res["issue"].nil?
|
47
|
-
GHI::Issue.new res["issue"]
|
42
|
+
GHI::Issue.new post(:close, number)["issue"]
|
48
43
|
end
|
49
44
|
|
50
45
|
def reopen(number)
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
GHI::Issue.new post(:reopen, number)
|
47
|
+
end
|
48
|
+
|
49
|
+
def add_label(label, number)
|
50
|
+
post "label/add", label, number
|
51
|
+
p res
|
52
|
+
end
|
53
|
+
|
54
|
+
def remove_label(label, number)
|
55
|
+
post "label/remove", label, number
|
56
|
+
end
|
57
|
+
|
58
|
+
def comment(number, comment)
|
59
|
+
post(:comment, number, comment)["comment"]
|
54
60
|
end
|
55
61
|
|
56
62
|
private
|
57
63
|
|
58
64
|
def get(*args)
|
59
|
-
res = Net::HTTP.get
|
60
|
-
|
65
|
+
res = YAML.load Net::HTTP.get(URI.parse(url(*args) + auth(true)))
|
66
|
+
raise ResponseError, errors(res) if res["error"]
|
67
|
+
res
|
61
68
|
end
|
62
69
|
|
63
70
|
def post(*args)
|
64
71
|
params = args.last.is_a?(Hash) ? args.pop : {}
|
65
72
|
params.update auth
|
66
|
-
res = Net::HTTP.post_form
|
67
|
-
|
73
|
+
res = YAML.load Net::HTTP.post_form(URI.parse(url(*args)), params).body
|
74
|
+
raise ResponseError, errors(res) if res["error"]
|
75
|
+
res
|
76
|
+
end
|
77
|
+
|
78
|
+
def errors(response)
|
79
|
+
[*response["error"]].map { |e| e["error"] } * ", "
|
68
80
|
end
|
69
81
|
|
70
82
|
def auth(query = false)
|
@@ -75,10 +87,10 @@ class GHI::API
|
|
75
87
|
end
|
76
88
|
end
|
77
89
|
|
78
|
-
def url(action,
|
90
|
+
def url(action, *args)
|
79
91
|
@url ||= API_URL.sub(":user", user).sub(":repo", repo)
|
80
92
|
uri = @url.sub ":action", action.to_s
|
81
|
-
uri += "/#{
|
93
|
+
uri += "/#{args.join("/")}" unless args.empty?
|
82
94
|
uri
|
83
95
|
end
|
84
96
|
end
|
data/lib/ghi/cli.rb
CHANGED
@@ -5,73 +5,80 @@ require "ghi/api"
|
|
5
5
|
require "ghi/issue"
|
6
6
|
|
7
7
|
class GHI::CLI
|
8
|
-
|
9
|
-
|
10
|
-
@api = GHI::API.new *(@user, @repo = $1, $2)
|
8
|
+
attr_reader :user, :repo, :api, :action, :state, :number, :title,
|
9
|
+
:search_term
|
11
10
|
|
11
|
+
def initialize
|
12
12
|
option_parser.parse!(ARGV)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
|
14
|
+
`git config --get remote.origin.url`.match %r{([^:/]+)/([^/]+).git$}
|
15
|
+
@user ||= $1
|
16
|
+
@repo ||= $2
|
17
|
+
@api = GHI::API.new user, repo
|
18
|
+
|
19
|
+
case action
|
20
|
+
when :search then search search_term, state
|
21
|
+
when :list then list state
|
22
|
+
when :show then show number
|
23
|
+
when :open then open title
|
24
|
+
when :edit then edit number
|
25
|
+
when :close then close number
|
26
|
+
when :reopen then reopen number
|
20
27
|
else puts option_parser
|
21
28
|
end
|
22
29
|
rescue GHI::API::InvalidConnection
|
23
30
|
warn "#{File.basename $0}: not a GitHub repo"
|
31
|
+
rescue GHI::API::ResponseError => e
|
32
|
+
warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
|
24
33
|
rescue OptionParser::InvalidOption, OptionParser::MissingArgument => e
|
25
34
|
warn "#{File.basename $0}: #{e.message}"
|
26
35
|
end
|
27
36
|
|
28
37
|
private
|
29
38
|
|
30
|
-
def options
|
31
|
-
@options ||= {}
|
32
|
-
end
|
33
|
-
|
34
39
|
def option_parser
|
35
40
|
@option_parser ||= OptionParser.new { |opts|
|
36
41
|
opts.banner = "Usage: #{File.basename $0} [options]"
|
37
42
|
|
38
|
-
opts.on("-l", "--list", "--show [number]") do |v|
|
39
|
-
|
43
|
+
opts.on("-l", "--list", "--search", "--show [state|term|number]") do |v|
|
44
|
+
@action = :list
|
40
45
|
case v
|
41
|
-
when nil, /^o
|
42
|
-
|
46
|
+
when nil, /^o$/
|
47
|
+
@state = :open
|
43
48
|
when /^\d+$/
|
44
|
-
|
45
|
-
|
46
|
-
when /^c
|
47
|
-
|
49
|
+
@action = :show
|
50
|
+
@number = v.to_i
|
51
|
+
when /^c$/
|
52
|
+
@state = :closed
|
48
53
|
else
|
49
|
-
|
54
|
+
@action = :search
|
55
|
+
@state ||= :open
|
56
|
+
@search_term = v
|
50
57
|
end
|
51
58
|
end
|
52
59
|
|
53
60
|
opts.on("-o", "--open", "--reopen [number]") do |v|
|
54
|
-
|
61
|
+
@action = :open
|
55
62
|
case v
|
56
63
|
when /^\d+$/
|
57
|
-
|
58
|
-
|
59
|
-
when /^l
|
60
|
-
|
61
|
-
|
64
|
+
@action = :reopen
|
65
|
+
@number = v.to_i
|
66
|
+
when /^l/, nil
|
67
|
+
@action = :list
|
68
|
+
@state = :open
|
62
69
|
else
|
63
|
-
|
70
|
+
@title = v
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
67
74
|
opts.on("-c", "--closed", "--close [number]") do |v|
|
68
75
|
case v
|
69
76
|
when /^\d+$/
|
70
|
-
|
71
|
-
|
72
|
-
when /^l
|
73
|
-
|
74
|
-
|
77
|
+
@action = :close
|
78
|
+
@number = v.to_i
|
79
|
+
when /^l/, nil
|
80
|
+
@action = :list
|
81
|
+
@state = :closed
|
75
82
|
else
|
76
83
|
raise OptionParser::InvalidOption
|
77
84
|
end
|
@@ -80,14 +87,20 @@ class GHI::CLI
|
|
80
87
|
opts.on("-e", "--edit [number]") do |v|
|
81
88
|
case v
|
82
89
|
when /^\d+$/
|
83
|
-
|
84
|
-
|
85
|
-
|
90
|
+
@action = :edit
|
91
|
+
@state = :closed
|
92
|
+
@number = v.to_i
|
86
93
|
else
|
87
94
|
raise OptionParser::MissingArgument
|
88
95
|
end
|
89
96
|
end
|
90
97
|
|
98
|
+
opts.on("-r", "--repo", "--repository [name]") do |v|
|
99
|
+
repo = v.split "/"
|
100
|
+
repo.unshift GHI.login if repo.length == 1
|
101
|
+
@user, @repo = repo
|
102
|
+
end
|
103
|
+
|
91
104
|
opts.on("-V", "--version") do
|
92
105
|
puts "#{File.basename($0)}: v#{GHI::VERSION}"
|
93
106
|
exit
|
@@ -100,9 +113,19 @@ class GHI::CLI
|
|
100
113
|
}
|
101
114
|
end
|
102
115
|
|
116
|
+
def search(term, state)
|
117
|
+
issues = api.search term, state
|
118
|
+
puts "# #{state.to_s.capitalize} #{term.inspect} issues on #{user}/#{repo}"
|
119
|
+
if issues.empty?
|
120
|
+
puts "none"
|
121
|
+
else
|
122
|
+
puts issues.map { |i| " #{i.number.to_s.rjust(3)}: #{i.title[0,72]}" }
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
103
126
|
def list(state)
|
104
|
-
issues =
|
105
|
-
puts "# #{state.to_s.capitalize} issues on
|
127
|
+
issues = api.list state
|
128
|
+
puts "# #{state.to_s.capitalize} issues on #{user}/#{repo}"
|
106
129
|
if issues.empty?
|
107
130
|
puts "none"
|
108
131
|
else
|
@@ -111,7 +134,7 @@ class GHI::CLI
|
|
111
134
|
end
|
112
135
|
|
113
136
|
def show(number)
|
114
|
-
issue =
|
137
|
+
issue = api.show number
|
115
138
|
puts <<-BODY
|
116
139
|
#{issue.number}: #{issue.title} [#{issue.state}]
|
117
140
|
|
@@ -136,7 +159,7 @@ BODY
|
|
136
159
|
#
|
137
160
|
# http://github.github.com/github-flavored-markdown
|
138
161
|
#
|
139
|
-
# On
|
162
|
+
# On #{user}/#{repo}:
|
140
163
|
#
|
141
164
|
# user: #{GHI.login}
|
142
165
|
BODY
|
@@ -150,7 +173,7 @@ BODY
|
|
150
173
|
else
|
151
174
|
title = lines.shift.strip
|
152
175
|
body = lines.join.sub(/\b\n\b/, " ").strip
|
153
|
-
issue =
|
176
|
+
issue = api.open title, body
|
154
177
|
puts " Opened issue #{issue.number}: #{issue.title[0,58]}"
|
155
178
|
end
|
156
179
|
end
|
@@ -159,7 +182,7 @@ BODY
|
|
159
182
|
edit = ENV["VISUAL"] || ENV["EDITOR"] || "vi"
|
160
183
|
begin
|
161
184
|
temp = Tempfile.open("open-issue-")
|
162
|
-
issue =
|
185
|
+
issue = api.show number
|
163
186
|
temp.write <<-BODY
|
164
187
|
#{issue.title}#{"\n\n" + issue.body unless issue.body.to_s.strip == ""}
|
165
188
|
# Please explain the issue. The first line will be used as the title.
|
@@ -193,7 +216,7 @@ BODY
|
|
193
216
|
else
|
194
217
|
title = lines.shift.strip
|
195
218
|
body = lines.join.sub(/\b\n\b/, " ").strip
|
196
|
-
issue =
|
219
|
+
issue = api.edit number, title, body
|
197
220
|
puts " Updated issue #{issue.number}: #{issue.title[0,58]}"
|
198
221
|
end
|
199
222
|
end
|
@@ -203,12 +226,12 @@ BODY
|
|
203
226
|
end
|
204
227
|
|
205
228
|
def close(number)
|
206
|
-
issue =
|
229
|
+
issue = api.close number
|
207
230
|
puts " Closed issue #{issue.number}: #{issue.title[0,58]}"
|
208
231
|
end
|
209
232
|
|
210
233
|
def reopen(number)
|
211
|
-
issue =
|
234
|
+
issue = api.reopen number
|
212
235
|
puts " Reopened issue #{issue.number}: #{issue.title[0,56]}"
|
213
236
|
end
|
214
237
|
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.2
|
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-21 00:00:00 -07:00
|
13
13
|
default_executable: ghi
|
14
14
|
dependencies: []
|
15
15
|
|