jira-auto-tool 0.1.1

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 (139) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +291 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/Guardfile +105 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +159 -0
  9. data/Rakefile +20 -0
  10. data/bin/jira-auto-tool +57 -0
  11. data/bin/jira-auto-tool.bat +2 -0
  12. data/bin/setup +8 -0
  13. data/bin/setup-dev-win.bat +3 -0
  14. data/cucumber.yml +7 -0
  15. data/features/align_sprint_time_in_dates.feature +33 -0
  16. data/features/assign_tickets_to_team_sprints.feature +73 -0
  17. data/features/cache_boards.feature +24 -0
  18. data/features/control_http_request_rate_limit.feature +17 -0
  19. data/features/create_sprints_using_existing_ones_as_reference.feature +79 -0
  20. data/features/list_boards.feature +12 -0
  21. data/features/list_project_fields.feature +89 -0
  22. data/features/list_sprint_prefixes.feature +77 -0
  23. data/features/quarterly_add_sprints_using_existing_ones_as_a_reference.feature +71 -0
  24. data/features/quarterly_create_sprints_until_specific_date.feature +75 -0
  25. data/features/quarterly_rename_sprints.feature +179 -0
  26. data/features/rename_sprints.feature +203 -0
  27. data/features/self_documented_command_line.feature +15 -0
  28. data/features/sprint_filtering.feature +111 -0
  29. data/features/step_definitions/execution_context_steps.rb +33 -0
  30. data/features/step_definitions/jira_board_steps.rb +102 -0
  31. data/features/step_definitions/jira_ticket_steps.rb +63 -0
  32. data/features/support/10.setup_cucumber.rb +10 -0
  33. data/features/support/env.rb +25 -0
  34. data/features/support/hooks.rb +25 -0
  35. data/features/support/setup_rspec.rb +14 -0
  36. data/features/support/setup_simplecov.rb +5 -0
  37. data/features/update_sprint_end_date_and_shift_following_ones.feature +52 -0
  38. data/lib/jira/auto/tool/board/cache.rb +67 -0
  39. data/lib/jira/auto/tool/board/unavailable_board.rb +36 -0
  40. data/lib/jira/auto/tool/board.rb +105 -0
  41. data/lib/jira/auto/tool/board_controller/options.rb +32 -0
  42. data/lib/jira/auto/tool/board_controller.rb +88 -0
  43. data/lib/jira/auto/tool/common_options.rb +37 -0
  44. data/lib/jira/auto/tool/config/options.rb +19 -0
  45. data/lib/jira/auto/tool/config.rb +64 -0
  46. data/lib/jira/auto/tool/fetch_custom_field_options.rb +47 -0
  47. data/lib/jira/auto/tool/field.rb +59 -0
  48. data/lib/jira/auto/tool/field_controller.rb +50 -0
  49. data/lib/jira/auto/tool/field_option.rb +35 -0
  50. data/lib/jira/auto/tool/get_createmeta_for_project.rb +24 -0
  51. data/lib/jira/auto/tool/helpers/environment_based_value.rb +96 -0
  52. data/lib/jira/auto/tool/helpers/option_parser.rb +16 -0
  53. data/lib/jira/auto/tool/helpers/overridable_time.rb +18 -0
  54. data/lib/jira/auto/tool/helpers/pagination.rb +50 -0
  55. data/lib/jira/auto/tool/jira_http_options.rb +20 -0
  56. data/lib/jira/auto/tool/next_sprint_creator.rb +60 -0
  57. data/lib/jira/auto/tool/performer/options.rb +76 -0
  58. data/lib/jira/auto/tool/performer/planning_increment_sprint_creator.rb +42 -0
  59. data/lib/jira/auto/tool/performer/prefix_sprint_updater.rb +42 -0
  60. data/lib/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator.rb +60 -0
  61. data/lib/jira/auto/tool/performer/quarterly_sprint_renamer.rb +19 -0
  62. data/lib/jira/auto/tool/performer/sprint_end_date_updater.rb +55 -0
  63. data/lib/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator.rb +19 -0
  64. data/lib/jira/auto/tool/performer/sprint_renamer/next_name_generator.rb +47 -0
  65. data/lib/jira/auto/tool/performer/sprint_renamer.rb +55 -0
  66. data/lib/jira/auto/tool/performer/sprint_time_in_dates_aligner.rb +52 -0
  67. data/lib/jira/auto/tool/project/options.rb +22 -0
  68. data/lib/jira/auto/tool/project/ticket_fields.rb +70 -0
  69. data/lib/jira/auto/tool/project.rb +40 -0
  70. data/lib/jira/auto/tool/rate_limited_jira_client.rb +50 -0
  71. data/lib/jira/auto/tool/request_builder/field_context_fetcher.rb +78 -0
  72. data/lib/jira/auto/tool/request_builder/field_option_fetcher.rb +54 -0
  73. data/lib/jira/auto/tool/request_builder/get.rb +29 -0
  74. data/lib/jira/auto/tool/request_builder/sprint_creator.rb +112 -0
  75. data/lib/jira/auto/tool/request_builder/sprint_state_updater.rb +60 -0
  76. data/lib/jira/auto/tool/request_builder.rb +89 -0
  77. data/lib/jira/auto/tool/setup_logging.rb +35 -0
  78. data/lib/jira/auto/tool/sprint/name.rb +105 -0
  79. data/lib/jira/auto/tool/sprint/prefix.rb +66 -0
  80. data/lib/jira/auto/tool/sprint.rb +183 -0
  81. data/lib/jira/auto/tool/sprint_controller/options.rb +61 -0
  82. data/lib/jira/auto/tool/sprint_controller.rb +152 -0
  83. data/lib/jira/auto/tool/sprint_state_controller.rb +58 -0
  84. data/lib/jira/auto/tool/team.rb +23 -0
  85. data/lib/jira/auto/tool/team_sprint_prefix_mapper/options.rb +27 -0
  86. data/lib/jira/auto/tool/team_sprint_prefix_mapper.rb +62 -0
  87. data/lib/jira/auto/tool/team_sprint_ticket_dispatcher.rb +76 -0
  88. data/lib/jira/auto/tool/ticket.rb +110 -0
  89. data/lib/jira/auto/tool/until_date.rb +68 -0
  90. data/lib/jira/auto/tool/version.rb +9 -0
  91. data/lib/jira/auto/tool.rb +216 -0
  92. data/sig/jira/sprint/tool.rbs +8 -0
  93. data/spec/jira/auto/tool/board/cache_spec.rb +179 -0
  94. data/spec/jira/auto/tool/board/unavailable_board_spec.rb +34 -0
  95. data/spec/jira/auto/tool/board_controller/options_spec.rb +52 -0
  96. data/spec/jira/auto/tool/board_controller_spec.rb +154 -0
  97. data/spec/jira/auto/tool/board_spec.rb +163 -0
  98. data/spec/jira/auto/tool/common_options_spec.rb +49 -0
  99. data/spec/jira/auto/tool/config_spec.rb +108 -0
  100. data/spec/jira/auto/tool/field_controller_spec.rb +121 -0
  101. data/spec/jira/auto/tool/field_option_spec.rb +42 -0
  102. data/spec/jira/auto/tool/field_spec.rb +99 -0
  103. data/spec/jira/auto/tool/helpers/environment_based_value_spec.rb +21 -0
  104. data/spec/jira/auto/tool/helpers/option_parser_spec.rb +21 -0
  105. data/spec/jira/auto/tool/helpers/overridable_time_spec.rb +43 -0
  106. data/spec/jira/auto/tool/helpers/pagination_spec.rb +72 -0
  107. data/spec/jira/auto/tool/jira_http_options_spec.rb +32 -0
  108. data/spec/jira/auto/tool/next_sprint_creator_spec.rb +85 -0
  109. data/spec/jira/auto/tool/performer/option_spec.rb +55 -0
  110. data/spec/jira/auto/tool/performer/planning_increment_sprint_creator_spec.rb +62 -0
  111. data/spec/jira/auto/tool/performer/prefix_sprint_updater_spec.rb +35 -0
  112. data/spec/jira/auto/tool/performer/quarterly_sprint_renamer/next_name_generator_spec.rb +175 -0
  113. data/spec/jira/auto/tool/performer/quarterly_sprint_renamer_spec.rb +239 -0
  114. data/spec/jira/auto/tool/performer/sprint_end_date_updater_spec.rb +90 -0
  115. data/spec/jira/auto/tool/performer/sprint_renamer/keep_same_name_generator_spec.rb +12 -0
  116. data/spec/jira/auto/tool/performer/sprint_renamer/next_name_generator_spec.rb +129 -0
  117. data/spec/jira/auto/tool/performer/sprint_renamer_spec.rb +240 -0
  118. data/spec/jira/auto/tool/performer/sprint_time_in_dates_aligner_spec.rb +132 -0
  119. data/spec/jira/auto/tool/project/ticket_fields_spec.rb +390 -0
  120. data/spec/jira/auto/tool/project_spec.rb +31 -0
  121. data/spec/jira/auto/tool/rate_limited_jira_client_spec.rb +82 -0
  122. data/spec/jira/auto/tool/request_builder/field_context_fetcher_spec.rb +54 -0
  123. data/spec/jira/auto/tool/request_builder/field_option_fetcher_spec.rb +64 -0
  124. data/spec/jira/auto/tool/request_builder/get_spec.rb +40 -0
  125. data/spec/jira/auto/tool/request_builder/sprint_creator_spec.rb +179 -0
  126. data/spec/jira/auto/tool/request_builder/sprint_state_updater_spec.rb +31 -0
  127. data/spec/jira/auto/tool/request_builder_spec.rb +73 -0
  128. data/spec/jira/auto/tool/sprint/name_spec.rb +101 -0
  129. data/spec/jira/auto/tool/sprint/prefix_spec.rb +207 -0
  130. data/spec/jira/auto/tool/sprint_controller_spec.rb +406 -0
  131. data/spec/jira/auto/tool/sprint_spec.rb +309 -0
  132. data/spec/jira/auto/tool/team_spec.rb +21 -0
  133. data/spec/jira/auto/tool/team_sprint_prefix_mapper_spec.rb +97 -0
  134. data/spec/jira/auto/tool/team_sprint_ticket_dispatcher_spec.rb +232 -0
  135. data/spec/jira/auto/tool/ticket_spec.rb +116 -0
  136. data/spec/jira/auto/tool/until_date_spec.rb +80 -0
  137. data/spec/jira/auto/tool_spec.rb +458 -0
  138. data/spec/spec_helper.rb +42 -0
  139. metadata +368 -0
@@ -0,0 +1,390 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+ require "jira/auto/tool/project/ticket_fields"
5
+
6
+ module Jira
7
+ module Auto
8
+ class Tool
9
+ class Project
10
+ # rubocop:disable Metrics/ClassLength
11
+ class TicketFields
12
+ RSpec.describe TicketFields do
13
+ let(:ticket_fields) { described_class.new(tool, project) }
14
+ let(:tool) { instance_double(Tool) }
15
+ let(:project) { instance_double(Project, key: "project_key") }
16
+
17
+ describe "#list" do
18
+ let(:expected_list_output) do
19
+ <<~EOELO
20
+ +----------------------------------------------------------------------------------------------------------------+
21
+ | Project project_key Ticket Fields |
22
+ +-------------+-----------+---------------------+------------+---------------------------------------------------+
23
+ | Ticket Type | Field Key | Field Name | Field Type | Allowed Values |
24
+ +-------------+-----------+---------------------+------------+---------------------------------------------------+
25
+ | Story | 10001 | key | String | n/a |
26
+ | Story | 10000 | Summary | String | n/a |
27
+ | Story | 10002 | Story Points | Number | n/a |
28
+ | Epic | 10001 | Implementation Team | Set | ["Food Platform", "Food Delivery", "Food Supply"] |
29
+ +-------------+-----------+---------------------+------------+---------------------------------------------------+
30
+ EOELO
31
+ end
32
+
33
+ before do
34
+ allow(ticket_fields)
35
+ .to receive_messages(table_rows: [
36
+ ["Story", 10_001, "key", "String", "n/a"],
37
+ ["Story", 10_000, "Summary", "String", "n/a"],
38
+ ["Story", 10_002, "Story Points", "Number", "n/a"],
39
+ ["Epic", 10_001, "Implementation Team", "Set",
40
+ ["Food Platform", "Food Delivery", "Food Supply"]]
41
+ ])
42
+ end
43
+
44
+ it do
45
+ expect { ticket_fields.list }.to output(expected_list_output).to_stdout
46
+ end
47
+ end
48
+
49
+ describe "#table_row_header" do
50
+ it {
51
+ expect(ticket_fields.table_row_header).to eq(["Ticket Type", "Field Key", "Field Name", "Field Type",
52
+ "Allowed Values"])
53
+ }
54
+ end
55
+
56
+ describe "#table_rows" do
57
+ let(:jira_client) { jira_resource_double(JIRA::Client) }
58
+ let(:createmeta) { jira_resource_double(JIRA::Resource::Createmeta, all: all_createmeta) }
59
+ let(:all_createmeta) do
60
+ [jira_resource_double(JIRA::Resource::Createmeta, attrs:
61
+ { "id" => "10006",
62
+ "key" => "JATCIDEVLX",
63
+ "name" => "JAT CI/CD - Dev - Linux",
64
+ "issuetypes" =>
65
+ [{ "id" => "10005",
66
+ "name" => "Task",
67
+ "untranslatedName" => "Task",
68
+ "subtask" => false,
69
+ "fields" =>
70
+ { "summary" =>
71
+ { "schema" => { "type" => "string", "system" => "summary" },
72
+ "name" => "Summary",
73
+ "key" => "summary" },
74
+ "customfield_10081" =>
75
+ { "schema" =>
76
+ { "type" => "date",
77
+ "custom" =>
78
+ "com.atlassian.jira.plugin.system.customfieldtypes:datepicker",
79
+ "customId" => 10_081 },
80
+ "name" => "Expected Start",
81
+ "key" => "customfield_10081" },
82
+ "customfield_10082" =>
83
+ { "schema" =>
84
+ { "type" => "option",
85
+ "custom" =>
86
+ "com.atlassian.jira.plugin.system.customfieldtypes:select",
87
+ "customId" => 10_082 },
88
+ "name" => "Implementation Team",
89
+ "key" => "customfield_10082",
90
+ "allowedValues" =>
91
+ [{ "value" => "A16 CRM", "id" => "10044" },
92
+ { "value" => "A16 E2E-Test", "id" => "10045" },
93
+ { "value" => "A16 Logistic", "id" => "10048" },
94
+ { "value" => "A16 Platform", "id" => "10046" },
95
+ { "value" => "A16 Sys-Team", "id" => "10047" }] },
96
+ "customfield_10020" =>
97
+ { "schema" =>
98
+ { "type" => "array",
99
+ "items" => "json",
100
+ "custom" => "com.pyxis.greenhopper.jira:gh-sprint",
101
+ "customId" => 10_020 },
102
+ "name" => "Sprint",
103
+ "key" => "customfield_10020" },
104
+ "customfield_10001" =>
105
+ { "schema" =>
106
+ { "type" => "team",
107
+ "custom" =>
108
+ "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team",
109
+ "customId" => 10_001,
110
+ "configuration" =>
111
+ { "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team" =>
112
+ true } },
113
+ "name" => "Team",
114
+ "key" => "customfield_10001" } } },
115
+ { "id" => "10006",
116
+ "name" => "Sub-task",
117
+ "untranslatedName" => "Sub-task",
118
+ "subtask" => true,
119
+ "fields" =>
120
+ { "summary" =>
121
+ { "schema" => { "type" => "string", "system" => "summary" },
122
+ "name" => "Summary",
123
+ "key" => "summary" },
124
+ "customfield_10081" =>
125
+ { "schema" =>
126
+ { "type" => "date",
127
+ "custom" =>
128
+ "com.atlassian.jira.plugin.system.customfieldtypes:datepicker",
129
+ "customId" => 10_081 },
130
+ "name" => "Expected Start",
131
+ "key" => "customfield_10081" },
132
+ "customfield_10082" =>
133
+ { "schema" =>
134
+ { "type" => "option",
135
+ "custom" =>
136
+ "com.atlassian.jira.plugin.system.customfieldtypes:select",
137
+ "customId" => 10_082 },
138
+ "name" => "Implementation Team",
139
+ "key" => "customfield_10082",
140
+ "allowedValues" =>
141
+ [{ "value" => "A16 CRM", "id" => "10044" },
142
+ { "value" => "A16 E2E-Test", "id" => "10045" },
143
+ { "value" => "A16 Logistic", "id" => "10048" },
144
+ { "value" => "A16 Platform", "id" => "10046" },
145
+ { "value" => "A16 Sys-Team", "id" => "10047" }] },
146
+ "customfield_10020" =>
147
+ { "schema" =>
148
+ { "type" => "array",
149
+ "items" => "json",
150
+ "custom" => "com.pyxis.greenhopper.jira:gh-sprint",
151
+ "customId" => 10_020 },
152
+ "name" => "Sprint",
153
+ "key" => "customfield_10020" },
154
+ "customfield_10001" =>
155
+ { "schema" =>
156
+ { "type" => "team",
157
+ "custom" =>
158
+ "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team",
159
+ "customId" => 10_001,
160
+ "configuration" =>
161
+ { "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team" =>
162
+ true } },
163
+ "name" => "Team",
164
+ "key" => "customfield_10001" } } },
165
+ { "id" => "10003",
166
+ "name" => "Story",
167
+ "untranslatedName" => "Story",
168
+ "subtask" => false,
169
+ "fields" =>
170
+ { "summary" =>
171
+ { "schema" => { "type" => "string", "system" => "summary" },
172
+ "name" => "Summary",
173
+ "key" => "summary" },
174
+ "customfield_10081" =>
175
+ { "schema" =>
176
+ { "type" => "date",
177
+ "custom" =>
178
+ "com.atlassian.jira.plugin.system.customfieldtypes:datepicker",
179
+ "customId" => 10_081 },
180
+ "name" => "Expected Start",
181
+ "key" => "customfield_10081" },
182
+ "customfield_10082" =>
183
+ { "schema" =>
184
+ { "type" => "option",
185
+ "custom" =>
186
+ "com.atlassian.jira.plugin.system.customfieldtypes:select",
187
+ "customId" => 10_082 },
188
+ "name" => "Implementation Team",
189
+ "key" => "customfield_10082",
190
+ "allowedValues" =>
191
+ [{ "value" => "A16 CRM", "id" => "10044" },
192
+ { "value" => "A16 E2E-Test", "id" => "10045" },
193
+ { "value" => "A16 Logistic", "id" => "10048" },
194
+ { "value" => "A16 Platform", "id" => "10046" },
195
+ { "value" => "A16 Sys-Team", "id" => "10047" }] },
196
+ "customfield_10020" =>
197
+ { "schema" =>
198
+ { "type" => "array",
199
+ "items" => "json",
200
+ "custom" => "com.pyxis.greenhopper.jira:gh-sprint",
201
+ "customId" => 10_020 },
202
+ "name" => "Sprint",
203
+ "key" => "customfield_10020" },
204
+ "customfield_10001" =>
205
+ { "schema" =>
206
+ { "type" => "team",
207
+ "custom" =>
208
+ "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team",
209
+ "customId" => 10_001,
210
+ "configuration" =>
211
+ { "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team" =>
212
+ true } },
213
+ "name" => "Team",
214
+ "key" => "customfield_10001" } } },
215
+ { "id" => "10007",
216
+ "name" => "Bug",
217
+ "untranslatedName" => "Bug",
218
+ "subtask" => false,
219
+ "fields" =>
220
+ { "summary" =>
221
+ { "schema" => { "type" => "string", "system" => "summary" },
222
+ "name" => "Summary",
223
+ "key" => "summary" },
224
+ "customfield_10081" =>
225
+ { "schema" =>
226
+ { "type" => "date",
227
+ "custom" =>
228
+ "com.atlassian.jira.plugin.system.customfieldtypes:datepicker",
229
+ "customId" => 10_081 },
230
+ "name" => "Expected Start",
231
+ "key" => "customfield_10081" },
232
+ "customfield_10082" =>
233
+ { "schema" =>
234
+ { "type" => "option",
235
+ "custom" =>
236
+ "com.atlassian.jira.plugin.system.customfieldtypes:select",
237
+ "customId" => 10_082 },
238
+ "name" => "Implementation Team",
239
+ "key" => "customfield_10082",
240
+ "allowedValues" =>
241
+ [{ "value" => "A16 CRM", "id" => "10044" },
242
+ { "value" => "A16 E2E-Test", "id" => "10045" },
243
+ { "value" => "A16 Logistic", "id" => "10048" },
244
+ { "value" => "A16 Platform", "id" => "10046" },
245
+ { "value" => "A16 Sys-Team", "id" => "10047" }] },
246
+ "customfield_10020" =>
247
+ { "schema" =>
248
+ { "type" => "array",
249
+ "items" => "json",
250
+ "custom" => "com.pyxis.greenhopper.jira:gh-sprint",
251
+ "customId" => 10_020 },
252
+ "name" => "Sprint",
253
+ "key" => "customfield_10020" },
254
+ "customfield_10001" =>
255
+ { "schema" =>
256
+ { "type" => "team",
257
+ "custom" =>
258
+ "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team",
259
+ "customId" => 10_001,
260
+ "configuration" =>
261
+ { "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team" =>
262
+ true } },
263
+ "name" => "Team",
264
+ "key" => "customfield_10001" },
265
+ "environment" =>
266
+ { "schema" => { "type" => "string", "system" => "environment" },
267
+ "name" => "Environment",
268
+ "key" => "environment" } } },
269
+ { "id" => "10000",
270
+ "name" => "Epic",
271
+ "untranslatedName" => "Epic",
272
+ "subtask" => false,
273
+ "fields" =>
274
+ { "summary" =>
275
+ { "schema" => { "type" => "string", "system" => "summary" },
276
+ "name" => "Summary",
277
+ "key" => "summary" },
278
+ "customfield_10081" =>
279
+ { "schema" =>
280
+ { "type" => "date",
281
+ "custom" =>
282
+ "com.atlassian.jira.plugin.system.customfieldtypes:datepicker",
283
+ "customId" => 10_081 },
284
+ "name" => "Expected Start",
285
+ "key" => "customfield_10081" },
286
+ "customfield_10082" =>
287
+ { "schema" =>
288
+ { "type" => "option",
289
+ "custom" =>
290
+ "com.atlassian.jira.plugin.system.customfieldtypes:select",
291
+ "customId" => 10_082 },
292
+ "name" => "Implementation Team",
293
+ "key" => "customfield_10082",
294
+ "allowedValues" =>
295
+ [{ "value" => "A16 CRM", "id" => "10044" },
296
+ { "value" => "A16 E2E-Test", "id" => "10045" },
297
+ { "value" => "A16 Logistic", "id" => "10048" },
298
+ { "value" => "A16 Platform", "id" => "10046" },
299
+ { "value" => "A16 Sys-Team", "id" => "10047" }] },
300
+ "customfield_10020" =>
301
+ { "schema" =>
302
+ { "type" => "array",
303
+ "items" => "json",
304
+ "custom" => "com.pyxis.greenhopper.jira:gh-sprint",
305
+ "customId" => 10_020 },
306
+ "name" => "Sprint",
307
+ "key" => "customfield_10020" },
308
+ "customfield_10001" =>
309
+ { "schema" =>
310
+ { "type" => "team",
311
+ "custom" =>
312
+ "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team",
313
+ "customId" => 10_001,
314
+ "configuration" =>
315
+ { "com.atlassian.jira.plugin.system.customfieldtypes:atlassian-team" =>
316
+ true } },
317
+ "name" => "Team",
318
+ "key" => "customfield_10001" } } }] })]
319
+ end
320
+
321
+ let(:expected_table_rows) do
322
+ [
323
+ ["Bug", "customfield_10001", "Team", "team", "n/a"],
324
+ ["Bug", "customfield_10020", "Sprint", "array", "n/a"],
325
+ ["Bug", "customfield_10081", "Expected Start", "date", "n/a"],
326
+ ["Bug", "customfield_10082", "Implementation Team", "option",
327
+ ["A16 CRM (10044)",
328
+ "A16 E2E-Test (10045)",
329
+ "A16 Logistic (10048)",
330
+ "A16 Platform (10046)",
331
+ "A16 Sys-Team (10047)"]],
332
+ ["Bug", "environment", "Environment", "string", "n/a"],
333
+ ["Bug", "summary", "Summary", "string", "n/a"],
334
+ ["Epic", "customfield_10001", "Team", "team", "n/a"],
335
+ ["Epic", "customfield_10020", "Sprint", "array", "n/a"],
336
+ ["Epic", "customfield_10081", "Expected Start", "date", "n/a"],
337
+ ["Epic", "customfield_10082", "Implementation Team", "option",
338
+ ["A16 CRM (10044)",
339
+ "A16 E2E-Test (10045)",
340
+ "A16 Logistic (10048)",
341
+ "A16 Platform (10046)",
342
+ "A16 Sys-Team (10047)"]],
343
+ ["Epic", "summary", "Summary", "string", "n/a"],
344
+ ["Story", "customfield_10001", "Team", "team", "n/a"],
345
+ ["Story", "customfield_10020", "Sprint", "array", "n/a"],
346
+ ["Story", "customfield_10081", "Expected Start", "date", "n/a"],
347
+ ["Story", "customfield_10082", "Implementation Team", "option",
348
+ ["A16 CRM (10044)",
349
+ "A16 E2E-Test (10045)",
350
+ "A16 Logistic (10048)",
351
+ "A16 Platform (10046)",
352
+ "A16 Sys-Team (10047)"]],
353
+ ["Story", "summary", "Summary", "string", "n/a"],
354
+ ["Sub-task", "customfield_10001", "Team", "team", "n/a"],
355
+ ["Sub-task", "customfield_10020", "Sprint", "array", "n/a"],
356
+ ["Sub-task", "customfield_10081", "Expected Start", "date", "n/a"],
357
+ ["Sub-task", "customfield_10082", "Implementation Team", "option",
358
+ ["A16 CRM (10044)",
359
+ "A16 E2E-Test (10045)",
360
+ "A16 Logistic (10048)",
361
+ "A16 Platform (10046)",
362
+ "A16 Sys-Team (10047)"]],
363
+ ["Sub-task", "summary", "Summary", "string", "n/a"],
364
+ ["Task", "customfield_10001", "Team", "team", "n/a"],
365
+ ["Task", "customfield_10020", "Sprint", "array", "n/a"],
366
+ ["Task", "customfield_10081", "Expected Start", "date", "n/a"],
367
+ ["Task", "customfield_10082", "Implementation Team", "option",
368
+ ["A16 CRM (10044)",
369
+ "A16 E2E-Test (10045)",
370
+ "A16 Logistic (10048)",
371
+ "A16 Platform (10046)",
372
+ "A16 Sys-Team (10047)"]],
373
+ ["Task", "summary", "Summary", "string", "n/a"]
374
+ ]
375
+ end
376
+
377
+ before do
378
+ allow(tool).to receive_messages(jira_client: jira_client)
379
+ allow(jira_client).to receive_messages(Createmeta: createmeta)
380
+ end
381
+
382
+ it { expect(ticket_fields.table_rows).to eq(expected_table_rows) }
383
+ end
384
+ end
385
+ end
386
+ # rubocop:enable Metrics/ClassLength
387
+ end
388
+ end
389
+ end
390
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ require "jira/auto/tool/project"
6
+
7
+ module Jira
8
+ module Auto
9
+ class Tool
10
+ class Project
11
+ RSpec.describe Project do
12
+ let(:tool) { instance_double(Tool, jira_client: jira_client) }
13
+ let(:jira_client) { instance_double(JIRA::Client) }
14
+
15
+ describe ".find" do
16
+ let(:jira_project) { jira_resource_double(JIRA::Resource::Project, key: "project_key") }
17
+ let(:actual_end_date) { described_class.find(tool, "project_key") }
18
+
19
+ before do
20
+ allow(jira_client)
21
+ .to receive_messages(Project: jira_resource_double("project_query", find: jira_project))
22
+ end
23
+
24
+ it { expect(actual_end_date.key).to eq("project_key") }
25
+ it { expect(actual_end_date).to be_a(described_class) }
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "jira/auto/tool/rate_limited_jira_client"
4
+
5
+ module Jira
6
+ module Auto
7
+ class Tool
8
+ class RateLimitedJiraClient
9
+ RSpec.describe RateLimitedJiraClient do
10
+ describe "#request" do
11
+ let(:client) { described_class.new({}, rate_interval:, rate_limit:) }
12
+ let(:rate_interval) { 2 }
13
+ let(:rate_limit) { 1 }
14
+ let(:oauth_client) { instance_double(JIRA::OauthClient, request: nil, consumer: nil) }
15
+ let(:rate_limiter) { instance_double(Ratelimit) }
16
+
17
+ before do
18
+ allow(described_class).to receive_messages(rate_limiter: rate_limiter)
19
+
20
+ allow(JIRA::OauthClient).to receive_messages(new: oauth_client)
21
+
22
+ allow(client).to receive_messages(original_request: :response)
23
+
24
+ allow(rate_limiter).to receive_messages(add: nil)
25
+ allow(rate_limiter).to receive(:exec_within_threshold).and_yield
26
+ end
27
+
28
+ it "returns the response" do
29
+ expect(client.request(:get, "/path/to/resource")).to eq(:response)
30
+ end
31
+
32
+ it "calls the original request method" do
33
+ client.request(:get, "/path/to/resource")
34
+
35
+ expect(client).to have_received(:original_request).with(:get, "/path/to/resource")
36
+ end
37
+
38
+ context "when it leverages the rate limiter" do
39
+ it "uses :exec_within_threshold to control rate limiting" do
40
+ allow(rate_limiter).to receive_messages(exec_within_threshold: nil)
41
+
42
+ 4.times { client.request(:get, "/path/to/resource") }
43
+
44
+ expect(rate_limiter)
45
+ .to have_received(:exec_within_threshold)
46
+ .with("jira_auto_tool_api_requests", { interval: rate_interval, threshold: rate_limit })
47
+ .exactly(4).times
48
+ end
49
+
50
+ it "adds keeps track of the rate limiter key calls" do
51
+ allow(rate_limiter).to receive_messages(add: nil)
52
+
53
+ 4.times { client.request(:get, "/path/to/resource") }
54
+
55
+ expect(rate_limiter)
56
+ .to have_received(:add)
57
+ .with("jira_auto_tool_api_requests")
58
+ .exactly(4).times
59
+ end
60
+ end
61
+
62
+ context "when it does not leverage the rate limiter" do
63
+ let(:rate_limit) { 0 }
64
+
65
+ it "does not use :exec_within_threshold to control rate limiting" do
66
+ client.request(:get, "/path/to/resource")
67
+
68
+ expect(rate_limiter).not_to have_received(:exec_within_threshold)
69
+ end
70
+
71
+ it "calls the original request method" do
72
+ client.request(:get, "/path/to/resource")
73
+
74
+ expect(client).to have_received(:original_request).with(:get, "/path/to/resource")
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+ require "jira/auto/tool/request_builder/field_context_fetcher"
5
+
6
+ module Jira
7
+ module Auto
8
+ class Tool
9
+ class RequestBuilder
10
+ RSpec.describe FieldContextFetcher do
11
+ let(:field_context_fetcher) { described_class.new(jira_client, field) }
12
+
13
+ let(:field) do
14
+ instance_double(Field, jira_client: jira_client, name: "a field name", type: "option",
15
+ id: "customfield_10000")
16
+ end
17
+
18
+ let(:jira_client) do
19
+ instance_spy(JIRA::Client, options: { context_path: :a_context_path }).as_null_object
20
+ end
21
+
22
+ it do
23
+ expect(field_context_fetcher.send(:request_path))
24
+ .to eq("/rest/api/3/field/#{field.id}/context")
25
+ end
26
+
27
+ describe ".fetch_field_contexts" do
28
+ let(:id_name_pairs) do
29
+ [
30
+ [10_578, "a field context name"],
31
+ [10_792, "another field context name"],
32
+ [10_793, "yet another field context name"]
33
+ ]
34
+ end
35
+
36
+ let(:jira_field_contexts) { id_name_pairs.collect { |id, name| { "id" => id, "name" => name } } }
37
+
38
+ let(:actual_response) do
39
+ instance_double(Net::HTTPResponse, code: "200", body: { "values" => jira_field_contexts }.to_json)
40
+ end
41
+
42
+ let(:actual_field_contexts) { jira_field_contexts.collect(&:symbolize_keys) }
43
+
44
+ it "returns the actual field options" do
45
+ allow(jira_client).to receive_messages(send: actual_response)
46
+
47
+ expect(described_class.fetch_field_contexts(field)).to eq(actual_field_contexts)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+ require "jira/auto/tool/request_builder/field_option_fetcher"
5
+
6
+ module Jira
7
+ module Auto
8
+ class Tool
9
+ class RequestBuilder
10
+ RSpec.describe FieldOptionFetcher do
11
+ let(:field_option_fetcher) { described_class.new(jira_client, field, field_context) }
12
+ let(:jira_client) { instance_spy(JIRA::Client, options: { context_path: :a_context_path }).as_null_object }
13
+ let(:field_context) { { "id" => context_id, "name" => "a context name" }.symbolize_keys }
14
+
15
+ let(:field) do
16
+ instance_double(Field, jira_client: jira_client, name: "a field name", type: "option",
17
+ id: "customfield_10000")
18
+ end
19
+
20
+ let(:context_id) { "10567" }
21
+
22
+ before do
23
+ allow(FieldContextFetcher)
24
+ .to receive_messages(fetch_field_contexts: [field_context])
25
+ end
26
+
27
+ it do
28
+ expect(field_option_fetcher.send(:request_path))
29
+ .to eq("/rest/api/3/field/#{field.id}/context/#{context_id}/option")
30
+ end
31
+
32
+ # rubocop:disable RSpec/MultipleMemoizedHelpers
33
+ describe ".fetch_field_options" do
34
+ let(:id_value_pairs) do
35
+ [
36
+ ["option_id_128", "a field option value"],
37
+ ["option_id_256", "another field option value"],
38
+ ["option_id_512", "yet another field option value"]
39
+ ]
40
+ end
41
+
42
+ let(:jira_options) { id_value_pairs.collect { |id, value| { "id" => id, "value" => value } } }
43
+
44
+ let(:actual_response) do
45
+ instance_double(Net::HTTPResponse, code: "200", body: { "values" => jira_options }.to_json)
46
+ end
47
+
48
+ let(:actual_field_options) do
49
+ id_value_pairs.collect { |id, value| FieldOption.new(jira_client, id, value) }
50
+ end
51
+
52
+ it "returns the actual field options" do
53
+ allow(jira_client).to receive_messages(send: actual_response)
54
+ allow(field).to receive_messages(field_context: field_context)
55
+
56
+ expect(described_class.fetch_field_options(field)).to eq(actual_field_options)
57
+ end
58
+ end
59
+ # rubocop:enable RSpec/MultipleMemoizedHelpers
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end