jira-ruby 1.1.3 → 2.3.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.
Files changed (108) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +5 -3
  4. data/Gemfile +7 -1
  5. data/Guardfile +1 -1
  6. data/README.md +452 -0
  7. data/Rakefile +6 -7
  8. data/example.rb +38 -6
  9. data/http-basic-example.rb +14 -13
  10. data/jira-ruby.gemspec +13 -13
  11. data/lib/jira/base.rb +58 -53
  12. data/lib/jira/base_factory.rb +3 -6
  13. data/lib/jira/client.rb +127 -30
  14. data/lib/jira/has_many_proxy.rb +0 -1
  15. data/lib/jira/http_client.rb +54 -16
  16. data/lib/jira/http_error.rb +3 -5
  17. data/lib/jira/jwt_client.rb +67 -0
  18. data/lib/jira/oauth_client.rb +47 -17
  19. data/lib/jira/request_client.rb +16 -5
  20. data/lib/jira/resource/agile.rb +34 -9
  21. data/lib/jira/resource/applinks.rb +5 -8
  22. data/lib/jira/resource/attachment.rb +41 -3
  23. data/lib/jira/resource/board.rb +91 -0
  24. data/lib/jira/resource/board_configuration.rb +9 -0
  25. data/lib/jira/resource/comment.rb +0 -2
  26. data/lib/jira/resource/component.rb +1 -3
  27. data/lib/jira/resource/createmeta.rb +14 -22
  28. data/lib/jira/resource/field.rb +22 -22
  29. data/lib/jira/resource/filter.rb +2 -2
  30. data/lib/jira/resource/issue.rb +69 -38
  31. data/lib/jira/resource/issue_picker_suggestions.rb +24 -0
  32. data/lib/jira/resource/issue_picker_suggestions_issue.rb +10 -0
  33. data/lib/jira/resource/issuelink.rb +3 -5
  34. data/lib/jira/resource/issuelinktype.rb +0 -1
  35. data/lib/jira/resource/issuetype.rb +1 -3
  36. data/lib/jira/resource/priority.rb +1 -3
  37. data/lib/jira/resource/project.rb +8 -8
  38. data/lib/jira/resource/rapidview.rb +28 -7
  39. data/lib/jira/resource/remotelink.rb +1 -4
  40. data/lib/jira/resource/resolution.rb +2 -4
  41. data/lib/jira/resource/serverinfo.rb +1 -2
  42. data/lib/jira/resource/sprint.rb +86 -17
  43. data/lib/jira/resource/sprint_report.rb +8 -0
  44. data/lib/jira/resource/status.rb +1 -3
  45. data/lib/jira/resource/suggested_issue.rb +9 -0
  46. data/lib/jira/resource/transition.rb +2 -6
  47. data/lib/jira/resource/user.rb +12 -2
  48. data/lib/jira/resource/version.rb +1 -3
  49. data/lib/jira/resource/watcher.rb +35 -0
  50. data/lib/jira/resource/webhook.rb +3 -6
  51. data/lib/jira/resource/worklog.rb +3 -5
  52. data/lib/jira/version.rb +1 -1
  53. data/lib/jira-ruby.rb +12 -2
  54. data/lib/tasks/generate.rake +4 -4
  55. data/spec/integration/attachment_spec.rb +17 -8
  56. data/spec/integration/comment_spec.rb +31 -34
  57. data/spec/integration/component_spec.rb +21 -24
  58. data/spec/integration/field_spec.rb +15 -18
  59. data/spec/integration/issue_spec.rb +45 -46
  60. data/spec/integration/issuelinktype_spec.rb +8 -11
  61. data/spec/integration/issuetype_spec.rb +5 -7
  62. data/spec/integration/priority_spec.rb +5 -8
  63. data/spec/integration/project_spec.rb +13 -20
  64. data/spec/integration/rapidview_spec.rb +17 -10
  65. data/spec/integration/resolution_spec.rb +7 -10
  66. data/spec/integration/status_spec.rb +5 -8
  67. data/spec/integration/transition_spec.rb +17 -20
  68. data/spec/integration/user_spec.rb +24 -8
  69. data/spec/integration/version_spec.rb +21 -25
  70. data/spec/integration/watcher_spec.rb +62 -0
  71. data/spec/integration/webhook.rb +8 -17
  72. data/spec/integration/worklog_spec.rb +30 -34
  73. data/spec/jira/base_factory_spec.rb +11 -12
  74. data/spec/jira/base_spec.rb +216 -229
  75. data/spec/jira/client_spec.rb +227 -159
  76. data/spec/jira/has_many_proxy_spec.rb +11 -12
  77. data/spec/jira/http_client_spec.rb +254 -31
  78. data/spec/jira/http_error_spec.rb +7 -9
  79. data/spec/jira/jwt_uri_builder_spec.rb +59 -0
  80. data/spec/jira/oauth_client_spec.rb +110 -39
  81. data/spec/jira/request_client_spec.rb +36 -9
  82. data/spec/jira/resource/agile_spec.rb +135 -0
  83. data/spec/jira/resource/attachment_spec.rb +127 -9
  84. data/spec/jira/resource/board_spec.rb +224 -0
  85. data/spec/jira/resource/createmeta_spec.rb +39 -34
  86. data/spec/jira/resource/field_spec.rb +42 -48
  87. data/spec/jira/resource/filter_spec.rb +40 -40
  88. data/spec/jira/resource/issue_picker_suggestions_spec.rb +79 -0
  89. data/spec/jira/resource/issue_spec.rb +88 -85
  90. data/spec/jira/resource/issuelink_spec.rb +1 -1
  91. data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +18 -0
  92. data/spec/jira/resource/project_factory_spec.rb +2 -4
  93. data/spec/jira/resource/project_spec.rb +86 -33
  94. data/spec/jira/resource/sprint_spec.rb +90 -0
  95. data/spec/jira/resource/user_factory_spec.rb +6 -8
  96. data/spec/jira/resource/worklog_spec.rb +9 -11
  97. data/spec/mock_responses/board/1.json +33 -0
  98. data/spec/mock_responses/board/1_issues.json +62 -0
  99. data/spec/mock_responses/empty_issues.json +8 -0
  100. data/spec/mock_responses/issue/10002/watchers.json +13 -0
  101. data/spec/mock_responses/issue.json +1 -1
  102. data/spec/mock_responses/sprint/1_issues.json +125 -0
  103. data/spec/spec_helper.rb +8 -9
  104. data/spec/support/clients_helper.rb +4 -4
  105. data/spec/support/shared_examples/integration.rb +60 -77
  106. metadata +115 -54
  107. data/README.rdoc +0 -329
  108. /data/spec/mock_responses/{attachment → issue/10002/attachments}/10000.json +0 -0
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Base do
4
-
5
4
  class JIRADelegation < SimpleDelegator # :nodoc:
6
5
  end
7
6
 
@@ -10,57 +9,56 @@ describe JIRA::Base do
10
9
 
11
10
  class JIRA::Resource::HasOneExample < JIRA::Base # :nodoc:
12
11
  has_one :deadbeef
13
- has_one :muffin, :class => JIRA::Resource::Deadbeef
14
- has_one :brunchmuffin, :class => JIRA::Resource::Deadbeef,
15
- :nested_under => 'nested'
12
+ has_one :muffin, class: JIRA::Resource::Deadbeef
13
+ has_one :brunchmuffin, class: JIRA::Resource::Deadbeef,
14
+ nested_under: 'nested'
16
15
  has_one :breakfastscone,
17
- :class => JIRA::Resource::Deadbeef,
18
- :nested_under => ['nested','breakfastscone']
16
+ class: JIRA::Resource::Deadbeef,
17
+ nested_under: %w[nested breakfastscone]
19
18
  has_one :irregularly_named_thing,
20
- :class => JIRA::Resource::Deadbeef,
21
- :attribute_key => 'irregularlyNamedThing'
19
+ class: JIRA::Resource::Deadbeef,
20
+ attribute_key: 'irregularlyNamedThing'
22
21
  end
23
22
 
24
23
  class JIRA::Resource::HasManyExample < JIRA::Base # :nodoc:
25
24
  has_many :deadbeefs
26
- has_many :brunchmuffins, :class => JIRA::Resource::Deadbeef,
27
- :nested_under => 'nested'
25
+ has_many :brunchmuffins, class: JIRA::Resource::Deadbeef,
26
+ nested_under: 'nested'
28
27
  has_many :breakfastscones,
29
- :class => JIRA::Resource::Deadbeef,
30
- :nested_under => ['nested','breakfastscone']
28
+ class: JIRA::Resource::Deadbeef,
29
+ nested_under: %w[nested breakfastscone]
31
30
  has_many :irregularly_named_things,
32
- :class => JIRA::Resource::Deadbeef,
33
- :attribute_key => 'irregularlyNamedThings'
34
-
31
+ class: JIRA::Resource::Deadbeef,
32
+ attribute_key: 'irregularlyNamedThings'
35
33
  end
36
34
 
37
- let(:client) { double("client") }
38
- let(:attrs) { Hash.new }
35
+ let(:client) { double('client') }
36
+ let(:attrs) { {} }
39
37
 
40
- subject { JIRA::Resource::Deadbeef.new(client, :attrs => attrs) }
38
+ subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
41
39
 
42
40
  let(:decorated) { JIRADelegation.new(subject) }
43
41
 
44
- describe "#respond_to?" do
45
- describe "when decorated using SimpleDelegator" do
46
- it "responds to client" do
42
+ describe '#respond_to?' do
43
+ describe 'when decorated using SimpleDelegator' do
44
+ it 'responds to client' do
47
45
  expect(decorated.respond_to?(:client)).to eq(true)
48
46
  end
49
- it "does not raise an error" do
50
- expect {
47
+ it 'does not raise an error' do
48
+ expect do
51
49
  decorated.respond_to?(:client)
52
- }.not_to raise_error
50
+ end.not_to raise_error
53
51
  end
54
52
  end
55
53
  end
56
54
 
57
- it "assigns the client and attrs" do
55
+ it 'assigns the client and attrs' do
58
56
  expect(subject.client).to eq(client)
59
57
  expect(subject.attrs).to eq(attrs)
60
58
  end
61
59
 
62
- it "returns all the deadbeefs" do
63
- response = double()
60
+ it 'returns all the deadbeefs' do
61
+ response = double
64
62
  expect(response).to receive(:body).and_return('[{"self":"http://deadbeef/","id":"98765"}]')
65
63
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef').and_return(response)
66
64
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
@@ -73,8 +71,8 @@ describe JIRA::Base do
73
71
  expect(first.expanded?).to be_falsey
74
72
  end
75
73
 
76
- it "finds a deadbeef by id" do
77
- response = instance_double("Response", body: '{"self":"http://deadbeef/","id":"98765"}')
74
+ it 'finds a deadbeef by id' do
75
+ response = instance_double('Response', body: '{"self":"http://deadbeef/","id":"98765"}')
78
76
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
79
77
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
80
78
  deadbeef = JIRA::Resource::Deadbeef.find(client, '98765')
@@ -84,16 +82,16 @@ describe JIRA::Base do
84
82
  expect(deadbeef.expanded?).to be_truthy
85
83
  end
86
84
 
87
- it "finds a deadbeef containing changelog by id" do
85
+ it 'finds a deadbeef containing changelog by id' do
88
86
  response = instance_double(
89
- "Response",
87
+ 'Response',
90
88
  body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
91
89
  )
92
90
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
93
91
 
94
92
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
95
93
 
96
- deadbeef = JIRA::Resource::Deadbeef.find(client, '98765', {expand:'changelog'})
94
+ deadbeef = JIRA::Resource::Deadbeef.find(client, '98765', expand: 'changelog')
97
95
  expect(deadbeef.client).to eq(client)
98
96
  expect(deadbeef.attrs['self']).to eq('http://deadbeef/')
99
97
  expect(deadbeef.attrs['id']).to eq('98765')
@@ -101,60 +99,58 @@ describe JIRA::Base do
101
99
  expect(deadbeef.attrs['changelog']['histories']).to eq([])
102
100
  end
103
101
 
104
- it "builds a deadbeef" do
105
- deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' => "98765" )
102
+ it 'builds a deadbeef' do
103
+ deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' => '98765')
106
104
  expect(deadbeef.expanded?).to be_falsey
107
105
 
108
106
  expect(deadbeef.client).to eq(client)
109
107
  expect(deadbeef.attrs['id']).to eq('98765')
110
108
  end
111
109
 
112
- it "returns the endpoint name" do
110
+ it 'returns the endpoint name' do
113
111
  expect(subject.class.endpoint_name).to eq('deadbeef')
114
112
  end
115
113
 
116
- it "returns the path_component" do
114
+ it 'returns the path_component' do
117
115
  attrs['id'] = '123'
118
116
  expect(subject.path_component).to eq('/deadbeef/123')
119
117
  end
120
118
 
121
- it "returns the path component for unsaved instances" do
119
+ it 'returns the path component for unsaved instances' do
122
120
  expect(subject.path_component).to eq('/deadbeef')
123
121
  end
124
122
 
125
- it "converts to a symbol" do
123
+ it 'converts to a symbol' do
126
124
  expect(subject.to_sym).to eq(:deadbeef)
127
125
  end
128
126
 
129
- describe "collection_path" do
130
-
127
+ describe 'collection_path' do
131
128
  before(:each) do
132
- expect(client).to receive(:options).and_return(:rest_base_path => '/deadbeef/bar')
129
+ expect(client).to receive(:options).and_return(rest_base_path: '/deadbeef/bar')
133
130
  end
134
131
 
135
- it "returns the collection_path" do
132
+ it 'returns the collection_path' do
136
133
  expect(subject.collection_path).to eq('/deadbeef/bar/deadbeef')
137
134
  end
138
135
 
139
- it "returns the collection_path with a prefix" do
136
+ it 'returns the collection_path with a prefix' do
140
137
  expect(subject.collection_path('/baz/')).to eq('/deadbeef/bar/baz/deadbeef')
141
138
  end
142
139
 
143
- it "has a class method that returns the collection_path" do
140
+ it 'has a class method that returns the collection_path' do
144
141
  expect(subject.class.collection_path(client)).to eq('/deadbeef/bar/deadbeef')
145
142
  end
146
143
  end
147
144
 
148
- it "parses json" do
149
- expect(described_class.parse_json('{"foo":"bar"}')).to eq({"foo" => "bar"})
145
+ it 'parses json' do
146
+ expect(described_class.parse_json('{"foo":"bar"}')).to eq('foo' => 'bar')
150
147
  end
151
148
 
152
- describe "dynamic instance methods" do
149
+ describe 'dynamic instance methods' do
150
+ let(:attrs) { { 'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy' } }
151
+ subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
153
152
 
154
- let(:attrs) { {'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy'} }
155
- subject { JIRA::Resource::Deadbeef.new(client, :attrs => attrs) }
156
-
157
- it "responds to each of the top level attribute names" do
153
+ it 'responds to each of the top level attribute names' do
158
154
  expect(subject).to respond_to(:foo)
159
155
  expect(subject).to respond_to('flum')
160
156
  expect(subject).to respond_to(:object_id)
@@ -169,39 +165,36 @@ describe JIRA::Base do
169
165
  end
170
166
  end
171
167
 
172
- describe "fetch" do
173
-
174
- subject { JIRA::Resource::Deadbeef.new(client, :attrs => {'id' => '98765'}) }
175
-
176
- describe "not cached" do
168
+ describe 'fetch' do
169
+ subject { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '98765' }) }
177
170
 
171
+ describe 'not cached' do
178
172
  before(:each) do
179
- response = instance_double("Response", body: '{"self":"http://deadbeef/","id":"98765"}')
173
+ response = instance_double('Response', body: '{"self":"http://deadbeef/","id":"98765"}')
180
174
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
181
175
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
182
176
  end
183
177
 
184
- it "sets expanded to true after fetch" do
178
+ it 'sets expanded to true after fetch' do
185
179
  expect(subject.expanded?).to be_falsey
186
180
  subject.fetch
187
181
  expect(subject.expanded?).to be_truthy
188
182
  end
189
183
 
190
- it "performs a fetch" do
184
+ it 'performs a fetch' do
191
185
  expect(subject.expanded?).to be_falsey
192
186
  subject.fetch
193
- expect(subject.self).to eq("http://deadbeef/")
194
- expect(subject.id).to eq("98765")
187
+ expect(subject.self).to eq('http://deadbeef/')
188
+ expect(subject.id).to eq('98765')
195
189
  end
196
190
 
197
- it "performs a fetch if already fetched and force flag is true" do
191
+ it 'performs a fetch if already fetched and force flag is true' do
198
192
  subject.expanded = true
199
193
  subject.fetch(true)
200
194
  end
201
-
202
195
  end
203
196
 
204
- describe "cached" do
197
+ describe 'cached' do
205
198
  it "doesn't perform a fetch if already fetched" do
206
199
  subject.expanded = true
207
200
  expect(client).not_to receive(:get)
@@ -212,25 +205,24 @@ describe JIRA::Base do
212
205
  context "with expand parameter 'changelog'" do
213
206
  it "fetchs changelogs '" do
214
207
  response = instance_double(
215
- "Response",
208
+ 'Response',
216
209
  body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
217
210
  )
218
211
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
219
212
 
220
213
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
221
214
 
222
- subject.fetch(false, {expand:'changelog'})
215
+ subject.fetch(false, expand: 'changelog')
223
216
 
224
- expect(subject.self).to eq("http://deadbeef/")
225
- expect(subject.id).to eq("98765")
217
+ expect(subject.self).to eq('http://deadbeef/')
218
+ expect(subject.id).to eq('98765')
226
219
  expect(subject.changelog['histories']).to eq([])
227
220
  end
228
221
  end
229
222
  end
230
223
 
231
- describe "save" do
232
-
233
- let(:response) { double() }
224
+ describe 'save' do
225
+ let(:response) { double }
234
226
 
235
227
  subject { JIRA::Resource::Deadbeef.new(client) }
236
228
 
@@ -238,49 +230,49 @@ describe JIRA::Base do
238
230
  expect(subject).to receive(:url).and_return('/foo/bar')
239
231
  end
240
232
 
241
- it "POSTs a new record" do
242
- response = instance_double("Response", body: '{"id":"123"}')
233
+ it 'POSTs a new record' do
234
+ response = instance_double('Response', body: '{"id":"123"}')
243
235
  allow(subject).to receive(:new_record?) { true }
244
- expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
245
- expect(subject.save("foo" => "bar")).to be_truthy
246
- expect(subject.id).to eq("123")
236
+ expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
237
+ expect(subject.save('foo' => 'bar')).to be_truthy
238
+ expect(subject.id).to eq('123')
247
239
  expect(subject.expanded).to be_falsey
248
240
  end
249
241
 
250
- it "PUTs an existing record" do
251
- response = instance_double("Response", body: nil)
242
+ it 'PUTs an existing record' do
243
+ response = instance_double('Response', body: nil)
252
244
  allow(subject).to receive(:new_record?) { false }
253
- expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
254
- expect(subject.save("foo" => "bar")).to be_truthy
245
+ expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
246
+ expect(subject.save('foo' => 'bar')).to be_truthy
255
247
  expect(subject.expanded).to be_falsey
256
248
  end
257
249
 
258
- it "merges attrs on save" do
259
- response = instance_double("Response", body: nil)
260
- expect(client).to receive(:post).with('/foo/bar','{"foo":{"fum":"dum"}}').and_return(response)
261
- subject.attrs = {"foo" => {"bar" => "baz"}}
262
- subject.save({"foo" => {"fum" => "dum"}})
263
- expect(subject.foo).to eq({"bar" => "baz", "fum" => "dum"})
250
+ it 'merges attrs on save' do
251
+ response = instance_double('Response', body: nil)
252
+ expect(client).to receive(:post).with('/foo/bar', '{"foo":{"fum":"dum"}}').and_return(response)
253
+ subject.attrs = { 'foo' => { 'bar' => 'baz' } }
254
+ subject.save('foo' => { 'fum' => 'dum' })
255
+ expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
264
256
  end
265
257
 
266
- it "returns false when an invalid field is set" do # The JIRA REST API apparently ignores fields that you aren't allowed to set manually
267
- response = instance_double("Response", body: '{"errorMessages":["blah"]}', status: 400)
258
+ it 'returns false when an invalid field is set' do # The JIRA REST API apparently ignores fields that you aren't allowed to set manually
259
+ response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
268
260
  allow(subject).to receive(:new_record?) { false }
269
- expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
270
- expect(subject.save("invalid_field" => "foobar")).to be_falsey
261
+ expect(client).to receive(:put).with('/foo/bar', '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
262
+ expect(subject.save('invalid_field' => 'foobar')).to be_falsey
271
263
  end
272
264
 
273
- it "returns false with exception details when non json response body (unauthorized)" do # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
274
- response = double("Response", body: 'totally invalid json', code: 401, message: "Unauthorized")
275
- expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
276
- expect(subject.save("foo" => "bar")).to be_falsey
277
- expect(subject.attrs["exception"]["code"]).to eq(401)
278
- expect(subject.attrs["exception"]["message"]).to eq("Unauthorized")
265
+ it 'returns false with exception details when non json response body (unauthorized)' do # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
266
+ response = double('Response', body: 'totally invalid json', code: 401, message: 'Unauthorized')
267
+ expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
268
+ expect(subject.save('foo' => 'bar')).to be_falsey
269
+ expect(subject.attrs['exception']['code']).to eq(401)
270
+ expect(subject.attrs['exception']['message']).to eq('Unauthorized')
279
271
  end
280
272
  end
281
273
 
282
- describe "save!" do
283
- let(:response) { double() }
274
+ describe 'save!' do
275
+ let(:response) { double }
284
276
 
285
277
  subject { JIRA::Resource::Deadbeef.new(client) }
286
278
 
@@ -288,145 +280,149 @@ describe JIRA::Base do
288
280
  expect(subject).to receive(:url).and_return('/foo/bar')
289
281
  end
290
282
 
291
- it "POSTs a new record" do
292
- response = instance_double("Response", body: '{"id":"123"}')
283
+ it 'POSTs a new record' do
284
+ response = instance_double('Response', body: '{"id":"123"}')
293
285
  allow(subject).to receive(:new_record?) { true }
294
- expect(client).to receive(:post).with('/foo/bar','{"foo":"bar"}').and_return(response)
295
- expect(subject.save!("foo" => "bar")).to be_truthy
296
- expect(subject.id).to eq("123")
286
+ expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
287
+ expect(subject.save!('foo' => 'bar')).to be_truthy
288
+ expect(subject.id).to eq('123')
297
289
  expect(subject.expanded).to be_falsey
298
290
  end
299
291
 
300
- it "PUTs an existing record" do
301
- response = instance_double("Response", body: nil)
292
+ it 'PUTs an existing record' do
293
+ response = instance_double('Response', body: nil)
302
294
  allow(subject).to receive(:new_record?) { false }
303
- expect(client).to receive(:put).with('/foo/bar','{"foo":"bar"}').and_return(response)
304
- expect(subject.save!("foo" => "bar")).to be_truthy
295
+ expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
296
+ expect(subject.save!('foo' => 'bar')).to be_truthy
305
297
  expect(subject.expanded).to be_falsey
306
298
  end
307
299
 
308
- it "throws an exception when an invalid field is set" do
309
- response = instance_double("Response", body: '{"errorMessages":["blah"]}', status: 400)
300
+ it 'throws an exception when an invalid field is set' do
301
+ response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
310
302
  allow(subject).to receive(:new_record?) { false }
311
- expect(client).to receive(:put).with('/foo/bar','{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
312
- expect(lambda{ subject.save!("invalid_field" => "foobar") }).to raise_error(JIRA::HTTPError)
303
+ expect(client).to receive(:put).with('/foo/bar', '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
304
+ expect(-> { subject.save!('invalid_field' => 'foobar') }).to raise_error(JIRA::HTTPError)
313
305
  end
314
306
  end
315
307
 
316
- describe "set_attrs" do
317
- it "merges hashes correctly when clobber is true (default)" do
318
- subject.attrs = {"foo" => {"bar" => "baz"}}
319
- subject.set_attrs({"foo" => {"fum" => "dum"}})
320
- expect(subject.foo).to eq({"fum" => "dum"})
308
+ describe 'set_attrs' do
309
+ it 'merges hashes correctly when clobber is true (default)' do
310
+ subject.attrs = { 'foo' => { 'bar' => 'baz' } }
311
+ subject.set_attrs('foo' => { 'fum' => 'dum' })
312
+ expect(subject.foo).to eq('fum' => 'dum')
321
313
  end
322
314
 
323
- it "merges hashes correctly when clobber is false" do
324
- subject.attrs = {"foo" => {"bar" => "baz"}}
325
- subject.set_attrs({"foo" => {"fum" => "dum"}}, false)
326
- expect(subject.foo).to eq({"bar" => "baz", "fum" => "dum"})
315
+ it 'merges hashes correctly when clobber is false' do
316
+ subject.attrs = { 'foo' => { 'bar' => 'baz' } }
317
+ subject.set_attrs({ 'foo' => { 'fum' => 'dum' } }, false)
318
+ expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
327
319
  end
328
320
  end
329
321
 
330
- describe "delete" do
331
-
322
+ describe 'delete' do
332
323
  before(:each) do
333
324
  expect(client).to receive(:delete).with('/foo/bar')
334
325
  allow(subject).to receive(:url) { '/foo/bar' }
335
326
  end
336
327
 
337
- it "flags itself as deleted" do
328
+ it 'flags itself as deleted' do
338
329
  expect(subject.deleted?).to be_falsey
339
330
  subject.delete
340
331
  expect(subject.deleted?).to be_truthy
341
332
  end
342
333
 
343
- it "sends a DELETE request" do
334
+ it 'sends a DELETE request' do
344
335
  subject.delete
345
336
  end
346
-
347
337
  end
348
338
 
349
- describe "new_record?" do
350
-
351
- it "returns true for new_record? when new object" do
339
+ describe 'new_record?' do
340
+ it 'returns true for new_record? when new object' do
352
341
  subject.attrs['id'] = nil
353
342
  expect(subject.new_record?).to be_truthy
354
343
  end
355
344
 
356
- it "returns false for new_record? when id is set" do
345
+ it 'returns false for new_record? when id is set' do
357
346
  subject.attrs['id'] = '123'
358
347
  expect(subject.new_record?).to be_falsey
359
348
  end
360
-
361
349
  end
362
350
 
363
- describe "has_errors?" do
364
-
365
- it "returns true when the response contains errors" do
366
- attrs["errors"] = {"invalid" => "Field invalid"}
351
+ describe 'has_errors?' do
352
+ it 'returns true when the response contains errors' do
353
+ attrs['errors'] = { 'invalid' => 'Field invalid' }
367
354
  expect(subject.has_errors?).to be_truthy
368
355
  end
369
356
 
370
- it "returns false when the response does not contain any errors" do
357
+ it 'returns false when the response does not contain any errors' do
371
358
  expect(subject.has_errors?).to be_falsey
372
359
  end
373
-
374
360
  end
375
361
 
376
362
  describe 'url' do
377
-
378
363
  before(:each) do
379
- allow(client).to receive(:options) { {:rest_base_path => '/foo/bar'} }
364
+ allow(client).to receive(:options) { { rest_base_path: '/foo/bar' } }
380
365
  end
381
366
 
382
- it "returns self as the URL if set" do
383
- pending("Identified bug on real jira instance")
367
+ it 'returns self as the URL if set' do
384
368
  attrs['self'] = 'http://foo/bar'
385
- expect(subject.url).to eq("http://foo/bar")
369
+ expect(subject.url).to eq('http://foo/bar')
386
370
  end
387
371
 
388
- it "generates the URL from id if self not set" do
372
+ it 'returns path as the URL if set and site options is specified' do
373
+ allow(client).to receive(:options) { { site: 'http://foo' } }
374
+ attrs['self'] = 'http://foo/bar'
375
+ expect(subject.url).to eq('/bar')
376
+ end
377
+
378
+ it 'returns path as the URL if set and site options is specified and ends with a slash' do
379
+ allow(client).to receive(:options) { { site: 'http://foo/' } }
380
+ attrs['self'] = 'http://foo/bar'
381
+ expect(subject.url).to eq('/bar')
382
+ end
383
+
384
+ it 'generates the URL from id if self not set' do
389
385
  attrs['self'] = nil
390
386
  attrs['id'] = '98765'
391
- expect(subject.url).to eq("/foo/bar/deadbeef/98765")
387
+ expect(subject.url).to eq('/foo/bar/deadbeef/98765')
392
388
  end
393
389
 
394
- it "generates the URL from collection_path if self and id not set" do
390
+ it 'generates the URL from collection_path if self and id not set' do
395
391
  attrs['self'] = nil
396
- attrs['id'] = nil
397
- expect(subject.url).to eq("/foo/bar/deadbeef")
392
+ attrs['id'] = nil
393
+ expect(subject.url).to eq('/foo/bar/deadbeef')
398
394
  end
399
395
 
400
- it "has a class method for the collection path" do
401
- expect(JIRA::Resource::Deadbeef.collection_path(client)).to eq("/foo/bar/deadbeef")
402
- #Should accept an optional prefix (flum in this case)
403
- expect(JIRA::Resource::Deadbeef.collection_path(client, '/flum/')).to eq("/foo/bar/flum/deadbeef")
396
+ it 'has a class method for the collection path' do
397
+ expect(JIRA::Resource::Deadbeef.collection_path(client)).to eq('/foo/bar/deadbeef')
398
+ # Should accept an optional prefix (flum in this case)
399
+ expect(JIRA::Resource::Deadbeef.collection_path(client, '/flum/')).to eq('/foo/bar/flum/deadbeef')
404
400
  end
405
401
 
406
- it "has a class method for the singular path" do
407
- expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123')).to eq("/foo/bar/deadbeef/abc123")
408
- #Should accept an optional prefix (flum in this case)
409
- expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123', '/flum/')).to eq("/foo/bar/flum/deadbeef/abc123")
402
+ it 'has a class method for the singular path' do
403
+ expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123')).to eq('/foo/bar/deadbeef/abc123')
404
+ # Should accept an optional prefix (flum in this case)
405
+ expect(JIRA::Resource::Deadbeef.singular_path(client, 'abc123', '/flum/')).to eq('/foo/bar/flum/deadbeef/abc123')
410
406
  end
411
407
  end
412
408
 
413
- it "returns the formatted attrs from to_s" do
409
+ it 'returns the formatted attrs from to_s' do
414
410
  subject.attrs['foo'] = 'bar'
415
411
  subject.attrs['dead'] = 'beef'
416
412
 
417
413
  expect(subject.to_s).to match(/#<JIRA::Resource::Deadbeef:\d+ @attrs=#{Regexp.quote(attrs.inspect)}>/)
418
414
  end
419
415
 
420
- it "returns the key attribute" do
416
+ it 'returns the key attribute' do
421
417
  expect(subject.class.key_attribute).to eq(:id)
422
418
  end
423
419
 
424
- it "returns the key value" do
420
+ it 'returns the key value' do
425
421
  subject.attrs['id'] = '123'
426
422
  expect(subject.key_value).to eq('123')
427
423
  end
428
424
 
429
- it "converts to json" do
425
+ it 'converts to json' do
430
426
  subject.attrs = { 'foo' => 'bar', 'dead' => 'beef' }
431
427
  expect(subject.to_json).to eq(subject.attrs.to_json)
432
428
 
@@ -435,53 +431,49 @@ describe JIRA::Base do
435
431
  expect(h.to_json).to eq(h_attrs.to_json)
436
432
  end
437
433
 
438
- describe "extract attrs from response" do
434
+ describe 'extract attrs from response' do
435
+ subject { JIRA::Resource::Deadbeef.new(client, attrs: {}) }
439
436
 
440
- subject { JIRA::Resource::Deadbeef.new(client, :attrs => {}) }
437
+ it 'sets the attrs from a response' do
438
+ response = instance_double('Response', body: '{"foo":"bar"}')
441
439
 
442
- it "sets the attrs from a response" do
443
- response = instance_double("Response", body: '{"foo":"bar"}')
444
-
445
- expect(subject.set_attrs_from_response(response)).to eq({'foo' => 'bar'})
446
- expect(subject.foo).to eq("bar")
440
+ expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
441
+ expect(subject.foo).to eq('bar')
447
442
  end
448
443
 
449
444
  it "doesn't clobber existing attrs not in response" do
450
- response = instance_double("Response", body: '{"foo":"bar"}')
445
+ response = instance_double('Response', body: '{"foo":"bar"}')
451
446
 
452
- subject.attrs = {'flum' => 'flar'}
453
- expect(subject.set_attrs_from_response(response)).to eq({'foo' => 'bar'})
454
- expect(subject.foo).to eq("bar")
455
- expect(subject.flum).to eq("flar")
447
+ subject.attrs = { 'flum' => 'flar' }
448
+ expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
449
+ expect(subject.foo).to eq('bar')
450
+ expect(subject.flum).to eq('flar')
456
451
  end
457
452
 
458
- it "handles nil response body" do
459
- response = instance_double("Response", body: nil)
453
+ it 'handles nil response body' do
454
+ response = instance_double('Response', body: nil)
460
455
 
461
- subject.attrs = {'flum' => 'flar'}
456
+ subject.attrs = { 'flum' => 'flar' }
462
457
  expect(subject.set_attrs_from_response(response)).to be_nil
463
458
  expect(subject.flum).to eq('flar')
464
459
  end
465
460
  end
466
461
 
467
- describe "nesting" do
468
-
469
- it "defaults collection_attributes_are_nested to false" do
462
+ describe 'nesting' do
463
+ it 'defaults collection_attributes_are_nested to false' do
470
464
  expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_falsey
471
465
  end
472
466
 
473
- it "allows collection_attributes_are_nested to be set" do
467
+ it 'allows collection_attributes_are_nested to be set' do
474
468
  JIRA::Resource::Deadbeef.nested_collections true
475
469
  expect(JIRA::Resource::Deadbeef.collection_attributes_are_nested).to be_truthy
476
470
  end
477
-
478
471
  end
479
472
 
480
- describe "has_many" do
473
+ describe 'has_many' do
474
+ subject { JIRA::Resource::HasManyExample.new(client, attrs: { 'deadbeefs' => [{ 'id' => '123' }] }) }
481
475
 
482
- subject { JIRA::Resource::HasManyExample.new(client, :attrs => {'deadbeefs' => [{'id' => '123'}]}) }
483
-
484
- it "returns a collection of instances for has_many relationships" do
476
+ it 'returns a collection of instances for has_many relationships' do
485
477
  expect(subject.deadbeefs.class).to eq(JIRA::HasManyProxy)
486
478
  expect(subject.deadbeefs.length).to eq(1)
487
479
  subject.deadbeefs.each do |deadbeef|
@@ -489,123 +481,118 @@ describe JIRA::Base do
489
481
  end
490
482
  end
491
483
 
492
- it "returns an empty collection for empty has_many relationships" do
484
+ it 'returns an empty collection for empty has_many relationships' do
493
485
  subject = JIRA::Resource::HasManyExample.new(client)
494
486
  expect(subject.deadbeefs.length).to eq(0)
495
487
  end
496
488
 
497
- it "allows the has_many attributes to be nested inside another attribute" do
498
- subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'nested' => {'brunchmuffins' => [{'id' => '123'},{'id' => '456'}]}})
489
+ it 'allows the has_many attributes to be nested inside another attribute' do
490
+ subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'nested' => { 'brunchmuffins' => [{ 'id' => '123' }, { 'id' => '456' }] } })
499
491
  expect(subject.brunchmuffins.length).to eq(2)
500
492
  subject.brunchmuffins.each do |brunchmuffin|
501
493
  expect(brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
502
494
  end
503
495
  end
504
496
 
505
- it "allows it to be deeply nested" do
506
- subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'nested' => {
507
- 'breakfastscone' => { 'breakfastscones' => [{'id' => '123'},{'id' => '456'}] }
508
- }})
497
+ it 'allows it to be deeply nested' do
498
+ subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'nested' => {
499
+ 'breakfastscone' => { 'breakfastscones' => [{ 'id' => '123' }, { 'id' => '456' }] }
500
+ } })
509
501
  expect(subject.breakfastscones.length).to eq(2)
510
502
  subject.breakfastscones.each do |breakfastscone|
511
503
  expect(breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
512
504
  end
513
505
  end
514
506
 
515
- it "short circuits missing deeply nested attrs" do
516
- subject = JIRA::Resource::HasManyExample.new(client, :attrs => {
517
- 'nested' => {}
518
- })
507
+ it 'short circuits missing deeply nested attrs' do
508
+ subject = JIRA::Resource::HasManyExample.new(client, attrs: {
509
+ 'nested' => {}
510
+ })
519
511
  expect(subject.breakfastscones.length).to eq(0)
520
512
  end
521
513
 
522
- it "allows the attribute key to be specified" do
523
- subject = JIRA::Resource::HasManyExample.new(client, :attrs => {'irregularlyNamedThings' => [{'id' => '123'},{'id' => '456'}]})
514
+ it 'allows the attribute key to be specified' do
515
+ subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'irregularlyNamedThings' => [{ 'id' => '123' }, { 'id' => '456' }] })
524
516
  expect(subject.irregularly_named_things.length).to eq(2)
525
517
  subject.irregularly_named_things.each do |thing|
526
518
  expect(thing.class).to eq(JIRA::Resource::Deadbeef)
527
519
  end
528
520
  end
529
521
 
530
- it "can build child instances" do
522
+ it 'can build child instances' do
531
523
  deadbeef = subject.deadbeefs.build
532
524
  expect(deadbeef.class).to eq(JIRA::Resource::Deadbeef)
533
525
  end
534
-
535
526
  end
536
527
 
537
- describe "has_one" do
528
+ describe 'has_one' do
529
+ subject { JIRA::Resource::HasOneExample.new(client, attrs: { 'deadbeef' => { 'id' => '123' } }) }
538
530
 
539
- subject { JIRA::Resource::HasOneExample.new(client, :attrs => {'deadbeef' => {'id' => '123'}}) }
540
-
541
- it "returns an instance for a has one relationship" do
531
+ it 'returns an instance for a has one relationship' do
542
532
  expect(subject.deadbeef.class).to eq(JIRA::Resource::Deadbeef)
543
533
  expect(subject.deadbeef.id).to eq('123')
544
534
  end
545
535
 
546
- it "returns nil when resource attribute is nonexistent" do
536
+ it 'returns nil when resource attribute is nonexistent' do
547
537
  subject = JIRA::Resource::HasOneExample.new(client)
548
538
  expect(subject.deadbeef).to be_nil
549
539
  end
550
540
 
551
- it "returns an instance with a different class name to the attribute name" do
552
- subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'muffin' => {'id' => '123'}})
541
+ it 'returns an instance with a different class name to the attribute name' do
542
+ subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'muffin' => { 'id' => '123' } })
553
543
  expect(subject.muffin.class).to eq(JIRA::Resource::Deadbeef)
554
544
  expect(subject.muffin.id).to eq('123')
555
545
  end
556
546
 
557
- it "allows the has_one attributes to be nested inside another attribute" do
558
- subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'nested' => {'brunchmuffin' => {'id' => '123'}}})
547
+ it 'allows the has_one attributes to be nested inside another attribute' do
548
+ subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'nested' => { 'brunchmuffin' => { 'id' => '123' } } })
559
549
  expect(subject.brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
560
550
  expect(subject.brunchmuffin.id).to eq('123')
561
551
  end
562
552
 
563
- it "allows it to be deeply nested" do
564
- subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'nested' => {
565
- 'breakfastscone' => { 'breakfastscone' => {'id' => '123'} }
566
- }})
553
+ it 'allows it to be deeply nested' do
554
+ subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'nested' => {
555
+ 'breakfastscone' => { 'breakfastscone' => { 'id' => '123' } }
556
+ } })
567
557
  expect(subject.breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
568
558
  expect(subject.breakfastscone.id).to eq('123')
569
559
  end
570
560
 
571
- it "allows the attribute key to be specified" do
572
- subject = JIRA::Resource::HasOneExample.new(client, :attrs => {'irregularlyNamedThing' => {'id' => '123'}})
561
+ it 'allows the attribute key to be specified' do
562
+ subject = JIRA::Resource::HasOneExample.new(client, attrs: { 'irregularlyNamedThing' => { 'id' => '123' } })
573
563
  expect(subject.irregularly_named_thing.class).to eq(JIRA::Resource::Deadbeef)
574
564
  expect(subject.irregularly_named_thing.id).to eq('123')
575
565
  end
576
-
577
566
  end
578
567
 
579
- describe "belongs_to" do
580
-
568
+ describe 'belongs_to' do
581
569
  class JIRA::Resource::BelongsToExample < JIRA::Base
582
570
  belongs_to :deadbeef
583
571
  end
584
572
 
585
- let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, :attrs => {'id' => "999"}) }
573
+ let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '999' }) }
586
574
 
587
- subject { JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'}, :deadbeef => deadbeef) }
575
+ subject { JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef: deadbeef) }
588
576
 
589
- it "sets up an accessor for the belongs to relationship" do
577
+ it 'sets up an accessor for the belongs to relationship' do
590
578
  expect(subject.deadbeef).to eq(deadbeef)
591
579
  end
592
580
 
593
- it "raises an exception when initialized without a belongs_to instance" do
581
+ it 'raises an exception when initialized without a belongs_to instance' do
594
582
  expect(lambda {
595
- JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'})
596
- }).to raise_exception(ArgumentError,"Required option :deadbeef missing")
583
+ JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' })
584
+ }).to raise_exception(ArgumentError, 'Required option :deadbeef missing')
597
585
  end
598
586
 
599
- it "returns the right url" do
600
- allow(client).to receive(:options) { { :rest_base_path => "/foo" } }
601
- expect(subject.url).to eq("/foo/deadbeef/999/belongstoexample/123")
587
+ it 'returns the right url' do
588
+ allow(client).to receive(:options) { { rest_base_path: '/foo' } }
589
+ expect(subject.url).to eq('/foo/deadbeef/999/belongstoexample/123')
602
590
  end
603
591
 
604
- it "can be initialized with an instance or a key value" do
605
- allow(client).to receive(:options) { { :rest_base_path => "/foo" } }
606
- subject = JIRA::Resource::BelongsToExample.new(client, :attrs => {'id' => '123'}, :deadbeef_id => '987')
607
- expect(subject.url).to eq("/foo/deadbeef/987/belongstoexample/123")
592
+ it 'can be initialized with an instance or a key value' do
593
+ allow(client).to receive(:options) { { rest_base_path: '/foo' } }
594
+ subject = JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef_id: '987')
595
+ expect(subject.url).to eq('/foo/deadbeef/987/belongstoexample/123')
608
596
  end
609
-
610
597
  end
611
598
  end