ruby_bugzilla 0.4.2 → 0.5.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/lib/ruby_bugzilla.rb +109 -10
- data/lib/ruby_bugzilla/version.rb +1 -1
- data/spec/ruby_bugzilla_spec.rb +143 -0
- metadata +3 -9
data/lib/ruby_bugzilla.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require 'linux_admin'
|
2
|
+
require "xmlrpc/client"
|
2
3
|
|
3
4
|
class RubyBugzilla
|
5
|
+
CLONE_FIELDS = [:assigned_to, :cc, :cf_devel_whiteboard, :cf_internal_whiteboard, :component,
|
6
|
+
:groups, :keywords, :op_sys, :platform, :priority, :product, :qa_contact, :severity,
|
7
|
+
:summary, :target_release, :url, :version, :whiteboard, :comments, :description,]
|
4
8
|
CMD = `which bugzilla`.chomp
|
5
9
|
COOKIES_FILE = File.expand_path('~/.bugzillacookies')
|
6
10
|
|
@@ -16,11 +20,12 @@ class RubyBugzilla
|
|
16
20
|
File.delete(COOKIES_FILE) if File.exists?(COOKIES_FILE)
|
17
21
|
end
|
18
22
|
|
19
|
-
attr_accessor :bugzilla_uri, :username, :password, :last_command
|
20
|
-
attr_reader :bugzilla_request_uri
|
23
|
+
attr_accessor :bugzilla_uri, :username, :password, :last_command, :xmlrpc
|
24
|
+
attr_reader :bugzilla_request_uri, :bugzilla_request_hostname
|
21
25
|
|
22
26
|
def bugzilla_uri=(value)
|
23
27
|
@bugzilla_request_uri = URI.join(value, "xmlrpc.cgi").to_s
|
28
|
+
@bugzilla_request_hostname = URI(value).hostname
|
24
29
|
@bugzilla_uri = value
|
25
30
|
end
|
26
31
|
|
@@ -31,6 +36,8 @@ class RubyBugzilla
|
|
31
36
|
self.bugzilla_uri = bugzilla_uri
|
32
37
|
self.username = username
|
33
38
|
self.password = password
|
39
|
+
self.xmlrpc = ::XMLRPC::Client.new(bugzilla_request_hostname, '/xmlrpc.cgi', 443, nil,
|
40
|
+
nil, username, password, true, 60)
|
34
41
|
end
|
35
42
|
|
36
43
|
def inspect
|
@@ -60,7 +67,7 @@ class RubyBugzilla
|
|
60
67
|
params["login"] = [username, password]
|
61
68
|
|
62
69
|
begin
|
63
|
-
|
70
|
+
execute_shell(params)
|
64
71
|
rescue
|
65
72
|
clear_login! # A failed login attempt could result in a corrupt COOKIES_FILE
|
66
73
|
raise
|
@@ -93,7 +100,7 @@ class RubyBugzilla
|
|
93
100
|
params["query"] = nil
|
94
101
|
set_params_options(params, options)
|
95
102
|
|
96
|
-
|
103
|
+
execute_shell(params)
|
97
104
|
end
|
98
105
|
|
99
106
|
# Modify an existing bug or set of bugs
|
@@ -123,16 +130,83 @@ class RubyBugzilla
|
|
123
130
|
params["modify"] = bug_ids
|
124
131
|
set_params_options(params, options)
|
125
132
|
|
126
|
-
|
133
|
+
execute_shell(params)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Clone of an existing bug
|
137
|
+
#
|
138
|
+
# Example:
|
139
|
+
# # Perform a clone of an existing bug, and return the new bug ID.
|
140
|
+
# bz.clone(948970)
|
141
|
+
#
|
142
|
+
# @param bug_id [String, Fixnum] A single bug id to process.
|
143
|
+
# @param overrides [Hash] The properties to change from the source bug. Some properties include
|
144
|
+
# * <tt>:target_release</tt> - The target release for the new cloned bug.
|
145
|
+
# * <tt>:assigned_to</tt> - The person to assign the new cloned bug to.
|
146
|
+
# @return [Fixnum] The bug id to the new, cloned, bug.
|
147
|
+
def clone(bug_id, overrides={})
|
148
|
+
raise ArgumentError, "bug_id must be numeric" unless bug_id.to_s =~ /^\d+$/
|
149
|
+
|
150
|
+
existing_bz = xmlrpc_bug_query(bug_id)
|
151
|
+
|
152
|
+
clone_description, clone_comment_is_private = assemble_clone_description(existing_bz)
|
153
|
+
|
154
|
+
params = {}
|
155
|
+
CLONE_FIELDS.each do |field|
|
156
|
+
next if field == :comments
|
157
|
+
params[field] = existing_bz[field.to_s]
|
158
|
+
end
|
159
|
+
|
160
|
+
# Apply overrides
|
161
|
+
overrides.each do |param, value|
|
162
|
+
params[param] = value
|
163
|
+
end
|
164
|
+
|
165
|
+
# Apply base clone fields
|
166
|
+
params[:cf_clone_of] = bug_id
|
167
|
+
params[:description] = clone_description
|
168
|
+
params[:comment_is_private] = clone_comment_is_private
|
169
|
+
|
170
|
+
execute_xmlrpc('create', params)[:id.to_s]
|
171
|
+
end
|
172
|
+
|
173
|
+
# XMLRPC Bug Query of an existing bug
|
174
|
+
#
|
175
|
+
# Example:
|
176
|
+
# # Perform an xmlrpc query for a single bug.
|
177
|
+
# bz.xmlrpc_bug_query(948970)
|
178
|
+
#
|
179
|
+
# @param bug_id [String, Fixnum] A single bug id to process.
|
180
|
+
# @return [Fixnum] The bug id to the new, cloned, bug.
|
181
|
+
def xmlrpc_bug_query(bug_id)
|
182
|
+
raise ArgumentError, "bug_id must be numeric" unless bug_id.to_s =~ /^\d+$/
|
183
|
+
|
184
|
+
params = {}
|
185
|
+
params[:Bugzilla_login] = username
|
186
|
+
params[:Bugzilla_password] = password
|
187
|
+
params[:ids] = bug_id
|
188
|
+
params[:include_fields] = CLONE_FIELDS
|
189
|
+
|
190
|
+
execute_xmlrpc('get', params)['bugs'].last
|
127
191
|
end
|
128
192
|
|
129
193
|
private
|
194
|
+
def assemble_clone_description(existing_bz)
|
195
|
+
clone_description = " +++ This bug was initially created as a clone of Bug ##{existing_bz[:id.to_s]} +++ \n"
|
196
|
+
clone_description << existing_bz[:description.to_s]
|
130
197
|
|
131
|
-
|
132
|
-
|
198
|
+
clone_comment_is_private = false
|
199
|
+
existing_bz[:comments.to_s].each do |comment|
|
200
|
+
clone_description << "\n\n"
|
201
|
+
clone_description << "*" * 70
|
202
|
+
clone_description << "\nFollowing comment by %s on %s\n\n" %
|
203
|
+
[comment['author'], comment['creation_time'].to_time]
|
204
|
+
clone_description << "\n\n"
|
205
|
+
clone_description << comment['text']
|
206
|
+
clone_comment_is_private = true if comment['is_private']
|
207
|
+
end
|
133
208
|
|
134
|
-
|
135
|
-
LinuxAdmin.run!(CMD, :params => params).output
|
209
|
+
[clone_description, clone_comment_is_private]
|
136
210
|
end
|
137
211
|
|
138
212
|
def set_params_options(params, options)
|
@@ -141,7 +215,24 @@ class RubyBugzilla
|
|
141
215
|
end
|
142
216
|
end
|
143
217
|
|
144
|
-
|
218
|
+
# Execute the command using LinuxAdmin to execute python-bugzilla shell commands.
|
219
|
+
def execute_shell(params)
|
220
|
+
params = {"--bugzilla=" => bugzilla_request_uri}.merge(params)
|
221
|
+
|
222
|
+
self.last_command = shell_command_string(CMD, params, password)
|
223
|
+
LinuxAdmin.run!(CMD, :params => params).output
|
224
|
+
end
|
225
|
+
|
226
|
+
# Bypass python-bugzilla and use the xmlrpc API directly.
|
227
|
+
def execute_xmlrpc(action, params)
|
228
|
+
cmd = "Bug.#{action}"
|
229
|
+
|
230
|
+
self.last_command = xmlrpc_command_string(cmd, params)
|
231
|
+
xmlrpc.call(cmd, params)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Build a printable representation of the python-bugzilla command executed.
|
235
|
+
def shell_command_string(cmd, params = {}, password=nil)
|
145
236
|
scrubbed_str = str = ""
|
146
237
|
str << cmd
|
147
238
|
params.each do |param, value|
|
@@ -158,4 +249,12 @@ class RubyBugzilla
|
|
158
249
|
scrubbed_str = str.sub(password, "********") unless password.nil?
|
159
250
|
scrubbed_str
|
160
251
|
end
|
252
|
+
|
253
|
+
# Build a printable representation of the xmlrcp command executed.
|
254
|
+
def xmlrpc_command_string(cmd, params = {})
|
255
|
+
clean_params = Hash[params]
|
256
|
+
clean_params[:Bugzilla_password] = "********"
|
257
|
+
"xmlrpc.call(#{cmd}, #{clean_params})"
|
258
|
+
end
|
259
|
+
|
161
260
|
end
|
data/spec/ruby_bugzilla_spec.rb
CHANGED
@@ -124,4 +124,147 @@ describe RubyBugzilla do
|
|
124
124
|
bz.last_command.should include("948972")
|
125
125
|
end
|
126
126
|
end
|
127
|
+
|
128
|
+
context "#xmlrpc_bug_query" do
|
129
|
+
it "when no argument is specified" do
|
130
|
+
expect { bz.xmlrpc_bug_query }.to raise_error(ArgumentError)
|
131
|
+
end
|
132
|
+
|
133
|
+
it "when an invalid argument is specified" do
|
134
|
+
expect { bz.xmlrpc_bug_query("not a Fixnum") }.to raise_error(ArgumentError)
|
135
|
+
end
|
136
|
+
|
137
|
+
it "when the specified bug does not exist" do
|
138
|
+
output = {}
|
139
|
+
|
140
|
+
allow(::XMLRPC::Client).to receive(:new).and_return(double('xmlrpc_client', :call => output))
|
141
|
+
expect { bz.xmlrpc_bug_query(94897099) }.to raise_error
|
142
|
+
end
|
143
|
+
|
144
|
+
it "when producing valid output" do
|
145
|
+
output = {
|
146
|
+
'bugs' => [
|
147
|
+
{
|
148
|
+
"priority" => "unspecified",
|
149
|
+
"keywords" => ["ZStream"],
|
150
|
+
"cc" => ["calvin@redhat.com", "hobbes@RedHat.com"],
|
151
|
+
},
|
152
|
+
]
|
153
|
+
}
|
154
|
+
|
155
|
+
allow(::XMLRPC::Client).to receive(:new).and_return(double('xmlrpc_client', :call => output))
|
156
|
+
existing_bz = bz.xmlrpc_bug_query("948972")
|
157
|
+
|
158
|
+
|
159
|
+
bz.last_command.should include("Bug.get")
|
160
|
+
|
161
|
+
existing_bz["priority"].should == "unspecified"
|
162
|
+
existing_bz["keywords"].should == ["ZStream"]
|
163
|
+
existing_bz["cc"].should == ["calvin@redhat.com", "hobbes@RedHat.com"]
|
164
|
+
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "#clone" do
|
169
|
+
it "when no argument is specified" do
|
170
|
+
expect { bz.clone }.to raise_error(ArgumentError)
|
171
|
+
end
|
172
|
+
|
173
|
+
it "when an invalid argument is specified" do
|
174
|
+
expect { bz.clone("not a Fixnum") }.to raise_error(ArgumentError)
|
175
|
+
end
|
176
|
+
|
177
|
+
it "when the specified bug to clone does not exist" do
|
178
|
+
output = {}
|
179
|
+
|
180
|
+
allow(::XMLRPC::Client).to receive(:new).and_return(double('xmlrpc_client', :call => output))
|
181
|
+
expect { bz.clone(94897099) }.to raise_error
|
182
|
+
end
|
183
|
+
|
184
|
+
it "when producing valid output" do
|
185
|
+
output = {"id" => 948992}
|
186
|
+
existing_bz = {
|
187
|
+
"description" => "Description of problem:\n\nIt's Broken",
|
188
|
+
"priority" => "unspecified",
|
189
|
+
"assigned_to" => "calvin@redhat.com",
|
190
|
+
"target_release" => ["---"],
|
191
|
+
"keywords" => ["ZStream"],
|
192
|
+
"cc" => ["calvin@redhat.com", "hobbes@RedHat.com"],
|
193
|
+
"comments" => [
|
194
|
+
{
|
195
|
+
"is_private" => false,
|
196
|
+
"count" => 0,
|
197
|
+
"time" => XMLRPC::DateTime.new(1969, 7, 20, 16, 18, 30),
|
198
|
+
"bug_id" => 948970,
|
199
|
+
"author" => "Calvin@redhat.com",
|
200
|
+
"text" => "It's Broken and impossible to reproduce",
|
201
|
+
"creation_time" => XMLRPC::DateTime.new(1969, 7, 20, 16, 18, 30),
|
202
|
+
"id" => 5777871,
|
203
|
+
"creator_id" => 349490
|
204
|
+
},
|
205
|
+
{
|
206
|
+
"is_private" => false,
|
207
|
+
"count" => 1,
|
208
|
+
"time" => XMLRPC::DateTime.new(1970, 11, 10, 16, 18, 30),
|
209
|
+
"bug_id" => 948970,
|
210
|
+
"author" => "Hobbes@redhat.com",
|
211
|
+
"text" => "Fix Me Now!",
|
212
|
+
"creation_time" => XMLRPC::DateTime.new(1972, 2, 14, 0, 0, 0),
|
213
|
+
"id" => 5782170,
|
214
|
+
"creator_id" => 349490
|
215
|
+
},]
|
216
|
+
}
|
217
|
+
|
218
|
+
RubyBugzilla.any_instance.stub(:xmlrpc_bug_query).and_return(existing_bz)
|
219
|
+
allow(::XMLRPC::Client).to receive(:new).and_return(double('xmlrpc_create', :call => output))
|
220
|
+
new_bz_id = bz.clone("948972")
|
221
|
+
|
222
|
+
bz.last_command.should include("Bug.create")
|
223
|
+
|
224
|
+
new_bz_id.should == output["id"]
|
225
|
+
end
|
226
|
+
|
227
|
+
it "when providing override values" do
|
228
|
+
output = {"id" => 948992}
|
229
|
+
existing_bz = {
|
230
|
+
"description" => "Description of problem:\n\nIt's Broken",
|
231
|
+
"priority" => "unspecified",
|
232
|
+
"assigned_to" => "calvin@redhat.com",
|
233
|
+
"target_release" => ["---"],
|
234
|
+
"keywords" => ["ZStream"],
|
235
|
+
"cc" => ["calvin@redhat.com", "hobbes@RedHat.com"],
|
236
|
+
"comments" => [
|
237
|
+
{
|
238
|
+
"is_private" => false,
|
239
|
+
"count" => 0,
|
240
|
+
"time" => XMLRPC::DateTime.new(1969, 7, 20, 16, 18, 30),
|
241
|
+
"bug_id" => 948970,
|
242
|
+
"author" => "Buzz.Aldrin@redhat.com",
|
243
|
+
"text" => "It's Broken and impossible to reproduce",
|
244
|
+
"creation_time" => XMLRPC::DateTime.new(1969, 7, 20, 16, 18, 30),
|
245
|
+
"id" => 5777871,
|
246
|
+
"creator_id" => 349490
|
247
|
+
},
|
248
|
+
{
|
249
|
+
"is_private" => false,
|
250
|
+
"count" => 1,
|
251
|
+
"time" => XMLRPC::DateTime.new(1970, 11, 10, 16, 18, 30),
|
252
|
+
"bug_id" => 948970,
|
253
|
+
"author" => "Neil.Armstrong@redhat.com",
|
254
|
+
"text" => "Fix Me Now!",
|
255
|
+
"creation_time" => XMLRPC::DateTime.new(1972, 2, 14, 0, 0, 0),
|
256
|
+
"id" => 5782170,
|
257
|
+
"creator_id" => 349490
|
258
|
+
},]
|
259
|
+
}
|
260
|
+
|
261
|
+
RubyBugzilla.any_instance.stub(:xmlrpc_bug_query).and_return(existing_bz)
|
262
|
+
allow(::XMLRPC::Client).to receive(:new).and_return(double('xmlrpc_create', :call => output))
|
263
|
+
new_bz_id = bz.clone("948972", {"assigned_to" => "Ham@NASA.gov", "target_release" => ["2.2.0"],} )
|
264
|
+
|
265
|
+
bz.last_command.should include("Bug.create")
|
266
|
+
|
267
|
+
new_bz_id.should == output["id"]
|
268
|
+
end
|
269
|
+
end
|
127
270
|
end
|
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
|
+
version: 0.5.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2014-01-08 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: bundler
|
@@ -125,21 +125,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
125
|
- - ! '>='
|
126
126
|
- !ruby/object:Gem::Version
|
127
127
|
version: '0'
|
128
|
-
segments:
|
129
|
-
- 0
|
130
|
-
hash: 3744538861231322525
|
131
128
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
129
|
none: false
|
133
130
|
requirements:
|
134
131
|
- - ! '>='
|
135
132
|
- !ruby/object:Gem::Version
|
136
133
|
version: '0'
|
137
|
-
segments:
|
138
|
-
- 0
|
139
|
-
hash: 3744538861231322525
|
140
134
|
requirements: []
|
141
135
|
rubyforge_project:
|
142
|
-
rubygems_version: 1.8.
|
136
|
+
rubygems_version: 1.8.25
|
143
137
|
signing_key:
|
144
138
|
specification_version: 3
|
145
139
|
summary: RubyBugzilla is a Ruby wrapper around the python-bugzilla CLI for easy access
|