ruby-bugzilla 0.4.0 → 0.4.1
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/bin/bzconsole +2 -2
- data/lib/bugzilla/version.rb +1 -1
- metadata +2 -4
- data/bin/bzconsole~ +0 -836
data/bin/bzconsole
CHANGED
@@ -890,7 +890,7 @@ begin
|
|
890
890
|
opt.on('-t', '--timeout=SEC', 'Set XMLRPC timeout in a second.') {|v| opts[:timeout] = v.to_i}
|
891
891
|
opt.on('-h', '--help', 'show this message') {|x| opts[:help] = true}
|
892
892
|
|
893
|
-
cmds = BzConsole.constants.sort.map {|x| (k = eval("BzConsole::#{x}")).class == Class && x != :CommandTemplate ? x.downcase : nil}.compact
|
893
|
+
cmds = BzConsole.constants.sort.map {|x| (k = eval("BzConsole::#{x}")).class == Class && x != :CommandTemplate ? x.downcase.to_sym : nil}.compact
|
894
894
|
|
895
895
|
subargv = opt.order(ARGV);
|
896
896
|
|
@@ -899,7 +899,7 @@ begin
|
|
899
899
|
if subargv.length > 0 then
|
900
900
|
n = cmds.index(command.to_sym)
|
901
901
|
unless n.nil? then
|
902
|
-
opts[:instance] = eval("BzConsole::#{cmds[n].capitalize}.new(Bugzilla::Plugin::Template.new)")
|
902
|
+
opts[:instance] = eval("BzConsole::#{cmds[n].to_s.capitalize}.new(Bugzilla::Plugin::Template.new)")
|
903
903
|
subargv = opts[:instance].parse(opt, subargv[1..-1], opts[:command])
|
904
904
|
else
|
905
905
|
STDERR.printf("E: Unknown command: %s\n", subargv[0])
|
data/lib/bugzilla/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-bugzilla
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
@@ -97,7 +97,6 @@ email:
|
|
97
97
|
- akira@tagoh.org
|
98
98
|
executables:
|
99
99
|
- bzconsole
|
100
|
-
- bzconsole~
|
101
100
|
extensions: []
|
102
101
|
extra_rdoc_files: []
|
103
102
|
files:
|
@@ -121,7 +120,6 @@ files:
|
|
121
120
|
- README.rdoc
|
122
121
|
- COPYING
|
123
122
|
- bin/bzconsole
|
124
|
-
- bin/bzconsole~
|
125
123
|
homepage: http://github.com/tagoh/ruby-bugzilla
|
126
124
|
licenses: []
|
127
125
|
post_install_message:
|
data/bin/bzconsole~
DELETED
@@ -1,836 +0,0 @@
|
|
1
|
-
#! /usr/bin/env ruby
|
2
|
-
# bzconsole.rb
|
3
|
-
# Copyright (C) 2010-2012 Red Hat, Inc.
|
4
|
-
#
|
5
|
-
# Authors:
|
6
|
-
# Akira TAGOH <tagoh@redhat.com>
|
7
|
-
#
|
8
|
-
# This library is free software; you can redistribute it and/or
|
9
|
-
# modify it under the terms of the GNU Lesser General Public
|
10
|
-
# License as published by the Free Software Foundation; either
|
11
|
-
# version 2 of the License, or (at your option) any later version.
|
12
|
-
#
|
13
|
-
# This library is distributed in the hope that it will be useful,
|
14
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
16
|
-
# Lesser General Public License for more details.
|
17
|
-
#
|
18
|
-
# You should have received a copy of the GNU Lesser General Public
|
19
|
-
# License along with this library; if not, write to the
|
20
|
-
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
21
|
-
# Boston, MA 02111-1307, USA.
|
22
|
-
|
23
|
-
require 'optparse'
|
24
|
-
require 'time'
|
25
|
-
require 'yaml'
|
26
|
-
require 'rubygems'
|
27
|
-
require 'pp'
|
28
|
-
require 'gruff'
|
29
|
-
require 'uri'
|
30
|
-
require 'highline/import'
|
31
|
-
|
32
|
-
begin
|
33
|
-
require 'bugzilla'
|
34
|
-
rescue LoadError
|
35
|
-
$:.push(File.join(File.dirname(__FILE__), '..', 'lib'))
|
36
|
-
require 'bugzilla'
|
37
|
-
end
|
38
|
-
|
39
|
-
$KCODE = 'u'
|
40
|
-
|
41
|
-
module BzConsole
|
42
|
-
|
43
|
-
class CommandTemplate
|
44
|
-
|
45
|
-
def initialize(plugin)
|
46
|
-
@n_args = 0
|
47
|
-
@defaultyamlfile = File.join(ENV['HOME'], ".bzconsole.yml")
|
48
|
-
@plugin = plugin
|
49
|
-
end # def initialize
|
50
|
-
|
51
|
-
attr_reader :n_args
|
52
|
-
|
53
|
-
def parse(parser, argv, opts)
|
54
|
-
raise RuntimeError, sprintf("No implementation for %s", self.class) if self.class =~ /CommandTemplate/
|
55
|
-
|
56
|
-
parser.on('-h', '--help', 'show this message') {|x| opts[:help] = true}
|
57
|
-
|
58
|
-
read_config(opts)
|
59
|
-
@plugin.run(:parser, nil, parser, argv, opts)
|
60
|
-
|
61
|
-
parser.order(argv)
|
62
|
-
end # def parse
|
63
|
-
|
64
|
-
def do(argv)
|
65
|
-
raise RuntimeError, sprintf("No implementation for %s", self.class)
|
66
|
-
end # def do
|
67
|
-
|
68
|
-
protected
|
69
|
-
|
70
|
-
def read_config(opts)
|
71
|
-
fname = opts[:config].nil? ? @defaultyamlfile : opts[:config]
|
72
|
-
begin
|
73
|
-
conf = YAML.load(File.open(fname).read)
|
74
|
-
rescue Errno::ENOENT
|
75
|
-
conf = {}
|
76
|
-
end
|
77
|
-
conf.each do |k, v|
|
78
|
-
if v.kind_of?(Hash) && v.include?(:Plugin) then
|
79
|
-
load(v[:Plugin])
|
80
|
-
end
|
81
|
-
end
|
82
|
-
conf
|
83
|
-
end # def read_config
|
84
|
-
|
85
|
-
def save_config(opts, conf)
|
86
|
-
fname = opts[:config].nil? ? @defaultyamlfile : opts[:config]
|
87
|
-
if File.exist?(fname) then
|
88
|
-
st = File.lstat(fname)
|
89
|
-
if st.mode & 0600 != 0600 then
|
90
|
-
raise RuntimeError, sprintf("The permissions of %s has to be 0600", fname)
|
91
|
-
end
|
92
|
-
end
|
93
|
-
File.open(fname, "w") {|f| f.chmod(0600); f.write(conf.to_yaml)}
|
94
|
-
end # def save_config
|
95
|
-
|
96
|
-
private
|
97
|
-
|
98
|
-
def get_proxy(info)
|
99
|
-
uri = info[:Proxy] || ENV["http_proxy"]
|
100
|
-
proxy_uri = uri.nil? ? nil : URI.parse(uri)
|
101
|
-
proxy_host = proxy_uri.nil? ? nil : proxy_uri.host
|
102
|
-
proxy_port = proxy_uri.nil? ? nil : proxy_uri.port
|
103
|
-
return proxy_host, proxy_port
|
104
|
-
end
|
105
|
-
|
106
|
-
end # class CommandTemplate
|
107
|
-
|
108
|
-
class Setup < CommandTemplate
|
109
|
-
|
110
|
-
def initialize(plugin)
|
111
|
-
super
|
112
|
-
|
113
|
-
@n_args = 0
|
114
|
-
end # def initialize
|
115
|
-
|
116
|
-
def parse(parser, argv, opts)
|
117
|
-
parser.banner = sprintf("Usage: %s [global options] setup", File.basename(__FILE__))
|
118
|
-
parser.separator ""
|
119
|
-
parser.separator "Command options:"
|
120
|
-
|
121
|
-
super
|
122
|
-
end # def parse
|
123
|
-
|
124
|
-
def do(argv, opts)
|
125
|
-
template = {
|
126
|
-
"rhbz"=>{
|
127
|
-
:Name=>"Red Hat Bugzilla",
|
128
|
-
:URL=>"https://bugzilla.redhat.com",
|
129
|
-
:User=>"account@example.com",
|
130
|
-
:Password=>"blahblahblah",
|
131
|
-
:ProductAliases=>{
|
132
|
-
'RHEL3'=>'Red Hat Enterprise Linux 3',
|
133
|
-
'RHEL4'=>'Red Hat Enterprise Linux 4',
|
134
|
-
'RHEL5'=>'Red Hat Enterprise Linux 5',
|
135
|
-
'RHEL6'=>'Red Hat Enterprise Linux 6'
|
136
|
-
},
|
137
|
-
:Plugin=>"ruby-bugzilla/rhbugzilla.rb"
|
138
|
-
},
|
139
|
-
"gnbz"=>{
|
140
|
-
:Name=>"GNOME Bugzilla",
|
141
|
-
:URL=>"https://bugzilla.gnome.org",
|
142
|
-
:User=>"account@example.com",
|
143
|
-
:Password=>"blahblahblah",
|
144
|
-
},
|
145
|
-
"fdobz"=>{
|
146
|
-
:Name=>"FreeDesktop Bugzilla",
|
147
|
-
:URL=>"https://bugs.freedesktop.org",
|
148
|
-
:User=>"account@example.com",
|
149
|
-
:Password=>"blahblahblah",
|
150
|
-
},
|
151
|
-
"mzbz"=>{
|
152
|
-
:Name=>"Mozilla Bugzilla",
|
153
|
-
:URL=>"https://bugzilla.mozilla.org",
|
154
|
-
:User=>"account@example.com",
|
155
|
-
:Password=>"blahblahblah",
|
156
|
-
}
|
157
|
-
}
|
158
|
-
|
159
|
-
template.each do |k, v|
|
160
|
-
@plugin.run(:pre, v[:URL].sub(/\Ahttps?:\/\//, '').sub(/\/\Z/, ''), :setup, v)
|
161
|
-
end
|
162
|
-
|
163
|
-
fname = opts[:config].nil? ? @defaultyamlfile : opts[:config]
|
164
|
-
if File.exist?(fname) then
|
165
|
-
raise RuntimeError, ".bzconsole.yml already exists. please remove it first to proceed to the next step."
|
166
|
-
end
|
167
|
-
File.open(fname, File::CREAT|File::WRONLY, 0600) do |f|
|
168
|
-
f.write(template.to_yaml)
|
169
|
-
end
|
170
|
-
printf("%s has been created. please modify your account information before operating.\n", fname)
|
171
|
-
end # def do
|
172
|
-
|
173
|
-
end # class Setup
|
174
|
-
|
175
|
-
class Login < CommandTemplate
|
176
|
-
|
177
|
-
def initialize(plugin)
|
178
|
-
super
|
179
|
-
|
180
|
-
@n_args = 1
|
181
|
-
end # def initialize
|
182
|
-
|
183
|
-
def parse(parser, argv, opts)
|
184
|
-
opts[:output] = File.join(ENV['HOME'], '.ruby-bugzilla-cookie.yml')
|
185
|
-
parser.banner = sprintf("Usage: %s [global options] login [command options] <prefix> ...", File.basename(__FILE__))
|
186
|
-
parser.separator ""
|
187
|
-
parser.separator "Command options:"
|
188
|
-
parser.on('-o', '--output=FILE', 'FILE to store the cookie') {|v| opts[:output] = v}
|
189
|
-
|
190
|
-
super
|
191
|
-
end # def parse
|
192
|
-
|
193
|
-
def do(argv, opts)
|
194
|
-
conf = read_config(opts)
|
195
|
-
conf.freeze
|
196
|
-
cconf = read_config({:config=>opts[:command][:output]})
|
197
|
-
argv.each do |prefix|
|
198
|
-
if prefix.nil? then
|
199
|
-
raise ArgumentError, "No prefix to log in"
|
200
|
-
end
|
201
|
-
unless conf.include?(prefix) then
|
202
|
-
raise RuntimeError, sprintf("No host information for %s", prefix)
|
203
|
-
end
|
204
|
-
|
205
|
-
info = conf[prefix]
|
206
|
-
uri = URI.parse(info[:URL])
|
207
|
-
host = uri.host
|
208
|
-
port = uri.port
|
209
|
-
path = uri.path.empty? ? nil : uri.path
|
210
|
-
login = info[:User].nil? ? ask("Bugzilla ID: ") : info[:User]
|
211
|
-
pass = info[:Password].nil? ? ask("Bugzilla password: ") {|q| q.echo = false} : info[:Password]
|
212
|
-
proxy_host, proxy_port = get_proxy(info)
|
213
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
214
|
-
|
215
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout)
|
216
|
-
user = Bugzilla::User.new(xmlrpc)
|
217
|
-
begin
|
218
|
-
result = user.login({'login'=>login, 'password'=>pass, 'remember'=>true})
|
219
|
-
cconf[host] = xmlrpc.cookie
|
220
|
-
save_config({:config=>opts[:command][:output]}, cconf)
|
221
|
-
rescue XMLRPC::FaultException => e
|
222
|
-
printf("E: %s\n", e.message)
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end # def do
|
226
|
-
|
227
|
-
end # class Login
|
228
|
-
|
229
|
-
class Getbug < CommandTemplate
|
230
|
-
|
231
|
-
def initialize(plugin)
|
232
|
-
super
|
233
|
-
|
234
|
-
@n_args = 1
|
235
|
-
end # def initialize
|
236
|
-
|
237
|
-
def parse(parser, argv, opts)
|
238
|
-
parser.banner = sprintf("Usage: %s [global options] getbug [command options] <prefix:bug number> ...", File.basename(__FILE__))
|
239
|
-
parser.separator ""
|
240
|
-
parser.separator "Command options:"
|
241
|
-
parser.on('-s', '--summary', 'Displays bugs summary only') {opts[:summary] = true}
|
242
|
-
parser.on('-d', '--details', 'Displays detailed bugs information') {opts[:details] = true}
|
243
|
-
parser.on('-a', '--all', 'Displays the whole data in bugs') {opts[:all] = true}
|
244
|
-
parser.on('--anonymous', 'Access to Bugzilla anonymously') {opts[:anonymous] = true}
|
245
|
-
|
246
|
-
super
|
247
|
-
end # def parse
|
248
|
-
|
249
|
-
def do(argv, opts)
|
250
|
-
real_do(argv, opts) do |result|
|
251
|
-
if opts[:command][:summary] == true then
|
252
|
-
printf("Bug#%s, %s, %s[%s, %s] %s\n",
|
253
|
-
result['id'],
|
254
|
-
result['product'],
|
255
|
-
result['component'],
|
256
|
-
result['status'],
|
257
|
-
result['severity'],
|
258
|
-
result['summary'])
|
259
|
-
elsif opts[:command][:details] == true then
|
260
|
-
printf("Bug#%s, %s, %s, %s[%s, %s, %s, %s] %s\n",
|
261
|
-
result['id'],
|
262
|
-
result['product'],
|
263
|
-
result['assigned_to'],
|
264
|
-
result['component'],
|
265
|
-
result['status'],
|
266
|
-
result['resolution'],
|
267
|
-
result['priority'],
|
268
|
-
result['severity'],
|
269
|
-
result['summary'])
|
270
|
-
else
|
271
|
-
printf("Bug#%s - %s\n", result['id'], result['summary'])
|
272
|
-
printf("Status:\t\t%s%s\n", result['status'], !result['resolution'].empty? ? sprintf("[%s]", result['resolution']) : "")
|
273
|
-
printf("Product:\t%s\n", result['product'])
|
274
|
-
printf("Component:\t%s\n", result['component'])
|
275
|
-
printf("Assinged To:\t%s\n", result['assigned_to'])
|
276
|
-
printf("Priority:\t%s\n", result['priority'])
|
277
|
-
printf("Severity:\t%s\n", result['severity'])
|
278
|
-
printf("Comments:\t%d\n\n", result['comments'].length)
|
279
|
-
i = 0
|
280
|
-
result['comments'].each do |c|
|
281
|
-
printf("Comment#%d%s %s %s\n", i, c['is_private'] == true ? "[private]" : "", c['author'], c['time'].to_time)
|
282
|
-
printf("\n %s\n\n", c['text'].split("\n").join("\n "))
|
283
|
-
i += 1
|
284
|
-
end
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end # def do
|
288
|
-
|
289
|
-
private
|
290
|
-
|
291
|
-
def real_do(argv, opts)
|
292
|
-
conf = read_config(opts)
|
293
|
-
conf.freeze
|
294
|
-
argv.each do |bugn|
|
295
|
-
bugn =~ /(.*):(.*)/
|
296
|
-
prefix = $1
|
297
|
-
nnn = $2
|
298
|
-
if prefix.nil? then
|
299
|
-
raise ArgumentError, sprintf("No prefix specified for Bug#%s", bugn)
|
300
|
-
end
|
301
|
-
unless conf.include?(prefix) then
|
302
|
-
raise RuntimeError, sprintf("No host information for %s", prefix)
|
303
|
-
end
|
304
|
-
|
305
|
-
info = conf[prefix]
|
306
|
-
uri = URI.parse(info[:URL])
|
307
|
-
host = uri.host
|
308
|
-
port = uri.port
|
309
|
-
path = uri.path.empty? ? nil : uri.path
|
310
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
311
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
312
|
-
proxy_host, proxy_port = get_proxy(info)
|
313
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
314
|
-
|
315
|
-
@plugin.run(:pre, host, :getbug, opts)
|
316
|
-
|
317
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout)
|
318
|
-
user = Bugzilla::User.new(xmlrpc)
|
319
|
-
user.session(login, pass) do
|
320
|
-
bug = Bugzilla::Bug.new(xmlrpc)
|
321
|
-
|
322
|
-
result = nil
|
323
|
-
if opts[:command][:summary] == true then
|
324
|
-
result = bug.get_bugs(nnn.split(','))
|
325
|
-
elsif opts[:command][:details] == true then
|
326
|
-
result = bug.get_bugs(nnn.split(','), ::Bugzilla::Bug::FIELDS_DETAILS)
|
327
|
-
else
|
328
|
-
result = bug.get_bugs(nnn.split(','), nil)
|
329
|
-
end
|
330
|
-
|
331
|
-
@plugin.run(:post, host, :getbug, result)
|
332
|
-
|
333
|
-
result.each do |r|
|
334
|
-
yield r
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
end # def real_do
|
339
|
-
|
340
|
-
end # class Getbug
|
341
|
-
|
342
|
-
class Search < CommandTemplate
|
343
|
-
|
344
|
-
def initialize(plugin)
|
345
|
-
super
|
346
|
-
|
347
|
-
@n_args = 1
|
348
|
-
end # def initialize
|
349
|
-
|
350
|
-
def parse(parser, argv, opts)
|
351
|
-
opts[:query] ||= {}
|
352
|
-
parser.banner = sprintf("Usage: %s [global options] search [command options] <prefix> ...", File.basename(__FILE__))
|
353
|
-
parser.separator ""
|
354
|
-
parser.separator "Search options:"
|
355
|
-
parser.on('--alias=ALIASES', 'filter out the result by the alias') {|v| opts[:query][:alias] ||= []; opts[:query][:alias].push(*v.split(','))}
|
356
|
-
parser.on('-a', '--assignee=ASSIGNEES', 'filter out the result by the specific assignees') {|v| opts[:query][:assigned_to] ||= []; opts[:query][:assigned_to].push(*v.split(','))}
|
357
|
-
parser.on('--bug=BUGS', 'filter out the result by the specific bug number') {|v| opts[:query][:id] ||= []; opts[:query][:id].push(*v.split(','))}
|
358
|
-
parser.on('-c', '--component=COMPONENTS', 'filter out the result by the specific components') {|v| opts[:query][:component] ||= []; opts[:query][:component].push(*v.split(','))}
|
359
|
-
parser.on('--create-time=TIME', 'Searches for bugs that were created at this time or later') {|v| opts[:query][:creation_time] = Time.parse(v)}
|
360
|
-
parser.on('--creator=CREATER', 'filter out the result by the specific user who reported bugs') {|v| opts[:query][:creator] ||= []; opts[:query][:creator].push(*v.split(','))}
|
361
|
-
parser.on('--last-change-time=TIME', 'Searches for bugs that were modified at this time or later') {|v| opts[:query][:last_change_time] = Time.parse(v)}
|
362
|
-
parser.on('--op-sys=NAMES', 'filter out the result by the operating system') {|v| opts[:query][:op_sys] ||= []; opts[:query][:op_sys].push(*v.split(','))}
|
363
|
-
parser.on('--platform=PLATFORMS', 'filter out the result by the platform') {|v| opts[:query][:platform] ||= []; opts[:query][:platform].push(*v.split(','))}
|
364
|
-
parser.on('--priority=PRIORITY', 'filter out the result by the priority') {|v| opts[:query][:priority] ||= []; opts[:query][:priority].push(*v.split(','))}
|
365
|
-
parser.on('-p', '--product=PRODUCTS', 'filter out the result by the specific products') {|v| opts[:query][:product] ||= []; opts[:query][:product].push(*v.split(','))}
|
366
|
-
parser.on('--resolution=RESOLUSIONS', 'filter out the result by the resolusions') {|v| opts[:query][:resolution] ||= []; opts[:query][:resolusion].push(*v.split(','))}
|
367
|
-
parser.on('--severity=SEVERITY', 'filter out the result by the severity') {|v| opts[:query][:severity] ||= []; opts[:query][:severity].push(*v.split(','))}
|
368
|
-
parser.on('-s', '--status=STATUSES', 'filter out the result by the status') {|v| opts[:query][:status] ||= []; opts[:query][:status].push(*v.split(','))}
|
369
|
-
parser.on('--summary=SUMMARY', 'filter out the result by the summary') {|v| opts[:query][:summary] ||= []; opts[:query][:summary] << v}
|
370
|
-
parser.on('--milestone=MILESTONE', 'filter out the result by the target milestone') {|v| opts[:query][:target_milestone] ||= []; opts[:query][:target_milestone].push(*v.split(','))}
|
371
|
-
parser.on('--whiteboard=STRING', 'filter out the result by the specific words in the status whiteboard') {|v| opts[:query][:whiteboard] ||= []; opts[:query][:whiteboard] << v}
|
372
|
-
parser.separator ""
|
373
|
-
parser.separator "Command options:"
|
374
|
-
parser.on('--short-list', 'Displays bugs summary only') {opts[:summary] = true}
|
375
|
-
parser.on('--detailed-list', 'Displays detailed bugs information') {opts[:details] = true}
|
376
|
-
parser.on('--anonymous', 'Access to Bugzilla anonymously') {opts[:anonymous] = true}
|
377
|
-
|
378
|
-
super
|
379
|
-
end # def parse
|
380
|
-
|
381
|
-
def do(argv, opts)
|
382
|
-
c = 0
|
383
|
-
real_do(argv, opts) do |result|
|
384
|
-
if opts[:command][:summary] == true then
|
385
|
-
printf("Bug#%s, %s, %s[%s, %s] %s\n",
|
386
|
-
result['id'] || result['bug_id'],
|
387
|
-
result['product'],
|
388
|
-
result['component'],
|
389
|
-
result['status'],
|
390
|
-
result['severity'],
|
391
|
-
result['summary'])
|
392
|
-
elsif opts[:command][:details] == true then
|
393
|
-
printf("Bug#%s, %s, %s, %s[%s, %s, %s, %s] %s\n",
|
394
|
-
result['id'],
|
395
|
-
result['product'],
|
396
|
-
result['assigned_to'],
|
397
|
-
result['component'],
|
398
|
-
result['status'],
|
399
|
-
result['resolution'],
|
400
|
-
result['priority'],
|
401
|
-
result['severity'],
|
402
|
-
result['summary'])
|
403
|
-
end
|
404
|
-
c += 1
|
405
|
-
end
|
406
|
-
printf("\n%d bug(s) found\n", c)
|
407
|
-
end # def do
|
408
|
-
|
409
|
-
private
|
410
|
-
|
411
|
-
def real_do(argv, opts)
|
412
|
-
conf = read_config(opts)
|
413
|
-
conf.freeze
|
414
|
-
argv.each do |prefix|
|
415
|
-
unless conf.include?(prefix) then
|
416
|
-
raise RuntimeError, sprintf("No host information for %s", prefix)
|
417
|
-
end
|
418
|
-
|
419
|
-
info = conf[prefix]
|
420
|
-
uri = URI.parse(info[:URL])
|
421
|
-
host = uri.host
|
422
|
-
port = uri.port
|
423
|
-
path = uri.path.empty? ? nil : uri.path
|
424
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
425
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
426
|
-
proxy_host, proxy_port = get_proxy(info)
|
427
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
428
|
-
|
429
|
-
@plugin.run(:pre, host, :search, opts[:command][:query])
|
430
|
-
|
431
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout)
|
432
|
-
user = Bugzilla::User.new(xmlrpc)
|
433
|
-
user.session(login, pass) do
|
434
|
-
bug = Bugzilla::Bug.new(xmlrpc)
|
435
|
-
|
436
|
-
opts[:command][:query][:product].map! {|x| info.include?(:ProductAliases) && info[:ProductAliases].include?(x) ? info[:ProductAliases][x] : x} if opts[:command][:query].include?(:product)
|
437
|
-
|
438
|
-
result = bug.search(opts[:command][:query])
|
439
|
-
|
440
|
-
@plugin.run(:post, host, :search, result)
|
441
|
-
|
442
|
-
if result.include?('bugs') then
|
443
|
-
result['bugs'].each do |r|
|
444
|
-
yield r
|
445
|
-
end
|
446
|
-
end
|
447
|
-
end
|
448
|
-
end
|
449
|
-
end # def real_do
|
450
|
-
|
451
|
-
end # class Search
|
452
|
-
|
453
|
-
class Show < CommandTemplate
|
454
|
-
|
455
|
-
def initialize(plugin)
|
456
|
-
super
|
457
|
-
|
458
|
-
@n_args = 1
|
459
|
-
end # def initialize
|
460
|
-
|
461
|
-
def parse(parser, argv, opts)
|
462
|
-
opts[:show] ||= {}
|
463
|
-
opts[:show][:mode] = :component
|
464
|
-
opts[:show][:field] = []
|
465
|
-
parser.banner = sprintf("Usage: %s [global options] show [command options] <prefix> ...", File.basename(__FILE__))
|
466
|
-
parser.separator ""
|
467
|
-
parser.separator "Command options:"
|
468
|
-
parser.on('-f', '--field', 'Displays available field informations') {|v| opts[:show][:mode] = :field}
|
469
|
-
parser.on('--field-name=NAME', 'Displays NAME field information') {|v| opts[:show][:field] << v.split(',')}
|
470
|
-
parser.on('-p', '--product', 'Displays available product names') {|v| opts[:show][:mode] = :product}
|
471
|
-
parser.on('-c', '--component', 'Displays available component names (default)') {|v| opts[:show][:mode] = :component}
|
472
|
-
parser.on('--anonymous', 'Access to Bugzilla anonymously') {opts[:anonymous] = true}
|
473
|
-
|
474
|
-
super
|
475
|
-
end # def parse
|
476
|
-
|
477
|
-
def do(argv, opts)
|
478
|
-
real_do(argv, opts) do |*result|
|
479
|
-
if opts[:command][:show][:mode] == :product then
|
480
|
-
printf("%s\n", result[0])
|
481
|
-
elsif opts[:command][:show][:mode] == :component then
|
482
|
-
printf("%s:\n", result[0])
|
483
|
-
printf(" %s\n", result[1].join("\n "))
|
484
|
-
end
|
485
|
-
end
|
486
|
-
end # def do
|
487
|
-
|
488
|
-
private
|
489
|
-
|
490
|
-
def real_do(argv, opts)
|
491
|
-
conf = read_config(opts)
|
492
|
-
conf.freeze
|
493
|
-
argv.each do |prefix|
|
494
|
-
unless conf.include?(prefix) then
|
495
|
-
raise RuntimeError, sprintf("No host information for %s", prefix)
|
496
|
-
end
|
497
|
-
|
498
|
-
info = conf[prefix]
|
499
|
-
uri = URI.parse(info[:URL])
|
500
|
-
host = uri.host
|
501
|
-
port = uri.port
|
502
|
-
path = uri.path.empty? ? nil : uri.path
|
503
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
504
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
505
|
-
proxy_host, proxy_port = get_proxy(info)
|
506
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
507
|
-
|
508
|
-
@plugin.run(:pre, host, :show, opts)
|
509
|
-
|
510
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout)
|
511
|
-
user = Bugzilla::User.new(xmlrpc)
|
512
|
-
user.session(login, pass) do
|
513
|
-
if opts[:command][:show][:mode] == :field then
|
514
|
-
bug = Bugzilla::Bug.new(xmlrpc)
|
515
|
-
|
516
|
-
result = bug.fields(opts[:command][:show][:field].flatten)
|
517
|
-
|
518
|
-
@plugin.run(:post, host, :show, result)
|
519
|
-
|
520
|
-
pp result
|
521
|
-
else
|
522
|
-
product = Bugzilla::Product.new(xmlrpc)
|
523
|
-
|
524
|
-
result = product.selectable_products
|
525
|
-
|
526
|
-
@plugin.run(:post, host, :show, result)
|
527
|
-
|
528
|
-
products = result.keys.sort
|
529
|
-
products.each do |p|
|
530
|
-
if opts[:command][:show][:mode] == :product then
|
531
|
-
yield p
|
532
|
-
elsif opts[:command][:show][:mode] == :component then
|
533
|
-
yield p, result[p][0].sort
|
534
|
-
end
|
535
|
-
end
|
536
|
-
end
|
537
|
-
end
|
538
|
-
end
|
539
|
-
end # def real_do
|
540
|
-
|
541
|
-
end # class Show
|
542
|
-
|
543
|
-
class Metrics < CommandTemplate
|
544
|
-
|
545
|
-
def initialize(plugin)
|
546
|
-
super
|
547
|
-
|
548
|
-
@n_args = 1
|
549
|
-
end # def initialize
|
550
|
-
|
551
|
-
def parse(parser, argv, opts)
|
552
|
-
opts[:metrics] = {}
|
553
|
-
opts[:query] = {}
|
554
|
-
opts[:metrics][:output] = 'bz-metrics.png'
|
555
|
-
opts[:metrics][:x_coordinate] = :monthly
|
556
|
-
|
557
|
-
parser.banner = sprintf("Usage: %s [global options] metrics [command options] <prefix> ...", File.basename(__FILE__))
|
558
|
-
parser.separator ""
|
559
|
-
parser.separator "Search options:"
|
560
|
-
parser.on('--alias=ALIASES', 'filter out the result by the alias') {|v| opts[:query][:alias] ||= []; opts[:query][:alias].push(*v.split(','))}
|
561
|
-
parser.on('-a', '--assignee=ASSIGNEES', 'filter out the result by the specific assignees') {|v| opts[:query][:assigned_to] ||= []; opts[:query][:assigned_to].push(*v.split(','))}
|
562
|
-
parser.on('--bug=BUGS', 'filter out the result by the specific bug number') {|v| opts[:query][:id] ||= []; opts[:query][:id].push(*v.split(','))}
|
563
|
-
parser.on('-c', '--component=COMPONENTS', 'filter out the result by the specific components') {|v| opts[:query][:component] ||= []; opts[:query][:component].push(*v.split(','))}
|
564
|
-
parser.on('--creator=CREATER', 'filter out the result by the specific user who reported bugs') {|v| opts[:query][:creator] ||= []; opts[:query][:creator].push(*v.split(','))}
|
565
|
-
parser.on('--op-sys=NAMES', 'filter out the result by the operating system') {|v| opts[:query][:op_sys] ||= []; opts[:query][:op_sys].push(*v.split(','))}
|
566
|
-
parser.on('--platform=PLATFORMS', 'filter out the result by the platform') {|v| opts[:query][:platform] ||= []; opts[:query][:platform].push(*v.split(','))}
|
567
|
-
parser.on('--priority=PRIORITY', 'filter out the result by the priority') {|v| opts[:query][:priority] ||= []; opts[:query][:priority].push(*v.split(','))}
|
568
|
-
parser.on('-p', '--product=PRODUCTS', 'filter out the result by the specific products') {|v| opts[:query][:product] ||= []; opts[:query][:product].push(*v.split(','))}
|
569
|
-
parser.on('--resolution=RESOLUSIONS', 'filter out the result by the resolusions') {|v| opts[:query][:resolution] ||= []; opts[:query][:resolusion].push(*v.split(','))}
|
570
|
-
parser.on('--severity=SEVERITY', 'filter out the result by the severity') {|v| opts[:query][:severity] ||= []; opts[:query][:severity].push(*v.split(','))}
|
571
|
-
parser.on('--summary=SUMMARY', 'filter out the result by the summary') {|v| opts[:query][:summary] ||= []; opts[:query][:summary] << v}
|
572
|
-
parser.on('--milestone=MILESTONE', 'filter out the result by the target milestone') {|v| opts[:query][:target_milestone] ||= []; opts[:query][:target_milestone].push(*v.split(','))}
|
573
|
-
parser.on('--whiteboard=STRING', 'filter out the result by the specific words in the status whiteboard') {|v| opts[:query][:whiteboard] ||= []; opts[:query][:whiteboard] << v}
|
574
|
-
parser.separator ""
|
575
|
-
parser.separator "Command options:"
|
576
|
-
parser.on('-t', '--title=TITLE', 'add TITLE to the graph') {|v| opts[:metrics][:title] = v}
|
577
|
-
parser.on('--begin-date=DATE', 'generate the graph since the beginning of month of DATE.') {|v| x = Time.parse(v); opts[:metrics][:begin_date] = Time.utc(x.year, x.month, 1, 0, 0, 0)}
|
578
|
-
parser.on('--end-date=DATE', 'generate the graph until the end of month of DATE.') {|v| x = Time.parse(v); opts[:metrics][:end_date] = Time.utc(x.year, x.month + 1, 1, 0, 0, 0) - 1}
|
579
|
-
parser.on('-o', '--output=FILE', 'generate the graph to FILE') {|v| opts[:metrics][:output] = v}
|
580
|
-
parser.on('--anonymous', 'access to Bugzilla anonymously') {|v| opts[:anonymous] = true}
|
581
|
-
parser.on('--weekly', 'genereate the graph with weekly X-coordinate') {|v| opts[:metrics][:x_coordinate] = :weekly}
|
582
|
-
parser.on('--monthly', 'genereate the graph with monthly X-coordinate (default)') {|v| opts[:metrics][:x_coordinate] = :monthly}
|
583
|
-
|
584
|
-
super
|
585
|
-
end # def parse
|
586
|
-
|
587
|
-
def do(argv, opts)
|
588
|
-
data = {
|
589
|
-
:label=>[],
|
590
|
-
'NEW'=>[],
|
591
|
-
'ASSIGNED'=>[],
|
592
|
-
'MODIFIED'=>[],
|
593
|
-
'ON_QA'=>[],
|
594
|
-
'CLOSED'=>[],
|
595
|
-
'OPEN'=>[]
|
596
|
-
}
|
597
|
-
last_label = nil
|
598
|
-
real_do(argv, opts) do |t, new, assigned, modified, on_qa, closed, open|
|
599
|
-
printf("%s, new: %d, assigned: %d, modified %d, on_qa %d, closed %d / open %d\n",
|
600
|
-
opts[:command][:metrics][:x_coordinate] == :weekly ? sprintf("week %d", Date.new(t.year, t.month, t.day).cweek) : t.strftime("%Y-%m"), new, assigned, modified, on_qa, closed, open)
|
601
|
-
data['NEW'] << new
|
602
|
-
data['ASSIGNED'] << assigned
|
603
|
-
data['MODIFIED'] << modified
|
604
|
-
data['ON_QA'] << on_qa
|
605
|
-
data['CLOSED'] << closed
|
606
|
-
data['OPEN'] << open
|
607
|
-
label = t.strftime("%Y/%m")
|
608
|
-
if last_label != label then
|
609
|
-
data[:label] << label
|
610
|
-
last_label = label
|
611
|
-
else
|
612
|
-
data[:label] << nil
|
613
|
-
end
|
614
|
-
end
|
615
|
-
|
616
|
-
timeline = data[:label]
|
617
|
-
data.delete(:label)
|
618
|
-
def timeline.to_hash
|
619
|
-
ret = {}
|
620
|
-
(0..self.length-1).each do |i|
|
621
|
-
ret[i] = self[i] unless self[i].nil?
|
622
|
-
end
|
623
|
-
ret
|
624
|
-
end # def timeline.to_hash
|
625
|
-
|
626
|
-
# output the trend graph
|
627
|
-
g = Gruff::Line.new
|
628
|
-
g.title = sprintf("Trend: %s", opts[:command][:metrics][:title])
|
629
|
-
g.labels = timeline.to_hash
|
630
|
-
data.each do |k, v|
|
631
|
-
next unless k == 'NEW' || k == 'OPEN' || k == 'CLOSED'
|
632
|
-
g.data(k, v)
|
633
|
-
end
|
634
|
-
g.write(sprintf("trend-%s", opts[:command][:metrics][:output]))
|
635
|
-
|
636
|
-
# output the activity graph
|
637
|
-
g = Gruff::StackedBar.new
|
638
|
-
g.title = sprintf("Activity: %s", opts[:command][:metrics][:title])
|
639
|
-
g.labels = timeline.to_hash
|
640
|
-
g.data('Resolved', data['CLOSED'])
|
641
|
-
x = []
|
642
|
-
(0..data['ASSIGNED'].length-1).each do |i|
|
643
|
-
x[i] = data['ASSIGNED'][i] + data['MODIFIED'][i] + data['ON_QA'][i]
|
644
|
-
end
|
645
|
-
g.data('Unresolved', x)
|
646
|
-
a = []
|
647
|
-
(0..data['OPEN'].length-1).each do |i|
|
648
|
-
a[i] = data['OPEN'][i] - x[i]
|
649
|
-
end
|
650
|
-
g.data('non-activity bugs', a)
|
651
|
-
g.write(sprintf("activity-%s", opts[:command][:metrics][:output]))
|
652
|
-
end # def do
|
653
|
-
|
654
|
-
private
|
655
|
-
|
656
|
-
def real_do(argv, opts)
|
657
|
-
conf = read_config(opts)
|
658
|
-
conf.freeze
|
659
|
-
argv.each do |prefix|
|
660
|
-
unless conf.include?(prefix) then
|
661
|
-
raise RuntimeError, sprintf("No host information for %s", prefix)
|
662
|
-
end
|
663
|
-
|
664
|
-
info = conf[prefix]
|
665
|
-
uri = URI.parse(info[:URL])
|
666
|
-
host = uri.host
|
667
|
-
port = uri.port
|
668
|
-
path = uri.path.empty? ? nil : uri.path
|
669
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
670
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
671
|
-
proxy_host, proxy_port = get_proxy(info)
|
672
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
673
|
-
|
674
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout)
|
675
|
-
user = Bugzilla::User.new(xmlrpc)
|
676
|
-
user.session(login, pass) do
|
677
|
-
bug = Bugzilla::Bug.new(xmlrpc)
|
678
|
-
|
679
|
-
opts[:command][:query][:product].map! {|x| info.include?(:ProductAliases) && info[:ProductAliases].include?(x) ? info[:ProductAliases][x] : x} if opts[:command][:query].include?(:product)
|
680
|
-
|
681
|
-
ts = opts[:command][:metrics][:begin_date] || Time.utc(Time.new.year, 1, 1)
|
682
|
-
te = opts[:command][:metrics][:end_date] || Time.utc(Time.new.year+1, 1, 1) - 1
|
683
|
-
if opts[:command][:metrics][:x_coordinate] == :weekly then
|
684
|
-
# align to the week
|
685
|
-
d = Date.new(ts.year, ts.month, ts.day)
|
686
|
-
ds = Date.commercial(d.year, d.cweek, 1)
|
687
|
-
d = Date.new(te.year, te.month, te.day)
|
688
|
-
de = Date.commercial(d.year, d.cweek, 7)
|
689
|
-
ts = Time.utc(ds.year, ds.month, ds.day)
|
690
|
-
te = Time.utc(de.year, de.month, de.day)
|
691
|
-
end
|
692
|
-
|
693
|
-
searchopts = opts[:command][:query].clone
|
694
|
-
|
695
|
-
@plugin.run(:pre, host, :metrics, searchopts, opts[:metrics])
|
696
|
-
|
697
|
-
if searchopts == opts[:command][:query] then
|
698
|
-
raise NoMethodError, "No method to deal with the query"
|
699
|
-
end
|
700
|
-
|
701
|
-
while ts < te do
|
702
|
-
searchopts = opts[:command][:query].clone
|
703
|
-
|
704
|
-
# don't rely on the status to deal with NEW bugs.
|
705
|
-
# unable to estimate the case bugs closed quickly
|
706
|
-
if opts[:command][:metrics][:x_coordinate] == :weekly then
|
707
|
-
d = Date.new(ts.year, ts.month, ts.day)
|
708
|
-
de = Date.commercial(d.year, d.cweek, 7)
|
709
|
-
drange = [ts, Time.utc(de.year, de.month, de.day, 23, 59, 59)]
|
710
|
-
else
|
711
|
-
drange = [ts, Time.utc(ts.year, ts.month + 1, 1) - 1]
|
712
|
-
end
|
713
|
-
searchopts[:creation_time] = drange
|
714
|
-
|
715
|
-
@plugin.run(:pre, host, :metrics, searchopts)
|
716
|
-
|
717
|
-
result = bug.search(searchopts)
|
718
|
-
|
719
|
-
@plugin.run(:post, host, :search, result)
|
720
|
-
|
721
|
-
new = result.include?('bugs') ? result['bugs'].length : 0
|
722
|
-
|
723
|
-
# for open bugs
|
724
|
-
# what we are interested in here would be how many bugs still keeps open.
|
725
|
-
searchopts = opts[:command][:query].clone
|
726
|
-
searchopts[:last_change_time] = drange
|
727
|
-
searchopts[:status] = '__open__'
|
728
|
-
|
729
|
-
@plugin.run(:pre, host, :metrics, searchopts)
|
730
|
-
|
731
|
-
result = bug.search(searchopts)
|
732
|
-
|
733
|
-
@plugin.run(:post, host, :search, result)
|
734
|
-
|
735
|
-
assigned = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'ASSIGNED' ? x : nil}.compact.length : 0
|
736
|
-
modified = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'MODIFIED' ? x : nil}.compact.length : 0
|
737
|
-
on_qa = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'ON_QA' ? x : nil}.compact.length : 0
|
738
|
-
|
739
|
-
# send a separate query for closed.
|
740
|
-
# just counting CLOSED the above is meaningless.
|
741
|
-
# what we are interested in here would be how much bugs are
|
742
|
-
# actually closed, but not how many closed bugs one worked on.
|
743
|
-
searchopts = opts[:command][:query].clone
|
744
|
-
searchopts[:last_change_time] = drange
|
745
|
-
searchopts[:status] = 'CLOSED'
|
746
|
-
|
747
|
-
@plugin.run(:pre, host, :metrics, searchopts)
|
748
|
-
|
749
|
-
result = bug.search(searchopts)
|
750
|
-
|
751
|
-
@plugin.run(:post, host, :search, result)
|
752
|
-
|
753
|
-
closed = result.include?('bugs') ? result['bugs'].length : 0
|
754
|
-
|
755
|
-
# obtain the information for open bugs that closed now
|
756
|
-
searchopts = opts[:command][:query].clone
|
757
|
-
searchopts[:status] = 'CLOSED'
|
758
|
-
searchopts[:metrics_closed_after] = drange[1] + 1
|
759
|
-
|
760
|
-
@plugin.run(:pre, host, :metrics, searchopts)
|
761
|
-
|
762
|
-
result = bug.search(searchopts)
|
763
|
-
|
764
|
-
@plugin.run(:post, host, :search, result)
|
765
|
-
|
766
|
-
open_bugs = result.include?('bugs') ? result['bugs'].length : 0
|
767
|
-
|
768
|
-
# obtain the information for open bugs
|
769
|
-
searchopts = opts[:command][:query].clone
|
770
|
-
searchopts[:metrics_not_closed] = drange[1]
|
771
|
-
|
772
|
-
@plugin.run(:pre, host, :metrics, searchopts)
|
773
|
-
|
774
|
-
result = bug.search(searchopts)
|
775
|
-
|
776
|
-
@plugin.run(:post, host, :search, result)
|
777
|
-
|
778
|
-
open_bugs += result.include?('bugs') ? result['bugs'].length : 0
|
779
|
-
|
780
|
-
yield ts, new, assigned, modified, on_qa, closed, open_bugs
|
781
|
-
|
782
|
-
ts = drange[1] + 1
|
783
|
-
end
|
784
|
-
end
|
785
|
-
end
|
786
|
-
end # def real_do
|
787
|
-
|
788
|
-
end # class Metrics
|
789
|
-
|
790
|
-
end # module BzConsole
|
791
|
-
|
792
|
-
begin
|
793
|
-
opts = {}
|
794
|
-
opts[:command] = {}
|
795
|
-
subargv = []
|
796
|
-
|
797
|
-
o = ARGV.options do |opt|
|
798
|
-
opt.banner = sprintf("Usage: %s [global options] <command> ...", File.basename(__FILE__))
|
799
|
-
opt.separator ""
|
800
|
-
opt.separator "Global options:"
|
801
|
-
opt.on('-c', '--config=FILE', 'read FILE as the configuration file.') {|v| opts[:config] = v}
|
802
|
-
opt.on('-t', '--timeout=SEC', 'Set XMLRPC timeout in a second.') {|v| opts[:timeout] = v.to_i}
|
803
|
-
opt.on('-h', '--help', 'show this message') {|x| opts[:help] = true}
|
804
|
-
|
805
|
-
cmds = BzConsole.constants.sort.map {|x| (k = eval("BzConsole::#{x}")).class == Class && x != "CommandTemplate" ? x.downcase : nil}.compact
|
806
|
-
|
807
|
-
subargv = opt.order(ARGV);
|
808
|
-
|
809
|
-
command = subargv[0]
|
810
|
-
|
811
|
-
if subargv.length > 0 then
|
812
|
-
n = cmds.index(command)
|
813
|
-
unless n.nil? then
|
814
|
-
opts[:instance] = eval("BzConsole::#{cmds[n].capitalize}.new(Bugzilla::Plugin::Template.new)")
|
815
|
-
subargv = opts[:instance].parse(opt, subargv[1..-1], opts[:command])
|
816
|
-
else
|
817
|
-
STDERR.printf("E: Unknown command: %s\n", subargv[0])
|
818
|
-
STDERR.printf(" Available commands: %s\n", cmds.join(' '))
|
819
|
-
exit 1
|
820
|
-
end
|
821
|
-
else
|
822
|
-
opt.separator ""
|
823
|
-
opt.separator "Available commands:"
|
824
|
-
opt.separator sprintf(" %s", cmds.join(' '))
|
825
|
-
end
|
826
|
-
|
827
|
-
if opts[:instance].nil? && subargv.length == 0 ||
|
828
|
-
opts[:help] == true ||
|
829
|
-
subargv.length < opts[:instance].n_args then
|
830
|
-
puts opt.help
|
831
|
-
exit
|
832
|
-
end
|
833
|
-
end
|
834
|
-
|
835
|
-
opts[:instance].do(subargv, opts)
|
836
|
-
end
|