jira-ruby 2.3.0 → 3.0.0.beta2
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/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +6 -0
- data/.github/workflows/CI.yml +29 -0
- data/.github/workflows/codeql.yml +96 -0
- data/.github/workflows/rubocop.yml +18 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +120 -0
- data/.yardopts +4 -0
- data/Gemfile +11 -3
- data/Guardfile +2 -0
- data/README.md +94 -18
- data/Rakefile +3 -4
- data/jira-ruby.gemspec +11 -17
- data/lib/jira/base.rb +37 -36
- data/lib/jira/base_factory.rb +4 -1
- data/lib/jira/client.rb +123 -50
- data/lib/jira/has_many_proxy.rb +32 -28
- data/lib/jira/http_client.rb +80 -13
- data/lib/jira/http_error.rb +4 -0
- data/lib/jira/jwt_client.rb +18 -42
- data/lib/jira/oauth_client.rb +68 -3
- data/lib/jira/railtie.rb +2 -0
- data/lib/jira/request_client.rb +31 -2
- data/lib/jira/resource/agile.rb +7 -9
- data/lib/jira/resource/applinks.rb +5 -3
- data/lib/jira/resource/attachment.rb +128 -3
- data/lib/jira/resource/board.rb +5 -3
- data/lib/jira/resource/board_configuration.rb +2 -0
- data/lib/jira/resource/comment.rb +2 -0
- data/lib/jira/resource/component.rb +2 -0
- data/lib/jira/resource/createmeta.rb +3 -1
- data/lib/jira/resource/field.rb +13 -12
- data/lib/jira/resource/filter.rb +2 -0
- data/lib/jira/resource/issue.rb +95 -44
- data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
- data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
- data/lib/jira/resource/issuelink.rb +6 -3
- data/lib/jira/resource/issuelinktype.rb +2 -0
- data/lib/jira/resource/issuetype.rb +2 -0
- data/lib/jira/resource/priority.rb +2 -0
- data/lib/jira/resource/project.rb +4 -2
- data/lib/jira/resource/rapidview.rb +5 -3
- data/lib/jira/resource/remotelink.rb +2 -0
- data/lib/jira/resource/resolution.rb +2 -0
- data/lib/jira/resource/serverinfo.rb +2 -0
- data/lib/jira/resource/sprint.rb +14 -23
- data/lib/jira/resource/status.rb +7 -1
- data/lib/jira/resource/status_category.rb +10 -0
- data/lib/jira/resource/suggested_issue.rb +2 -0
- data/lib/jira/resource/transition.rb +2 -0
- data/lib/jira/resource/user.rb +3 -1
- data/lib/jira/resource/version.rb +2 -0
- data/lib/jira/resource/watcher.rb +3 -2
- data/lib/jira/resource/webhook.rb +9 -3
- data/lib/jira/resource/worklog.rb +3 -2
- data/lib/jira/version.rb +3 -1
- data/lib/jira-ruby.rb +5 -3
- data/lib/tasks/generate.rake +3 -1
- data/spec/data/files/short.txt +1 -0
- data/spec/integration/attachment_spec.rb +3 -3
- data/spec/integration/comment_spec.rb +8 -8
- data/spec/integration/component_spec.rb +7 -7
- data/spec/integration/field_spec.rb +3 -3
- data/spec/integration/issue_spec.rb +20 -16
- data/spec/integration/issuelinktype_spec.rb +3 -3
- data/spec/integration/issuetype_spec.rb +3 -3
- data/spec/integration/priority_spec.rb +3 -3
- data/spec/integration/project_spec.rb +8 -8
- data/spec/integration/rapidview_spec.rb +10 -10
- data/spec/integration/resolution_spec.rb +3 -3
- data/spec/integration/status_category_spec.rb +20 -0
- data/spec/integration/status_spec.rb +4 -8
- data/spec/integration/transition_spec.rb +2 -2
- data/spec/integration/user_spec.rb +34 -11
- data/spec/integration/version_spec.rb +7 -7
- data/spec/integration/watcher_spec.rb +21 -18
- data/spec/integration/webhook_spec.rb +33 -0
- data/spec/integration/worklog_spec.rb +8 -8
- data/spec/jira/base_factory_spec.rb +13 -3
- data/spec/jira/base_spec.rb +135 -98
- data/spec/jira/client_spec.rb +63 -47
- data/spec/jira/has_many_proxy_spec.rb +3 -3
- data/spec/jira/http_client_spec.rb +94 -27
- data/spec/jira/http_error_spec.rb +2 -2
- data/spec/jira/oauth_client_spec.rb +14 -8
- data/spec/jira/request_client_spec.rb +4 -4
- data/spec/jira/resource/agile_spec.rb +30 -30
- data/spec/jira/resource/attachment_spec.rb +170 -57
- data/spec/jira/resource/board_spec.rb +24 -23
- data/spec/jira/resource/createmeta_spec.rb +48 -48
- data/spec/jira/resource/field_spec.rb +44 -27
- data/spec/jira/resource/filter_spec.rb +4 -4
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
- data/spec/jira/resource/issue_spec.rb +49 -43
- data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
- data/spec/jira/resource/project_factory_spec.rb +3 -2
- data/spec/jira/resource/project_spec.rb +14 -14
- data/spec/jira/resource/sprint_spec.rb +88 -9
- data/spec/jira/resource/status_spec.rb +21 -0
- data/spec/jira/resource/user_factory_spec.rb +5 -5
- data/spec/jira/resource/worklog_spec.rb +4 -4
- data/spec/mock_responses/sprint/1.json +13 -0
- data/spec/mock_responses/status/1.json +8 -1
- data/spec/mock_responses/status.json +40 -5
- data/spec/mock_responses/statuscategory/1.json +7 -0
- data/spec/mock_responses/statuscategory.json +30 -0
- data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/support/clients_helper.rb +3 -5
- data/spec/support/mock_client.rb +9 -0
- data/spec/support/mock_response.rb +8 -0
- data/spec/support/shared_examples/integration.rb +25 -28
- metadata +27 -260
- data/.travis.yml +0 -9
- data/example.rb +0 -232
- data/http-basic-example.rb +0 -113
- data/lib/jira/resource/sprint_report.rb +0 -8
- data/lib/jira/tasks.rb +0 -0
- data/spec/integration/webhook.rb +0 -25
- data/spec/jira/jwt_uri_builder_spec.rb +0 -59
data/spec/jira/base_spec.rb
CHANGED
@@ -4,46 +4,59 @@ describe JIRA::Base do
|
|
4
4
|
class JIRADelegation < SimpleDelegator # :nodoc:
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
nested_under: %w[nested breakfastscone]
|
30
|
-
has_many :irregularly_named_things,
|
31
|
-
class: JIRA::Resource::Deadbeef,
|
32
|
-
attribute_key: 'irregularlyNamedThings'
|
7
|
+
module JIRA
|
8
|
+
module Resource
|
9
|
+
class Deadbeef < JIRA::Base # :nodoc:
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module JIRA
|
15
|
+
module Resource
|
16
|
+
class HasOneExample < JIRA::Base # :nodoc:
|
17
|
+
has_one :deadbeef
|
18
|
+
has_one :muffin, class: JIRA::Resource::Deadbeef
|
19
|
+
has_one :brunchmuffin, class: JIRA::Resource::Deadbeef,
|
20
|
+
nested_under: 'nested'
|
21
|
+
has_one :breakfastscone,
|
22
|
+
class: JIRA::Resource::Deadbeef,
|
23
|
+
nested_under: %w[nested breakfastscone]
|
24
|
+
has_one :irregularly_named_thing,
|
25
|
+
class: JIRA::Resource::Deadbeef,
|
26
|
+
attribute_key: 'irregularlyNamedThing'
|
27
|
+
end
|
28
|
+
end
|
33
29
|
end
|
34
30
|
|
31
|
+
module JIRA
|
32
|
+
module Resource
|
33
|
+
class HasManyExample < JIRA::Base # :nodoc:
|
34
|
+
has_many :deadbeefs
|
35
|
+
has_many :brunchmuffins, class: JIRA::Resource::Deadbeef,
|
36
|
+
nested_under: 'nested'
|
37
|
+
has_many :breakfastscones,
|
38
|
+
class: JIRA::Resource::Deadbeef,
|
39
|
+
nested_under: %w[nested breakfastscone]
|
40
|
+
has_many :irregularly_named_things,
|
41
|
+
class: JIRA::Resource::Deadbeef,
|
42
|
+
attribute_key: 'irregularlyNamedThings'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs:) }
|
48
|
+
|
35
49
|
let(:client) { double('client') }
|
36
50
|
let(:attrs) { {} }
|
37
51
|
|
38
|
-
subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
|
39
|
-
|
40
52
|
let(:decorated) { JIRADelegation.new(subject) }
|
41
53
|
|
42
54
|
describe '#respond_to?' do
|
43
55
|
describe 'when decorated using SimpleDelegator' do
|
44
56
|
it 'responds to client' do
|
45
|
-
expect(decorated.respond_to?(:client)).to
|
57
|
+
expect(decorated.respond_to?(:client)).to be(true)
|
46
58
|
end
|
59
|
+
|
47
60
|
it 'does not raise an error' do
|
48
61
|
expect do
|
49
62
|
decorated.respond_to?(:client)
|
@@ -68,23 +81,23 @@ describe JIRA::Base do
|
|
68
81
|
expect(first.class).to eq(JIRA::Resource::Deadbeef)
|
69
82
|
expect(first.attrs['self']).to eq('http://deadbeef/')
|
70
83
|
expect(first.attrs['id']).to eq('98765')
|
71
|
-
expect(first
|
84
|
+
expect(first).not_to be_expanded
|
72
85
|
end
|
73
86
|
|
74
87
|
it 'finds a deadbeef by id' do
|
75
|
-
response = instance_double(
|
88
|
+
response = instance_double(Response, body: '{"self":"http://deadbeef/","id":"98765"}')
|
76
89
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
|
77
90
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
78
91
|
deadbeef = JIRA::Resource::Deadbeef.find(client, '98765')
|
79
92
|
expect(deadbeef.client).to eq(client)
|
80
93
|
expect(deadbeef.attrs['self']).to eq('http://deadbeef/')
|
81
94
|
expect(deadbeef.attrs['id']).to eq('98765')
|
82
|
-
expect(deadbeef
|
95
|
+
expect(deadbeef).to be_expanded
|
83
96
|
end
|
84
97
|
|
85
98
|
it 'finds a deadbeef containing changelog by id' do
|
86
99
|
response = instance_double(
|
87
|
-
|
100
|
+
Response,
|
88
101
|
body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
|
89
102
|
)
|
90
103
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
|
@@ -95,13 +108,13 @@ describe JIRA::Base do
|
|
95
108
|
expect(deadbeef.client).to eq(client)
|
96
109
|
expect(deadbeef.attrs['self']).to eq('http://deadbeef/')
|
97
110
|
expect(deadbeef.attrs['id']).to eq('98765')
|
98
|
-
expect(deadbeef
|
111
|
+
expect(deadbeef).to be_expanded
|
99
112
|
expect(deadbeef.attrs['changelog']['histories']).to eq([])
|
100
113
|
end
|
101
114
|
|
102
115
|
it 'builds a deadbeef' do
|
103
116
|
deadbeef = JIRA::Resource::Deadbeef.build(client, 'id' => '98765')
|
104
|
-
expect(deadbeef
|
117
|
+
expect(deadbeef).not_to be_expanded
|
105
118
|
|
106
119
|
expect(deadbeef.client).to eq(client)
|
107
120
|
expect(deadbeef.attrs['id']).to eq('98765')
|
@@ -125,7 +138,7 @@ describe JIRA::Base do
|
|
125
138
|
end
|
126
139
|
|
127
140
|
describe 'collection_path' do
|
128
|
-
before
|
141
|
+
before do
|
129
142
|
expect(client).to receive(:options).and_return(rest_base_path: '/deadbeef/bar')
|
130
143
|
end
|
131
144
|
|
@@ -147,8 +160,9 @@ describe JIRA::Base do
|
|
147
160
|
end
|
148
161
|
|
149
162
|
describe 'dynamic instance methods' do
|
163
|
+
subject { JIRA::Resource::Deadbeef.new(client, attrs:) }
|
164
|
+
|
150
165
|
let(:attrs) { { 'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy' } }
|
151
|
-
subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
|
152
166
|
|
153
167
|
it 'responds to each of the top level attribute names' do
|
154
168
|
expect(subject).to respond_to(:foo)
|
@@ -169,20 +183,20 @@ describe JIRA::Base do
|
|
169
183
|
subject { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '98765' }) }
|
170
184
|
|
171
185
|
describe 'not cached' do
|
172
|
-
before
|
173
|
-
response = instance_double(
|
186
|
+
before do
|
187
|
+
response = instance_double(Response, body: '{"self":"http://deadbeef/","id":"98765"}')
|
174
188
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
|
175
189
|
expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
|
176
190
|
end
|
177
191
|
|
178
192
|
it 'sets expanded to true after fetch' do
|
179
|
-
expect(subject
|
193
|
+
expect(subject).not_to be_expanded
|
180
194
|
subject.fetch
|
181
|
-
expect(subject
|
195
|
+
expect(subject).to be_expanded
|
182
196
|
end
|
183
197
|
|
184
198
|
it 'performs a fetch' do
|
185
|
-
expect(subject
|
199
|
+
expect(subject).not_to be_expanded
|
186
200
|
subject.fetch
|
187
201
|
expect(subject.self).to eq('http://deadbeef/')
|
188
202
|
expect(subject.id).to eq('98765')
|
@@ -191,6 +205,10 @@ describe JIRA::Base do
|
|
191
205
|
it 'performs a fetch if already fetched and force flag is true' do
|
192
206
|
subject.expanded = true
|
193
207
|
subject.fetch(true)
|
208
|
+
|
209
|
+
expect(subject.self).to eq('http://deadbeef/')
|
210
|
+
expect(subject.id).to eq('98765')
|
211
|
+
expect(subject).to be_expanded
|
194
212
|
end
|
195
213
|
end
|
196
214
|
|
@@ -205,7 +223,7 @@ describe JIRA::Base do
|
|
205
223
|
context "with expand parameter 'changelog'" do
|
206
224
|
it "fetchs changelogs '" do
|
207
225
|
response = instance_double(
|
208
|
-
|
226
|
+
Response,
|
209
227
|
body: '{"self":"http://deadbeef/","id":"98765","changelog":{"histories":[]}}'
|
210
228
|
)
|
211
229
|
expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765?expand=changelog').and_return(response)
|
@@ -222,17 +240,17 @@ describe JIRA::Base do
|
|
222
240
|
end
|
223
241
|
|
224
242
|
describe 'save' do
|
225
|
-
let(:response) { double }
|
226
|
-
|
227
243
|
subject { JIRA::Resource::Deadbeef.new(client) }
|
228
244
|
|
229
|
-
|
245
|
+
let(:response) { double }
|
246
|
+
|
247
|
+
before do
|
230
248
|
expect(subject).to receive(:url).and_return('/foo/bar')
|
231
249
|
end
|
232
250
|
|
233
251
|
it 'POSTs a new record' do
|
234
|
-
response = instance_double(
|
235
|
-
allow(subject).to receive(:new_record?)
|
252
|
+
response = instance_double(Response, body: '{"id":"123"}')
|
253
|
+
allow(subject).to receive(:new_record?).and_return(true)
|
236
254
|
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
237
255
|
expect(subject.save('foo' => 'bar')).to be_truthy
|
238
256
|
expect(subject.id).to eq('123')
|
@@ -240,30 +258,33 @@ describe JIRA::Base do
|
|
240
258
|
end
|
241
259
|
|
242
260
|
it 'PUTs an existing record' do
|
243
|
-
response = instance_double(
|
244
|
-
allow(subject).to receive(:new_record?)
|
261
|
+
response = instance_double(Response, body: nil)
|
262
|
+
allow(subject).to receive(:new_record?).and_return(false)
|
245
263
|
expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
246
264
|
expect(subject.save('foo' => 'bar')).to be_truthy
|
247
265
|
expect(subject.expanded).to be_falsey
|
248
266
|
end
|
249
267
|
|
250
268
|
it 'merges attrs on save' do
|
251
|
-
response = instance_double(
|
269
|
+
response = instance_double(Response, body: nil)
|
252
270
|
expect(client).to receive(:post).with('/foo/bar', '{"foo":{"fum":"dum"}}').and_return(response)
|
253
271
|
subject.attrs = { 'foo' => { 'bar' => 'baz' } }
|
254
272
|
subject.save('foo' => { 'fum' => 'dum' })
|
255
273
|
expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
|
256
274
|
end
|
257
275
|
|
258
|
-
it 'returns false when an invalid field is set' do
|
259
|
-
|
260
|
-
|
261
|
-
|
276
|
+
it 'returns false when an invalid field is set' do
|
277
|
+
# The JIRA REST API apparently ignores fields that you aren't allowed to set manually
|
278
|
+
response = instance_double(Response, body: '{"errorMessages":["blah"]}', status: 400)
|
279
|
+
allow(subject).to receive(:new_record?).and_return(false)
|
280
|
+
expect(client).to receive(:put).with('/foo/bar',
|
281
|
+
'{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
262
282
|
expect(subject.save('invalid_field' => 'foobar')).to be_falsey
|
263
283
|
end
|
264
284
|
|
265
|
-
it 'returns false with exception details when non json response body (unauthorized)' do
|
266
|
-
|
285
|
+
it 'returns false with exception details when non json response body (unauthorized)' do
|
286
|
+
# Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
|
287
|
+
response = double(Response, body: 'totally invalid json', code: 401, message: 'Unauthorized')
|
267
288
|
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
|
268
289
|
expect(subject.save('foo' => 'bar')).to be_falsey
|
269
290
|
expect(subject.attrs['exception']['code']).to eq(401)
|
@@ -272,17 +293,17 @@ describe JIRA::Base do
|
|
272
293
|
end
|
273
294
|
|
274
295
|
describe 'save!' do
|
275
|
-
let(:response) { double }
|
276
|
-
|
277
296
|
subject { JIRA::Resource::Deadbeef.new(client) }
|
278
297
|
|
279
|
-
|
298
|
+
let(:response) { double }
|
299
|
+
|
300
|
+
before do
|
280
301
|
expect(subject).to receive(:url).and_return('/foo/bar')
|
281
302
|
end
|
282
303
|
|
283
304
|
it 'POSTs a new record' do
|
284
|
-
response = instance_double(
|
285
|
-
allow(subject).to receive(:new_record?)
|
305
|
+
response = instance_double(Response, body: '{"id":"123"}')
|
306
|
+
allow(subject).to receive(:new_record?).and_return(true)
|
286
307
|
expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
287
308
|
expect(subject.save!('foo' => 'bar')).to be_truthy
|
288
309
|
expect(subject.id).to eq('123')
|
@@ -290,18 +311,19 @@ describe JIRA::Base do
|
|
290
311
|
end
|
291
312
|
|
292
313
|
it 'PUTs an existing record' do
|
293
|
-
response = instance_double(
|
294
|
-
allow(subject).to receive(:new_record?)
|
314
|
+
response = instance_double(Response, body: nil)
|
315
|
+
allow(subject).to receive(:new_record?).and_return(false)
|
295
316
|
expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
|
296
317
|
expect(subject.save!('foo' => 'bar')).to be_truthy
|
297
318
|
expect(subject.expanded).to be_falsey
|
298
319
|
end
|
299
320
|
|
300
321
|
it 'throws an exception when an invalid field is set' do
|
301
|
-
response = instance_double(
|
302
|
-
allow(subject).to receive(:new_record?)
|
303
|
-
expect(client).to receive(:put).with('/foo/bar',
|
304
|
-
|
322
|
+
response = instance_double(Response, body: '{"errorMessages":["blah"]}', status: 400)
|
323
|
+
allow(subject).to receive(:new_record?).and_return(false)
|
324
|
+
expect(client).to receive(:put).with('/foo/bar',
|
325
|
+
'{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
|
326
|
+
expect { subject.save!('invalid_field' => 'foobar') }.to raise_error(JIRA::HTTPError)
|
305
327
|
end
|
306
328
|
end
|
307
329
|
|
@@ -320,48 +342,51 @@ describe JIRA::Base do
|
|
320
342
|
end
|
321
343
|
|
322
344
|
describe 'delete' do
|
323
|
-
before
|
345
|
+
before do
|
324
346
|
expect(client).to receive(:delete).with('/foo/bar')
|
325
|
-
allow(subject).to receive(:url)
|
347
|
+
allow(subject).to receive(:url).and_return('/foo/bar')
|
326
348
|
end
|
327
349
|
|
328
350
|
it 'flags itself as deleted' do
|
329
|
-
expect(subject
|
351
|
+
expect(subject).not_to be_deleted
|
330
352
|
subject.delete
|
331
|
-
expect(subject
|
353
|
+
expect(subject).to be_deleted
|
332
354
|
end
|
333
355
|
|
334
356
|
it 'sends a DELETE request' do
|
335
357
|
subject.delete
|
358
|
+
|
359
|
+
expect(subject).to have_received(:url)
|
360
|
+
expect(subject).to be_deleted
|
336
361
|
end
|
337
362
|
end
|
338
363
|
|
339
364
|
describe 'new_record?' do
|
340
365
|
it 'returns true for new_record? when new object' do
|
341
366
|
subject.attrs['id'] = nil
|
342
|
-
expect(subject
|
367
|
+
expect(subject).to be_new_record
|
343
368
|
end
|
344
369
|
|
345
370
|
it 'returns false for new_record? when id is set' do
|
346
371
|
subject.attrs['id'] = '123'
|
347
|
-
expect(subject
|
372
|
+
expect(subject).not_to be_new_record
|
348
373
|
end
|
349
374
|
end
|
350
375
|
|
351
376
|
describe 'has_errors?' do
|
352
377
|
it 'returns true when the response contains errors' do
|
353
378
|
attrs['errors'] = { 'invalid' => 'Field invalid' }
|
354
|
-
expect(subject
|
379
|
+
expect(subject).to have_errors
|
355
380
|
end
|
356
381
|
|
357
382
|
it 'returns false when the response does not contain any errors' do
|
358
|
-
expect(subject
|
383
|
+
expect(subject).not_to have_errors
|
359
384
|
end
|
360
385
|
end
|
361
386
|
|
362
387
|
describe 'url' do
|
363
|
-
before
|
364
|
-
allow(client).to receive(:options)
|
388
|
+
before do
|
389
|
+
allow(client).to receive(:options).and_return({ rest_base_path: '/foo/bar' })
|
365
390
|
end
|
366
391
|
|
367
392
|
it 'returns self as the URL if set' do
|
@@ -370,13 +395,13 @@ describe JIRA::Base do
|
|
370
395
|
end
|
371
396
|
|
372
397
|
it 'returns path as the URL if set and site options is specified' do
|
373
|
-
allow(client).to receive(:options)
|
398
|
+
allow(client).to receive(:options).and_return({ site: 'http://foo' })
|
374
399
|
attrs['self'] = 'http://foo/bar'
|
375
400
|
expect(subject.url).to eq('/bar')
|
376
401
|
end
|
377
402
|
|
378
403
|
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)
|
404
|
+
allow(client).to receive(:options).and_return({ site: 'http://foo/' })
|
380
405
|
attrs['self'] = 'http://foo/bar'
|
381
406
|
expect(subject.url).to eq('/bar')
|
382
407
|
end
|
@@ -428,21 +453,21 @@ describe JIRA::Base do
|
|
428
453
|
|
429
454
|
h = { 'key' => subject }
|
430
455
|
h_attrs = { 'key' => subject.attrs }
|
431
|
-
expect(h.to_json).to eq(h_attrs.to_json)
|
456
|
+
expect(h['key'].to_json).to eq(h_attrs['key'].to_json)
|
432
457
|
end
|
433
458
|
|
434
459
|
describe 'extract attrs from response' do
|
435
460
|
subject { JIRA::Resource::Deadbeef.new(client, attrs: {}) }
|
436
461
|
|
437
462
|
it 'sets the attrs from a response' do
|
438
|
-
response = instance_double(
|
463
|
+
response = instance_double(Response, body: '{"foo":"bar"}')
|
439
464
|
|
440
465
|
expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
|
441
466
|
expect(subject.foo).to eq('bar')
|
442
467
|
end
|
443
468
|
|
444
469
|
it "doesn't clobber existing attrs not in response" do
|
445
|
-
response = instance_double(
|
470
|
+
response = instance_double(Response, body: '{"foo":"bar"}')
|
446
471
|
|
447
472
|
subject.attrs = { 'flum' => 'flar' }
|
448
473
|
expect(subject.set_attrs_from_response(response)).to eq('foo' => 'bar')
|
@@ -451,7 +476,7 @@ describe JIRA::Base do
|
|
451
476
|
end
|
452
477
|
|
453
478
|
it 'handles nil response body' do
|
454
|
-
response = instance_double(
|
479
|
+
response = instance_double(Response, body: nil)
|
455
480
|
|
456
481
|
subject.attrs = { 'flum' => 'flar' }
|
457
482
|
expect(subject.set_attrs_from_response(response)).to be_nil
|
@@ -487,7 +512,9 @@ describe JIRA::Base do
|
|
487
512
|
end
|
488
513
|
|
489
514
|
it 'allows the has_many attributes to be nested inside another attribute' do
|
490
|
-
subject = JIRA::Resource::HasManyExample.new(client,
|
515
|
+
subject = JIRA::Resource::HasManyExample.new(client,
|
516
|
+
attrs: { 'nested' => { 'brunchmuffins' => [{ 'id' => '123' },
|
517
|
+
{ 'id' => '456' }] } })
|
491
518
|
expect(subject.brunchmuffins.length).to eq(2)
|
492
519
|
subject.brunchmuffins.each do |brunchmuffin|
|
493
520
|
expect(brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
|
@@ -495,9 +522,12 @@ describe JIRA::Base do
|
|
495
522
|
end
|
496
523
|
|
497
524
|
it 'allows it to be deeply nested' do
|
498
|
-
subject = JIRA::Resource::HasManyExample.new(
|
499
|
-
|
500
|
-
|
525
|
+
subject = JIRA::Resource::HasManyExample.new(
|
526
|
+
client,
|
527
|
+
attrs: {
|
528
|
+
'nested' => { 'breakfastscone' => { 'breakfastscones' => [{ 'id' => '123' }, { 'id' => '456' }] } }
|
529
|
+
}
|
530
|
+
)
|
501
531
|
expect(subject.breakfastscones.length).to eq(2)
|
502
532
|
subject.breakfastscones.each do |breakfastscone|
|
503
533
|
expect(breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
|
@@ -512,7 +542,9 @@ describe JIRA::Base do
|
|
512
542
|
end
|
513
543
|
|
514
544
|
it 'allows the attribute key to be specified' do
|
515
|
-
subject = JIRA::Resource::HasManyExample.new(client,
|
545
|
+
subject = JIRA::Resource::HasManyExample.new(client,
|
546
|
+
attrs: { 'irregularlyNamedThings' => [{ 'id' => '123' },
|
547
|
+
{ 'id' => '456' }] })
|
516
548
|
expect(subject.irregularly_named_things.length).to eq(2)
|
517
549
|
subject.irregularly_named_things.each do |thing|
|
518
550
|
expect(thing.class).to eq(JIRA::Resource::Deadbeef)
|
@@ -545,7 +577,8 @@ describe JIRA::Base do
|
|
545
577
|
end
|
546
578
|
|
547
579
|
it 'allows the has_one attributes to be nested inside another attribute' do
|
548
|
-
subject = JIRA::Resource::HasOneExample.new(client,
|
580
|
+
subject = JIRA::Resource::HasOneExample.new(client,
|
581
|
+
attrs: { 'nested' => { 'brunchmuffin' => { 'id' => '123' } } })
|
549
582
|
expect(subject.brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
|
550
583
|
expect(subject.brunchmuffin.id).to eq('123')
|
551
584
|
end
|
@@ -566,31 +599,35 @@ describe JIRA::Base do
|
|
566
599
|
end
|
567
600
|
|
568
601
|
describe 'belongs_to' do
|
569
|
-
|
570
|
-
|
602
|
+
module JIRA
|
603
|
+
module Resource
|
604
|
+
class BelongsToExample < JIRA::Base
|
605
|
+
belongs_to :deadbeef
|
606
|
+
end
|
607
|
+
end
|
571
608
|
end
|
572
609
|
|
573
|
-
|
610
|
+
subject { JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef:) }
|
574
611
|
|
575
|
-
|
612
|
+
let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '999' }) }
|
576
613
|
|
577
614
|
it 'sets up an accessor for the belongs to relationship' do
|
578
615
|
expect(subject.deadbeef).to eq(deadbeef)
|
579
616
|
end
|
580
617
|
|
581
618
|
it 'raises an exception when initialized without a belongs_to instance' do
|
582
|
-
expect
|
619
|
+
expect do
|
583
620
|
JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' })
|
584
|
-
|
621
|
+
end.to raise_exception(ArgumentError, 'Required option :deadbeef missing')
|
585
622
|
end
|
586
623
|
|
587
624
|
it 'returns the right url' do
|
588
|
-
allow(client).to receive(:options)
|
625
|
+
allow(client).to receive(:options).and_return({ rest_base_path: '/foo' })
|
589
626
|
expect(subject.url).to eq('/foo/deadbeef/999/belongstoexample/123')
|
590
627
|
end
|
591
628
|
|
592
629
|
it 'can be initialized with an instance or a key value' do
|
593
|
-
allow(client).to receive(:options)
|
630
|
+
allow(client).to receive(:options).and_return({ rest_base_path: '/foo' })
|
594
631
|
subject = JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef_id: '987')
|
595
632
|
expect(subject.url).to eq('/foo/deadbeef/987/belongstoexample/123')
|
596
633
|
end
|