ghi 0.2.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.
- data/History.rdoc +180 -0
- data/Manifest.txt +14 -0
- data/README.rdoc +92 -0
- data/bin/ghi +6 -0
- data/lib/ghi.rb +55 -0
- data/lib/ghi/api.rb +106 -0
- data/lib/ghi/cli.rb +608 -0
- data/lib/ghi/issue.rb +29 -0
- data/spec/ghi/api_spec.rb +194 -0
- data/spec/ghi/cli_spec.rb +258 -0
- data/spec/ghi/issue_spec.rb +26 -0
- data/spec/ghi_spec.rb +91 -0
- metadata +70 -0
data/lib/ghi/cli.rb
ADDED
@@ -0,0 +1,608 @@
|
|
1
|
+
require "optparse"
|
2
|
+
require "tempfile"
|
3
|
+
require "ghi"
|
4
|
+
require "ghi/api"
|
5
|
+
require "ghi/issue"
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "launchy"
|
9
|
+
rescue LoadError
|
10
|
+
# No launchy!
|
11
|
+
end
|
12
|
+
|
13
|
+
module GHI::CLI #:nodoc:
|
14
|
+
module FileHelper
|
15
|
+
def launch_editor(file)
|
16
|
+
system "#{editor} #{file.path}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def gets_from_editor(issue)
|
20
|
+
if windows?
|
21
|
+
warn "Please supply the message with the -m option"
|
22
|
+
exit 1
|
23
|
+
end
|
24
|
+
|
25
|
+
if in_repo?
|
26
|
+
File.open message_path, "a+", &file_proc(issue)
|
27
|
+
else
|
28
|
+
Tempfile.open message_filename, &file_proc(issue)
|
29
|
+
end
|
30
|
+
|
31
|
+
return @message if comment?
|
32
|
+
return @message.shift.strip, @message.join.sub(/\b\n\b/, " ").strip
|
33
|
+
end
|
34
|
+
|
35
|
+
def delete_message
|
36
|
+
File.delete message_path
|
37
|
+
rescue Errno::ENOENT, TypeError
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def message_path
|
42
|
+
File.join gitdir, message_filename
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def editor
|
48
|
+
ENV["GHI_EDITOR"] || ENV["VISUAL"] || ENV["EDITOR"] || "vi"
|
49
|
+
end
|
50
|
+
|
51
|
+
def gitdir
|
52
|
+
@gitdir ||= `git rev-parse --git-dir 2>/dev/null`.chomp
|
53
|
+
end
|
54
|
+
|
55
|
+
def message_filename
|
56
|
+
@message_filename ||= "GHI_#{action.to_s.upcase}#{number}_MESSAGE"
|
57
|
+
end
|
58
|
+
|
59
|
+
def file_proc(issue)
|
60
|
+
lambda do |file|
|
61
|
+
file << edit_format(issue).join("\n") if File.zero? file.path
|
62
|
+
file.rewind
|
63
|
+
launch_editor file
|
64
|
+
@message = File.readlines(file.path).find_all { |l| !l.match(/^#/) }
|
65
|
+
|
66
|
+
if message.to_s =~ /\A\s*\Z/
|
67
|
+
raise GHI::API::InvalidRequest, "can't file empty message"
|
68
|
+
end
|
69
|
+
raise GHI::API::InvalidRequest, "no change" if issue == message
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def in_repo?
|
74
|
+
!gitdir.empty? && user == local_user && repo == local_repo
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module FormattingHelper
|
79
|
+
def list_header(term = nil)
|
80
|
+
if term
|
81
|
+
"# #{state.to_s.capitalize} #{term.inspect} issues on #{user}/#{repo}"
|
82
|
+
else
|
83
|
+
"# #{state.to_s.capitalize} issues on #{user}/#{repo}"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def list_format(issues, verbosity = nil)
|
88
|
+
unless issues.empty?
|
89
|
+
if verbosity
|
90
|
+
issues.map { |i| ["=" * 79] + show_format(i) }
|
91
|
+
else
|
92
|
+
issues.map { |i| " #{i.number.to_s.rjust 3}: #{truncate i.title, 72}" }
|
93
|
+
end
|
94
|
+
else
|
95
|
+
"none"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def edit_format(issue)
|
100
|
+
l = []
|
101
|
+
l << issue.title if issue.title && !comment?
|
102
|
+
l << ""
|
103
|
+
l << issue.body if issue.body && !comment?
|
104
|
+
if comment?
|
105
|
+
l << "# Please enter your comment."
|
106
|
+
else
|
107
|
+
l << "# Please explain the issue. The first line will become the title."
|
108
|
+
end
|
109
|
+
l << "# Lines beginning '#' will be ignored; ghi aborts empty messages."
|
110
|
+
l << "# All line breaks will be honored in accordance with GFM:"
|
111
|
+
l << "#"
|
112
|
+
l << "# http://github.github.com/github-flavored-markdown"
|
113
|
+
l << "#"
|
114
|
+
l << "# On #{user}/#{repo}:"
|
115
|
+
l << "#"
|
116
|
+
l += show_format(issue, false).map { |line| "# #{line}" }
|
117
|
+
end
|
118
|
+
|
119
|
+
def show_format(issue, verbose = true)
|
120
|
+
l = []
|
121
|
+
l << " number: #{issue.number}" if issue.number
|
122
|
+
l << " state: #{issue.state}" if issue.state
|
123
|
+
l << " title: #{indent(issue.title, 15, 0)}" if issue.title
|
124
|
+
l << " user: #{issue.user || GHI.login}"
|
125
|
+
l << " votes: #{issue.votes}" if issue.votes
|
126
|
+
l << " created at: #{issue.created_at}" if issue.created_at
|
127
|
+
l << " updated at: #{issue.updated_at}" if issue.updated_at
|
128
|
+
return l unless verbose
|
129
|
+
l << ""
|
130
|
+
l += indent(issue.body)[0..-2]
|
131
|
+
end
|
132
|
+
|
133
|
+
def action_format(value = nil)
|
134
|
+
key = "#{action.to_s.capitalize.sub(/e?$/, "ed")} issue #{number}"
|
135
|
+
"#{key}: #{truncate value.to_s, 78 - key.length}"
|
136
|
+
end
|
137
|
+
|
138
|
+
def truncate(string, length)
|
139
|
+
result = string.scan(/.{0,#{length - 3}}(?:\s|\Z)/).first.strip
|
140
|
+
result << "..." if result != string
|
141
|
+
result
|
142
|
+
end
|
143
|
+
|
144
|
+
def indent(string, level = 4, first = level)
|
145
|
+
lines = string.scan(/.{0,#{79 - level}}(?:\s|\Z)/).map { |line|
|
146
|
+
" " * level + line
|
147
|
+
}
|
148
|
+
lines.first.sub!(/^\s+/) {} if first != level
|
149
|
+
lines
|
150
|
+
end
|
151
|
+
|
152
|
+
private
|
153
|
+
|
154
|
+
def comment?
|
155
|
+
![:open, :edit].include?(action)
|
156
|
+
end
|
157
|
+
|
158
|
+
def puts(*args)
|
159
|
+
args = args.flatten.each { |arg|
|
160
|
+
arg.gsub!(/\B\*(.+)\*\B/) { "\e[1m#$1\e[0m" } # Bold
|
161
|
+
arg.gsub!(/\B_(.+)_\B/) { "\e[4m#$1\e[0m" } # Underline
|
162
|
+
arg.gsub!(/(state:)?(# Open.*| open)$/) { "#$1\e[32m#$2\e[0m" }
|
163
|
+
arg.gsub!(/(state:)?(# Closed.*| closed)$/) { "#$1\e[31m#$2\e[0m" }
|
164
|
+
marked = [GHI.login, search_term, tag, "(?:#|gh)-\d+"].compact * "|"
|
165
|
+
unless arg.include? "\e"
|
166
|
+
arg.gsub!(/(#{marked})/i) { "\e[1;4;33m#{$&}\e[0m" }
|
167
|
+
end
|
168
|
+
} if colorize?
|
169
|
+
rescue NoMethodError
|
170
|
+
# Do nothing.
|
171
|
+
ensure
|
172
|
+
$stdout.puts(*args)
|
173
|
+
end
|
174
|
+
|
175
|
+
def colorize?
|
176
|
+
return @colorize if defined? @colorize
|
177
|
+
@colorize = if $stdout.isatty && !windows?
|
178
|
+
!`git config --get-regexp color`.chomp.empty?
|
179
|
+
else
|
180
|
+
false
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def prepare_stdout
|
185
|
+
return if @prepared || @no_pager || !$stdout.isatty || pager.nil?
|
186
|
+
colorize? # Check for colorization.
|
187
|
+
$stdout = pager
|
188
|
+
@prepared = true
|
189
|
+
end
|
190
|
+
|
191
|
+
def pager
|
192
|
+
return @pager if defined? @pager
|
193
|
+
pagers = [ENV["GHI_PAGER"], "less -EMRX", "pager", "more"].compact.uniq
|
194
|
+
pagers.each { |pager| return @pager = IO.popen(pager, "w") rescue nil }
|
195
|
+
end
|
196
|
+
|
197
|
+
def windows?
|
198
|
+
RUBY_PLATFORM.include? "mswin"
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
class Executable
|
203
|
+
include FileHelper, FormattingHelper
|
204
|
+
|
205
|
+
attr_reader :message, :local_user, :local_repo, :user, :repo, :api,
|
206
|
+
:action, :search_term, :number, :title, :body, :tag, :args, :verbosity
|
207
|
+
|
208
|
+
def parse!(*argv)
|
209
|
+
@args, @argv = argv, argv.dup
|
210
|
+
|
211
|
+
remotes = `git config --get-regexp remote\..+\.url`.split /\n/
|
212
|
+
repo_expression = %r{([^:/]+)/([^/\s]+)(?:\.git)$}
|
213
|
+
if remote = remotes.find { |r| r.include? "github.com" }
|
214
|
+
remote.match repo_expression
|
215
|
+
@user, @repo = $1, $2
|
216
|
+
end
|
217
|
+
|
218
|
+
option_parser.parse!(*args)
|
219
|
+
|
220
|
+
if action.nil? && fallback_parsing(*args).nil?
|
221
|
+
puts option_parser
|
222
|
+
exit
|
223
|
+
end
|
224
|
+
rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
|
225
|
+
if fallback_parsing(*e.args).nil?
|
226
|
+
warn "#{File.basename $0}: #{e.message}"
|
227
|
+
puts option_parser
|
228
|
+
exit 1
|
229
|
+
end
|
230
|
+
rescue OptionParser::MissingArgument, OptionParser::AmbiguousOption => e
|
231
|
+
warn "#{File.basename $0}: #{e.message}"
|
232
|
+
puts option_parser
|
233
|
+
exit 1
|
234
|
+
ensure
|
235
|
+
run!
|
236
|
+
$stdout.close_write
|
237
|
+
end
|
238
|
+
|
239
|
+
def run!
|
240
|
+
@api = GHI::API.new user, repo
|
241
|
+
|
242
|
+
case action
|
243
|
+
when :search then search
|
244
|
+
when :list then list
|
245
|
+
when :show then show
|
246
|
+
when :open then open
|
247
|
+
when :edit then edit
|
248
|
+
when :close then close
|
249
|
+
when :reopen then reopen
|
250
|
+
when :comment then prepare_comment && comment
|
251
|
+
when :label, :claim then prepare_label && label
|
252
|
+
when :unlabel then prepare_label && unlabel
|
253
|
+
when :url then url
|
254
|
+
end
|
255
|
+
rescue GHI::API::InvalidConnection
|
256
|
+
if action
|
257
|
+
code = 1
|
258
|
+
warn "#{File.basename $0}: not a GitHub repo"
|
259
|
+
puts option_parser if args.flatten.empty?
|
260
|
+
exit 1
|
261
|
+
end
|
262
|
+
rescue GHI::API::InvalidRequest => e
|
263
|
+
warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
|
264
|
+
delete_message
|
265
|
+
exit 1
|
266
|
+
rescue GHI::API::ResponseError => e
|
267
|
+
warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
|
268
|
+
exit 1
|
269
|
+
end
|
270
|
+
|
271
|
+
def commenting?
|
272
|
+
@commenting
|
273
|
+
end
|
274
|
+
|
275
|
+
def state
|
276
|
+
@state || :open
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
def option_parser
|
282
|
+
@option_parser ||= OptionParser.new { |opts|
|
283
|
+
opts.banner = "Usage: #{File.basename $0} [options]"
|
284
|
+
|
285
|
+
opts.on("-l", "--list", "--search", "--show [state|term|number]") do |v|
|
286
|
+
@action = :list
|
287
|
+
case v
|
288
|
+
when nil, /^o(?:pen)?$/
|
289
|
+
# Defaults.
|
290
|
+
when /^\d+$/
|
291
|
+
@action = :show
|
292
|
+
@number = v.to_i
|
293
|
+
when /^c(?:losed)?$/
|
294
|
+
@state = :closed
|
295
|
+
when /^u$/
|
296
|
+
@action = :url
|
297
|
+
when /^v$/
|
298
|
+
@verbosity = true
|
299
|
+
else
|
300
|
+
@action = :search
|
301
|
+
@search_term = v
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
opts.on("-v", "--verbose") do |v|
|
306
|
+
if v
|
307
|
+
@action ||= :list
|
308
|
+
@verbosity = true
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
opts.on("-o", "--open", "--reopen [title|number]") do |v|
|
313
|
+
@action = :open
|
314
|
+
case v
|
315
|
+
when /^\d+$/
|
316
|
+
@action = :reopen
|
317
|
+
@number = v.to_i
|
318
|
+
when /^l$/
|
319
|
+
@action = :list
|
320
|
+
when /^m$/
|
321
|
+
@title = args * " "
|
322
|
+
when /^u$/
|
323
|
+
@action = :url
|
324
|
+
else
|
325
|
+
@title = v
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
opts.on("-c", "--closed", "--close [number]") do |v|
|
330
|
+
case v
|
331
|
+
when /^\d+$/
|
332
|
+
@action = :close
|
333
|
+
@number = v.to_i unless v.nil?
|
334
|
+
when /^l$/
|
335
|
+
@action = :list
|
336
|
+
@state = :closed
|
337
|
+
when /^u$/
|
338
|
+
@action = :url
|
339
|
+
@state = :closed
|
340
|
+
when nil
|
341
|
+
if @action.nil? || @number
|
342
|
+
@action = :close
|
343
|
+
else
|
344
|
+
@state = :closed
|
345
|
+
end
|
346
|
+
else
|
347
|
+
raise OptionParser::InvalidArgument
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
opts.on("-e", "--edit [number]") do |v|
|
352
|
+
case v
|
353
|
+
when /^\d+$/
|
354
|
+
@action = :edit
|
355
|
+
@number = v.to_i
|
356
|
+
when nil
|
357
|
+
raise OptionParser::MissingArgument
|
358
|
+
else
|
359
|
+
raise OptionParser::InvalidArgument
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
opts.on("-r", "--repo", "--repository [name]") do |v|
|
364
|
+
case v
|
365
|
+
when nil
|
366
|
+
raise OptionParser::MissingArgument
|
367
|
+
else
|
368
|
+
repo = v.split "/"
|
369
|
+
repo.unshift GHI.login if repo.length == 1
|
370
|
+
@user, @repo = repo
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
opts.on("-m", "--comment [number|comment]") do |v|
|
375
|
+
case v
|
376
|
+
when /^\d+$/, nil
|
377
|
+
@action ||= :comment
|
378
|
+
@number ||= v.to_i unless v.nil?
|
379
|
+
@commenting = true
|
380
|
+
else
|
381
|
+
@body = v
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
opts.on("-t", "--label [number] [label]") do |v|
|
386
|
+
raise OptionParser::MissingArgument if v.nil?
|
387
|
+
@action ||= :label
|
388
|
+
@number = v.to_i
|
389
|
+
end
|
390
|
+
|
391
|
+
opts.on("--claim [number]") do |v|
|
392
|
+
raise OptionParser::MissingArgument if v.nil?
|
393
|
+
@action = :claim
|
394
|
+
@number = v.to_i
|
395
|
+
@tag = GHI.login
|
396
|
+
end
|
397
|
+
|
398
|
+
opts.on("-d", "--unlabel [number] [label]") do |v|
|
399
|
+
@action = :unlabel
|
400
|
+
case v
|
401
|
+
when /^\d+$/
|
402
|
+
@number = v.to_i
|
403
|
+
when /^\w+$/
|
404
|
+
@tag = v
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
opts.on("-u", "--url [state|number]") do |v|
|
409
|
+
@action = :url
|
410
|
+
case v
|
411
|
+
when /^\d+$/
|
412
|
+
@number = v.to_i
|
413
|
+
when /^c(?:losed)?$/
|
414
|
+
@state = :closed
|
415
|
+
when /^u(?:nread)?$/
|
416
|
+
@state = :unread
|
417
|
+
end
|
418
|
+
end
|
419
|
+
|
420
|
+
opts.on("--[no-]color") do |v|
|
421
|
+
@colorize = v
|
422
|
+
end
|
423
|
+
|
424
|
+
opts.on("--[no-]pager") do |v|
|
425
|
+
@no_pager = (v == false)
|
426
|
+
end
|
427
|
+
|
428
|
+
opts.on_tail("-V", "--version") do
|
429
|
+
puts "#{File.basename($0)}: v#{GHI::VERSION}"
|
430
|
+
exit
|
431
|
+
end
|
432
|
+
|
433
|
+
opts.on_tail("-h", "--help") do
|
434
|
+
puts opts
|
435
|
+
exit
|
436
|
+
end
|
437
|
+
}
|
438
|
+
end
|
439
|
+
|
440
|
+
def search
|
441
|
+
prepare_stdout
|
442
|
+
puts list_header(search_term)
|
443
|
+
issues = api.search search_term, state
|
444
|
+
puts list_format(issues, verbosity)
|
445
|
+
end
|
446
|
+
|
447
|
+
def list
|
448
|
+
prepare_stdout
|
449
|
+
puts list_header
|
450
|
+
issues = api.list(state)
|
451
|
+
puts list_format(issues, verbosity)
|
452
|
+
end
|
453
|
+
|
454
|
+
def show
|
455
|
+
prepare_stdout
|
456
|
+
issue = api.show number
|
457
|
+
puts show_format(issue)
|
458
|
+
end
|
459
|
+
|
460
|
+
def open
|
461
|
+
if title.nil?
|
462
|
+
new_title, new_body = gets_from_editor GHI::Issue.new("title" => body)
|
463
|
+
elsif @commenting && body.nil?
|
464
|
+
new_title, new_body = gets_from_editor GHI::Issue.new("title" => title)
|
465
|
+
end
|
466
|
+
new_title ||= title
|
467
|
+
new_body ||= body
|
468
|
+
issue = api.open new_title, new_body
|
469
|
+
delete_message
|
470
|
+
@number = issue.number
|
471
|
+
puts action_format(issue.title)
|
472
|
+
end
|
473
|
+
|
474
|
+
def edit
|
475
|
+
shown = api.show number
|
476
|
+
new_title, new_body = gets_from_editor(shown) if body.nil?
|
477
|
+
new_title ||= shown.title
|
478
|
+
new_body ||= body
|
479
|
+
issue = api.edit number, new_title, new_body
|
480
|
+
delete_message
|
481
|
+
puts action_format(issue.title)
|
482
|
+
end
|
483
|
+
|
484
|
+
def close
|
485
|
+
raise GHI::API::InvalidRequest, "need a number" if number.nil?
|
486
|
+
issue = api.close number
|
487
|
+
if @commenting || new_body = body
|
488
|
+
new_body ||= gets_from_editor issue
|
489
|
+
comment = api.comment number, new_body
|
490
|
+
end
|
491
|
+
puts action_format(issue.title)
|
492
|
+
puts "(comment #{comment["status"]})" if comment
|
493
|
+
end
|
494
|
+
|
495
|
+
def reopen
|
496
|
+
issue = api.reopen number
|
497
|
+
if @commenting || new_body = body
|
498
|
+
new_body ||= gets_from_editor issue
|
499
|
+
comment = api.comment number, new_body
|
500
|
+
end
|
501
|
+
puts action_format(issue.title)
|
502
|
+
puts "(comment #{comment["status"]})" if comment
|
503
|
+
end
|
504
|
+
|
505
|
+
def prepare_label
|
506
|
+
@tag ||= (body || args * " ")
|
507
|
+
raise GHI::API::InvalidRequest, "need a label" if @tag.empty?
|
508
|
+
true
|
509
|
+
end
|
510
|
+
|
511
|
+
def label
|
512
|
+
labels = api.add_label tag, number
|
513
|
+
puts action_format
|
514
|
+
puts indent(labels.join(", "))
|
515
|
+
end
|
516
|
+
|
517
|
+
def unlabel
|
518
|
+
labels = api.remove_label tag, number
|
519
|
+
puts action_format
|
520
|
+
puts indent(labels.empty? ? "no labels" : labels.join(", "))
|
521
|
+
end
|
522
|
+
|
523
|
+
def prepare_comment
|
524
|
+
@body = args.flatten.first
|
525
|
+
@commenting = false unless body.nil?
|
526
|
+
true
|
527
|
+
end
|
528
|
+
|
529
|
+
def comment
|
530
|
+
@body ||= gets_from_editor api.show(number)
|
531
|
+
comment = api.comment(number, body)
|
532
|
+
delete_message
|
533
|
+
puts "(comment #{comment["status"]})"
|
534
|
+
end
|
535
|
+
|
536
|
+
def url
|
537
|
+
url = "http://github.com/#{user}/#{repo}/issues"
|
538
|
+
if number.nil?
|
539
|
+
url << "/#{state}" unless state == :open
|
540
|
+
else
|
541
|
+
url << "#issue/#{number}"
|
542
|
+
end
|
543
|
+
defined?(Launchy) ? Launchy.open(url) : puts(url)
|
544
|
+
end
|
545
|
+
|
546
|
+
#-
|
547
|
+
# Because these are mere fallbacks, any options used earlier will muddle
|
548
|
+
# things: `ghi list` will work, `ghi list -c` will not.
|
549
|
+
#
|
550
|
+
# Argument parsing will have to better integrate with option parsing to
|
551
|
+
# overcome this.
|
552
|
+
#+
|
553
|
+
def fallback_parsing(*arguments)
|
554
|
+
arguments = arguments.flatten
|
555
|
+
case command = arguments.shift
|
556
|
+
when nil, "list"
|
557
|
+
@action = :list
|
558
|
+
if arg = arguments.shift
|
559
|
+
@state ||= arg.to_sym if %w(open closed).include? arg
|
560
|
+
@user, @repo = arg.split "/" if arg.count("/") == 1
|
561
|
+
end
|
562
|
+
when "search"
|
563
|
+
@action = :search
|
564
|
+
@search_term ||= arguments.shift
|
565
|
+
when "show", /^-?(\d+)$/
|
566
|
+
@action = :show
|
567
|
+
@number ||= ($1 || arguments.shift[/\d+/]).to_i
|
568
|
+
when "open"
|
569
|
+
@action = :open
|
570
|
+
when "edit"
|
571
|
+
@action = :edit
|
572
|
+
@number ||= arguments.shift[/\d+/].to_i
|
573
|
+
when "close"
|
574
|
+
@action = :close
|
575
|
+
@number ||= arguments.shift[/\d+/].to_i
|
576
|
+
when "reopen"
|
577
|
+
@action = :reopen
|
578
|
+
@number ||= arguments.shift[/\d+/].to_i
|
579
|
+
when "label"
|
580
|
+
@action = :label
|
581
|
+
@number ||= arguments.shift[/\d+/].to_i
|
582
|
+
@label ||= arguments.shift
|
583
|
+
when "unlabel"
|
584
|
+
@action = :unlabel
|
585
|
+
@number ||= arguments.shift[/\d+/].to_i
|
586
|
+
@label ||= arguments.shift
|
587
|
+
when "comment"
|
588
|
+
@action = :comment
|
589
|
+
@number ||= arguments.shift[/\d+/].to_i
|
590
|
+
when "claim"
|
591
|
+
@action = :claim
|
592
|
+
@number ||= arguments.shift[/\d+/].to_i
|
593
|
+
when %r{^([^/]+)/([^/]+)$}
|
594
|
+
@action = :list
|
595
|
+
@user, @repo = $1, $2
|
596
|
+
end
|
597
|
+
if @action
|
598
|
+
@args = @argv.dup
|
599
|
+
args.delete_if { |arg| arg == command }
|
600
|
+
option_parser.parse!(*args)
|
601
|
+
return true
|
602
|
+
end
|
603
|
+
unless command.start_with? "-"
|
604
|
+
warn "#{File.basename $0}: what do you mean, '#{command}'?"
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|
608
|
+
end
|