jira-ruby 2.3.0 → 3.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +20 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  4. data/.github/dependabot.yml +6 -0
  5. data/.github/workflows/CI.yml +28 -0
  6. data/.github/workflows/codeql.yml +100 -0
  7. data/.github/workflows/rubocop.yml +18 -0
  8. data/.rubocop.yml +188 -0
  9. data/Gemfile +11 -3
  10. data/Guardfile +2 -0
  11. data/README.md +94 -18
  12. data/Rakefile +3 -4
  13. data/jira-ruby.gemspec +11 -17
  14. data/lib/jira/base.rb +37 -28
  15. data/lib/jira/base_factory.rb +4 -1
  16. data/lib/jira/client.rb +64 -46
  17. data/lib/jira/has_many_proxy.rb +4 -2
  18. data/lib/jira/http_client.rb +17 -13
  19. data/lib/jira/http_error.rb +4 -0
  20. data/lib/jira/jwt_client.rb +18 -42
  21. data/lib/jira/oauth_client.rb +6 -3
  22. data/lib/jira/railtie.rb +2 -0
  23. data/lib/jira/request_client.rb +5 -1
  24. data/lib/jira/resource/agile.rb +7 -9
  25. data/lib/jira/resource/applinks.rb +5 -3
  26. data/lib/jira/resource/attachment.rb +43 -3
  27. data/lib/jira/resource/board.rb +5 -3
  28. data/lib/jira/resource/board_configuration.rb +2 -0
  29. data/lib/jira/resource/comment.rb +2 -0
  30. data/lib/jira/resource/component.rb +2 -0
  31. data/lib/jira/resource/createmeta.rb +3 -1
  32. data/lib/jira/resource/field.rb +9 -4
  33. data/lib/jira/resource/filter.rb +2 -0
  34. data/lib/jira/resource/issue.rb +35 -44
  35. data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
  36. data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
  37. data/lib/jira/resource/issuelink.rb +2 -0
  38. data/lib/jira/resource/issuelinktype.rb +2 -0
  39. data/lib/jira/resource/issuetype.rb +2 -0
  40. data/lib/jira/resource/priority.rb +2 -0
  41. data/lib/jira/resource/project.rb +4 -2
  42. data/lib/jira/resource/rapidview.rb +5 -3
  43. data/lib/jira/resource/remotelink.rb +2 -0
  44. data/lib/jira/resource/resolution.rb +2 -0
  45. data/lib/jira/resource/serverinfo.rb +2 -0
  46. data/lib/jira/resource/sprint.rb +14 -23
  47. data/lib/jira/resource/status.rb +7 -1
  48. data/lib/jira/resource/status_category.rb +10 -0
  49. data/lib/jira/resource/suggested_issue.rb +2 -0
  50. data/lib/jira/resource/transition.rb +2 -0
  51. data/lib/jira/resource/user.rb +3 -1
  52. data/lib/jira/resource/version.rb +2 -0
  53. data/lib/jira/resource/watcher.rb +2 -1
  54. data/lib/jira/resource/webhook.rb +4 -2
  55. data/lib/jira/resource/worklog.rb +3 -2
  56. data/lib/jira/version.rb +3 -1
  57. data/lib/jira-ruby.rb +5 -3
  58. data/lib/tasks/generate.rake +4 -2
  59. data/spec/data/files/short.txt +1 -0
  60. data/spec/integration/attachment_spec.rb +3 -3
  61. data/spec/integration/comment_spec.rb +8 -8
  62. data/spec/integration/component_spec.rb +7 -7
  63. data/spec/integration/field_spec.rb +3 -3
  64. data/spec/integration/issue_spec.rb +20 -16
  65. data/spec/integration/issuelinktype_spec.rb +3 -3
  66. data/spec/integration/issuetype_spec.rb +3 -3
  67. data/spec/integration/priority_spec.rb +3 -3
  68. data/spec/integration/project_spec.rb +7 -7
  69. data/spec/integration/rapidview_spec.rb +9 -9
  70. data/spec/integration/resolution_spec.rb +3 -3
  71. data/spec/integration/status_category_spec.rb +20 -0
  72. data/spec/integration/status_spec.rb +4 -8
  73. data/spec/integration/transition_spec.rb +2 -2
  74. data/spec/integration/user_spec.rb +22 -8
  75. data/spec/integration/version_spec.rb +7 -7
  76. data/spec/integration/watcher_spec.rb +17 -18
  77. data/spec/integration/webhook.rb +5 -4
  78. data/spec/integration/worklog_spec.rb +8 -8
  79. data/spec/jira/base_factory_spec.rb +2 -1
  80. data/spec/jira/base_spec.rb +55 -41
  81. data/spec/jira/client_spec.rb +48 -34
  82. data/spec/jira/has_many_proxy_spec.rb +3 -3
  83. data/spec/jira/http_client_spec.rb +94 -27
  84. data/spec/jira/http_error_spec.rb +2 -2
  85. data/spec/jira/oauth_client_spec.rb +8 -6
  86. data/spec/jira/request_client_spec.rb +4 -4
  87. data/spec/jira/resource/agile_spec.rb +28 -28
  88. data/spec/jira/resource/attachment_spec.rb +142 -52
  89. data/spec/jira/resource/board_spec.rb +21 -20
  90. data/spec/jira/resource/createmeta_spec.rb +48 -48
  91. data/spec/jira/resource/field_spec.rb +30 -12
  92. data/spec/jira/resource/filter_spec.rb +4 -4
  93. data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
  94. data/spec/jira/resource/issue_spec.rb +43 -37
  95. data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
  96. data/spec/jira/resource/project_factory_spec.rb +3 -2
  97. data/spec/jira/resource/project_spec.rb +16 -16
  98. data/spec/jira/resource/sprint_spec.rb +70 -3
  99. data/spec/jira/resource/status_spec.rb +21 -0
  100. data/spec/jira/resource/user_factory_spec.rb +4 -4
  101. data/spec/jira/resource/worklog_spec.rb +3 -3
  102. data/spec/mock_responses/sprint/1.json +13 -0
  103. data/spec/mock_responses/status/1.json +8 -1
  104. data/spec/mock_responses/status.json +40 -5
  105. data/spec/mock_responses/statuscategory/1.json +7 -0
  106. data/spec/mock_responses/statuscategory.json +30 -0
  107. data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
  108. data/spec/spec_helper.rb +1 -0
  109. data/spec/support/clients_helper.rb +3 -5
  110. data/spec/support/shared_examples/integration.rb +25 -28
  111. metadata +25 -257
  112. data/.travis.yml +0 -9
  113. data/example.rb +0 -232
  114. data/http-basic-example.rb +0 -113
  115. data/lib/jira/resource/sprint_report.rb +0 -8
  116. data/lib/jira/tasks.rb +0 -0
  117. data/spec/jira/jwt_uri_builder_spec.rb +0 -59
@@ -8,14 +8,15 @@ describe JIRA::Resource::Webhook do
8
8
  let(:key) { '2' }
9
9
 
10
10
  let(:expected_attributes) do
11
- { 'name' => 'from API', 'url' => 'http://localhost:3000/webhooks/1', 'excludeBody' => false, 'filters' => { 'issue-related-events-section' => '' }, 'events' => [], 'enabled' => true, 'self' => 'http://localhost:2990/jira/rest/webhooks/1.0/webhook/2', 'lastUpdatedUser' => 'admin', 'lastUpdatedDisplayName' => 'admin', 'lastUpdated' => 1_453_306_520_188 }
11
+ { 'name' => 'from API', 'url' => 'http://localhost:3000/webhooks/1', 'excludeBody' => false,
12
+ 'filters' => { 'issue-related-events-section' => '' }, 'events' => [], 'enabled' => true, 'self' => 'http://localhost:2990/jira/rest/webhooks/1.0/webhook/2', 'lastUpdatedUser' => 'admin', 'lastUpdatedDisplayName' => 'admin', 'lastUpdated' => 1_453_306_520_188 }
12
13
  end
13
14
 
14
15
  let(:expected_collection_length) { 1 }
15
16
 
16
- it_should_behave_like 'a resource'
17
- it_should_behave_like 'a resource with a collection GET endpoint'
18
- it_should_behave_like 'a resource with a singular GET endpoint'
17
+ it_behaves_like 'a resource'
18
+ it_behaves_like 'a resource with a collection GET endpoint'
19
+ it_behaves_like 'a resource with a singular GET endpoint'
19
20
 
20
21
  it 'returns a collection of components' do
21
22
  stub_request(:get, site_url + described_class.singular_path(client, key))
@@ -7,7 +7,7 @@ describe JIRA::Resource::Worklog do
7
7
 
8
8
  let(:key) { '10000' }
9
9
 
10
- let(:target) { JIRA::Resource::Worklog.new(client, attrs: { 'id' => '99999' }, issue_id: '54321') }
10
+ let(:target) { described_class.new(client, attrs: { 'id' => '99999' }, issue_id: '54321') }
11
11
 
12
12
  let(:expected_collection_length) { 3 }
13
13
 
@@ -22,7 +22,7 @@ describe JIRA::Resource::Worklog do
22
22
  let(:expected_attributes) do
23
23
  {
24
24
  'self' => 'http://localhost:2990/jira/rest/api/2/issue/10002/worklog/10000',
25
- 'id' => key,
25
+ 'id' => key,
26
26
  'comment' => 'Some epic work.'
27
27
  }
28
28
  end
@@ -41,11 +41,11 @@ describe JIRA::Resource::Worklog do
41
41
  { 'id' => '10001', 'timeSpent' => '4d' }
42
42
  end
43
43
 
44
- it_should_behave_like 'a resource'
45
- it_should_behave_like 'a resource with a collection GET endpoint'
46
- it_should_behave_like 'a resource with a singular GET endpoint'
47
- it_should_behave_like 'a resource with a DELETE endpoint'
48
- it_should_behave_like 'a resource with a POST endpoint'
49
- it_should_behave_like 'a resource with a PUT endpoint'
44
+ it_behaves_like 'a resource'
45
+ it_behaves_like 'a resource with a collection GET endpoint'
46
+ it_behaves_like 'a resource with a singular GET endpoint'
47
+ it_behaves_like 'a resource with a DELETE endpoint'
48
+ it_behaves_like 'a resource with a POST endpoint'
49
+ it_behaves_like 'a resource with a PUT endpoint'
50
50
  end
51
51
  end
@@ -4,9 +4,10 @@ describe JIRA::BaseFactory do
4
4
  class JIRA::Resource::FooFactory < JIRA::BaseFactory; end
5
5
  class JIRA::Resource::Foo; end
6
6
 
7
- let(:client) { double }
8
7
  subject { JIRA::Resource::FooFactory.new(client) }
9
8
 
9
+ let(:client) { double }
10
+
10
11
  it 'initializes correctly' do
11
12
  expect(subject.class).to eq(JIRA::Resource::FooFactory)
12
13
  expect(subject.client).to eq(client)
@@ -32,11 +32,11 @@ describe JIRA::Base do
32
32
  attribute_key: 'irregularlyNamedThings'
33
33
  end
34
34
 
35
+ subject { JIRA::Resource::Deadbeef.new(client, attrs:) }
36
+
35
37
  let(:client) { double('client') }
36
38
  let(:attrs) { {} }
37
39
 
38
- subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
39
-
40
40
  let(:decorated) { JIRADelegation.new(subject) }
41
41
 
42
42
  describe '#respond_to?' do
@@ -44,6 +44,7 @@ describe JIRA::Base do
44
44
  it 'responds to client' do
45
45
  expect(decorated.respond_to?(:client)).to eq(true)
46
46
  end
47
+
47
48
  it 'does not raise an error' do
48
49
  expect do
49
50
  decorated.respond_to?(:client)
@@ -125,7 +126,7 @@ describe JIRA::Base do
125
126
  end
126
127
 
127
128
  describe 'collection_path' do
128
- before(:each) do
129
+ before do
129
130
  expect(client).to receive(:options).and_return(rest_base_path: '/deadbeef/bar')
130
131
  end
131
132
 
@@ -147,8 +148,9 @@ describe JIRA::Base do
147
148
  end
148
149
 
149
150
  describe 'dynamic instance methods' do
151
+ subject { JIRA::Resource::Deadbeef.new(client, attrs:) }
152
+
150
153
  let(:attrs) { { 'foo' => 'bar', 'flum' => 'goo', 'object_id' => 'dummy' } }
151
- subject { JIRA::Resource::Deadbeef.new(client, attrs: attrs) }
152
154
 
153
155
  it 'responds to each of the top level attribute names' do
154
156
  expect(subject).to respond_to(:foo)
@@ -169,7 +171,7 @@ describe JIRA::Base do
169
171
  subject { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '98765' }) }
170
172
 
171
173
  describe 'not cached' do
172
- before(:each) do
174
+ before do
173
175
  response = instance_double('Response', body: '{"self":"http://deadbeef/","id":"98765"}')
174
176
  expect(client).to receive(:get).with('/jira/rest/api/2/deadbeef/98765').and_return(response)
175
177
  expect(JIRA::Resource::Deadbeef).to receive(:collection_path).and_return('/jira/rest/api/2/deadbeef')
@@ -222,17 +224,17 @@ describe JIRA::Base do
222
224
  end
223
225
 
224
226
  describe 'save' do
225
- let(:response) { double }
226
-
227
227
  subject { JIRA::Resource::Deadbeef.new(client) }
228
228
 
229
- before(:each) do
229
+ let(:response) { double }
230
+
231
+ before do
230
232
  expect(subject).to receive(:url).and_return('/foo/bar')
231
233
  end
232
234
 
233
235
  it 'POSTs a new record' do
234
236
  response = instance_double('Response', body: '{"id":"123"}')
235
- allow(subject).to receive(:new_record?) { true }
237
+ allow(subject).to receive(:new_record?).and_return(true)
236
238
  expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
237
239
  expect(subject.save('foo' => 'bar')).to be_truthy
238
240
  expect(subject.id).to eq('123')
@@ -241,7 +243,7 @@ describe JIRA::Base do
241
243
 
242
244
  it 'PUTs an existing record' do
243
245
  response = instance_double('Response', body: nil)
244
- allow(subject).to receive(:new_record?) { false }
246
+ allow(subject).to receive(:new_record?).and_return(false)
245
247
  expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
246
248
  expect(subject.save('foo' => 'bar')).to be_truthy
247
249
  expect(subject.expanded).to be_falsey
@@ -255,14 +257,17 @@ describe JIRA::Base do
255
257
  expect(subject.foo).to eq('bar' => 'baz', 'fum' => 'dum')
256
258
  end
257
259
 
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
260
+ it 'returns false when an invalid field is set' do
261
+ # The JIRA REST API apparently ignores fields that you aren't allowed to set manually
259
262
  response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
260
- allow(subject).to receive(:new_record?) { false }
261
- expect(client).to receive(:put).with('/foo/bar', '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
263
+ allow(subject).to receive(:new_record?).and_return(false)
264
+ expect(client).to receive(:put).with('/foo/bar',
265
+ '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
262
266
  expect(subject.save('invalid_field' => 'foobar')).to be_falsey
263
267
  end
264
268
 
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
269
+ it 'returns false with exception details when non json response body (unauthorized)' do
270
+ # Unauthorized requests return a non-json body. This makes sure we can handle non-json bodies on HTTPError
266
271
  response = double('Response', body: 'totally invalid json', code: 401, message: 'Unauthorized')
267
272
  expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_raise(JIRA::HTTPError.new(response))
268
273
  expect(subject.save('foo' => 'bar')).to be_falsey
@@ -272,17 +277,17 @@ describe JIRA::Base do
272
277
  end
273
278
 
274
279
  describe 'save!' do
275
- let(:response) { double }
276
-
277
280
  subject { JIRA::Resource::Deadbeef.new(client) }
278
281
 
279
- before(:each) do
282
+ let(:response) { double }
283
+
284
+ before do
280
285
  expect(subject).to receive(:url).and_return('/foo/bar')
281
286
  end
282
287
 
283
288
  it 'POSTs a new record' do
284
289
  response = instance_double('Response', body: '{"id":"123"}')
285
- allow(subject).to receive(:new_record?) { true }
290
+ allow(subject).to receive(:new_record?).and_return(true)
286
291
  expect(client).to receive(:post).with('/foo/bar', '{"foo":"bar"}').and_return(response)
287
292
  expect(subject.save!('foo' => 'bar')).to be_truthy
288
293
  expect(subject.id).to eq('123')
@@ -291,7 +296,7 @@ describe JIRA::Base do
291
296
 
292
297
  it 'PUTs an existing record' do
293
298
  response = instance_double('Response', body: nil)
294
- allow(subject).to receive(:new_record?) { false }
299
+ allow(subject).to receive(:new_record?).and_return(false)
295
300
  expect(client).to receive(:put).with('/foo/bar', '{"foo":"bar"}').and_return(response)
296
301
  expect(subject.save!('foo' => 'bar')).to be_truthy
297
302
  expect(subject.expanded).to be_falsey
@@ -299,9 +304,10 @@ describe JIRA::Base do
299
304
 
300
305
  it 'throws an exception when an invalid field is set' do
301
306
  response = instance_double('Response', body: '{"errorMessages":["blah"]}', status: 400)
302
- allow(subject).to receive(:new_record?) { false }
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)
307
+ allow(subject).to receive(:new_record?).and_return(false)
308
+ expect(client).to receive(:put).with('/foo/bar',
309
+ '{"invalid_field":"foobar"}').and_raise(JIRA::HTTPError.new(response))
310
+ expect { subject.save!('invalid_field' => 'foobar') }.to raise_error(JIRA::HTTPError)
305
311
  end
306
312
  end
307
313
 
@@ -320,9 +326,9 @@ describe JIRA::Base do
320
326
  end
321
327
 
322
328
  describe 'delete' do
323
- before(:each) do
329
+ before do
324
330
  expect(client).to receive(:delete).with('/foo/bar')
325
- allow(subject).to receive(:url) { '/foo/bar' }
331
+ allow(subject).to receive(:url).and_return('/foo/bar')
326
332
  end
327
333
 
328
334
  it 'flags itself as deleted' do
@@ -360,8 +366,8 @@ describe JIRA::Base do
360
366
  end
361
367
 
362
368
  describe 'url' do
363
- before(:each) do
364
- allow(client).to receive(:options) { { rest_base_path: '/foo/bar' } }
369
+ before do
370
+ allow(client).to receive(:options).and_return({ rest_base_path: '/foo/bar' })
365
371
  end
366
372
 
367
373
  it 'returns self as the URL if set' do
@@ -370,13 +376,13 @@ describe JIRA::Base do
370
376
  end
371
377
 
372
378
  it 'returns path as the URL if set and site options is specified' do
373
- allow(client).to receive(:options) { { site: 'http://foo' } }
379
+ allow(client).to receive(:options).and_return({ site: 'http://foo' })
374
380
  attrs['self'] = 'http://foo/bar'
375
381
  expect(subject.url).to eq('/bar')
376
382
  end
377
383
 
378
384
  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/' } }
385
+ allow(client).to receive(:options).and_return({ site: 'http://foo/' })
380
386
  attrs['self'] = 'http://foo/bar'
381
387
  expect(subject.url).to eq('/bar')
382
388
  end
@@ -428,7 +434,7 @@ describe JIRA::Base do
428
434
 
429
435
  h = { 'key' => subject }
430
436
  h_attrs = { 'key' => subject.attrs }
431
- expect(h.to_json).to eq(h_attrs.to_json)
437
+ expect(h['key'].to_json).to eq(h_attrs['key'].to_json)
432
438
  end
433
439
 
434
440
  describe 'extract attrs from response' do
@@ -487,7 +493,9 @@ describe JIRA::Base do
487
493
  end
488
494
 
489
495
  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' }] } })
496
+ subject = JIRA::Resource::HasManyExample.new(client,
497
+ attrs: { 'nested' => { 'brunchmuffins' => [{ 'id' => '123' },
498
+ { 'id' => '456' }] } })
491
499
  expect(subject.brunchmuffins.length).to eq(2)
492
500
  subject.brunchmuffins.each do |brunchmuffin|
493
501
  expect(brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
@@ -495,9 +503,12 @@ describe JIRA::Base do
495
503
  end
496
504
 
497
505
  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
- } })
506
+ subject = JIRA::Resource::HasManyExample.new(
507
+ client,
508
+ attrs: {
509
+ 'nested' => { 'breakfastscone' => { 'breakfastscones' => [{ 'id' => '123' }, { 'id' => '456' }] } }
510
+ }
511
+ )
501
512
  expect(subject.breakfastscones.length).to eq(2)
502
513
  subject.breakfastscones.each do |breakfastscone|
503
514
  expect(breakfastscone.class).to eq(JIRA::Resource::Deadbeef)
@@ -512,7 +523,9 @@ describe JIRA::Base do
512
523
  end
513
524
 
514
525
  it 'allows the attribute key to be specified' do
515
- subject = JIRA::Resource::HasManyExample.new(client, attrs: { 'irregularlyNamedThings' => [{ 'id' => '123' }, { 'id' => '456' }] })
526
+ subject = JIRA::Resource::HasManyExample.new(client,
527
+ attrs: { 'irregularlyNamedThings' => [{ 'id' => '123' },
528
+ { 'id' => '456' }] })
516
529
  expect(subject.irregularly_named_things.length).to eq(2)
517
530
  subject.irregularly_named_things.each do |thing|
518
531
  expect(thing.class).to eq(JIRA::Resource::Deadbeef)
@@ -545,7 +558,8 @@ describe JIRA::Base do
545
558
  end
546
559
 
547
560
  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' } } })
561
+ subject = JIRA::Resource::HasOneExample.new(client,
562
+ attrs: { 'nested' => { 'brunchmuffin' => { 'id' => '123' } } })
549
563
  expect(subject.brunchmuffin.class).to eq(JIRA::Resource::Deadbeef)
550
564
  expect(subject.brunchmuffin.id).to eq('123')
551
565
  end
@@ -570,27 +584,27 @@ describe JIRA::Base do
570
584
  belongs_to :deadbeef
571
585
  end
572
586
 
573
- let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '999' }) }
587
+ subject { JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef:) }
574
588
 
575
- subject { JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef: deadbeef) }
589
+ let(:deadbeef) { JIRA::Resource::Deadbeef.new(client, attrs: { 'id' => '999' }) }
576
590
 
577
591
  it 'sets up an accessor for the belongs to relationship' do
578
592
  expect(subject.deadbeef).to eq(deadbeef)
579
593
  end
580
594
 
581
595
  it 'raises an exception when initialized without a belongs_to instance' do
582
- expect(lambda {
596
+ expect do
583
597
  JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' })
584
- }).to raise_exception(ArgumentError, 'Required option :deadbeef missing')
598
+ end.to raise_exception(ArgumentError, 'Required option :deadbeef missing')
585
599
  end
586
600
 
587
601
  it 'returns the right url' do
588
- allow(client).to receive(:options) { { rest_base_path: '/foo' } }
602
+ allow(client).to receive(:options).and_return({ rest_base_path: '/foo' })
589
603
  expect(subject.url).to eq('/foo/deadbeef/999/belongstoexample/123')
590
604
  end
591
605
 
592
606
  it 'can be initialized with an instance or a key value' do
593
- allow(client).to receive(:options) { { rest_base_path: '/foo' } }
607
+ allow(client).to receive(:options).and_return({ rest_base_path: '/foo' })
594
608
  subject = JIRA::Resource::BelongsToExample.new(client, attrs: { 'id' => '123' }, deadbeef_id: '987')
595
609
  expect(subject.url).to eq('/foo/deadbeef/987/belongstoexample/123')
596
610
  end
@@ -28,7 +28,7 @@ RSpec.shared_examples 'Client Common Tests' do
28
28
  expect(subject).to receive(:merge_default_headers).exactly(3).times.with({})
29
29
 
30
30
  # response for merging headers for http methods with body
31
- expect(subject).to receive(:merge_default_headers).exactly(2).times.with(content_type_header)
31
+ expect(subject).to receive(:merge_default_headers).twice.with(content_type_header)
32
32
 
33
33
  %i[delete get head].each { |method| subject.send(method, '/path', {}) }
34
34
  %i[post put].each { |method| subject.send(method, '/path', '', content_type_header) }
@@ -62,13 +62,20 @@ RSpec.shared_examples 'Client Common Tests' do
62
62
 
63
63
  describe 'SSL client options' do
64
64
  context 'without certificate and key' do
65
- let(:options) { { use_client_cert: true } }
66
65
  subject { JIRA::Client.new(options) }
67
66
 
67
+ let(:options) { { use_client_cert: true } }
68
+
68
69
  it 'raises an ArgumentError' do
69
- expect { subject }.to raise_exception(ArgumentError, 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true')
70
+ expect do
71
+ subject
72
+ end.to raise_exception(ArgumentError,
73
+ 'Options: :cert_path or :ssl_client_cert must be set when :use_client_cert is true')
70
74
  options[:ssl_client_cert] = '<cert></cert>'
71
- expect { subject }.to raise_exception(ArgumentError, 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true')
75
+ expect do
76
+ subject
77
+ end.to raise_exception(ArgumentError,
78
+ 'Options: :key_path or :ssl_client_key must be set when :use_client_cert is true')
72
79
  end
73
80
  end
74
81
  end
@@ -77,11 +84,13 @@ end
77
84
  RSpec.shared_examples 'HttpClient tests' do
78
85
  it 'makes a valid request' do
79
86
  %i[delete get head].each do |method|
80
- expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
87
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', nil,
88
+ headers).and_return(successful_response)
81
89
  subject.send(method, '/path', headers)
82
90
  end
83
91
  %i[post put].each do |method|
84
- expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
92
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', '',
93
+ merged_headers).and_return(successful_response)
85
94
  subject.send(method, '/path', '', headers)
86
95
  end
87
96
  end
@@ -106,11 +115,13 @@ RSpec.shared_examples 'OAuth Common Tests' do
106
115
  describe 'that call a oauth client' do
107
116
  specify 'which makes a request' do
108
117
  %i[delete get head].each do |method|
109
- expect(subject.request_client).to receive(:make_request).with(method, '/path', nil, headers).and_return(successful_response)
118
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', nil,
119
+ headers).and_return(successful_response)
110
120
  subject.send(method, '/path', {})
111
121
  end
112
122
  %i[post put].each do |method|
113
- expect(subject.request_client).to receive(:make_request).with(method, '/path', '', merged_headers).and_return(successful_response)
123
+ expect(subject.request_client).to receive(:make_request).with(method, '/path', '',
124
+ merged_headers).and_return(successful_response)
114
125
  subject.send(method, '/path', '', {})
115
126
  end
116
127
  end
@@ -130,20 +141,22 @@ describe JIRA::Client do
130
141
 
131
142
  context 'behaviour that applies to all client classes irrespective of authentication method' do
132
143
  it 'allows the overriding of some options' do
133
- client = JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar', site: 'http://foo.com/')
144
+ client = described_class.new(consumer_key: 'foo', consumer_secret: 'bar', site: 'http://foo.com/')
134
145
  expect(client.options[:site]).to eq('http://foo.com/')
135
146
  expect(JIRA::Client::DEFAULT_OPTIONS[:site]).not_to eq('http://foo.com/')
136
147
  end
137
148
  end
138
149
 
139
150
  context 'with basic http authentication' do
140
- subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :basic) }
151
+ subject { described_class.new(username: 'foo', password: 'bar', auth_type: :basic) }
141
152
 
142
- before(:each) do
143
- stub_request(:get, 'https://foo:bar@localhost:2990/jira/rest/api/2/project')
153
+ before do
154
+ stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
155
+ .with(headers: { 'Authorization' => "Basic #{Base64.strict_encode64('foo:bar').chomp}" })
144
156
  .to_return(status: 200, body: '[]', headers: {})
145
157
 
146
- stub_request(:get, 'https://foo:badpassword@localhost:2990/jira/rest/api/2/project')
158
+ stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
159
+ .with(headers: { 'Authorization' => "Basic #{Base64.strict_encode64('foo:badpassword').chomp}" })
147
160
  .to_return(status: 401, headers: {})
148
161
  end
149
162
 
@@ -157,33 +170,33 @@ describe JIRA::Client do
157
170
  expect(subject.options[:password]).to eq('bar')
158
171
  end
159
172
 
160
- it 'fails with wrong user name and password' do
161
- bad_login = JIRA::Client.new(username: 'foo', password: 'badpassword', auth_type: :basic)
162
- expect(bad_login.authenticated?).to be_falsey
163
- expect { bad_login.Project.all }.to raise_error JIRA::HTTPError
164
- end
165
-
166
173
  it 'only returns a true for #authenticated? once we have requested some data' do
167
- expect(subject.authenticated?).to be_falsey
174
+ expect(subject.authenticated?).to be_nil
168
175
  expect(subject.Project.all).to be_empty
169
176
  expect(subject.authenticated?).to be_truthy
170
177
  end
178
+
179
+ it 'fails with wrong user name and password' do
180
+ bad_login = described_class.new(username: 'foo', password: 'badpassword', auth_type: :basic)
181
+ expect(bad_login.authenticated?).to be_falsey
182
+ expect { bad_login.Project.all }.to raise_error JIRA::HTTPError
183
+ end
171
184
  end
172
185
 
173
186
  context 'with cookie authentication' do
174
- subject { JIRA::Client.new(username: 'foo', password: 'bar', auth_type: :cookie) }
187
+ subject { described_class.new(username: 'foo', password: 'bar', auth_type: :cookie) }
175
188
 
176
189
  let(:session_cookie) { '6E3487971234567896704A9EB4AE501F' }
177
190
  let(:session_body) do
178
191
  {
179
- 'session': { 'name' => 'JSESSIONID', 'value' => session_cookie },
180
- 'loginInfo': { 'failedLoginCount' => 1, 'loginCount' => 2,
192
+ session: { 'name' => 'JSESSIONID', 'value' => session_cookie },
193
+ loginInfo: { 'failedLoginCount' => 1, 'loginCount' => 2,
181
194
  'lastFailedLoginTime' => (DateTime.now - 2).iso8601,
182
195
  'previousLoginTime' => (DateTime.now - 5).iso8601 }
183
196
  }
184
197
  end
185
198
 
186
- before(:each) do
199
+ before do
187
200
  # General case of API call with no authentication, or wrong authentication
188
201
  stub_request(:post, 'https://localhost:2990/jira/rest/auth/1/session')
189
202
  .to_return(status: 401, headers: {})
@@ -210,7 +223,7 @@ describe JIRA::Client do
210
223
  end
211
224
 
212
225
  it 'does not authenticate with an incorrect username and password' do
213
- bad_client = JIRA::Client.new(username: 'foo', password: 'bad_password', auth_type: :cookie)
226
+ bad_client = described_class.new(username: 'foo', password: 'bad_password', auth_type: :cookie)
214
227
  expect(bad_client).not_to be_authenticated
215
228
  end
216
229
 
@@ -222,7 +235,7 @@ describe JIRA::Client do
222
235
 
223
236
  context 'with jwt authentication' do
224
237
  subject do
225
- JIRA::Client.new(
238
+ described_class.new(
226
239
  issuer: 'foo',
227
240
  base_url: 'https://host.tld',
228
241
  shared_secret: 'shared_secret_key',
@@ -230,10 +243,10 @@ describe JIRA::Client do
230
243
  )
231
244
  end
232
245
 
233
- before(:each) do
246
+ before do
234
247
  stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
235
- .with(query: hash_including(:jwt))
236
- .to_return(status: 200, body: '[]', headers: {})
248
+ .with(headers: { 'Authorization' => /JWT .+/ })
249
+ .to_return(status: 200, body: '[]', headers: {})
237
250
  end
238
251
 
239
252
  include_examples 'Client Common Tests'
@@ -248,8 +261,8 @@ describe JIRA::Client do
248
261
  context 'with a incorrect jwt key' do
249
262
  before do
250
263
  stub_request(:get, 'https://localhost:2990/jira/rest/api/2/project')
251
- .with(query: hash_including(:jwt))
252
- .to_return(status: 401, body: '[]', headers: {})
264
+ .with(headers: { 'Authorization' => /JWT .+/ })
265
+ .to_return(status: 401, body: '[]', headers: {})
253
266
  end
254
267
 
255
268
  it 'is not authenticated' do
@@ -269,20 +282,21 @@ describe JIRA::Client do
269
282
  end
270
283
 
271
284
  context 'oauth authentication' do
272
- subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar') }
285
+ subject { described_class.new(consumer_key: 'foo', consumer_secret: 'bar') }
273
286
 
274
287
  include_examples 'OAuth Common Tests'
275
288
  end
276
289
 
277
290
  context 'with oauth_2legged' do
278
- subject { JIRA::Client.new(consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged) }
291
+ subject { described_class.new(consumer_key: 'foo', consumer_secret: 'bar', auth_type: :oauth_2legged) }
279
292
 
280
293
  include_examples 'OAuth Common Tests'
281
294
  end
282
295
 
283
296
  context 'with unknown options' do
297
+ subject { described_class.new(options) }
298
+
284
299
  let(:options) { { 'username' => 'foo', 'password' => 'bar', auth_type: :basic } }
285
- subject { JIRA::Client.new(options) }
286
300
 
287
301
  it 'raises an ArgumentError' do
288
302
  expect { subject }.to raise_exception(ArgumentError, 'Unknown option(s) given: ["username", "password"]')
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe JIRA::HasManyProxy do
4
4
  class Foo; end
5
5
 
6
- subject { JIRA::HasManyProxy.new(parent, Foo, collection) }
6
+ subject { described_class.new(parent, Foo, collection) }
7
7
 
8
8
  let(:parent) { double('parent') }
9
9
  let(:collection) { double('collection') }
@@ -25,7 +25,7 @@ describe JIRA::HasManyProxy do
25
25
  foo = double('foo')
26
26
  allow(parent).to receive(:client).and_return(client)
27
27
  allow(parent).to receive(:to_sym).and_return(:parent)
28
- expect(Foo).to receive(:new).with(client, attrs: { 'foo' => 'bar' }, parent: parent).and_return(foo)
28
+ expect(Foo).to receive(:new).with(client, attrs: { 'foo' => 'bar' }, parent:).and_return(foo)
29
29
  expect(collection).to receive(:<<).with(foo)
30
30
  expect(subject.build('foo' => 'bar')).to eq(foo)
31
31
  end
@@ -35,7 +35,7 @@ describe JIRA::HasManyProxy do
35
35
  client = double('client')
36
36
  allow(parent).to receive(:client).and_return(client)
37
37
  allow(parent).to receive(:to_sym).and_return(:parent)
38
- expect(Foo).to receive(:all).with(client, parent: parent).and_return(foo)
38
+ expect(Foo).to receive(:all).with(client, parent:).and_return(foo)
39
39
  expect(subject.all).to eq(foo)
40
40
  end
41
41