jira-ruby 2.3.0 → 3.2.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.
- 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 +30 -0
- data/.github/workflows/codeql.yml +96 -0
- data/.github/workflows/rubocop.yml +18 -0
- data/.gitignore +3 -1
- data/.rubocop.yml +123 -0
- data/.yardopts +4 -0
- data/Gemfile +11 -3
- data/Guardfile +2 -0
- data/README.md +94 -19
- data/Rakefile +3 -4
- data/jira-ruby.gemspec +12 -17
- data/lib/jira/atlassian/jwt.rb +76 -0
- data/lib/jira/base.rb +37 -36
- data/lib/jira/base_factory.rb +4 -1
- data/lib/jira/client.rb +132 -51
- 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 +19 -43
- 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 +144 -4
- data/lib/jira/resource/board.rb +5 -3
- data/lib/jira/resource/board_configuration.rb +2 -0
- data/lib/jira/resource/comment.rb +14 -0
- data/lib/jira/resource/component.rb +2 -0
- data/lib/jira/resource/createmeta.rb +7 -5
- data/lib/jira/resource/field.rb +13 -12
- data/lib/jira/resource/filter.rb +2 -0
- data/lib/jira/resource/issue.rb +148 -54
- 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/properties.rb +56 -0
- 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 +15 -2
- data/lib/jira/version.rb +3 -1
- data/lib/jira-ruby.rb +6 -3
- data/lib/tasks/generate.rake +3 -1
- data/spec/data/files/jwt-signed-urls.json +317 -0
- 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 +21 -18
- 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/properties_spec.rb +45 -0
- 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 +5 -4
- 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 +35 -0
- data/spec/integration/worklog_spec.rb +8 -8
- data/spec/jira/atlassian/jwt_spec.rb +60 -0
- data/spec/jira/base_factory_spec.rb +13 -3
- data/spec/jira/base_spec.rb +135 -98
- data/spec/jira/client_spec.rb +72 -56
- 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 +32 -32
- 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 +7 -6
- data/spec/jira/resource/issue_picker_suggestions_spec.rb +17 -17
- data/spec/jira/resource/issue_spec.rb +159 -93
- 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 +16 -16
- 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/board/1_issues.json +2 -1
- data/spec/mock_responses/issue/10002/properties/foo.json +4 -0
- data/spec/mock_responses/issue/10002/properties/xyz.json +4 -0
- data/spec/mock_responses/issue/10002/properties/xyz.put.json +4 -0
- data/spec/mock_responses/issue/10002/properties.json +12 -0
- data/spec/mock_responses/issue.json +1 -0
- data/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.full.json +2 -1
- data/spec/mock_responses/rapidview/SAMPLEPROJECT.issues.json +2 -1
- 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 +5 -7
- data/spec/support/mock_client.rb +9 -0
- data/spec/support/mock_response.rb +8 -0
- data/spec/support/shared_examples/integration.rb +51 -58
- metadata +45 -257
- 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/mock_responses/jira/rest/webhooks/1.0/webhook.json +0 -11
- data/spec/mock_responses/webhook/webhook.json +0 -11
- /data/spec/mock_responses/{jira/rest/webhooks/1.0/webhook → webhook}/2.json +0 -0
|
@@ -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(:
|
|
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
|
|
16
|
+
before do
|
|
17
17
|
response = double
|
|
18
18
|
allow(response).to receive(:body).and_return('{"key":"foo","id":"101"}')
|
|
19
|
-
allow(
|
|
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 =
|
|
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
|
|
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,123 +36,179 @@ describe JIRA::Resource::Issue do
|
|
|
34
36
|
end
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
it '
|
|
39
|
+
it 'finds all issues' do
|
|
38
40
|
response = double
|
|
39
41
|
empty_response = double
|
|
40
42
|
issue = double
|
|
41
43
|
|
|
42
44
|
allow(response).to receive(:body).and_return('{"issues":[{"id":"1","summary":"Bugs Everywhere"}]}')
|
|
43
|
-
expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=0')
|
|
45
|
+
expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?expand=transitions.fields&maxResults=1000&startAt=0')
|
|
44
46
|
.and_return(response)
|
|
45
47
|
allow(empty_response).to receive(:body).and_return('{"issues":[]}')
|
|
46
|
-
expect(client).to receive(:get).with('/jira/rest/api/2/search?expand=transitions.fields&maxResults=1000&startAt=1')
|
|
48
|
+
expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?expand=transitions.fields&maxResults=1000&startAt=1')
|
|
47
49
|
.and_return(empty_response)
|
|
48
50
|
|
|
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
|
-
|
|
54
|
+
described_class.all(client)
|
|
53
55
|
end
|
|
54
56
|
|
|
55
|
-
it '
|
|
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(
|
|
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 =
|
|
66
|
-
issue_from_key =
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
issue = double
|
|
73
|
+
describe '.jql' do
|
|
74
|
+
subject { described_class.jql(client, 'foo bar', args) }
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
expect(issue).to receive(:build).with(%w[key foo]).and_return('')
|
|
76
|
+
let(:args) { {} }
|
|
77
|
+
let(:issue) { double }
|
|
78
|
+
let(:response) { double }
|
|
79
|
+
let(:response_string) { '{"issues": {"key":"foo"}, "isLast": true}' }
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
before do
|
|
82
|
+
allow(response).to receive(:body).and_return(response_string)
|
|
83
|
+
allow(client).to receive(:Issue).and_return(issue)
|
|
84
|
+
allow(issue).to receive(:build).with(%w[key foo]).and_return('')
|
|
85
|
+
end
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
it 'searches an issue with a jql query string' do
|
|
88
|
+
expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?jql=foo+bar')
|
|
89
|
+
.and_return(response)
|
|
90
|
+
expect(described_class.jql(client, 'foo bar')).to eq([''])
|
|
91
|
+
end
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
expect(client).to receive(:Issue).and_return(issue)
|
|
93
|
-
expect(issue).to receive(:build).with(%w[key foo]).and_return('')
|
|
93
|
+
it 'passes thorugh the reconcileIssues parameter' do
|
|
94
|
+
expect(client).to receive(:get)
|
|
95
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&reconcileIssues=true')
|
|
96
|
+
.and_return(response)
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
expect(described_class.jql(client, 'foo bar', reconcile_issues: true)).to eq([''])
|
|
99
|
+
end
|
|
97
100
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
+
it 'searches an issue with a jql query string and fields' do
|
|
102
|
+
expect(client).to receive(:get)
|
|
103
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&fields=foo,bar')
|
|
104
|
+
.and_return(response)
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
.with('/jira/rest/api/2/search?jql=foo+bar&startAt=1&maxResults=3')
|
|
105
|
-
.and_return(response)
|
|
106
|
-
expect(client).to receive(:Issue).and_return(issue)
|
|
107
|
-
expect(issue).to receive(:build).with(%w[key foo]).and_return('')
|
|
106
|
+
expect(described_class.jql(client, 'foo bar', fields: %w[foo bar])).to eq([''])
|
|
107
|
+
end
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
context 'when maxResults is provided' do
|
|
110
|
+
let(:args) { { max_results: } }
|
|
111
111
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
issue = double
|
|
112
|
+
context 'with non-zero' do
|
|
113
|
+
let(:max_results) { 3 }
|
|
115
114
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
it 'searches an issue with a jql query string and maxResults' do
|
|
116
|
+
expect(client).to receive(:get)
|
|
117
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&maxResults=3')
|
|
118
|
+
.and_return(response)
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
expect(subject).to eq([''])
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
context 'with zero' do
|
|
125
|
+
let(:response_string) { '{"total": 1, "issues": []}' }
|
|
126
|
+
let(:max_results) { 0 }
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
it 'searches an issue with a jql query string and should return the count of tickets' do
|
|
129
|
+
expect(client).to receive(:get)
|
|
130
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&maxResults=0')
|
|
131
|
+
.and_return(response)
|
|
132
|
+
|
|
133
|
+
expect(subject).to eq(1)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'searches an issue with a jql query string and string expand' do
|
|
139
|
+
expect(client).to receive(:get)
|
|
140
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&expand=transitions')
|
|
141
|
+
.and_return(response)
|
|
134
142
|
|
|
135
|
-
|
|
143
|
+
expect(described_class.jql(client, 'foo bar', expand: 'transitions')).to eq([''])
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
it 'searches an issue with a jql query string and array expand' do
|
|
147
|
+
expect(client).to receive(:get)
|
|
148
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&expand=transitions')
|
|
149
|
+
.and_return(response)
|
|
150
|
+
|
|
151
|
+
expect(described_class.jql(client, 'foo bar', expand: %w[transitions])).to eq([''])
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
context 'when pagination is required' do
|
|
155
|
+
let(:response_string) { '{"issues": [{"key":"foo"}], "isLast": false, "nextPageToken": "abc"}' }
|
|
156
|
+
let(:second_response_string) { '{"issues": [{"key":"bar"}], "isLast": true}' }
|
|
157
|
+
|
|
158
|
+
before do
|
|
159
|
+
allow(issue).to receive(:build).with({ 'key' => 'foo' }).and_return('1')
|
|
160
|
+
allow(issue).to receive(:build).with({ 'key' => 'bar' }).and_return('2')
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it 'makes multiple requests' do
|
|
164
|
+
expect(client).to receive(:get)
|
|
165
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar')
|
|
166
|
+
.and_return(response)
|
|
167
|
+
expect(client).to receive(:get)
|
|
168
|
+
.with('/jira/rest/api/2/search/jql?jql=foo+bar&nextPageToken=abc')
|
|
169
|
+
.and_return(double(body: second_response_string))
|
|
170
|
+
|
|
171
|
+
expect(subject).to eq(%w[1 2])
|
|
172
|
+
end
|
|
173
|
+
end
|
|
136
174
|
end
|
|
137
175
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
176
|
+
describe '.jql_paged' do
|
|
177
|
+
let(:issue) { double }
|
|
178
|
+
let(:response) { double }
|
|
141
179
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
.
|
|
145
|
-
.and_return(
|
|
146
|
-
|
|
147
|
-
|
|
180
|
+
before do
|
|
181
|
+
allow(response).to receive(:body).and_return(response_string)
|
|
182
|
+
allow(client).to receive(:Issue).and_return(issue)
|
|
183
|
+
allow(issue).to receive(:build).with({ 'key' => 'foo' }).and_return('1')
|
|
184
|
+
allow(issue).to receive(:build).with({ 'key' => 'bar' }).and_return('2')
|
|
185
|
+
allow(issue).to receive(:build).with({ 'key' => 'baz' }).and_return('3')
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
context 'without next_page_token (first page)' do
|
|
189
|
+
subject { described_class.jql_paged(client, 'foo bar', page_size: 2) }
|
|
190
|
+
|
|
191
|
+
before { expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?jql=foo+bar').and_return(response) }
|
|
192
|
+
|
|
193
|
+
let(:response) { double }
|
|
194
|
+
let(:response_string) { '{"issues": [{"key":"foo"},{"key":"bar"}], "isLast": false, "nextPageToken": "abc"}' }
|
|
148
195
|
|
|
149
|
-
|
|
196
|
+
it { is_expected.to eq(issues: %w[1 2], next_page_token: 'abc', total: nil) }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
context 'with next_page_token' do
|
|
200
|
+
subject { described_class.jql_paged(client, 'foo bar', page_size: 2, next_page_token: 'abc') }
|
|
201
|
+
|
|
202
|
+
let(:response_string) { '{"issues": [{"key":"baz"}], "isLast": true}' }
|
|
203
|
+
|
|
204
|
+
before { expect(client).to receive(:get).with('/jira/rest/api/2/search/jql?jql=foo+bar&nextPageToken=abc').and_return(double(body: response_string)) }
|
|
205
|
+
|
|
206
|
+
it { is_expected.to eq(issues: %w[3], next_page_token: nil, total: nil) }
|
|
207
|
+
end
|
|
150
208
|
end
|
|
151
209
|
|
|
152
|
-
it '
|
|
153
|
-
subject =
|
|
210
|
+
it 'returns meta data available for editing an issue' do
|
|
211
|
+
subject = described_class.new(client, attrs: { 'fields' => { 'key' => 'TST=123' } })
|
|
154
212
|
response = double
|
|
155
213
|
|
|
156
214
|
allow(response).to receive(:body).and_return(
|
|
@@ -164,29 +222,31 @@ describe JIRA::Resource::Issue do
|
|
|
164
222
|
end
|
|
165
223
|
|
|
166
224
|
it 'provides direct accessors to the fields' do
|
|
167
|
-
subject =
|
|
225
|
+
subject = described_class.new(client, attrs: { 'fields' => { 'foo' => 'bar' } })
|
|
168
226
|
expect(subject).to respond_to(:foo)
|
|
169
227
|
expect(subject.foo).to eq('bar')
|
|
170
228
|
end
|
|
171
229
|
|
|
172
230
|
describe 'relationships' do
|
|
173
231
|
subject do
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
232
|
+
described_class.new(client, attrs: {
|
|
233
|
+
'id' => '123',
|
|
234
|
+
'fields' => {
|
|
235
|
+
'reporter' => { 'foo' => 'bar' },
|
|
236
|
+
'assignee' => { 'foo' => 'bar' },
|
|
237
|
+
'project' => { 'foo' => 'bar' },
|
|
238
|
+
'priority' => { 'foo' => 'bar' },
|
|
239
|
+
'issuetype' => { 'foo' => 'bar' },
|
|
240
|
+
'status' => { 'foo' => 'bar' },
|
|
241
|
+
'resolution' => { 'foo' => 'bar' },
|
|
242
|
+
'components' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
|
|
243
|
+
'versions' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
|
|
244
|
+
'comment' => { 'comments' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] },
|
|
245
|
+
'attachment' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }],
|
|
246
|
+
'worklog' => { 'worklogs' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }] }
|
|
247
|
+
},
|
|
248
|
+
'properties' => [{ 'foo' => 'bar' }, { 'baz' => 'flum' }]
|
|
249
|
+
})
|
|
190
250
|
end
|
|
191
251
|
|
|
192
252
|
it 'has the correct relationships' do
|
|
@@ -208,6 +268,9 @@ describe JIRA::Resource::Issue do
|
|
|
208
268
|
expect(subject).to have_one(:status, JIRA::Resource::Status)
|
|
209
269
|
expect(subject.status.foo).to eq('bar')
|
|
210
270
|
|
|
271
|
+
expect(subject).to have_one(:resolution, JIRA::Resource::Resolution)
|
|
272
|
+
expect(subject.resolution.foo).to eq('bar')
|
|
273
|
+
|
|
211
274
|
expect(subject).to have_many(:components, JIRA::Resource::Component)
|
|
212
275
|
expect(subject.components.length).to eq(2)
|
|
213
276
|
|
|
@@ -222,6 +285,9 @@ describe JIRA::Resource::Issue do
|
|
|
222
285
|
|
|
223
286
|
expect(subject).to have_many(:worklogs, JIRA::Resource::Worklog)
|
|
224
287
|
expect(subject.worklogs.length).to eq(2)
|
|
288
|
+
|
|
289
|
+
expect(subject).to have_many(:properties, JIRA::Resource::Properties)
|
|
290
|
+
expect(subject.properties.length).to eq(2)
|
|
225
291
|
end
|
|
226
292
|
end
|
|
227
293
|
end
|
|
@@ -5,9 +5,9 @@ describe JIRA::Resource::IssuePickerSuggestionsIssue do
|
|
|
5
5
|
|
|
6
6
|
describe 'relationships' do
|
|
7
7
|
subject do
|
|
8
|
-
|
|
9
|
-
|
|
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(
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
described_class.new(client, attrs: {
|
|
34
|
+
'key' => 'test'
|
|
35
|
+
})
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
it 'returns issues' do
|
|
@@ -42,7 +42,7 @@ describe JIRA::Resource::Project do
|
|
|
42
42
|
issue_factory = double('issue factory')
|
|
43
43
|
|
|
44
44
|
expect(client).to receive(:get)
|
|
45
|
-
.with('/jira/rest/api/2/search?jql=project%3D%22test%22')
|
|
45
|
+
.with('/jira/rest/api/2/search/jql?jql=project%3D%22test%22')
|
|
46
46
|
.and_return(response)
|
|
47
47
|
expect(client).to receive(:Issue).and_return(issue_factory)
|
|
48
48
|
expect(issue_factory).to receive(:build)
|
|
@@ -58,7 +58,7 @@ describe JIRA::Resource::Project do
|
|
|
58
58
|
issue_factory = double('issue factory')
|
|
59
59
|
|
|
60
60
|
expect(client).to receive(:get)
|
|
61
|
-
.with('/jira/rest/api/2/search?jql=project%3D%22test%22&expand=changelog&startAt=1&maxResults=100')
|
|
61
|
+
.with('/jira/rest/api/2/search/jql?jql=project%3D%22test%22&expand=changelog&startAt=1&maxResults=100')
|
|
62
62
|
.and_return(response)
|
|
63
63
|
expect(client).to receive(:Issue).and_return(issue_factory)
|
|
64
64
|
expect(issue_factory).to receive(:build)
|
|
@@ -69,12 +69,12 @@ describe JIRA::Resource::Project do
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
describe 'users' do
|
|
72
|
-
let(:project) {
|
|
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
|
|
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:
|
|
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:
|
|
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
|
|
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: {
|
|
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) { "
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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_issue' 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
|
+
expect(sprint.add_issue(issue)).to eq(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
|
+
expect(sprint.add_issues(issues)).to eq(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
|