ruby-bugzilla 0.5.3 → 0.6.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.
- checksums.yaml +4 -4
- data/{README.rdoc → README.md} +28 -0
- data/bin/bzconsole +237 -100
- data/lib/bugzilla/bug.rb +4 -4
- data/lib/bugzilla/plugin.rb +5 -5
- data/lib/bugzilla/user.rb +33 -1
- data/lib/bugzilla/user.rb~ +31 -23
- data/lib/bugzilla/version.rb +2 -2
- data/lib/ruby-bugzilla/nvbugzilla.rb +55 -0
- metadata +30 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7f1b54d90d2ee896e2db7a4a7bdff393ab698fd8
|
4
|
+
data.tar.gz: 763e07f07701a042631ee927e72df2b5493aa46e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dc22720a84cad9fb8db09d30a24129be68bf33b4cdc9142dd8ba978e1f0f27b609c8513a4cfd634b8f2b8469ca60d3506d4e033a9e29e3f9044731ea21fafe84
|
7
|
+
data.tar.gz: 724df22354b693e721a8599c0962e3fcaecfcb3e109457583c4d04904db5aa9db6df97989110df6da5343457ac774d0365b1e4cb53b7dca8cc1f6cadeb869f01
|
data/{README.rdoc → README.md}
RENAMED
@@ -10,6 +10,34 @@ APIs are available:
|
|
10
10
|
* Bugzilla::WebService::Product[http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Product.html]
|
11
11
|
* Bugzilla::WebService::User[http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/User.html]
|
12
12
|
|
13
|
+
|
14
|
+
== bzconsole usage
|
15
|
+
|
16
|
+
as example, in the bin directory, we have a tool named bzconsole. with that, you can login, search and get a bug. some examples:
|
17
|
+
|
18
|
+
list all new bugs, from Novell, created after 2014-09-25, with product Security (SUSE Security Incidents):
|
19
|
+
|
20
|
+
````
|
21
|
+
bzconsole search --status=NEW --create-time=2014-09-25 --product=Security --detailed-list nvbz
|
22
|
+
````
|
23
|
+
|
24
|
+
similar for Red Hat:
|
25
|
+
|
26
|
+
````
|
27
|
+
bzconsole search --status=NEW --create-time=2014-09-28 --product=Security --detailed-list rhbz
|
28
|
+
````
|
29
|
+
|
30
|
+
search without login:
|
31
|
+
|
32
|
+
````
|
33
|
+
bzconsole search --status=NEW --anonymous --create-time=2014-09-28 --product=Security --detailed-list rhbz
|
34
|
+
````
|
35
|
+
|
36
|
+
get a specific bug:
|
37
|
+
|
38
|
+
````
|
39
|
+
bzconsole getbug nvbz:889526
|
40
|
+
````
|
13
41
|
== Copyright
|
14
42
|
|
15
43
|
Copyright (c) 2010-2014 Red Hat, Inc. See COPYING for details.
|
data/bin/bzconsole
CHANGED
@@ -41,10 +41,29 @@ rescue LoadError
|
|
41
41
|
require 'bugzilla/bug'
|
42
42
|
end
|
43
43
|
|
44
|
+
module BzConsole
|
45
|
+
module Utils
|
46
|
+
def get_xmlrpc(conf = {},opts = {})
|
47
|
+
info = conf
|
48
|
+
uri = URI.parse(info[:URL])
|
49
|
+
host = uri.host
|
50
|
+
port = uri.port
|
51
|
+
path = uri.path.empty? ? nil : uri.path
|
52
|
+
proxy_host, proxy_port = get_proxy(info)
|
53
|
+
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
54
|
+
yield host if block_given? # if you want to run some pre hook
|
55
|
+
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout, uri.user, uri.password)
|
56
|
+
[xmlrpc,host]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
44
61
|
module BzConsole
|
45
62
|
|
46
63
|
class CommandTemplate
|
47
64
|
|
65
|
+
include Utils
|
66
|
+
|
48
67
|
def initialize(plugin)
|
49
68
|
@n_args = 0
|
50
69
|
@defaultyamlfile = File.join(ENV['HOME'], ".bzconsole.yml")
|
@@ -112,7 +131,6 @@ module BzConsole
|
|
112
131
|
|
113
132
|
def initialize(plugin)
|
114
133
|
super
|
115
|
-
|
116
134
|
@n_args = 0
|
117
135
|
end # def initialize
|
118
136
|
|
@@ -135,7 +153,8 @@ module BzConsole
|
|
135
153
|
'RHEL3'=>'Red Hat Enterprise Linux 3',
|
136
154
|
'RHEL4'=>'Red Hat Enterprise Linux 4',
|
137
155
|
'RHEL5'=>'Red Hat Enterprise Linux 5',
|
138
|
-
'RHEL6'=>'Red Hat Enterprise Linux 6'
|
156
|
+
'RHEL6'=>'Red Hat Enterprise Linux 6',
|
157
|
+
'Security'=>'Security Response'
|
139
158
|
},
|
140
159
|
:Plugin=>"ruby-bugzilla/rhbugzilla.rb"
|
141
160
|
},
|
@@ -156,6 +175,16 @@ module BzConsole
|
|
156
175
|
:URL=>"https://bugzilla.mozilla.org",
|
157
176
|
:User=>"account@example.com",
|
158
177
|
:Password=>"blahblahblah",
|
178
|
+
},
|
179
|
+
"nvbz"=>{
|
180
|
+
:Name=>"Novell Bugzilla",
|
181
|
+
:URL=>"https://bugzilla.novell.com",
|
182
|
+
:User=>"account@example.com",
|
183
|
+
:Password=>"blahblahblah",
|
184
|
+
:ProductAliases=>{
|
185
|
+
'Security'=>'SUSE Security Incidents'
|
186
|
+
},
|
187
|
+
:Plugin=>"ruby-bugzilla/nvbugzilla.rb"
|
159
188
|
}
|
160
189
|
}
|
161
190
|
|
@@ -179,7 +208,6 @@ module BzConsole
|
|
179
208
|
|
180
209
|
def initialize(plugin)
|
181
210
|
super
|
182
|
-
|
183
211
|
@n_args = 1
|
184
212
|
end # def initialize
|
185
213
|
|
@@ -206,17 +234,12 @@ module BzConsole
|
|
206
234
|
end
|
207
235
|
|
208
236
|
info = conf[prefix]
|
209
|
-
uri = URI.parse(info[:URL])
|
210
|
-
host = uri.host
|
211
|
-
port = uri.port
|
212
|
-
path = uri.path.empty? ? nil : uri.path
|
213
237
|
login = info[:User].nil? ? ask("Bugzilla ID: ") : info[:User]
|
214
238
|
pass = info[:Password].nil? ? ask("Bugzilla password: ") {|q| q.echo = false} : info[:Password]
|
215
|
-
proxy_host, proxy_port = get_proxy(info)
|
216
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
217
239
|
|
218
|
-
xmlrpc =
|
240
|
+
xmlrpc,host = get_xmlrpc(conf[prefix],opts)
|
219
241
|
user = Bugzilla::User.new(xmlrpc)
|
242
|
+
|
220
243
|
begin
|
221
244
|
result = user.login({'login'=>login, 'password'=>pass, 'remember'=>true})
|
222
245
|
cconf[host] = xmlrpc.cookie
|
@@ -285,7 +308,7 @@ module BzConsole
|
|
285
308
|
printf("Comments:\t%d\n\n", result['comments'].length)
|
286
309
|
i = 0
|
287
310
|
result['comments'].each do |c|
|
288
|
-
printf("Comment#%d%s %s %s\n", i, c['is_private'] == true ? "[private]" : "", c['
|
311
|
+
printf("Comment#%d%s %s %s\n", i, c['is_private'] == true ? "[private]" : "", c['creator'], c['creation_time'].to_time)
|
289
312
|
printf("\n %s\n\n", c['text'].split("\n").join("\n "))
|
290
313
|
i += 1
|
291
314
|
end
|
@@ -310,18 +333,13 @@ module BzConsole
|
|
310
333
|
end
|
311
334
|
|
312
335
|
info = conf[prefix]
|
313
|
-
|
314
|
-
|
315
|
-
port = uri.port
|
316
|
-
path = uri.path.empty? ? nil : uri.path
|
317
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
318
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
319
|
-
proxy_host, proxy_port = get_proxy(info)
|
320
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
336
|
+
login = info[:User].nil? ? ask("Bugzilla ID: ") : info[:User]
|
337
|
+
pass = info[:Password].nil? ? ask("Bugzilla password: ") {|q| q.echo = false} : info[:Password]
|
321
338
|
|
322
|
-
|
339
|
+
xmlrpc,host = get_xmlrpc(conf[prefix],opts) do |h|
|
340
|
+
@plugin.run(:pre, h, :getbug, opts)
|
341
|
+
end
|
323
342
|
|
324
|
-
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout, uri.user, uri.password)
|
325
343
|
user = Bugzilla::User.new(xmlrpc)
|
326
344
|
user.session(login, pass) do
|
327
345
|
bug = Bugzilla::Bug.new(xmlrpc)
|
@@ -438,19 +456,19 @@ module BzConsole
|
|
438
456
|
xmlrpc = Bugzilla::XMLRPC.new(host, port, path, proxy_host, proxy_port, timeout, uri.user, uri.password)
|
439
457
|
user = Bugzilla::User.new(xmlrpc)
|
440
458
|
user.session(login, pass) do
|
441
|
-
|
442
|
-
|
443
|
-
|
459
|
+
bug = Bugzilla::Bug.new(xmlrpc)
|
460
|
+
opts[:command][:query][:product].map! { |x| info.include?(:ProductAliases) &&
|
461
|
+
info[:ProductAliases].include?(x) ? info[:ProductAliases][x] : x } if opts[:command][:query].include?(:product)
|
444
462
|
|
445
|
-
|
463
|
+
result = bug.search(opts[:command][:query])
|
446
464
|
|
447
|
-
|
465
|
+
@plugin.run(:post, host, :search, result)
|
448
466
|
|
449
|
-
|
450
|
-
|
451
|
-
|
467
|
+
if result.include?('bugs') then
|
468
|
+
result['bugs'].each do |r|
|
469
|
+
yield r
|
470
|
+
end
|
452
471
|
end
|
453
|
-
end
|
454
472
|
end
|
455
473
|
end
|
456
474
|
end # def real_do
|
@@ -622,7 +640,7 @@ module BzConsole
|
|
622
640
|
timeline = data[:label]
|
623
641
|
data.delete(:label)
|
624
642
|
def timeline.to_hash
|
625
|
-
|
643
|
+
ret = {}
|
626
644
|
(0..self.length-1).each do |i|
|
627
645
|
ret[i] = self[i] unless self[i].nil?
|
628
646
|
end
|
@@ -668,16 +686,11 @@ module BzConsole
|
|
668
686
|
end
|
669
687
|
|
670
688
|
info = conf[prefix]
|
671
|
-
|
672
|
-
|
673
|
-
port = uri.port
|
674
|
-
path = uri.path.empty? ? nil : uri.path
|
675
|
-
login = opts[:command][:anonymous] == true ? nil : info[:User]
|
676
|
-
pass = opts[:command][:anonymous] == true ? nil : info[:Password]
|
677
|
-
proxy_host, proxy_port = get_proxy(info)
|
678
|
-
timeout = opts[:timeout].nil? ? 60 : opts[:timeout]
|
689
|
+
login = info[:User].nil? ? ask("Bugzilla ID: ") : info[:User]
|
690
|
+
pass = info[:Password].nil? ? ask("Bugzilla password: ") {|q| q.echo = false} : info[:Password]
|
679
691
|
|
680
|
-
|
692
|
+
|
693
|
+
xmlrpc,host = get_xmlrpc(conf[prefix],opts)
|
681
694
|
user = Bugzilla::User.new(xmlrpc)
|
682
695
|
user.session(login, pass) do
|
683
696
|
bug = Bugzilla::Bug.new(xmlrpc)
|
@@ -700,97 +713,95 @@ module BzConsole
|
|
700
713
|
|
701
714
|
@plugin.run(:pre, host, :metrics, searchopts, opts[:metrics])
|
702
715
|
|
703
|
-
if searchopts == opts[:command][:query]
|
704
|
-
raise NoMethodError, "No method to deal with the query"
|
705
|
-
end
|
716
|
+
raise NoMethodError, "No method to deal with the query" if searchopts == opts[:command][:query]
|
706
717
|
|
707
718
|
while ts < te do
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
searchopts[:creation_time] = drange
|
719
|
+
searchopts = opts[:command][:query].clone
|
720
|
+
|
721
|
+
# don't rely on the status to deal with NEW bugs.
|
722
|
+
# unable to estimate the case bugs closed quickly
|
723
|
+
if opts[:command][:metrics][:x_coordinate] == :weekly then
|
724
|
+
d = Date.new(ts.year, ts.month, ts.day)
|
725
|
+
de = Date.commercial(d.year, d.cweek, 7)
|
726
|
+
drange = [ts, Time.utc(de.year, de.month, de.day, 23, 59, 59)]
|
727
|
+
else
|
728
|
+
drange = [ts, Time.utc(ts.year, ts.month + 1, 1) - 1]
|
729
|
+
end
|
720
730
|
|
721
|
-
|
731
|
+
searchopts[:creation_time] = drange
|
722
732
|
|
723
|
-
|
733
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
724
734
|
|
725
|
-
|
735
|
+
result = bug.search(searchopts)
|
726
736
|
|
727
|
-
|
737
|
+
@plugin.run(:post, host, :search, result)
|
728
738
|
|
729
|
-
|
730
|
-
# what we are interested in here would be how many bugs still keeps open.
|
731
|
-
searchopts = opts[:command][:query].clone
|
732
|
-
searchopts[:last_change_time] = drange
|
733
|
-
searchopts[:status] = '__open__'
|
739
|
+
new = result.include?('bugs') ? result['bugs'].length : 0
|
734
740
|
|
735
|
-
|
741
|
+
# for open bugs
|
742
|
+
# what we are interested in here would be how many bugs still keeps open.
|
743
|
+
searchopts = opts[:command][:query].clone
|
744
|
+
searchopts[:last_change_time] = drange
|
745
|
+
searchopts[:status] = '__open__'
|
736
746
|
|
737
|
-
|
747
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
738
748
|
|
739
|
-
|
749
|
+
result = bug.search(searchopts)
|
740
750
|
|
741
|
-
|
742
|
-
modified = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'MODIFIED' ? x : nil}.compact.length : 0
|
743
|
-
on_qa = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'ON_QA' ? x : nil}.compact.length : 0
|
751
|
+
@plugin.run(:post, host, :search, result)
|
744
752
|
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
# actually closed, but not how many closed bugs one worked on.
|
749
|
-
searchopts = opts[:command][:query].clone
|
750
|
-
searchopts[:last_change_time] = drange
|
751
|
-
searchopts[:status] = 'CLOSED'
|
753
|
+
assigned = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'ASSIGNED' ? x : nil}.compact.length : 0
|
754
|
+
modified = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'MODIFIED' ? x : nil}.compact.length : 0
|
755
|
+
on_qa = result.include?('bugs') ? result['bugs'].map{|x| x['status'] == 'ON_QA' ? x : nil}.compact.length : 0
|
752
756
|
|
753
|
-
|
757
|
+
# send a separate query for closed.
|
758
|
+
# just counting CLOSED the above is meaningless.
|
759
|
+
# what we are interested in here would be how much bugs are
|
760
|
+
# actually closed, but not how many closed bugs one worked on.
|
761
|
+
searchopts = opts[:command][:query].clone
|
762
|
+
searchopts[:last_change_time] = drange
|
763
|
+
searchopts[:status] = 'CLOSED'
|
754
764
|
|
755
|
-
|
765
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
756
766
|
|
757
|
-
|
767
|
+
result = bug.search(searchopts)
|
758
768
|
|
759
|
-
|
769
|
+
@plugin.run(:post, host, :search, result)
|
760
770
|
|
761
|
-
|
762
|
-
searchopts = opts[:command][:query].clone
|
763
|
-
searchopts[:status] = 'CLOSED'
|
764
|
-
searchopts[:metrics_closed_after] = drange[1] + 1
|
771
|
+
closed = result.include?('bugs') ? result['bugs'].length : 0
|
765
772
|
|
766
|
-
|
773
|
+
# obtain the information for open bugs that closed now
|
774
|
+
searchopts = opts[:command][:query].clone
|
775
|
+
searchopts[:status] = 'CLOSED'
|
776
|
+
searchopts[:metrics_closed_after] = drange[1] + 1
|
767
777
|
|
768
|
-
|
778
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
769
779
|
|
770
|
-
|
780
|
+
result = bug.search(searchopts)
|
771
781
|
|
772
|
-
|
782
|
+
@plugin.run(:post, host, :search, result)
|
773
783
|
|
774
|
-
|
775
|
-
searchopts = opts[:command][:query].clone
|
776
|
-
searchopts[:metrics_not_closed] = drange[1]
|
784
|
+
open_bugs = result.include?('bugs') ? result['bugs'].length : 0
|
777
785
|
|
778
|
-
|
786
|
+
# obtain the information for open bugs
|
787
|
+
searchopts = opts[:command][:query].clone
|
788
|
+
searchopts[:metrics_not_closed] = drange[1]
|
779
789
|
|
780
|
-
|
790
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
781
791
|
|
782
|
-
|
792
|
+
result = bug.search(searchopts)
|
783
793
|
|
784
|
-
|
794
|
+
@plugin.run(:post, host, :search, result)
|
785
795
|
|
786
|
-
|
796
|
+
open_bugs += result.include?('bugs') ? result['bugs'].length : 0
|
787
797
|
|
788
|
-
|
789
|
-
|
798
|
+
yield ts, new, assigned, modified, on_qa, closed, open_bugs
|
799
|
+
|
800
|
+
ts = drange[1] + 1
|
801
|
+
end #while
|
790
802
|
end
|
791
803
|
end
|
792
804
|
end # def real_do
|
793
|
-
|
794
805
|
end # class Metrics
|
795
806
|
|
796
807
|
class Newbug < CommandTemplate
|
@@ -876,6 +887,132 @@ module BzConsole
|
|
876
887
|
|
877
888
|
end # class Newbug
|
878
889
|
|
890
|
+
class Responsetime < CommandTemplate
|
891
|
+
|
892
|
+
def initialize(plugin)
|
893
|
+
super
|
894
|
+
@n_args = 1
|
895
|
+
end # def initialize
|
896
|
+
|
897
|
+
def parse(parser, argv, opts)
|
898
|
+
opts[:responsetime] = {}
|
899
|
+
opts[:query] = {}
|
900
|
+
parser.banner = sprintf("Usage: %s [global options] responsetime [command options] <prefix:bug number>...", File.basename(__FILE__))
|
901
|
+
parser.separator ""
|
902
|
+
parser.separator "Search options:"
|
903
|
+
parser.on('--alias=ALIASES', 'filter out the result by the alias') {|v| opts[:query][:alias] ||= []; opts[:query][:alias].push(*v.split(','))}
|
904
|
+
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(','))}
|
905
|
+
parser.on('--bug=BUGS', 'filter out the result by the specific bug number') {|v| opts[:query][:id] ||= []; opts[:query][:id].push(*v.split(','))}
|
906
|
+
parser.on('-c', '--component=COMPONENTS', 'filter out the result by the specific components') {|v| opts[:query][:component] ||= []; opts[:query][:component].push(*v.split(','))}
|
907
|
+
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(','))}
|
908
|
+
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(','))}
|
909
|
+
parser.on('--platform=PLATFORMS', 'filter out the result by the platform') {|v| opts[:query][:platform] ||= []; opts[:query][:platform].push(*v.split(','))}
|
910
|
+
parser.on('--priority=PRIORITY', 'filter out the result by the priority') {|v| opts[:query][:priority] ||= []; opts[:query][:priority].push(*v.split(','))}
|
911
|
+
parser.on('-p', '--product=PRODUCTS', 'filter out the result by the specific products') {|v| opts[:query][:product] ||= []; opts[:query][:product].push(*v.split(','))}
|
912
|
+
parser.on('--resolution=RESOLUSIONS', 'filter out the result by the resolusions') {|v| opts[:query][:resolution] ||= []; opts[:query][:resolusion].push(*v.split(','))}
|
913
|
+
parser.on('--severity=SEVERITY', 'filter out the result by the severity') {|v| opts[:query][:severity] ||= []; opts[:query][:severity].push(*v.split(','))}
|
914
|
+
parser.on('--summary=SUMMARY', 'filter out the result by the summary') {|v| opts[:query][:summary] ||= []; opts[:query][:summary] << v}
|
915
|
+
parser.on('--milestone=MILESTONE', 'filter out the result by the target milestone') {|v| opts[:query][:target_milestone] ||= []; opts[:query][:target_milestone].push(*v.split(','))}
|
916
|
+
parser.on('--whiteboard=STRING', 'filter out the result by the specific words in the status whiteboard') {|v| opts[:query][:whiteboard] ||= []; opts[:query][:whiteboard] << v}
|
917
|
+
parser.separator ""
|
918
|
+
parser.separator "Command Options:"
|
919
|
+
parser.on('--begin-date=DATE', 'Analyse the response time since DATE') {|v| x = Time.parse(v); opts[:responsetime][:begin_date] = Time.utc(x.year, x.month, x.day, 0, 0, 0)}
|
920
|
+
parser.on('--end-date=DATE', 'Analyse the response time until DATE') {|v| x = Time.parse(v); opts[:responsetime][:end_date] = Time.utc(x.year, x.month, x.day, 23, 59, 59)}
|
921
|
+
parser.on('--anonymous','access to Bugzilla anonymously') {|v| opts[:anonymous] = true}
|
922
|
+
|
923
|
+
super
|
924
|
+
end # def parse
|
925
|
+
|
926
|
+
def do(argv, opts)
|
927
|
+
real_do(argv, opts) do |ts, te, login, user, bug|
|
928
|
+
printf("Bug#%s: [%s] - [%s] [%s] %s - %d comments\n", bug['id'], bug['product'], bug['component'], bug['status'], bug['summary'], bug['comments'].length)
|
929
|
+
|
930
|
+
ucache = {}
|
931
|
+
st = nil
|
932
|
+
total = 0
|
933
|
+
notyetrespond = false
|
934
|
+
ncomment = 0
|
935
|
+
n = 0
|
936
|
+
over = ""
|
937
|
+
bug['comments'].each do |comment|
|
938
|
+
u = nil
|
939
|
+
if ucache.include?(comment['creator']) then
|
940
|
+
u = ucache[comment['creator']]
|
941
|
+
else
|
942
|
+
u = user.get_userinfo(comment['creator'])
|
943
|
+
u = u[0] #FIXME
|
944
|
+
ucache[comment['creator']] = u
|
945
|
+
end
|
946
|
+
printf(" #%d. On %s, %s wrote\n", comment['count'], comment['creation_time'].to_time, comment['creator'].include?('@') ? sprintf("%s <%s>", u['real_name'], comment['creator']) : comment['creator'])
|
947
|
+
if comment['creator'] != login then
|
948
|
+
if !notyetrespond then
|
949
|
+
st = comment['creation_time'].to_time
|
950
|
+
notyetrespond = true
|
951
|
+
end
|
952
|
+
else
|
953
|
+
ncomment += 1
|
954
|
+
et = comment['creation_time'].to_time
|
955
|
+
if !st.nil? then
|
956
|
+
total += (et - st)
|
957
|
+
end
|
958
|
+
st = et
|
959
|
+
notyetrespond = false
|
960
|
+
end
|
961
|
+
n += 1
|
962
|
+
end
|
963
|
+
x = ncomment
|
964
|
+
if notyetrespond && bug['bug_status'] != 'CLOSED' then
|
965
|
+
total += (te - st)
|
966
|
+
over = '>'
|
967
|
+
x = 1 if x == 0
|
968
|
+
end
|
969
|
+
printf(" Own comment#: %d - avg. response time: %s%.f days\n", ncomment, over, total.to_f / x / 86400.0)
|
970
|
+
end
|
971
|
+
end # def do
|
972
|
+
|
973
|
+
def real_do(argv, opts)
|
974
|
+
conf = read_config(opts)
|
975
|
+
conf.freeze
|
976
|
+
argv.each do |prefix|
|
977
|
+
unless conf.include?(prefix) then
|
978
|
+
raise RuntimeError, sprintf("No host information for %s", prefix)
|
979
|
+
end
|
980
|
+
|
981
|
+
info = conf[prefix]
|
982
|
+
login = info[:User].nil? ? ask("Bugzilla ID: ") : info[:User]
|
983
|
+
pass = info[:Password].nil? ? ask("Bugzilla password: ") {|q| q.echo = false} : info[:Password]
|
984
|
+
|
985
|
+
xmlrpc, host = get_xmlrpc(conf[prefix], opts)
|
986
|
+
user = Bugzilla::User.new(xmlrpc)
|
987
|
+
user.session(login, pass) do
|
988
|
+
bug = Bugzilla::Bug.new(xmlrpc)
|
989
|
+
|
990
|
+
opts[:command][:query][:product].map! {|x| info.include?(:ProductAliases) && info[:ProductAliases].include?(x) ? info[:ProductAliases][x] : x} if opts[:command][:query].include?(:product)
|
991
|
+
ts = opts[:command][:responsetime][:begin_date] || Time.utc(Time.new.year, 1, 1)
|
992
|
+
te = opts[:command][:responsetime][:end_date] || Time.utc(Time.new.year+1, 1, 1) - 1
|
993
|
+
searchopts = opts[:command][:query].clone
|
994
|
+
searchopts[:last_change_time] = [ts, te]
|
995
|
+
|
996
|
+
@plugin.run(:pre, host, :metrics, searchopts)
|
997
|
+
|
998
|
+
result = bug.search(searchopts)
|
999
|
+
|
1000
|
+
@plugin.run(:post, host, :search, result)
|
1001
|
+
|
1002
|
+
if result.include?('bugs') then
|
1003
|
+
ids = result['bugs'].map {|x| x['id']}
|
1004
|
+
res = bug.get_bugs(ids, nil)
|
1005
|
+
res.each do |r|
|
1006
|
+
yield ts, te, login, user, r
|
1007
|
+
end
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
end # def real_do
|
1012
|
+
|
1013
|
+
|
1014
|
+
end # class
|
1015
|
+
|
879
1016
|
end # module BzConsole
|
880
1017
|
|
881
1018
|
begin
|
data/lib/bugzilla/bug.rb
CHANGED
@@ -289,10 +289,10 @@ See http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html
|
|
289
289
|
if args[0].kind_of?(Hash) then
|
290
290
|
params = args[0]
|
291
291
|
elsif args[0].kind_of?(Array) then
|
292
|
-
|
292
|
+
params['ids'] = args[0]
|
293
293
|
elsif args[0].kind_of?(Integer) ||
|
294
|
-
|
295
|
-
|
294
|
+
args[0].kind_of?(String) then
|
295
|
+
params['ids'] = [args[0]]
|
296
296
|
else
|
297
297
|
raise ArgumentError, "Invalid parameters"
|
298
298
|
end
|
@@ -316,7 +316,7 @@ See http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html
|
|
316
316
|
|
317
317
|
res = check_version("3.0.4")
|
318
318
|
unless res[0] then
|
319
|
-
|
319
|
+
required_fields.push(*defaulted_fields)
|
320
320
|
end
|
321
321
|
required_fields.each do |f|
|
322
322
|
raise ArgumentError, sprintf("Required fields isn't given: %s", f) unless args[0].include?(f)
|
data/lib/bugzilla/plugin.rb
CHANGED
@@ -38,20 +38,20 @@ module Bugzilla
|
|
38
38
|
@@plugins = []
|
39
39
|
|
40
40
|
def initialize
|
41
|
-
|
41
|
+
@hostname = nil
|
42
42
|
end # def initialize
|
43
43
|
|
44
44
|
attr_reader :hostname
|
45
45
|
|
46
46
|
def Template.inherited(subclass)
|
47
|
-
|
47
|
+
@@plugins << subclass
|
48
48
|
end # def inherited
|
49
49
|
|
50
50
|
def run(hook, host, *args)
|
51
51
|
@@plugins.each do |k|
|
52
|
-
|
53
|
-
|
54
|
-
|
52
|
+
i = k.new
|
53
|
+
if i.hostname == host || host.nil? then
|
54
|
+
case hook
|
55
55
|
when :parser
|
56
56
|
i.parserhook(*args)
|
57
57
|
when :pre
|
data/lib/bugzilla/user.rb
CHANGED
@@ -89,6 +89,35 @@ Keeps the bugzilla session during doing something in the block.
|
|
89
89
|
|
90
90
|
=begin rdoc
|
91
91
|
|
92
|
+
==== Bugzilla::User#get_userinfo(params)
|
93
|
+
|
94
|
+
=end
|
95
|
+
|
96
|
+
def get_userinfo(user)
|
97
|
+
p = {}
|
98
|
+
ids = []
|
99
|
+
names = []
|
100
|
+
|
101
|
+
if user.kind_of?(Array) then
|
102
|
+
user.each do |u|
|
103
|
+
names << u if u.kind_of?(String)
|
104
|
+
id << u if u.kind_of?(Integer)
|
105
|
+
end
|
106
|
+
elsif user.kind_of?(String) then
|
107
|
+
names << user
|
108
|
+
elsif user.kind_of?(Integer) then
|
109
|
+
ids << user
|
110
|
+
else
|
111
|
+
raise ArgumentError, sprintf("Unknown type of arguments: %s", user.class)
|
112
|
+
end
|
113
|
+
|
114
|
+
result = get({'ids'=>ids, 'names'=>names})
|
115
|
+
|
116
|
+
result['users']
|
117
|
+
end # def get_userinfo
|
118
|
+
|
119
|
+
=begin rdoc
|
120
|
+
|
92
121
|
==== Bugzilla::User#login(params)
|
93
122
|
|
94
123
|
Raw Bugzilla API to log into Bugzilla.
|
@@ -136,8 +165,11 @@ See http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/User.html
|
|
136
165
|
# FIXME
|
137
166
|
end # def _update
|
138
167
|
|
139
|
-
def
|
168
|
+
def _get(cmd, *args)
|
169
|
+
raise ArgumentError, "Invalid parameters" unless args[0].kind_of?(Hash)
|
170
|
+
|
140
171
|
requires_version(cmd, 3.4)
|
172
|
+
res = @iface.call(cmd, args[0])
|
141
173
|
# FIXME
|
142
174
|
end # def _get
|
143
175
|
|
data/lib/bugzilla/user.rb~
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# user.rb
|
2
|
-
# Copyright (C) 2010-
|
2
|
+
# Copyright (C) 2010-2014 Red Hat, Inc.
|
3
3
|
#
|
4
4
|
# Authors:
|
5
5
|
# Akira TAGOH <tagoh@redhat.com>
|
@@ -52,36 +52,39 @@ Keeps the bugzilla session during doing something in the block.
|
|
52
52
|
else
|
53
53
|
fname = File.join(ENV['HOME'], '.ruby-bugzilla-cookie.yml')
|
54
54
|
end
|
55
|
+
host = @iface.instance_variable_get(:@xmlrpc).instance_variable_get(:@host)
|
56
|
+
val = nil
|
57
|
+
|
55
58
|
if File.exist?(fname) && File.lstat(fname).mode & 0600 == 0600 then
|
56
59
|
conf = YAML.load(File.open(fname).read)
|
57
|
-
host = @iface.instance_variable_get(:@xmlrpc).instance_variable_get(:@host)
|
58
60
|
val = conf[host]
|
59
|
-
|
60
|
-
|
61
|
-
print "Using token\n"
|
62
|
-
@iface.token = val
|
63
|
-
else
|
64
|
-
print "Using cookie\n"
|
65
|
-
@iface.cookie = cookie
|
66
|
-
end
|
67
|
-
yield
|
68
|
-
if key == :token then
|
69
|
-
conf[host] = @iface.token
|
70
|
-
else
|
71
|
-
conf[host] = @iface.cookie
|
72
|
-
end
|
73
|
-
File.open(fname, 'w') {|f| f.chmod(0600); f.write(conf.to_yaml)}
|
74
|
-
return
|
75
|
-
end
|
61
|
+
else
|
62
|
+
conf = {}
|
76
63
|
end
|
77
|
-
if
|
64
|
+
if !val.nil? then
|
65
|
+
if key == :token then
|
66
|
+
print "Using token\n"
|
67
|
+
@iface.token = val
|
68
|
+
else
|
69
|
+
print "Using cookie\n"
|
70
|
+
@iface.cookie = cookie
|
71
|
+
end
|
72
|
+
yield
|
73
|
+
elsif user.nil? || password.nil? then
|
78
74
|
yield
|
75
|
+
return
|
79
76
|
else
|
80
77
|
login({'login'=>user, 'password'=>password, 'remember'=>true})
|
81
78
|
yield
|
82
|
-
logout
|
83
79
|
end
|
84
|
-
|
80
|
+
if key == :token then
|
81
|
+
conf[host] = @iface.token
|
82
|
+
else
|
83
|
+
conf[host] = @iface.cookie
|
84
|
+
end
|
85
|
+
File.open(fname, 'w') {|f| f.chmod(0600); f.write(conf.to_yaml)}
|
86
|
+
|
87
|
+
return key
|
85
88
|
end # def session
|
86
89
|
|
87
90
|
=begin rdoc
|
@@ -109,7 +112,12 @@ See http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/User.html
|
|
109
112
|
def _login(cmd, *args)
|
110
113
|
raise ArgumentError, "Invalid parameters" unless args[0].kind_of?(Hash)
|
111
114
|
|
112
|
-
@iface.call(cmd,args[0])
|
115
|
+
res = @iface.call(cmd,args[0])
|
116
|
+
unless res['token'].nil? then
|
117
|
+
@iface.token = res['token']
|
118
|
+
end
|
119
|
+
|
120
|
+
return res
|
113
121
|
end # def _login
|
114
122
|
|
115
123
|
def _logout(cmd, *args)
|
data/lib/bugzilla/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# version.rb
|
2
|
-
# Copyright (C) 2010-
|
2
|
+
# Copyright (C) 2010-2015 Red Hat, Inc.
|
3
3
|
#
|
4
4
|
# Authors:
|
5
5
|
# Akira TAGOH <tagoh@redhat.com>
|
@@ -26,6 +26,6 @@
|
|
26
26
|
|
27
27
|
module Bugzilla
|
28
28
|
|
29
|
-
VERSION = "0.
|
29
|
+
VERSION = "0.6.0"
|
30
30
|
|
31
31
|
end # module Bugzilla
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# nvbugzilla.rb
|
2
|
+
# Copyright (C) 2014 Novell, Inc.
|
3
|
+
#
|
4
|
+
# Authors:
|
5
|
+
# Victor Pereira <vpereira@suse.com>
|
6
|
+
#
|
7
|
+
# This library is free software: you can redistribute it and/or
|
8
|
+
# modify it under the terms of the GNU Lesser General Public
|
9
|
+
# License as published by the Free Software Foundation, either
|
10
|
+
# version 3 of the License, or (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This library is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
require 'rubygems'
|
21
|
+
|
22
|
+
#begin
|
23
|
+
# gem 'ruby-bugzilla'
|
24
|
+
#rescue Gem::LoadError
|
25
|
+
# require File.join(File.dirname(__FILE__), "..", "bugzilla.rb")
|
26
|
+
#end
|
27
|
+
|
28
|
+
module Bugzilla
|
29
|
+
|
30
|
+
module Plugin
|
31
|
+
|
32
|
+
class Novell < ::Bugzilla::Plugin::Template
|
33
|
+
|
34
|
+
def initialize
|
35
|
+
super
|
36
|
+
@hostname = "bugzilla.novell.com"
|
37
|
+
end # def initialize
|
38
|
+
|
39
|
+
def parserhook(*args)
|
40
|
+
super
|
41
|
+
end # def parserhook
|
42
|
+
|
43
|
+
def prehook(*args)
|
44
|
+
super
|
45
|
+
end # def prehook
|
46
|
+
|
47
|
+
def posthook(*args)
|
48
|
+
super
|
49
|
+
end # def posthook
|
50
|
+
|
51
|
+
end # class Novell
|
52
|
+
|
53
|
+
end # module Plugin
|
54
|
+
|
55
|
+
end # module Bugzilla
|
metadata
CHANGED
@@ -1,83 +1,83 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-bugzilla
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Akira TAGOH
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2.0'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: gruff
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: highline
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rmagick
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- -
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: bundler
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '1.0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.0'
|
83
83
|
description: This aims to provide similar features to access to Bugzilla through WebService
|
@@ -89,27 +89,28 @@ executables:
|
|
89
89
|
extensions: []
|
90
90
|
extra_rdoc_files: []
|
91
91
|
files:
|
92
|
-
-
|
92
|
+
- COPYING
|
93
|
+
- README.md
|
94
|
+
- bin/bzconsole
|
95
|
+
- lib/bugzilla.rb
|
96
|
+
- lib/bugzilla/api_tmpl.rb
|
97
|
+
- lib/bugzilla/bug.rb
|
98
|
+
- lib/bugzilla/bugzilla.rb
|
93
99
|
- lib/bugzilla/bugzilla.rb~
|
100
|
+
- lib/bugzilla/classification.rb
|
101
|
+
- lib/bugzilla/group.rb
|
102
|
+
- lib/bugzilla/plugin.rb
|
94
103
|
- lib/bugzilla/product.rb
|
95
104
|
- lib/bugzilla/skeleton.rb
|
105
|
+
- lib/bugzilla/skeleton.rb~
|
96
106
|
- lib/bugzilla/user.rb
|
107
|
+
- lib/bugzilla/user.rb~
|
108
|
+
- lib/bugzilla/version.rb
|
109
|
+
- lib/bugzilla/version.rb~
|
97
110
|
- lib/bugzilla/xmlrpc.rb
|
98
111
|
- lib/bugzilla/xmlrpc.rb~
|
99
|
-
- lib/bugzilla/
|
100
|
-
- lib/bugzilla/group.rb
|
101
|
-
- lib/bugzilla/plugin.rb
|
102
|
-
- lib/bugzilla/version.rb~
|
103
|
-
- lib/bugzilla/bugzilla.rb
|
104
|
-
- lib/bugzilla/user.rb~
|
105
|
-
- lib/bugzilla/classification.rb
|
106
|
-
- lib/bugzilla/bug.rb
|
107
|
-
- lib/bugzilla/api_tmpl.rb
|
108
|
-
- lib/bugzilla.rb
|
112
|
+
- lib/ruby-bugzilla/nvbugzilla.rb
|
109
113
|
- lib/ruby-bugzilla/rhbugzilla.rb
|
110
|
-
- README.rdoc
|
111
|
-
- COPYING
|
112
|
-
- bin/bzconsole
|
113
114
|
homepage: http://rubygems.org/gems/ruby-bugzilla
|
114
115
|
licenses: []
|
115
116
|
metadata: {}
|
@@ -119,17 +120,17 @@ require_paths:
|
|
119
120
|
- lib
|
120
121
|
required_ruby_version: !ruby/object:Gem::Requirement
|
121
122
|
requirements:
|
122
|
-
- -
|
123
|
+
- - ">="
|
123
124
|
- !ruby/object:Gem::Version
|
124
125
|
version: '0'
|
125
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
127
|
requirements:
|
127
|
-
- -
|
128
|
+
- - ">="
|
128
129
|
- !ruby/object:Gem::Version
|
129
130
|
version: 1.3.6
|
130
131
|
requirements: []
|
131
132
|
rubyforge_project:
|
132
|
-
rubygems_version: 2.
|
133
|
+
rubygems_version: 2.2.2
|
133
134
|
signing_key:
|
134
135
|
specification_version: 4
|
135
136
|
summary: Ruby binding for Bugzilla WebService APIs
|