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.
Files changed (122) 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 +29 -0
  6. data/.github/workflows/codeql.yml +96 -0
  7. data/.github/workflows/rubocop.yml +18 -0
  8. data/.gitignore +3 -1
  9. data/.rubocop.yml +120 -0
  10. data/.yardopts +4 -0
  11. data/Gemfile +11 -3
  12. data/Guardfile +2 -0
  13. data/README.md +94 -18
  14. data/Rakefile +3 -4
  15. data/jira-ruby.gemspec +11 -17
  16. data/lib/jira/base.rb +37 -36
  17. data/lib/jira/base_factory.rb +4 -1
  18. data/lib/jira/client.rb +123 -50
  19. data/lib/jira/has_many_proxy.rb +32 -28
  20. data/lib/jira/http_client.rb +80 -13
  21. data/lib/jira/http_error.rb +4 -0
  22. data/lib/jira/jwt_client.rb +18 -42
  23. data/lib/jira/oauth_client.rb +68 -3
  24. data/lib/jira/railtie.rb +2 -0
  25. data/lib/jira/request_client.rb +31 -2
  26. data/lib/jira/resource/agile.rb +7 -9
  27. data/lib/jira/resource/applinks.rb +5 -3
  28. data/lib/jira/resource/attachment.rb +128 -3
  29. data/lib/jira/resource/board.rb +5 -3
  30. data/lib/jira/resource/board_configuration.rb +2 -0
  31. data/lib/jira/resource/comment.rb +2 -0
  32. data/lib/jira/resource/component.rb +2 -0
  33. data/lib/jira/resource/createmeta.rb +3 -1
  34. data/lib/jira/resource/field.rb +13 -12
  35. data/lib/jira/resource/filter.rb +2 -0
  36. data/lib/jira/resource/issue.rb +95 -44
  37. data/lib/jira/resource/issue_picker_suggestions.rb +4 -1
  38. data/lib/jira/resource/issue_picker_suggestions_issue.rb +2 -0
  39. data/lib/jira/resource/issuelink.rb +6 -3
  40. data/lib/jira/resource/issuelinktype.rb +2 -0
  41. data/lib/jira/resource/issuetype.rb +2 -0
  42. data/lib/jira/resource/priority.rb +2 -0
  43. data/lib/jira/resource/project.rb +4 -2
  44. data/lib/jira/resource/rapidview.rb +5 -3
  45. data/lib/jira/resource/remotelink.rb +2 -0
  46. data/lib/jira/resource/resolution.rb +2 -0
  47. data/lib/jira/resource/serverinfo.rb +2 -0
  48. data/lib/jira/resource/sprint.rb +14 -23
  49. data/lib/jira/resource/status.rb +7 -1
  50. data/lib/jira/resource/status_category.rb +10 -0
  51. data/lib/jira/resource/suggested_issue.rb +2 -0
  52. data/lib/jira/resource/transition.rb +2 -0
  53. data/lib/jira/resource/user.rb +3 -1
  54. data/lib/jira/resource/version.rb +2 -0
  55. data/lib/jira/resource/watcher.rb +3 -2
  56. data/lib/jira/resource/webhook.rb +9 -3
  57. data/lib/jira/resource/worklog.rb +3 -2
  58. data/lib/jira/version.rb +3 -1
  59. data/lib/jira-ruby.rb +5 -3
  60. data/lib/tasks/generate.rake +3 -1
  61. data/spec/data/files/short.txt +1 -0
  62. data/spec/integration/attachment_spec.rb +3 -3
  63. data/spec/integration/comment_spec.rb +8 -8
  64. data/spec/integration/component_spec.rb +7 -7
  65. data/spec/integration/field_spec.rb +3 -3
  66. data/spec/integration/issue_spec.rb +20 -16
  67. data/spec/integration/issuelinktype_spec.rb +3 -3
  68. data/spec/integration/issuetype_spec.rb +3 -3
  69. data/spec/integration/priority_spec.rb +3 -3
  70. data/spec/integration/project_spec.rb +8 -8
  71. data/spec/integration/rapidview_spec.rb +10 -10
  72. data/spec/integration/resolution_spec.rb +3 -3
  73. data/spec/integration/status_category_spec.rb +20 -0
  74. data/spec/integration/status_spec.rb +4 -8
  75. data/spec/integration/transition_spec.rb +2 -2
  76. data/spec/integration/user_spec.rb +34 -11
  77. data/spec/integration/version_spec.rb +7 -7
  78. data/spec/integration/watcher_spec.rb +21 -18
  79. data/spec/integration/webhook_spec.rb +33 -0
  80. data/spec/integration/worklog_spec.rb +8 -8
  81. data/spec/jira/base_factory_spec.rb +13 -3
  82. data/spec/jira/base_spec.rb +135 -98
  83. data/spec/jira/client_spec.rb +63 -47
  84. data/spec/jira/has_many_proxy_spec.rb +3 -3
  85. data/spec/jira/http_client_spec.rb +94 -27
  86. data/spec/jira/http_error_spec.rb +2 -2
  87. data/spec/jira/oauth_client_spec.rb +14 -8
  88. data/spec/jira/request_client_spec.rb +4 -4
  89. data/spec/jira/resource/agile_spec.rb +30 -30
  90. data/spec/jira/resource/attachment_spec.rb +170 -57
  91. data/spec/jira/resource/board_spec.rb +24 -23
  92. data/spec/jira/resource/createmeta_spec.rb +48 -48
  93. data/spec/jira/resource/field_spec.rb +44 -27
  94. data/spec/jira/resource/filter_spec.rb +4 -4
  95. data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
  96. data/spec/jira/resource/issue_spec.rb +49 -43
  97. data/spec/jira/resource/jira_picker_suggestions_issue_spec.rb +3 -3
  98. data/spec/jira/resource/project_factory_spec.rb +3 -2
  99. data/spec/jira/resource/project_spec.rb +14 -14
  100. data/spec/jira/resource/sprint_spec.rb +88 -9
  101. data/spec/jira/resource/status_spec.rb +21 -0
  102. data/spec/jira/resource/user_factory_spec.rb +5 -5
  103. data/spec/jira/resource/worklog_spec.rb +4 -4
  104. data/spec/mock_responses/sprint/1.json +13 -0
  105. data/spec/mock_responses/status/1.json +8 -1
  106. data/spec/mock_responses/status.json +40 -5
  107. data/spec/mock_responses/statuscategory/1.json +7 -0
  108. data/spec/mock_responses/statuscategory.json +30 -0
  109. data/spec/mock_responses/{user_username=admin.json → user_accountId=1234567890abcdef01234567.json} +2 -1
  110. data/spec/spec_helper.rb +1 -0
  111. data/spec/support/clients_helper.rb +3 -5
  112. data/spec/support/mock_client.rb +9 -0
  113. data/spec/support/mock_response.rb +8 -0
  114. data/spec/support/shared_examples/integration.rb +25 -28
  115. metadata +27 -260
  116. data/.travis.yml +0 -9
  117. data/example.rb +0 -232
  118. data/http-basic-example.rb +0 -113
  119. data/lib/jira/resource/sprint_report.rb +0 -8
  120. data/lib/jira/tasks.rb +0 -0
  121. data/spec/integration/webhook.rb +0 -25
  122. data/spec/jira/jwt_uri_builder_spec.rb +0 -59
@@ -7,25 +7,27 @@ describe JIRA::Resource::Issue do
7
7
  let(:client) do
8
8
  client = double(options: { rest_base_path: '/jira/rest/api/2' })
9
9
  allow(client).to receive(:Field).and_return(JIRA::Resource::FieldFactory.new(client))
10
- allow(client).to receive(:cache).and_return(OpenStruct.new)
10
+ allow(client).to receive(:field_map_cache).and_return(nil)
11
11
  client
12
12
  end
13
13
 
14
14
  describe '#respond_to?' do
15
15
  describe 'when decorated by SimpleDelegator' do
16
- before(:each) do
16
+ before do
17
17
  response = double
18
18
  allow(response).to receive(:body).and_return('{"key":"foo","id":"101"}')
19
- allow(JIRA::Resource::Issue).to receive(:collection_path).and_return('/jira/rest/api/2/issue')
19
+ allow(described_class).to receive(:collection_path).and_return('/jira/rest/api/2/issue')
20
20
  allow(client).to receive(:get).with('/jira/rest/api/2/issue/101')
21
21
  .and_return(response)
22
22
 
23
- issue = JIRA::Resource::Issue.find(client, 101)
23
+ issue = described_class.find(client, 101)
24
24
  @decorated = JIRAResourceDelegation.new(issue)
25
25
  end
26
+
26
27
  it 'responds to key' do
27
- expect(@decorated.respond_to?(:key)).to eq(true)
28
+ expect(@decorated.respond_to?(:key)).to be(true)
28
29
  end
30
+
29
31
  it 'does not raise an error' do
30
32
  expect do
31
33
  @issue.respond_to?(:project)
@@ -34,7 +36,7 @@ describe JIRA::Resource::Issue do
34
36
  end
35
37
  end
36
38
 
37
- it 'should find all issues' do
39
+ it 'finds all issues' do
38
40
  response = double
39
41
  empty_response = double
40
42
  issue = double
@@ -49,26 +51,26 @@ describe JIRA::Resource::Issue do
49
51
  expect(client).to receive(:Issue).and_return(issue)
50
52
  expect(issue).to receive(:build).with({ 'id' => '1', 'summary' => 'Bugs Everywhere' })
51
53
 
52
- issues = JIRA::Resource::Issue.all(client)
54
+ described_class.all(client)
53
55
  end
54
56
 
55
- it 'should find an issue by key or id' do
57
+ it 'finds an issue by key or id' do
56
58
  response = double
57
59
 
58
60
  allow(response).to receive(:body).and_return('{"key":"foo","id":"101"}')
59
- allow(JIRA::Resource::Issue).to receive(:collection_path).and_return('/jira/rest/api/2/issue')
61
+ allow(described_class).to receive(:collection_path).and_return('/jira/rest/api/2/issue')
60
62
  expect(client).to receive(:get).with('/jira/rest/api/2/issue/foo')
61
63
  .and_return(response)
62
64
  expect(client).to receive(:get).with('/jira/rest/api/2/issue/101')
63
65
  .and_return(response)
64
66
 
65
- issue_from_id = JIRA::Resource::Issue.find(client, 101)
66
- issue_from_key = JIRA::Resource::Issue.find(client, 'foo')
67
+ issue_from_id = described_class.find(client, 101)
68
+ issue_from_key = described_class.find(client, 'foo')
67
69
 
68
70
  expect(issue_from_id.attrs).to eq(issue_from_key.attrs)
69
71
  end
70
72
 
71
- it 'should search an issue with a jql query string' do
73
+ it 'searches an issue with a jql query string' do
72
74
  response = double
73
75
  issue = double
74
76
 
@@ -78,10 +80,10 @@ describe JIRA::Resource::Issue do
78
80
  expect(client).to receive(:Issue).and_return(issue)
79
81
  expect(issue).to receive(:build).with(%w[key foo]).and_return('')
80
82
 
81
- expect(JIRA::Resource::Issue.jql(client, 'foo bar')).to eq([''])
83
+ expect(described_class.jql(client, 'foo bar')).to eq([''])
82
84
  end
83
85
 
84
- it 'should search an issue with a jql query string and fields' do
86
+ it 'searches an issue with a jql query string and fields' do
85
87
  response = double
86
88
  issue = double
87
89
 
@@ -92,10 +94,10 @@ describe JIRA::Resource::Issue do
92
94
  expect(client).to receive(:Issue).and_return(issue)
93
95
  expect(issue).to receive(:build).with(%w[key foo]).and_return('')
94
96
 
95
- expect(JIRA::Resource::Issue.jql(client, 'foo bar', fields: %w[foo bar])).to eq([''])
97
+ expect(described_class.jql(client, 'foo bar', fields: %w[foo bar])).to eq([''])
96
98
  end
97
99
 
98
- it 'should search an issue with a jql query string, start at, and maxResults' do
100
+ it 'searches an issue with a jql query string, start at, and maxResults' do
99
101
  response = double
100
102
  issue = double
101
103
 
@@ -106,22 +108,22 @@ describe JIRA::Resource::Issue do
106
108
  expect(client).to receive(:Issue).and_return(issue)
107
109
  expect(issue).to receive(:build).with(%w[key foo]).and_return('')
108
110
 
109
- expect(JIRA::Resource::Issue.jql(client, 'foo bar', start_at: 1, max_results: 3)).to eq([''])
111
+ expect(described_class.jql(client, 'foo bar', start_at: 1, max_results: 3)).to eq([''])
110
112
  end
111
113
 
112
- it 'should search an issue with a jql query string and maxResults equals zero and should return the count of tickets' do
114
+ it 'searches an issue with a jql query string and maxResults equals zero and should return the count of tickets' do
113
115
  response = double
114
- issue = double
116
+ double
115
117
 
116
118
  allow(response).to receive(:body).and_return('{"total": 1, "issues": []}')
117
119
  expect(client).to receive(:get)
118
120
  .with('/jira/rest/api/2/search?jql=foo+bar&maxResults=0')
119
121
  .and_return(response)
120
122
 
121
- expect(JIRA::Resource::Issue.jql(client, 'foo bar', max_results: 0)).to eq(1)
123
+ expect(described_class.jql(client, 'foo bar', max_results: 0)).to eq(1)
122
124
  end
123
125
 
124
- it 'should search an issue with a jql query string and string expand' do
126
+ it 'searches an issue with a jql query string and string expand' do
125
127
  response = double
126
128
  issue = double
127
129
 
@@ -132,10 +134,10 @@ describe JIRA::Resource::Issue do
132
134
  expect(client).to receive(:Issue).and_return(issue)
133
135
  expect(issue).to receive(:build).with(%w[key foo]).and_return('')
134
136
 
135
- expect(JIRA::Resource::Issue.jql(client, 'foo bar', expand: 'transitions')).to eq([''])
137
+ expect(described_class.jql(client, 'foo bar', expand: 'transitions')).to eq([''])
136
138
  end
137
139
 
138
- it 'should search an issue with a jql query string and array expand' do
140
+ it 'searches an issue with a jql query string and array expand' do
139
141
  response = double
140
142
  issue = double
141
143
 
@@ -146,11 +148,11 @@ describe JIRA::Resource::Issue do
146
148
  expect(client).to receive(:Issue).and_return(issue)
147
149
  expect(issue).to receive(:build).with(%w[key foo]).and_return('')
148
150
 
149
- expect(JIRA::Resource::Issue.jql(client, 'foo bar', expand: %w[transitions])).to eq([''])
151
+ expect(described_class.jql(client, 'foo bar', expand: %w[transitions])).to eq([''])
150
152
  end
151
153
 
152
- it 'should return meta data available for editing an issue' do
153
- subject = JIRA::Resource::Issue.new(client, attrs: { 'fields' => { 'key' => 'TST=123' } })
154
+ it 'returns meta data available for editing an issue' do
155
+ subject = described_class.new(client, attrs: { 'fields' => { 'key' => 'TST=123' } })
154
156
  response = double
155
157
 
156
158
  allow(response).to receive(:body).and_return(
@@ -164,29 +166,30 @@ describe JIRA::Resource::Issue do
164
166
  end
165
167
 
166
168
  it 'provides direct accessors to the fields' do
167
- subject = JIRA::Resource::Issue.new(client, attrs: { 'fields' => { 'foo' => 'bar' } })
169
+ subject = described_class.new(client, attrs: { 'fields' => { 'foo' => 'bar' } })
168
170
  expect(subject).to respond_to(:foo)
169
171
  expect(subject.foo).to eq('bar')
170
172
  end
171
173
 
172
174
  describe 'relationships' do
173
175
  subject do
174
- JIRA::Resource::Issue.new(client, attrs: {
175
- 'id' => '123',
176
- 'fields' => {
177
- 'reporter' => { 'foo' => 'bar' },
178
- 'assignee' => { 'foo' => 'bar' },
179
- 'project' => { 'foo' => 'bar' },
180
- 'priority' => { 'foo' => 'bar' },
181
- 'issuetype' => { 'foo' => 'bar' },
182
- 'status' => { 'foo' => 'bar' },
183
- 'components' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
184
- 'versions' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
185
- 'comment' => { 'comments' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] },
186
- 'attachment' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
187
- 'worklog' => { 'worklogs' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] }
188
- }
189
- })
176
+ described_class.new(client, attrs: {
177
+ 'id' => '123',
178
+ 'fields' => {
179
+ 'reporter' => { 'foo' => 'bar' },
180
+ 'assignee' => { 'foo' => 'bar' },
181
+ 'project' => { 'foo' => 'bar' },
182
+ 'priority' => { 'foo' => 'bar' },
183
+ 'issuetype' => { 'foo' => 'bar' },
184
+ 'status' => { 'foo' => 'bar' },
185
+ 'resolution' => { 'foo' => 'bar' },
186
+ 'components' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
187
+ 'versions' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
188
+ 'comment' => { 'comments' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] },
189
+ 'attachment' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
190
+ 'worklog' => { 'worklogs' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] }
191
+ }
192
+ })
190
193
  end
191
194
 
192
195
  it 'has the correct relationships' do
@@ -208,6 +211,9 @@ describe JIRA::Resource::Issue do
208
211
  expect(subject).to have_one(:status, JIRA::Resource::Status)
209
212
  expect(subject.status.foo).to eq('bar')
210
213
 
214
+ expect(subject).to have_one(:resolution, JIRA::Resource::Resolution)
215
+ expect(subject.resolution.foo).to eq('bar')
216
+
211
217
  expect(subject).to have_many(:components, JIRA::Resource::Component)
212
218
  expect(subject.components.length).to eq(2)
213
219
 
@@ -5,9 +5,9 @@ describe JIRA::Resource::IssuePickerSuggestionsIssue do
5
5
 
6
6
  describe 'relationships' do
7
7
  subject do
8
- JIRA::Resource::IssuePickerSuggestionsIssue.new(client, attrs: {
9
- 'issues' => [{ 'id' => '1'}, { 'id' => '2' }]
10
- })
8
+ described_class.new(client, attrs: {
9
+ 'issues' => [{ 'id' => '1' }, { 'id' => '2' }]
10
+ })
11
11
  end
12
12
 
13
13
  it 'has the correct relationships' do
@@ -1,11 +1,12 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::ProjectFactory do
4
+ subject { described_class.new(client) }
5
+
4
6
  let(:client) { double }
5
- subject { JIRA::Resource::ProjectFactory.new(client) }
6
7
 
7
8
  it 'initializes correctly' do
8
- expect(subject.class).to eq(JIRA::Resource::ProjectFactory)
9
+ expect(subject.class).to eq(described_class)
9
10
  expect(subject.client).to eq(client)
10
11
  end
11
12
  end
@@ -9,11 +9,11 @@ describe JIRA::Resource::Project do
9
9
 
10
10
  describe 'relationships' do
11
11
  subject do
12
- JIRA::Resource::Project.new(client, attrs: {
13
- 'lead' => { 'foo' => 'bar' },
14
- 'issueTypes' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
15
- 'versions' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }]
16
- })
12
+ described_class.new(client, attrs: {
13
+ 'lead' => { 'foo' => 'bar' },
14
+ 'issueTypes' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
15
+ 'versions' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }]
16
+ })
17
17
  end
18
18
 
19
19
  it 'has the correct relationships' do
@@ -30,9 +30,9 @@ describe JIRA::Resource::Project do
30
30
 
31
31
  describe 'issues' do
32
32
  subject do
33
- JIRA::Resource::Project.new(client, attrs: {
34
- 'key' => 'test'
35
- })
33
+ described_class.new(client, attrs: {
34
+ 'key' => 'test'
35
+ })
36
36
  end
37
37
 
38
38
  it 'returns issues' do
@@ -69,12 +69,12 @@ describe JIRA::Resource::Project do
69
69
  end
70
70
 
71
71
  describe 'users' do
72
- let(:project) { JIRA::Resource::Project.new(client, attrs: { 'key' => project_key }) }
72
+ let(:project) { described_class.new(client, attrs: { 'key' => project_key }) }
73
73
  let(:project_key) { SecureRandom.hex }
74
74
  let(:response) { double('response', body: '[{}]') }
75
75
 
76
- context 'pagination' do
77
- before(:each) do
76
+ context 'with pagination' do
77
+ before do
78
78
  user_factory = double('user factory')
79
79
  expect(client).to receive(:User).and_return(user_factory)
80
80
  expect(user_factory).to receive(:build).with(any_args)
@@ -95,7 +95,7 @@ describe JIRA::Resource::Project do
95
95
  .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&startAt=#{start_at}")
96
96
  .and_return(response)
97
97
 
98
- project.users(start_at: start_at)
98
+ project.users(start_at:)
99
99
  end
100
100
 
101
101
  it 'accepts max_results option' do
@@ -105,7 +105,7 @@ describe JIRA::Resource::Project do
105
105
  .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&maxResults=#{max_results}")
106
106
  .and_return(response)
107
107
 
108
- project.users(max_results: max_results)
108
+ project.users(max_results:)
109
109
  end
110
110
 
111
111
  it 'accepts start_at and max_results options' do
@@ -116,7 +116,7 @@ describe JIRA::Resource::Project do
116
116
  .with("/jira/rest/api/2/user/assignable/search?project=#{project_key}&startAt=#{start_at}&maxResults=#{max_results}")
117
117
  .and_return(response)
118
118
 
119
- project.users(start_at: start_at, max_results: max_results)
119
+ project.users(start_at:, max_results:)
120
120
  end
121
121
  end
122
122
  end
@@ -2,19 +2,32 @@ require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::Sprint do
4
4
  let(:client) do
5
- client = double(options: { site: 'https://foo.bar.com', context_path: '/jira' })
5
+ client = double(options: { rest_base_path: '/jira/rest/api/2', context_path: '/jira' })
6
6
  allow(client).to receive(:Sprint).and_return(JIRA::Resource::SprintFactory.new(client))
7
7
  client
8
8
  end
9
9
  let(:sprint) { described_class.new(client) }
10
- let(:agile_sprint_path) { "#{sprint.client.options[:context_path]}/rest/agile/1.0/sprint/#{sprint.id}" }
10
+ let(:agile_sprint_path) { "/jira/rest/agile/1.0/sprint/#{sprint.id}" }
11
+ let(:response) { double }
12
+
13
+ describe 'get_sprint_details' do
14
+ let(:sprint) { described_class.find(client, '1') }
15
+
16
+ it 'check each of the date attributes' do
17
+ allow(client).to receive(:get).and_return(double(body: get_mock_response('sprint/1.json')))
18
+
19
+ expect(sprint.start_date).to eq Date.parse('2024-01-01T03:20:00.000Z')
20
+ expect(sprint.end_date).to eq Date.parse('2024-01-15T03:20:00.000Z')
21
+ expect(sprint.complete_date).to eq Date.parse('2024-01-16T03:48:00.000Z')
22
+ end
23
+ end
11
24
 
12
25
  describe '::find' do
13
26
  let(:response) { double('Response', body: '{"some_detail":"some detail"}') }
14
27
 
15
28
  it 'fetches the sprint from JIRA' do
16
29
  expect(client).to receive(:get).with('/jira/rest/agile/1.0/sprint/111').and_return(response)
17
- expect(JIRA::Resource::Sprint.find(client, '111')).to be_a(JIRA::Resource::Sprint)
30
+ expect(described_class.find(client, '111')).to be_a(described_class)
18
31
  end
19
32
  end
20
33
 
@@ -30,7 +43,9 @@ describe JIRA::Resource::Sprint do
30
43
  let(:given_attrs) { { start_date: '2016-06-10' } }
31
44
 
32
45
  it 'calls save on the super class with the given attributes & agile url' do
33
- expect_any_instance_of(JIRA::Base).to receive(:save).with(given_attrs, agile_sprint_path)
46
+ mock_response = double('response', body: '{"id":"123"}')
47
+
48
+ expect(client).to receive(:post).with(agile_sprint_path, given_attrs.to_json).and_return(mock_response)
34
49
 
35
50
  sprint.save(given_attrs)
36
51
  end
@@ -38,7 +53,9 @@ describe JIRA::Resource::Sprint do
38
53
 
39
54
  context 'when attributes are not specified' do
40
55
  it 'calls save on the super class with the instance attributes & agile url' do
41
- expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_path)
56
+ mock_response = double('response', body: '{"id":"123"}')
57
+
58
+ expect(client).to receive(:post).with(agile_sprint_path, instance_attrs.to_json).and_return(mock_response)
42
59
 
43
60
  sprint.save
44
61
  end
@@ -46,7 +63,9 @@ describe JIRA::Resource::Sprint do
46
63
 
47
64
  context 'when providing the path argument' do
48
65
  it 'ignores it' do
49
- expect_any_instance_of(JIRA::Base).to receive(:save).with(instance_attrs, agile_sprint_path)
66
+ mock_response = double('response', body: '{"id":"123"}')
67
+
68
+ expect(client).to receive(:post).with(agile_sprint_path, instance_attrs.to_json).and_return(mock_response)
50
69
 
51
70
  sprint.save({}, 'mavenlink.com')
52
71
  end
@@ -64,7 +83,9 @@ describe JIRA::Resource::Sprint do
64
83
  let(:given_attrs) { { start_date: '2016-06-10' } }
65
84
 
66
85
  it 'calls save! on the super class with the given attributes & agile url' do
67
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(given_attrs, agile_sprint_path)
86
+ mock_response = double('response', body: '{"id":"123"}')
87
+
88
+ expect(client).to receive(:post).with(agile_sprint_path, given_attrs.to_json).and_return(mock_response)
68
89
 
69
90
  sprint.save!(given_attrs)
70
91
  end
@@ -72,7 +93,9 @@ describe JIRA::Resource::Sprint do
72
93
 
73
94
  context 'when attributes are not specified' do
74
95
  it 'calls save! on the super class with the instance attributes & agile url' do
75
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_path)
96
+ mock_response = double('response', body: '{"id":"123"}')
97
+
98
+ expect(client).to receive(:post).with(agile_sprint_path, instance_attrs.to_json).and_return(mock_response)
76
99
 
77
100
  sprint.save!
78
101
  end
@@ -80,11 +103,67 @@ describe JIRA::Resource::Sprint do
80
103
 
81
104
  context 'when providing the path argument' do
82
105
  it 'ignores it' do
83
- expect_any_instance_of(JIRA::Base).to receive(:save!).with(instance_attrs, agile_sprint_path)
106
+ mock_response = double('response', body: '{"id":"123"}')
107
+
108
+ expect(client).to receive(:post).with(agile_sprint_path, instance_attrs.to_json).and_return(mock_response)
84
109
 
85
110
  sprint.save!({}, 'mavenlink.com')
86
111
  end
87
112
  end
88
113
  end
114
+
115
+ context 'when an issue exists' do
116
+ let(:issue_id) { 1001 }
117
+ let(:post_issue_path) do
118
+ described_class.agile_path(client, sprint.id)
119
+ '/jira/rest/agile/1.0/sprint//issue'
120
+ end
121
+ let(:issue) do
122
+ issue = double
123
+ allow(issue).to receive(:id).and_return(issue_id)
124
+ issue
125
+ end
126
+ let(:post_issue_input) do
127
+ { issues: [issue.id] }
128
+ end
129
+
130
+ describe '#add_issu' do
131
+ context 'when an issue is passed' do
132
+ it 'posts with the issue id' do
133
+ expect(client).to receive(:post).with(post_issue_path, post_issue_input.to_json)
134
+
135
+ sprint.add_issue(issue)
136
+ end
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'when multiple issues exist' do
142
+ let(:issue_ids) { [1001, 1012] }
143
+ let(:post_issue_path) do
144
+ described_class.agile_path(client, sprint.id)
145
+ '/jira/rest/agile/1.0/sprint//issue'
146
+ end
147
+ let(:issues) do
148
+ issue_ids.map do |issue_id|
149
+ issue = double
150
+ allow(issue).to receive(:id).and_return(issue_id)
151
+ issue
152
+ end
153
+ end
154
+ let(:post_issue_input) do
155
+ { issues: issue_ids }
156
+ end
157
+
158
+ describe '#add_issues' do
159
+ context 'when an issue is passed' do
160
+ it 'posts with the issue id' do
161
+ expect(client).to receive(:post).with(post_issue_path, post_issue_input.to_json)
162
+
163
+ sprint.add_issues(issues)
164
+ end
165
+ end
166
+ end
167
+ end
89
168
  end
90
169
  end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe JIRA::Resource::Status do
4
+ let(:client) do
5
+ client = double(options: { rest_base_path: '/jira/rest/api/2' })
6
+ allow(client).to receive(:Field).and_return(JIRA::Resource::FieldFactory.new(client))
7
+ allow(client).to receive(:field_map_cache).and_return(nil)
8
+ client
9
+ end
10
+
11
+ describe '#status_category' do
12
+ subject do
13
+ described_class.new(client, attrs: JSON.parse(File.read('spec/mock_responses/status/1.json')))
14
+ end
15
+
16
+ it 'has a status_category relationship' do
17
+ expect(subject).to have_one(:status_category, JIRA::Resource::StatusCategory)
18
+ expect(subject.status_category.name).to eq('To Do')
19
+ end
20
+ end
21
+ end
@@ -1,22 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe JIRA::Resource::UserFactory do
4
+ subject { described_class.new(client) }
5
+
4
6
  let(:client) do
5
- instance_double('Client', options: { rest_base_path: '/jira/rest/api/2' })
7
+ instance_double(Client, options: { rest_base_path: '/jira/rest/api/2' })
6
8
  end
7
9
 
8
- subject { JIRA::Resource::UserFactory.new(client) }
9
-
10
10
  describe '#myself' do
11
11
  let(:response) do
12
12
  instance_double(
13
- 'Response', body: get_mock_response('user_username=admin.json')
13
+ Response, body: get_mock_response('user_accountId=1234567890abcdef01234567.json')
14
14
  )
15
15
  end
16
16
 
17
17
  let(:user) { subject.myself }
18
18
 
19
- before(:each) do
19
+ before do
20
20
  allow(client).to receive(:get).with(
21
21
  '/jira/rest/api/2/myself'
22
22
  ).and_return(response)
@@ -5,10 +5,10 @@ describe JIRA::Resource::Worklog do
5
5
 
6
6
  describe 'relationships' do
7
7
  subject do
8
- JIRA::Resource::Worklog.new(client, issue_id: '99999', attrs: {
9
- 'author' => { 'foo' => 'bar' },
10
- 'updateAuthor' => { 'foo' => 'bar' }
11
- })
8
+ described_class.new(client, issue_id: '99999', attrs: {
9
+ 'author' => { 'foo' => 'bar' },
10
+ 'updateAuthor' => { 'foo' => 'bar' }
11
+ })
12
12
  end
13
13
 
14
14
  it 'has the correct relationships' do
@@ -0,0 +1,13 @@
1
+ {
2
+ "id": 1,
3
+ "self": "https://localhost:2990/jira/rest/agile/1.0/sprint/1",
4
+ "state": "closed",
5
+ "name": "SP Sprint 1",
6
+ "startDate": "2024-01-01T03:20:00.000Z",
7
+ "endDate": "2024-01-15T03:20:00.000Z",
8
+ "completeDate": "2024-01-16T03:48:00.000Z",
9
+ "createdDate": "2024-01-01T00:00:00.000Z",
10
+ "originBoardId": 1,
11
+ "goal": "",
12
+ "rapidview_id": 1
13
+ }
@@ -3,5 +3,12 @@
3
3
  "description": "The issue is open and ready for the assignee to start work on it.",
4
4
  "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif",
5
5
  "name": "Open",
6
- "id": "1"
6
+ "id": "1",
7
+ "statusCategory": {
8
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/2",
9
+ "id": 2,
10
+ "key": "new",
11
+ "colorName": "blue-gray",
12
+ "name": "To Do"
13
+ }
7
14
  }
@@ -4,34 +4,69 @@
4
4
  "description": "The issue is open and ready for the assignee to start work on it.",
5
5
  "iconUrl": "http://localhost:2990/jira/images/icons/status_open.gif",
6
6
  "name": "Open",
7
- "id": "1"
7
+ "id": "1",
8
+ "statusCategory": {
9
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/2",
10
+ "id": 2,
11
+ "key": "new",
12
+ "colorName": "blue-gray",
13
+ "name": "To Do"
14
+ }
8
15
  },
9
16
  {
10
17
  "self": "http://localhost:2990/jira/rest/api/2/status/3",
11
18
  "description": "This issue is being actively worked on at the moment by the assignee.",
12
19
  "iconUrl": "http://localhost:2990/jira/images/icons/status_inprogress.gif",
13
20
  "name": "In Progress",
14
- "id": "3"
21
+ "id": "3",
22
+ "statusCategory": {
23
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/4",
24
+ "id": 4,
25
+ "key": "indeterminate",
26
+ "colorName": "yellow",
27
+ "name": "In Progress"
28
+ }
15
29
  },
16
30
  {
17
31
  "self": "http://localhost:2990/jira/rest/api/2/status/4",
18
32
  "description": "This issue was once resolved, but the resolution was deemed incorrect. From here issues are either marked assigned or resolved.",
19
33
  "iconUrl": "http://localhost:2990/jira/images/icons/status_reopened.gif",
20
34
  "name": "Reopened",
21
- "id": "4"
35
+ "id": "4",
36
+ "statusCategory": {
37
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/2",
38
+ "id": 2,
39
+ "key": "new",
40
+ "colorName": "blue-gray",
41
+ "name": "To Do"
42
+ }
22
43
  },
23
44
  {
24
45
  "self": "http://localhost:2990/jira/rest/api/2/status/5",
25
46
  "description": "A resolution has been taken, and it is awaiting verification by reporter. From here issues are either reopened, or are closed.",
26
47
  "iconUrl": "http://localhost:2990/jira/images/icons/status_resolved.gif",
27
48
  "name": "Resolved",
28
- "id": "5"
49
+ "id": "5",
50
+ "statusCategory": {
51
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/3",
52
+ "id": 3,
53
+ "key": "done",
54
+ "colorName": "green",
55
+ "name": "Done"
56
+ }
29
57
  },
30
58
  {
31
59
  "self": "http://localhost:2990/jira/rest/api/2/status/6",
32
60
  "description": "The issue is considered finished, the resolution is correct. Issues which are closed can be reopened.",
33
61
  "iconUrl": "http://localhost:2990/jira/images/icons/status_closed.gif",
34
62
  "name": "Closed",
35
- "id": "6"
63
+ "id": "6",
64
+ "statusCategory": {
65
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/3",
66
+ "id": 3,
67
+ "key": "done",
68
+ "colorName": "green",
69
+ "name": "Done"
70
+ }
36
71
  }
37
72
  ]
@@ -0,0 +1,7 @@
1
+ {
2
+ "self": "http://localhost:2990/jira/rest/api/2/statuscategory/1",
3
+ "id": 1,
4
+ "key": "undefined",
5
+ "colorName": "medium-gray",
6
+ "name": "No Category"
7
+ }