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.
@@ -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
- execute(params)
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
- execute(params)
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
- execute(params)
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
- def execute(params)
132
- params = {"--bugzilla=" => bugzilla_request_uri}.merge(params)
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
- self.last_command = string_command(CMD, params, password)
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
- def string_command(cmd, params = {}, password=nil)
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
@@ -1,3 +1,3 @@
1
1
  class RubyBugzilla
2
- VERSION = "0.4.2"
2
+ VERSION = "0.5.1"
3
3
  end
@@ -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.2
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: 2013-12-12 00:00:00.000000000 Z
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.23
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