ticket-replicator 1.0.0 → 1.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.
@@ -20,12 +20,13 @@ module Ticket
20
20
  end
21
21
 
22
22
  describe ".fields_to_load" do
23
- it { expect(described_class.fields_to_load).to eq(%i[id status resolution priority summary]) }
23
+ it { expect(described_class.fields_to_load).to eq(%i[id status resolution priority summary source_ticket_url]) }
24
24
  end
25
25
 
26
26
  describe "#run" do
27
27
  it do
28
28
  expect(loader).to receive(:save_ticket)
29
+ expect(loader).to receive(:update_source_ticket_remote_link)
29
30
  expect(loader).to receive(:transition_ticket_to_the_expected_status)
30
31
 
31
32
  loader.run
@@ -41,7 +42,7 @@ module Ticket
41
42
  it do
42
43
  expect(loader).to receive(:create_ticket)
43
44
 
44
- loader.ticket
45
+ loader.send(:ticket)
45
46
  end
46
47
  end
47
48
 
@@ -51,7 +52,7 @@ module Ticket
51
52
  it do
52
53
  expect(loader).to receive(:fetch_ticket)
53
54
 
54
- loader.ticket
55
+ loader.send(:ticket)
55
56
  end
56
57
  end
57
58
  end
@@ -107,7 +108,7 @@ module Ticket
107
108
  it do
108
109
  expect(jira_project).to receive(:replicated_tickets).and_return(replicated_tickets)
109
110
 
110
- expect(loader.fetch_ticket).to be(:a_ticket)
111
+ expect(loader.send(:fetch_ticket)).to be(:a_ticket)
111
112
  end
112
113
  end
113
114
 
@@ -127,7 +128,7 @@ module Ticket
127
128
  expect(issue_accessor).to receive(:build).and_return(jira_ticket)
128
129
  expect(Ticket).to receive(:new).with(jira_auto_tool, jira_ticket).and_return(:ticket)
129
130
 
130
- expect(loader.create_ticket).to eq(:ticket)
131
+ expect(loader.send(:create_ticket)).to eq(:ticket)
131
132
  end
132
133
  end
133
134
 
@@ -148,26 +149,14 @@ module Ticket
148
149
  ticket: ticket,
149
150
  :ticket_fields_need_to_be_updated? => ticket_fields_need_to_be_updated?
150
151
  )
151
-
152
- allow(jira_project)
153
- .to receive_messages(resolutions: {
154
- "Done" => nil, "Won't Do" => nil, "Duplicate" => nil, "Cannot Reproduce" => nil
155
- })
156
152
  end
157
153
 
158
154
  context "when the previously replicated needs to be updated " do
159
155
  let(:ticket_fields_need_to_be_updated?) { true }
160
156
 
161
157
  it do
162
- expect(jira_ticket).to receive(:save!).with({
163
- fields: {
164
- project: { key: "PROJKEY" },
165
- issuetype: { name: "Bug" },
166
- resolution: { name: "Done" },
167
- priority: { name: "Low" },
168
- summary: "PREFIX | summary"
169
- }
170
- })
158
+ allow(loader).to receive_messages(attributes_for_save: { fields: { a: "b" } })
159
+ expect(jira_ticket).to receive(:save!).with({ fields: { a: "b" } })
171
160
 
172
161
  expect(jira_ticket).to receive(:fetch)
173
162
 
@@ -187,6 +176,95 @@ module Ticket
187
176
  end
188
177
  end
189
178
 
179
+ describe "#attributes_for_save" do
180
+ let(:loader) { described_class.send(:new, jira_project, row) }
181
+
182
+ let(:row) do
183
+ { id: "123", priority: "Low", resolution: "Done", status: "Open", summary: "PREFIX | summary",
184
+ team: "A Team" }
185
+ end
186
+
187
+ before do
188
+ allow(jira_project)
189
+ .to receive_messages(resolutions: {
190
+ "Done" => nil, "Won't Do" => nil, "Duplicate" => nil, "Cannot Reproduce" => nil
191
+ })
192
+
193
+ allow(loader).to receive_messages(exclude_resolution?: exclude_resolution?)
194
+ end
195
+
196
+ context "when the resolution is not excluded" do
197
+ let(:exclude_resolution?) { false }
198
+
199
+ it do
200
+ expect(loader.send(:attributes_for_save)).to eq({
201
+ fields: {
202
+ project: { key: "PROJKEY" },
203
+ issuetype: { name: "Bug" },
204
+ priority: { name: "Low" },
205
+ resolution: { name: "Done" },
206
+ summary: "PREFIX | summary"
207
+ }
208
+ })
209
+ end
210
+ end
211
+
212
+ context "when excluding the resolution" do
213
+ let(:exclude_resolution?) { true }
214
+
215
+ it do
216
+ expect(loader.send(:attributes_for_save)).to eq({
217
+ fields: {
218
+ project: { key: "PROJKEY" },
219
+ issuetype: { name: "Bug" },
220
+ priority: { name: "Low" },
221
+ summary: "PREFIX | summary"
222
+ }
223
+ })
224
+ end
225
+ end
226
+ end
227
+
228
+ describe "#exclude_resolution?" do
229
+ before { allow(ENV).to receive(:[]).with("TICKET_REPLICATOR_DISABLE_RESOLUTION_LOADING").and_return(env_value) }
230
+
231
+ context "when the environment variable is not set to true" do
232
+ let(:env_value) { nil }
233
+
234
+ it { expect(loader.send(:exclude_resolution?)).to be_falsey }
235
+ end
236
+
237
+ context "when the environment variable is set to true" do
238
+ let(:env_value) { "true" }
239
+
240
+ it { expect(loader.send(:exclude_resolution?)).to be_truthy }
241
+ end
242
+ end
243
+
244
+ describe "#build_ticket_link_attributes" do
245
+ it "builds the link attributes with a default application" do
246
+ expect(described_class.send(:build_ticket_link_attributes,
247
+ "https://url/to/source/ticket/123", "Source Ticket 123"))
248
+ .to eq({ "object" => { "url" => "https://url/to/source/ticket/123", "title" => "Source Ticket 123" },
249
+ "application" => { "name" => "Ticket Source" } })
250
+ end
251
+
252
+ it "builds the link attributes with a custom application" do
253
+ expect(described_class.send(:build_ticket_link_attributes,
254
+ "https://url/to/source/ticket/123", "Source Ticket 123",
255
+ "A custom application"))
256
+ .to eq({ "object" => { "url" => "https://url/to/source/ticket/123", "title" => "Source Ticket 123" },
257
+ "application" => { "name" => "A custom application" } })
258
+ end
259
+
260
+ it "builds the link attributes with no application" do
261
+ expect(described_class.send(:build_ticket_link_attributes,
262
+ "https://url/to/source/ticket/123", "Source Ticket 123",
263
+ nil))
264
+ .to eq({ "object" => { "url" => "https://url/to/source/ticket/123", "title" => "Source Ticket 123" } })
265
+ end
266
+ end
267
+
190
268
  describe "#ticket_fields_need_to_be_updated?" do
191
269
  before do
192
270
  allow(loader).to receive_messages(ticket_previously_replicated?: ticket_previously_replicated?,
@@ -197,21 +275,21 @@ module Ticket
197
275
  let(:ticket_previously_replicated?) { false }
198
276
  let(:ticket_fields_changed?) { false }
199
277
 
200
- it { expect(loader.ticket_fields_need_to_be_updated?).to be_truthy }
278
+ it { expect(loader.send(:ticket_fields_need_to_be_updated?)).to be_truthy }
201
279
  end
202
280
 
203
281
  context "when the fields changed since last replication" do
204
282
  let(:ticket_previously_replicated?) { true }
205
283
  let(:ticket_fields_changed?) { true }
206
284
 
207
- it { expect(loader.ticket_fields_need_to_be_updated?).to be_truthy }
285
+ it { expect(loader.send(:ticket_fields_need_to_be_updated?)).to be_truthy }
208
286
  end
209
287
 
210
288
  context "when the fields did not change since last replication" do
211
289
  let(:ticket_previously_replicated?) { true }
212
290
  let(:ticket_fields_changed?) { false }
213
291
 
214
- it { expect(loader.ticket_fields_need_to_be_updated?).to be_falsey }
292
+ it { expect(loader.send(:ticket_fields_need_to_be_updated?)).to be_falsey }
215
293
  end
216
294
  end
217
295
 
@@ -221,75 +299,227 @@ module Ticket
221
299
  end
222
300
 
223
301
  let(:loader) { described_class.send(:new, jira_project, row) }
224
- let(:jira_ticket) { double(JIRA::Resource::Issue, summary: current_summary, priority: current_priority) }
302
+
303
+ let(:jira_ticket) do
304
+ double(JIRA::Resource::Issue,
305
+ summary: current_summary,
306
+ priority: current_priority,
307
+ resolution: current_resolution)
308
+ end
225
309
 
226
310
  before do
227
311
  expect(loader).to receive(:ticket).at_least(:once).and_return(jira_ticket)
228
312
  end
229
313
 
230
- context "when both summary and priority changed" do
314
+ context "when summary, priority and resolution changed" do
231
315
  let(:current_summary) { "PREFIX | different summary" }
232
316
  let(:current_priority) { "High" }
317
+ let(:current_resolution) { "Won't Do" }
233
318
 
234
- it { expect(loader.ticket_fields_changed?).to be_truthy }
319
+ it { expect(loader.send(:ticket_fields_changed?)).to be_truthy }
235
320
  end
236
321
 
237
322
  context "when only summary changed" do
238
323
  let(:current_summary) { "PREFIX | different summary" }
239
324
  let(:current_priority) { "Low" }
325
+ let(:current_resolution) { "" }
240
326
 
241
- it { expect(loader.ticket_fields_changed?).to be_truthy }
327
+ it { expect(loader.send(:ticket_fields_changed?)).to be_truthy }
242
328
  end
243
329
 
244
330
  context "when only priority changed" do
245
331
  let(:current_summary) { "PREFIX | summary" }
246
332
  let(:current_priority) { "High" }
333
+ let(:current_resolution) { "" }
247
334
 
248
- it { expect(loader.ticket_fields_changed?).to be_truthy }
335
+ it { expect(loader.send(:ticket_fields_changed?)).to be_truthy }
336
+ end
337
+
338
+ context "when only resolution changed" do
339
+ let(:current_summary) { "PREFIX | summary" }
340
+ let(:current_priority) { "Low" }
341
+ let(:current_resolution) { "Done" }
342
+
343
+ before do
344
+ allow(loader).to receive_messages(exclude_resolution?: exclude_resolution?)
345
+ end
346
+
347
+ context "when the resolution is not excluded" do
348
+ let(:exclude_resolution?) { false }
349
+
350
+ it { expect(loader.send(:ticket_fields_changed?)).to be_truthy }
351
+ end
352
+
353
+ context "when excluding the resolution" do
354
+ let(:exclude_resolution?) { true }
355
+
356
+ it { expect(loader.send(:ticket_fields_changed?)).to be_falsey }
357
+ end
249
358
  end
250
359
 
251
360
  context "when neither summary nor priority changed" do
252
361
  let(:current_summary) { "PREFIX | summary" }
253
362
  let(:current_priority) { "Low" }
363
+ let(:current_resolution) { "" }
254
364
 
255
- it { expect(loader.ticket_fields_changed?).to be_falsey }
365
+ it { expect(loader.send(:ticket_fields_changed?)).to be_falsey }
256
366
  end
257
367
  end
258
368
 
259
369
  describe "#ticket_previously_replicated?" do
260
370
  let(:loader) { described_class.send(:new, jira_project, row) }
261
- let(:replicated_tickets) { { "123" => "a_ticket" } }
371
+ let(:replicated_tickets) { { "123" => "a_ticket", "880" => "another_ticket" } }
262
372
 
263
373
  before { expect(jira_project).to receive(:replicated_tickets).and_return(replicated_tickets) }
264
374
 
265
375
  context "when previously replicated" do
266
376
  let(:row) { { id: "123" } }
267
377
 
268
- it { expect(loader.ticket_previously_replicated?).to be_truthy }
378
+ it { expect(loader.send(:ticket_previously_replicated?)).to be_truthy }
269
379
  end
270
380
 
271
381
  context "when previously replicated" do
272
382
  let(:row) { { id: "456" } }
273
383
 
274
- it { expect(loader.ticket_previously_replicated?).to be_falsey }
384
+ it { expect(loader.send(:ticket_previously_replicated?)).to be_falsey }
275
385
  end
276
386
  end
277
387
 
278
- describe "#transition_ticket_to_the_expected_status" do
388
+ # rubocop:disable Metrics/BlockLength
389
+ context "when caring for the source ticket link" do
390
+ def build_link(url, title, application_name = "Ticket Source")
391
+ RowLoader.build_ticket_link_attributes(url, title, application_name)
392
+ end
393
+
279
394
  let(:loader) { described_class.send(:new, jira_project, row) }
280
- let(:row) { { id: "123", status: "Testing" } }
395
+ let(:row) { { id: "123", source_ticket_url: "https://url/to/source/ticket/123" } }
396
+ let(:ticket) { instance_double(Ticket, jira_ticket: jira_ticket) }
397
+ let(:jira_ticket) { double(JIRA::Resource::Issue, remotelink: double(build: remotelink)) }
398
+ let(:remotelink) { instance_double(JIRA::Resource::Remotelink) }
281
399
 
282
- let(:ticket) { double(Ticket) }
400
+ before { allow(loader).to receive_messages(ticket: ticket) }
283
401
 
284
- it do
285
- expect(loader).to receive(:ticket).at_least(:once).and_return(ticket)
286
- expect(ticket).to receive(:transition_to).with("Testing")
402
+ let(:expected_link) { build_link("https://url/to/source/ticket/123", "Source Ticket 123") }
403
+
404
+ describe "#source_ticket_link_title" do
405
+ it { expect(loader.send(:source_ticket_link_title)).to eq("Source Ticket 123") }
406
+ end
407
+
408
+ describe "#update_source_ticket_remote_link" do
409
+ before do
410
+ allow(loader).to receive_messages(source_ticket_link_needs_update?: needs_update)
411
+ end
412
+
413
+ context "when the link does not exist" do
414
+ let(:needs_update) { true }
415
+
416
+ before { allow(ticket).to receive_messages(source_ticket_link: nil) }
417
+
418
+ it "setups the link" do
419
+ expect(remotelink).to receive(:save!).with(expected_link)
420
+
421
+ loader.send(:update_source_ticket_remote_link)
422
+ end
423
+ end
424
+
425
+ context "when the link needs to be updated" do
426
+ let(:needs_update) { true }
427
+ let(:source_ticket_link) { instance_double(JIRA::Resource::Remotelink) }
428
+
429
+ before { allow(ticket).to receive_messages(source_ticket_link: source_ticket_link) }
430
+
431
+ it "deletes the previous link and creates a new one" do
432
+ expect(source_ticket_link).to receive(:delete)
433
+ expect(remotelink).to receive(:save!).with(expected_link)
434
+
435
+ loader.send(:update_source_ticket_remote_link)
436
+ end
437
+ end
438
+
439
+ context "when the link does not need to be updated" do
440
+ let(:needs_update) { false }
441
+
442
+ it "no link creation happens" do
443
+ expect(remotelink).not_to receive(:save!)
287
444
 
288
- loader.transition_ticket_to_the_expected_status
445
+ loader.send(:update_source_ticket_remote_link)
446
+ end
447
+ end
448
+ end
449
+
450
+ describe "#source_ticket_link_needs_update?" do
451
+ before do
452
+ allow(ticket).to receive_messages(source_ticket_link: remote_link)
453
+ end
454
+
455
+ context "when link has yet to be created" do
456
+ let(:remote_link) { nil }
457
+
458
+ it { expect(loader.send(:source_ticket_link_needs_update?)).to be_truthy }
459
+ end
460
+
461
+ context "when link already exists" do
462
+ let(:remote_link) do
463
+ instance_double(JIRA::Resource::Remotelink,
464
+ attrs: source_ticket_link,
465
+ inspect: "<JIRA::Resource::Remotelink attrs: #{source_ticket_link}>")
466
+ end
467
+
468
+ context "when the link is not up to date" do
469
+ let(:source_ticket_link) { build_link(existing_url, existing_title) }
470
+
471
+ context "when url has changed" do
472
+ let(:existing_url) { "https://__OLD_URL__/to/source/ticket/1234" }
473
+ let(:existing_title) { "Source Ticket 123" }
474
+
475
+ it { expect(loader.send(:source_ticket_link_needs_update?)).to be_truthy }
476
+ end
477
+
478
+ context "when title has changed" do
479
+ let(:existing_url) { "https://url/to/source/ticket/123" }
480
+ let(:existing_title) { "__OLD TITLE__Source Ticket 1234" }
481
+
482
+ it { expect(loader.send(:source_ticket_link_needs_update?)).to be_truthy }
483
+ end
484
+ end
485
+
486
+ context "when the link is up to date" do
487
+ let(:existing_url) { "https://url/to/source/ticket/123" }
488
+ let(:existing_title) { "Source Ticket 123" }
489
+ let(:source_ticket_link) do
490
+ { "object" => {
491
+ "url" => "https://url/to/source/ticket/123",
492
+ "title" => "Source Ticket 123",
493
+ "icon" => { "title" => "link", "url16x16" => "https://url/to/source/ticket/123/icon" }
494
+ },
495
+ "application" => { "name" => "Ticket Source" },
496
+ "extra_attributes" =>
497
+ { "id" => 10_443, "self" => "https://url/to/source/ticket/123/remotelink/10443" } }
498
+ end
499
+
500
+ it("only checks the needed attributes") {
501
+ expect(loader.send(:source_ticket_link_needs_update?)).to be_falsey
502
+ }
503
+ end
504
+ end
505
+ end
506
+ # rubocop:enable Metrics/BlockLength
507
+
508
+ describe "#transition_ticket_to_the_expected_status" do
509
+ let(:loader) { described_class.send(:new, jira_project, row) }
510
+ let(:row) { { id: "123", status: "Testing" } }
511
+
512
+ let(:ticket) { double(Ticket) }
513
+
514
+ it do
515
+ expect(loader).to receive(:ticket).at_least(:once).and_return(ticket)
516
+ expect(ticket).to receive(:transition_to).with("Testing")
517
+
518
+ loader.send(:transition_ticket_to_the_expected_status)
519
+ end
289
520
  end
290
521
  end
291
522
  end
523
+ # rubocop:enable Metrics/ClassLength
292
524
  end
293
-
294
- # rubocop:enable Metrics/ClassLength
295
525
  end