ticket-replicator 0.1.1 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a75b95b01e3dcdc1937e0b795196c22c1bf351e856fe07880c2151b1c7f2eeee
4
- data.tar.gz: e5c1ab35f039f7e1e07bfe1ad06103053602f25a2c7f17273730b0383cc7f871
3
+ metadata.gz: 7606fa759b9d684b5f7ba6f51ae8492d0d75aa12f35aecf18dcacad00128d3ed
4
+ data.tar.gz: 31c447e651e6f1a3ee29f99d3ff5d82716f17ea2f26c0bcf99e120f73164695f
5
5
  SHA512:
6
- metadata.gz: 5c0923f1770341ee1e9c106c6073c60c7316bb58694069b9abffa5e023ed538d83a4a8af195050da47d9d664a8176adc5edaff7c03bea88c24b5e22869decf2c
7
- data.tar.gz: c15c602ec455f084eddcf051644e359783ff3ac2366aa4935233a97731d28c3731f2c31c540161d563be626e7c34237cde171975ffa5725d1eb436d7f8ae1bc9
6
+ metadata.gz: 83564cefebd76b731d4bf201bf85aa076f11ad69344d8d6bc81ff43677946bc7050318f57fea6528ecf222a203a815e28dd8120b5fd4d9a2feb610c8e00a0a66
7
+ data.tar.gz: 9c7e90104e65a3ad37316714715c18ef83280b0d27feb272d73f110aeeda7d5cb47d22aaeff8a4c901ebd714115c9ae38078bdd9a1696c66eb46652466d1120b
data/.rubocop.yml CHANGED
@@ -7,6 +7,9 @@ Metrics/BlockLength:
7
7
  AllowedMethods:
8
8
  - describe
9
9
 
10
+ Metrics/ClassLength:
11
+ Max: 150
12
+
10
13
  Style/Documentation:
11
14
  Enabled: false
12
15
 
@@ -20,35 +20,8 @@ status_mapping:
20
20
  defaults_to: keep_original_value
21
21
 
22
22
  resolution_mapping:
23
- defaults_to: keep_original_value
24
- "New":
25
- "Open":
26
- "In Process":
27
- "In Review":
28
- "On Hold":
29
- Deferred:
30
- Defect Correction in Process:
23
+ defaults_to: blank_value
31
24
  "Fixed": "Fixed"
32
25
  "Closed": "Done"
33
26
  "Rejected": "Won't Do"
34
27
  "Resolved": "Fixed"
35
- "Confirmed":
36
- "Forwarded":
37
- "Information Required":
38
- Wait for Defect Correction:
39
- Solution Proposal:
40
- Tester Action:
41
- Wait on External:
42
-
43
- team_mapping:
44
- defaults_to: keep_original_value
45
- "Frontend": "Web Team"
46
- "Backend": "Server Team"
47
- "Integration": "Integration Team"
48
- "Mobile": "Mobile Team"
49
- "Security": "Security Team"
50
- "DevOps": "DevOps Team"
51
- "QA": "Quality Assurance"
52
- "Architecture": "Architecture Team"
53
- "UX": "Design Team"
54
- "Performance": "Performance Team"
data/cucumber.yml CHANGED
@@ -4,4 +4,4 @@
4
4
  %>
5
5
  default: <%= shared_args %> --format pretty --tags ' <%= default_tags %>'
6
6
  guard: <%= shared_args %> --format rerun --out rerun_failures.txt --format progress --tags ' <%= default_tags %>'
7
- rake: <%= shared_args %> --format progress --tags 'not @wip'
7
+ rake: <%= shared_args %> --format progress --tags 'not @wip and <%= default_tags %>'
@@ -13,117 +13,117 @@ Feature: Load tickets into Jira
13
13
  Scenario: Load tickets in Jira
14
14
  Given a file named "queue/20.transformed/sap_solution_manager_defects.csv" with:
15
15
  """
16
- "ID","Status","Resolution","Priority","Team","Summary"
17
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
18
- "10002","In Process","","Highest","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
19
- "10003","Confirmed","Fixed","Medium","A16 Logistic","SMAN-10003 | Invalid date format in SOAP response (10003)"
20
- "10004","Closed","Done","Low","A16 Market","SMAN-10004 | App crashes when offline on Android 12 (10004)"
21
- "10005","Open","","High","A16 CRM","SMAN-10005 | Session tokens not properly invalidated (10005)"
22
- "10006","Solution Proposal","","Medium","A16 Supply","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
23
- "10007","Withdrawn","Won't Do","Low","A16 E2E-Test","SMAN-10007 | Test data missing edge case scenarios (10007)"
24
- "10008","Open","","Highest","A16 Markets","SMAN-10008 | Memory leak in caching implementation (10008)"
25
- "10009","Wait on External","","Medium","A16 Platform","SMAN-10009 | Inconsistent button styles across modules (10009)"
16
+ "ID","Status","Resolution","Priority","Summary"
17
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
18
+ "10002","In Process","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
19
+ "10003","Confirmed","Done","Medium","SMAN-10003 | Invalid date format in SOAP response (10003)"
20
+ "10004","Closed","Done","Low","SMAN-10004 | App crashes when offline on Android 12 (10004)"
21
+ "10005","Open","","High","SMAN-10005 | Session tokens not properly invalidated (10005)"
22
+ "10006","Solution Proposal","","Medium","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
23
+ "10007","Withdrawn","Won't Do","Low","SMAN-10007 | Test data missing edge case scenarios (10007)"
24
+ "10008","Open","","Highest","SMAN-10008 | Memory leak in caching implementation (10008)"
25
+ "10009","Wait on External","","Medium","SMAN-10009 | Inconsistent button styles across modules (10009)"
26
26
  """
27
27
  When I successfully run `ticket-replicator --load`
28
28
  Then the Jira project should only have the following tickets:
29
- | status | resolution | priority | team | summary | source ticket url |
30
- | Open | | Highest | A16 Restaurant | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
31
- | In Process | | Highest | A16 Platform | SMAN-10002 \| Database deadlock during order processing (10002) | https://sap.example/id/10002 |
32
- | Confirmed | Fixed | Medium | A16 Logistic | SMAN-10003 \| Invalid date format in SOAP response (10003) | https://sap.example/id/10003 |
33
- | Closed | Done | Low | A16 Market | SMAN-10004 \| App crashes when offline on Android 12 (10004) | https://sap.example/id/10004 |
34
- | Open | | High | A16 CRM | SMAN-10005 \| Session tokens not properly invalidated (10005) | https://sap.example/id/10005 |
35
- | Solution Proposal | | Medium | A16 Supply | SMAN-10006 \| Jenkins pipeline timeout on large builds (10006) | https://sap.example/id/10006 |
36
- | Withdrawn | Won't Do | Low | A16 E2E-Test | SMAN-10007 \| Test data missing edge case scenarios (10007) | https://sap.example/id/10007 |
37
- | Open | | Highest | A16 Markets | SMAN-10008 \| Memory leak in caching implementation (10008) | https://sap.example/id/10008 |
38
- | Wait on External | | Medium | A16 Platform | SMAN-10009 \| Inconsistent button styles across modules (10009) | https://sap.example/id/10009 |
29
+ | status | resolution | priority | summary | source ticket url |
30
+ | Open | | Highest | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
31
+ | In Process | | Highest | SMAN-10002 \| Database deadlock during order processing (10002) | https://sap.example/id/10002 |
32
+ | Confirmed | Done | Medium | SMAN-10003 \| Invalid date format in SOAP response (10003) | https://sap.example/id/10003 |
33
+ | Closed | Done | Low | SMAN-10004 \| App crashes when offline on Android 12 (10004) | https://sap.example/id/10004 |
34
+ | Open | | High | SMAN-10005 \| Session tokens not properly invalidated (10005) | https://sap.example/id/10005 |
35
+ | Solution Proposal | | Medium | SMAN-10006 \| Jenkins pipeline timeout on large builds (10006) | https://sap.example/id/10006 |
36
+ | Withdrawn | Won't Do | Low | SMAN-10007 \| Test data missing edge case scenarios (10007) | https://sap.example/id/10007 |
37
+ | Open | | Highest | SMAN-10008 \| Memory leak in caching implementation (10008) | https://sap.example/id/10008 |
38
+ | Wait on External | | Medium | SMAN-10009 \| Inconsistent button styles across modules (10009) | https://sap.example/id/10009 |
39
39
  And the source ticket URL is found in the ticket descriptions of those tickets
40
40
 
41
41
  Scenario: Loading the ticket information twice in Jira does not create additional tickets
42
42
  Given a file named "queue/20.transformed/sap_solution_manager_defects.csv" with:
43
43
  """
44
- "ID","Status","Resolution","Priority","Team","Summary"
45
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
46
- "10002","In Process","","Highest","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
44
+ "ID","Status","Resolution","Priority","Summary"
45
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
46
+ "10002","In Process","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
47
47
  """
48
48
  And a file named "queue/20.transformed/sap_solution_manager_defects.SAME_CONTENT.csv" with:
49
49
  """
50
- "ID","Status","Resolution","Priority","Team","Summary"
51
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
52
- "10002","In Process","","Highest","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
50
+ "ID","Status","Resolution","Priority","Summary"
51
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
52
+ "10002","In Process","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
53
53
  """
54
54
  When I successfully run `ticket-replicator --load`
55
55
  Then the Jira project should only have the following tickets:
56
- | status | resolution | priority | team | summary | source ticket url |
57
- | Open | | Highest | A16 Restaurant | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
58
- | In Process | | Highest | A16 Platform | SMAN-10002 \| Database deadlock during order processing (10002) | https://sap.example/id/10002 |
56
+ | status | resolution | priority | summary | source ticket url |
57
+ | Open | | Highest | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
58
+ | In Process | | Highest | SMAN-10002 \| Database deadlock during order processing (10002) | https://sap.example/id/10002 |
59
59
  And the source ticket URL is found in the ticket descriptions of those tickets
60
60
 
61
61
  Scenario: Tickets are updated only if changes happened or they were not replicated before
62
62
  Given a file named "queue/20.transformed/2025-03-29.16h16.sap_solution_manager_defects.csv" with:
63
63
  """
64
- "ID","Status","Resolution","Priority","Team","Summary"
65
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
66
- "10002","In Process","","Medium","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
67
- "10016","Confirmed","Fixed","High","Performance Team","SMAN-10016 | Slow response time on product search API (10016)"
64
+ "ID","Status","Resolution","Priority","Summary"
65
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
66
+ "10002","In Process","Cannot Reproduce","Medium","SMAN-10002 | Database deadlock during order processing (10002)"
67
+ "10016","Confirmed","Done","High","SMAN-10016 | Slow response time on product search API (10016)"
68
68
  """
69
69
  And I successfully run `ticket-replicator --load`
70
70
  When a file named "queue/20.transformed/2025-03-29.19h56.update_tickets.csv" with:
71
71
  """
72
- "ID","Status","Resolution","Priority","Team","Summary"
73
- "10001","Closed","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
74
- "10002","In Process","","High","A16 Platform","SMAN-10002 | *Recurring* database deadlock during order processing (10002)"
75
- "10008","Open","","Highest","A16 Markets","SMAN-10008 | Memory leak in caching implementation (10008)"
76
- "10016","Confirmed","Fixed","High","Performance Team","SMAN-10016 | Slow response time on product search API (10016)"
72
+ "ID","Status","Resolution","Priority","Summary"
73
+ "10001","Closed","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
74
+ "10002","In Process","","High","SMAN-10002 | *Recurring* database deadlock during order processing (10002)"
75
+ "10008","Open","","Highest","SMAN-10008 | Memory leak in caching implementation (10008)"
76
+ "10016","Confirmed","Done","High","SMAN-10016 | Slow response time on product search API (10016)"
77
77
  """
78
78
  And I successfully run `ticket-replicator --jira-http-debug --load`
79
79
  Then the Jira project should only have the following tickets:
80
- | example purpose | status | resolution | priority | team | summary | source ticket url |
81
- | one update due to status change | Closed | | Highest | A16 Restaurant | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
82
- | one update due to priority and summary updates | In Process | | High | A16 Platform | SMAN-10002 \| *Recurring* database deadlock during order processing (10002) | https://sap.example/id/10002 |
83
- | two updates due to new ticket created (fields and status changes) | Open | | Highest | A16 Markets | SMAN-10008 \| Memory leak in caching implementation (10008) | https://sap.example/id/10008 |
84
- | no update since no status or field change | Confirmed | Fixed | High | Performance Team | SMAN-10016 \| Slow response time on product search API (10016) | https://sap.example/id/10016 |
80
+ | example purpose | status | resolution | priority | summary | source ticket url |
81
+ | one update due to status change | Closed | | Highest | SMAN-10001 \| Login page randomly fails to load CSS assets (10001) | https://sap.example/id/10001 |
82
+ | one update due to priority, resolution and summary updates | In Process | | High | SMAN-10002 \| *Recurring* database deadlock during order processing (10002) | https://sap.example/id/10002 |
83
+ | two updates due to new ticket created (fields and status changes) | Open | | Highest | SMAN-10008 \| Memory leak in caching implementation (10008) | https://sap.example/id/10008 |
84
+ | no update since no status or field change | Confirmed | Done | High | SMAN-10016 \| Slow response time on product search API (10016) | https://sap.example/id/10016 |
85
85
  And only 4 Jira update requests were emitted
86
86
 
87
87
  Scenario: Attempting to set an unexpected status generates information about the current row being loaded
88
88
  Given a file named "queue/20.transformed/sap_solution_manager_defects.csv" with:
89
89
  """
90
- "ID","Status","Resolution","Priority","Team","Summary"
91
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
92
- "10002","In Process","","Highest","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
93
- "10003","Confirmed","Fixed","Medium","A16 Logistic","SMAN-10003 | Invalid date format in SOAP response (10003)"
94
- "10004","____ INEXISTING STATUS ____","Done","Low","A16 Market","SMAN-10004 | App crashes when offline on Android 12 (10004)"
95
- "10005","Open","","High","A16 CRM","SMAN-10005 | Session tokens not properly invalidated (10005)"
96
- "10006","Solution Proposal","","Medium","A16 Supply","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
97
- "10007","Withdrawn","Won't Do","Low","A16 E2E-Test","SMAN-10007 | Test data missing edge case scenarios (10007)"
98
- "10008","Open","","Highest","A16 Markets","SMAN-10008 | Memory leak in caching implementation (10008)"
99
- "10009","Wait on External","","Medium","A16 Platform","SMAN-10009 | Inconsistent button styles across modules (10009)"
90
+ "ID","Status","Resolution","Priority","Summary"
91
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
92
+ "10002","In Process","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
93
+ "10003","Confirmed","Done","Medium","SMAN-10003 | Invalid date format in SOAP response (10003)"
94
+ "10004","____ INEXISTING STATUS ____","Done","Low","SMAN-10004 | App crashes when offline on Android 12 (10004)"
95
+ "10005","Open","","High","SMAN-10005 | Session tokens not properly invalidated (10005)"
96
+ "10006","Solution Proposal","","Medium","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
97
+ "10007","Withdrawn","Won't Do","Low","SMAN-10007 | Test data missing edge case scenarios (10007)"
98
+ "10008","Open","","Highest","SMAN-10008 | Memory leak in caching implementation (10008)"
99
+ "10009","Wait on External","","Medium","SMAN-10009 | Inconsistent button styles across modules (10009)"
100
100
  """
101
101
  When I run `ticket-replicator --load`
102
102
  Then it should fail with:
103
103
  """
104
104
  ERROR Object : Ticket::Replicator::FileLoader::LoadError: queue/20.transformed/sap_solution_manager_defects.csv:5: error while loading row:
105
105
  No transition found for "____ INEXISTING STATUS ____" in ["No Error -> No Error", "Tester Action -> Tester Action", "Close Bug -> Closed", "Confirmed -> Confirmed", "Defect Correction in Process -> Defect Correction in Process", "Deferred -> Deferred", "Forwarded -> Forwarded", "Information Required -> Information Required", "New -> New", "Open -> Open", "Solution Proposal -> Solution Proposal", "Wait for Defect Correction -> Wait for Defect Correction", "Wait on External -> Wait on External", "Withdrawn -> Withdrawn", "In Process -> In Process"].:
106
- #<CSV::Row id:"10004" status:"____ INEXISTING STATUS ____" resolution:"Done" priority:"Low" team:"A16 Market" summary:"SMAN-10004 | App crashes when offline on Android 12 (10004)">
106
+ #<CSV::Row id:"10004" status:"____ INEXISTING STATUS ____" resolution:"Done" priority:"Low" summary:"SMAN-10004 | App crashes when offline on Android 12 (10004)">
107
107
  """
108
108
 
109
109
  Scenario: Attempting to set an unexpected priority generates information about the current row being loaded
110
110
  Given a file named "queue/20.transformed/sap_solution_manager_defects.csv" with:
111
111
  """
112
- "ID","Status","Resolution","Priority","Team","Summary"
113
- "10001","Open","","Highest","A16 Restaurant","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
114
- "10002","In Process","","Highest","A16 Platform","SMAN-10002 | Database deadlock during order processing (10002)"
115
- "10003","Confirmed","Fixed","Medium","A16 Logistic","SMAN-10003 | Invalid date format in SOAP response (10003)"
116
- "10004","Closed","Done","Low","A16 Market","SMAN-10004 | App crashes when offline on Android 12 (10004)"
117
- "10005","Open","","High","A16 CRM","SMAN-10005 | Session tokens not properly invalidated (10005)"
118
- "10006","Solution Proposal","","Medium","A16 Supply","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
119
- "10007","Withdrawn","Won't Do","Low","A16 E2E-Test","SMAN-10007 | Test data missing edge case scenarios (10007)"
120
- "10008","Open","","____ UNEXPECTED PRIORITY ____","A16 Markets","SMAN-10008 | Memory leak in caching implementation (10008)"
121
- "10009","Wait on External","","Medium","A16 Platform","SMAN-10009 | Inconsistent button styles across modules (10009)"
112
+ "ID","Status","Resolution","Priority","Summary"
113
+ "10001","Open","","Highest","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
114
+ "10002","In Process","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
115
+ "10003","Confirmed","Done","Medium","SMAN-10003 | Invalid date format in SOAP response (10003)"
116
+ "10004","Closed","Done","Low","SMAN-10004 | App crashes when offline on Android 12 (10004)"
117
+ "10005","Open","","High","SMAN-10005 | Session tokens not properly invalidated (10005)"
118
+ "10006","Solution Proposal","","Medium","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
119
+ "10007","Withdrawn","Won't Do","Low","SMAN-10007 | Test data missing edge case scenarios (10007)"
120
+ "10008","Open","","____ UNEXPECTED PRIORITY ____","SMAN-10008 | Memory leak in caching implementation (10008)"
121
+ "10009","Wait on External","","Medium","SMAN-10009 | Inconsistent button styles across modules (10009)"
122
122
  """
123
123
  When I run `ticket-replicator --load`
124
124
  Then it should fail with:
125
125
  """
126
126
  ERROR Object : Ticket::Replicator::FileLoader::LoadError: queue/20.transformed/sap_solution_manager_defects.csv:9: error while loading row:
127
127
  Bad Request:
128
- #<CSV::Row id:"10008" status:"Open" resolution:"" priority:"____ UNEXPECTED PRIORITY ____" team:"A16 Markets" summary:"SMAN-10008 | Memory leak in caching implementation (10008)">
128
+ #<CSV::Row id:"10008" status:"Open" resolution:"" priority:"____ UNEXPECTED PRIORITY ____" summary:"SMAN-10008 | Memory leak in caching implementation (10008)">
129
129
  """
@@ -36,38 +36,11 @@ Feature: Setup Ticket Replicator
36
36
  defaults_to: keep_original_value
37
37
 
38
38
  resolution_mapping:
39
- defaults_to: keep_original_value
40
- "New":
41
- "Open":
42
- "In Process":
43
- "In Review":
44
- "On Hold":
45
- Deferred:
46
- Defect Correction in Process:
39
+ defaults_to: blank_value
47
40
  "Fixed": "Fixed"
48
41
  "Closed": "Done"
49
42
  "Rejected": "Won't Do"
50
43
  "Resolved": "Fixed"
51
- "Confirmed":
52
- "Forwarded":
53
- "Information Required":
54
- Wait for Defect Correction:
55
- Solution Proposal:
56
- Tester Action:
57
- Wait on External:
58
-
59
- team_mapping:
60
- defaults_to: keep_original_value
61
- "Frontend": "Web Team"
62
- "Backend": "Server Team"
63
- "Integration": "Integration Team"
64
- "Mobile": "Mobile Team"
65
- "Security": "Security Team"
66
- "DevOps": "DevOps Team"
67
- "QA": "Quality Assurance"
68
- "Architecture": "Architecture Team"
69
- "UX": "Design Team"
70
- "Performance": "Performance Team"
71
44
  """
72
45
  And a directory named "queue/10.extracted" should exist
73
46
 
@@ -12,7 +12,7 @@ Given(/^the project has no tickets$/) do
12
12
  end
13
13
 
14
14
  Then(/^the Jira project should only have the following tickets:$/) do |table|
15
- keys = table.headers - ["example purpose", "source ticket url", "team", "resolution"]
15
+ keys = table.headers - ["example purpose", "source ticket url"]
16
16
 
17
17
  expected_tickets = table.hashes.map { |ticket| keys.collect { |key| ticket[key] } }.sort
18
18
 
@@ -39,57 +39,40 @@ Feature: Transform SAP tickets to Jira format
39
39
  "Confirmed": "Open"
40
40
 
41
41
  resolution_mapping:
42
- "New": ""
43
- "Open": ""
44
- "In Progress": ""
45
- "In Review": ""
46
- "On Hold": ""
47
- "Fixed": "Fixed"
42
+ "defaults_to": blank_value
43
+ "Fixed": "Done"
48
44
  "Closed": "Done"
49
45
  "Rejected": "Won't Do"
50
- "Resolved": "Fixed"
51
- "Confirmed": ""
52
-
53
- team_mapping:
54
- "Frontend": "Web Team"
55
- "Backend": "Server Team"
56
- "Integration": "Integration Team"
57
- "Mobile": "Mobile Team"
58
- "Security": "Security Team"
59
- "DevOps": "DevOps Team"
60
- "QA": "Quality Assurance"
61
- "Architecture": "Architecture Team"
62
- "UX": "Design Team"
63
- "Performance": "Performance Team"
46
+ "Resolved": "Done"
64
47
  """
65
48
  Given a file named "queue/10.extracted/sap_solution_manager_defects.csv" with:
66
49
  """
67
- "ID","Status","Priority","Team","Summary"
68
- "10001","New","2-High","Frontend","Login page randomly fails to load CSS assets (10001)"
69
- "10002","In Progress","1-Critical","Backend","Database deadlock during order processing (10002)"
70
- "10003","Resolved","3-Medium","Integration","Invalid date format in SOAP response (10003)"
71
- "10004","Closed","4-Low","Mobile","App crashes when offline on Android 12 (10004)"
72
- "10005","Open","2-High","Security","Session tokens not properly invalidated (10005)"
73
- "10006","In Review","3-Medium","DevOps","Jenkins pipeline timeout on large builds (10006)"
74
- "10007","Rejected","4-Low","QA","Test data missing edge case scenarios (10007)"
75
- "10008","Confirmed","1-Critical","Architecture","Memory leak in caching implementation (10008)"
76
- "10009","On Hold","3-Medium","UX","Inconsistent button styles across modules (10009)"
77
- "10010","Fixed","2-High","Performance","Slow response time on product search API (10010)"
50
+ "ID","Status","Priority","Summary"
51
+ "10001","New","2-High","Login page randomly fails to load CSS assets (10001)"
52
+ "10002","In Progress","1-Critical","Database deadlock during order processing (10002)"
53
+ "10003","Resolved","3-Medium","Invalid date format in SOAP response (10003)"
54
+ "10004","Closed","4-Low","App crashes when offline on Android 12 (10004)"
55
+ "10005","Open","2-High","Session tokens not properly invalidated (10005)"
56
+ "10006","In Review","3-Medium","Jenkins pipeline timeout on large builds (10006)"
57
+ "10007","Rejected","4-Low","Test data missing edge case scenarios (10007)"
58
+ "10008","Confirmed","1-Critical","Memory leak in caching implementation (10008)"
59
+ "10009","On Hold","3-Medium","Inconsistent button styles across modules (10009)"
60
+ "10010","Fixed","2-High","Slow response time on product search API (10010)"
78
61
  """
79
62
  When I successfully run `ticket-replicator --transform`
80
63
  Then a file named "queue/20.transformed/sap_solution_manager_defects.csv" should contain exactly:
81
64
  """
82
- "ID","Status","Resolution","Priority","Team","Summary"
83
- "10001","Open","","High","Web Team","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
84
- "10002","In Progress","","Highest","Server Team","SMAN-10002 | Database deadlock during order processing (10002)"
85
- "10003","Resolved","Fixed","Medium","Integration Team","SMAN-10003 | Invalid date format in SOAP response (10003)"
86
- "10004","Closed","Done","Low","Mobile Team","SMAN-10004 | App crashes when offline on Android 12 (10004)"
87
- "10005","Open","","High","Security Team","SMAN-10005 | Session tokens not properly invalidated (10005)"
88
- "10006","In Review","","Medium","DevOps Team","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
89
- "10007","Closed","Won't Do","Low","Quality Assurance","SMAN-10007 | Test data missing edge case scenarios (10007)"
90
- "10008","Open","","Highest","Architecture Team","SMAN-10008 | Memory leak in caching implementation (10008)"
91
- "10009","Blocked","","Medium","Design Team","SMAN-10009 | Inconsistent button styles across modules (10009)"
92
- "10010","Resolved","Fixed","High","Performance Team","SMAN-10010 | Slow response time on product search API (10010)"
65
+ "ID","Status","Resolution","Priority","Summary"
66
+ "10001","Open","","High","SMAN-10001 | Login page randomly fails to load CSS assets (10001)"
67
+ "10002","In Progress","","Highest","SMAN-10002 | Database deadlock during order processing (10002)"
68
+ "10003","Resolved","Done","Medium","SMAN-10003 | Invalid date format in SOAP response (10003)"
69
+ "10004","Closed","Done","Low","SMAN-10004 | App crashes when offline on Android 12 (10004)"
70
+ "10005","Open","","High","SMAN-10005 | Session tokens not properly invalidated (10005)"
71
+ "10006","In Review","","Medium","SMAN-10006 | Jenkins pipeline timeout on large builds (10006)"
72
+ "10007","Closed","Won't Do","Low","SMAN-10007 | Test data missing edge case scenarios (10007)"
73
+ "10008","Open","","Highest","SMAN-10008 | Memory leak in caching implementation (10008)"
74
+ "10009","Blocked","","Medium","SMAN-10009 | Inconsistent button styles across modules (10009)"
75
+ "10010","Resolved","Done","High","SMAN-10010 | Slow response time on product search API (10010)"
93
76
  """
94
77
 
95
78
  Scenario: Transform valid ticket Excel
@@ -113,38 +96,12 @@ Feature: Transform SAP tickets to Jira format
113
96
  defaults_to: keep_original_value
114
97
 
115
98
  resolution_mapping:
116
- defaults_to: keep_original_value
117
- "New":
118
- "Open":
119
- "In Process":
120
- "In Review":
121
- "On Hold":
122
- Deferred:
123
- Defect Correction in Process:
124
- "Fixed": "Fixed"
99
+ defaults_to: blank_value
100
+ "Fixed": "Done"
125
101
  "Closed": "Done"
126
102
  "Rejected": "Won't Do"
127
- "Resolved": "Fixed"
128
- "Confirmed":
129
- "Forwarded":
130
- "Information Required":
131
- Wait for Defect Correction:
132
- Solution Proposal:
133
- Tester Action:
134
- Wait on External:
135
-
136
- team_mapping:
137
- defaults_to: keep_original_value
138
- "Frontend": "Web Team"
139
- "Backend": "Server Team"
140
- "Integration": "Integration Team"
141
- "Mobile": "Mobile Team"
142
- "Security": "Security Team"
143
- "DevOps": "DevOps Team"
144
- "QA": "Quality Assurance"
145
- "Architecture": "Architecture Team"
146
- "UX": "Design Team"
147
- "Performance": "Performance Team"
103
+ "Resolved": "Done"
104
+ "Withdrawn": "Cannot Reproduce"
148
105
  """
149
106
  And an Excel file named "queue/10.extracted/sap_solution_manager_defects.xlsx"
150
107
  And it has a tab named "SAP Document Export" with the following rows:
@@ -170,24 +127,24 @@ Feature: Transform SAP tickets to Jira format
170
127
  When I successfully run `ticket-replicator --transform`
171
128
  Then a file named "queue/20.transformed/sap_solution_manager_defects.csv" should contain exactly:
172
129
  """
173
- "ID","Status","Resolution","Priority","Team","Summary"
174
- "3000017049","Closed","Done","Medium","A Team","SMAN-3000017049 | Summary"
175
- "9400011377","Confirmed","","Low","A Team","SMAN-9400011377 | Summary"
176
- "3000016618","Defect Correction in Process","","Medium","A Team","SMAN-3000016618 | Summary"
177
- "9400013805","Deferred","","Medium","A Team","SMAN-9400013805 | Summary"
178
- "9400013816","Forwarded","","High","A Team","SMAN-9400013816 | Summary"
179
- "9400011382","In Process","","Medium","A Team","SMAN-9400011382 | Summary"
180
- "9400011393","Information Required","","Medium","A Team","SMAN-9400011393 | Summary"
181
- "9400011381","New","","Medium","A Team","SMAN-9400011381 | Summary"
182
- "3000016617","No Error","No Error","Medium","A Team","SMAN-3000016617 | Summary"
183
- "9400011372","Open","","Highest","A Team","SMAN-9400011372 | Summary"
184
- "9400011403","Solution Proposal","","Medium","A Team","SMAN-9400011403 | Summary"
185
- "9400011380","Tester Action","","Medium","A Team","SMAN-9400011380 | Summary"
186
- "9400011705","Wait for Defect Correction","","Medium","A Team","SMAN-9400011705 | Summary"
187
- "9400011437","Wait on External","","Medium","A Team","SMAN-9400011437 | Summary"
188
- "9400011466","Withdrawn","Withdrawn","Medium","A Team","SMAN-9400011466 | Summary"
189
- "3000017667","Closed","Done","Medium","Another Team","SMAN-3000017667 | Summary"
190
- "3000018423","No Error","No Error","Medium","A Team","SMAN-3000018423 | Summary"
130
+ "ID","Status","Resolution","Priority","Summary"
131
+ "3000017049","Closed","Done","Medium","SMAN-3000017049 | Summary"
132
+ "9400011377","Confirmed","","Low","SMAN-9400011377 | Summary"
133
+ "3000016618","Defect Correction in Process","","Medium","SMAN-3000016618 | Summary"
134
+ "9400013805","Deferred","","Medium","SMAN-9400013805 | Summary"
135
+ "9400013816","Forwarded","","High","SMAN-9400013816 | Summary"
136
+ "9400011382","In Process","","Medium","SMAN-9400011382 | Summary"
137
+ "9400011393","Information Required","","Medium","SMAN-9400011393 | Summary"
138
+ "9400011381","New","","Medium","SMAN-9400011381 | Summary"
139
+ "3000016617","No Error","","Medium","SMAN-3000016617 | Summary"
140
+ "9400011372","Open","","Highest","SMAN-9400011372 | Summary"
141
+ "9400011403","Solution Proposal","","Medium","SMAN-9400011403 | Summary"
142
+ "9400011380","Tester Action","","Medium","SMAN-9400011380 | Summary"
143
+ "9400011705","Wait for Defect Correction","","Medium","SMAN-9400011705 | Summary"
144
+ "9400011437","Wait on External","","Medium","SMAN-9400011437 | Summary"
145
+ "9400011466","Withdrawn","Cannot Reproduce","Medium","SMAN-9400011466 | Summary"
146
+ "3000017667","Closed","Done","Medium","SMAN-3000017667 | Summary"
147
+ "3000018423","No Error","","Medium","SMAN-3000018423 | Summary"
191
148
  """
192
149
 
193
150
  Scenario: Processing an invalid Excel file generates an error with relevant information
@@ -213,9 +170,6 @@ Feature: Transform SAP tickets to Jira format
213
170
  resolution_mapping:
214
171
  defaults_to: keep_original_value
215
172
 
216
- team_mapping:
217
- defaults_to: keep_original_value
218
-
219
173
  """
220
174
  And a file named "queue/10.extracted/invalid_file.xlsx" with:
221
175
  """
@@ -249,10 +203,7 @@ Feature: Transform SAP tickets to Jira format
249
203
  defaults_to: keep_original_value
250
204
 
251
205
  resolution_mapping:
252
- defaults_to: keep_original_value
253
-
254
- team_mapping:
255
- defaults_to: keep_original_value
206
+ defaults_to: blank_value
256
207
 
257
208
  """
258
209
  And an Excel file named "queue/10.extracted/sap_solution_manager_defects_with_missing_priority_column.xlsx"
@@ -291,10 +242,7 @@ Feature: Transform SAP tickets to Jira format
291
242
  defaults_to: keep_original_value
292
243
 
293
244
  resolution_mapping:
294
- defaults_to: keep_original_value
295
-
296
- team_mapping:
297
- defaults_to: keep_original_value
245
+ defaults_to: blank_value
298
246
 
299
247
  """
300
248
  And an Excel file named "queue/10.extracted/sap_solution_manager_defects.xlsx"
@@ -28,38 +28,11 @@ Feature: Transform and load extracted ticket queue
28
28
  defaults_to: keep_original_value
29
29
 
30
30
  resolution_mapping:
31
- defaults_to: keep_original_value
32
- "New":
33
- "Open":
34
- "In Process":
35
- "In Review":
36
- "On Hold":
37
- Deferred:
38
- Defect Correction in Process:
39
- "Fixed": "Fixed"
31
+ defaults_to: blank_value
32
+ "Fixed": "Done"
40
33
  "Closed": "Done"
41
- "Rejected": "Won't Do"
42
- "Resolved": "Fixed"
43
- "Confirmed":
44
- "Forwarded":
45
- "Information Required":
46
- Wait for Defect Correction:
47
- Solution Proposal:
48
- Tester Action:
49
- Wait on External:
50
-
51
- team_mapping:
52
- defaults_to: keep_original_value
53
- "Frontend": "Web Team"
54
- "Backend": "Server Team"
55
- "Integration": "Integration Team"
56
- "Mobile": "Mobile Team"
57
- "Security": "Security Team"
58
- "DevOps": "DevOps Team"
59
- "QA": "Quality Assurance"
60
- "Architecture": "Architecture Team"
61
- "UX": "Design Team"
62
- "Performance": "Performance Team"
34
+ "Withdrawn": "Won't Do"
35
+ "Resolved": "Done"
63
36
  """
64
37
  And the project has no tickets
65
38
 
@@ -74,7 +47,7 @@ Feature: Transform and load extracted ticket queue
74
47
  | 9400013816 | Summary | 2: High | Forwarded | A Team |
75
48
  | 9400011382 | Summary | 3: Medium | In Process | A Team |
76
49
  | 9400011393 | Summary | 3: Medium | Information Required | A Team |
77
- | 9400011381 | Summary | 3: Medium | New | A Team |
50
+ | 9400011381 | Summary | 3: Medium | Withdrawn | A Team |
78
51
  | 3000016617 | Summary | 3: Medium | No Error | A Team |
79
52
  | 9400011372 | Summary | 1: Critical | Open | A Team |
80
53
  | 9400011466 | Summary | 3: Medium | Withdrawn | A Team |
@@ -84,20 +57,20 @@ Feature: Transform and load extracted ticket queue
84
57
  And the current date time is "2025-05-10 07:52:00 UTC"
85
58
  When I successfully run `ticket-replicator --ticket-queue-transform-and-load`
86
59
  Then the Jira project should only have the following tickets:
87
- | status | resolution | priority | team | summary | source ticket url |
88
- | Closed | Done | Medium | A Team | SMAN-3000017049 \| Summary | https://example.com/defect/3000017049 |
89
- | Confirmed | | Low | A Team | SMAN-9400011377 \| Summary | https://example.com/defect/9400011377 |
90
- | Defect Correction in Process | | Medium | A Team | SMAN-3000016618 \| Summary | https://example.com/defect/3000016618 |
91
- | Deferred | | Medium | A Team | SMAN-9400013805 \| Summary | https://example.com/defect/9400013805 |
92
- | Forwarded | | High | A Team | SMAN-9400013816 \| Summary | https://example.com/defect/9400013816 |
93
- | In Process | | Medium | A Team | SMAN-9400011382 \| Summary | https://example.com/defect/9400011382 |
94
- | Information Required | | Medium | A Team | SMAN-9400011393 \| Summary | https://example.com/defect/9400011393 |
95
- | New | | Medium | A Team | SMAN-9400011381 \| Summary | https://example.com/defect/9400011381 |
96
- | No Error | | Medium | A Team | SMAN-3000016617 \| Summary | https://example.com/defect/3000016617 |
97
- | Open | | Highest | A Team | SMAN-9400011372 \| Summary | https://example.com/defect/9400011372 |
98
- | Withdrawn | Won't Do | Medium | A Team | SMAN-9400011466 \| Summary | https://example.com/defect/9400011466 |
99
- | Closed | Done | Medium | Another Team | SMAN-3000017667 \| Summary | https://example.com/defect/3000017667 |
100
- | No Error | | Medium | A Team | SMAN-3000018423 \| Summary | https://example.com/defect/3000018423 |
60
+ | status | resolution | priority | summary | source ticket url |
61
+ | Closed | Done | Medium | SMAN-3000017049 \| Summary | https://example.com/defect/3000017049 |
62
+ | Confirmed | | Low | SMAN-9400011377 \| Summary | https://example.com/defect/9400011377 |
63
+ | Defect Correction in Process | | Medium | SMAN-3000016618 \| Summary | https://example.com/defect/3000016618 |
64
+ | Deferred | | Medium | SMAN-9400013805 \| Summary | https://example.com/defect/9400013805 |
65
+ | Forwarded | | High | SMAN-9400013816 \| Summary | https://example.com/defect/9400013816 |
66
+ | In Process | | Medium | SMAN-9400011382 \| Summary | https://example.com/defect/9400011382 |
67
+ | Information Required | | Medium | SMAN-9400011393 \| Summary | https://example.com/defect/9400011393 |
68
+ | Withdrawn | Won't Do | Medium | SMAN-9400011381 \| Summary | https://example.com/defect/9400011381 |
69
+ | No Error | | Medium | SMAN-3000016617 \| Summary | https://example.com/defect/3000016617 |
70
+ | Open | | Highest | SMAN-9400011372 \| Summary | https://example.com/defect/9400011372 |
71
+ | Withdrawn | Won't Do | Medium | SMAN-9400011466 \| Summary | https://example.com/defect/9400011466 |
72
+ | Closed | Done | Medium | SMAN-3000017667 \| Summary | https://example.com/defect/3000017667 |
73
+ | No Error | | Medium | SMAN-3000018423 \| Summary | https://example.com/defect/3000018423 |
101
74
  # TODO: And the source ticket URL is found in the ticket descriptions of those tickets
102
75
  And a file named "queue/30.archived/2025-05-10.07h52m00.sap_solution_manager_defects.xlsx" should exist
103
76
  And the file named "queue/10.extracted/sap_solution_manager_defects.xlsx" should not exist anymore
@@ -8,7 +8,7 @@ module Ticket
8
8
  class LoadError < StandardError; end
9
9
 
10
10
  def self.run_on(jira_project, file_path)
11
- log.info { "Loading #{file_path} into #{jira_project.project_key}..." }
11
+ log.debug { "Loading #{file_path} into #{jira_project.project_key}..." }
12
12
 
13
13
  new(jira_project, file_path).run
14
14
  end
@@ -30,6 +30,10 @@ module Ticket
30
30
  @ticket_type_name ||= ENV.fetch("TICKET_REPLICATOR_JIRA_TICKET_TYPE_NAME")
31
31
  end
32
32
 
33
+ def resolutions
34
+ @resolutions ||= jira_client.Resolution.all.to_h { |resolution| [resolution.name, resolution] }
35
+ end
36
+
33
37
  def replicated_tickets
34
38
  @replicated_tickets ||= all_replicated_ticket_pages.to_h { |ticket| [ticket.source_id, ticket] }
35
39
  end
@@ -27,6 +27,7 @@ module Ticket
27
27
  jira_project.replicated_tickets.key?(id)
28
28
  end
29
29
 
30
+ # rubocop:disable Metrics/MethodLength
30
31
  def save_ticket
31
32
  return unless ticket_fields_need_to_be_updated?
32
33
 
@@ -34,9 +35,8 @@ module Ticket
34
35
  fields: {
35
36
  project: { key: jira_project.project_key },
36
37
  issuetype: { name: jira_project.ticket_type_name },
37
- # resolution: { name: resolution },
38
+ resolution: jira_resolution_value,
38
39
  priority: { name: priority },
39
- # implementation_team: { name: team },
40
40
  summary: summary
41
41
  }
42
42
  })
@@ -44,6 +44,20 @@ module Ticket
44
44
  ticket.jira_ticket.fetch
45
45
  end
46
46
 
47
+ def jira_resolution_value
48
+ return if resolution.blank?
49
+ return { name: resolution } if jira_project.resolutions.key?(resolution)
50
+
51
+ log.warn do
52
+ "Setting resolution to unset since " \
53
+ "resolution #{resolution.inspect} not found in #{jira_project.resolutions.inspect}!"
54
+ end
55
+
56
+ nil
57
+ end
58
+
59
+ # rubocop:enable Metrics/MethodLength
60
+
47
61
  def ticket_fields_need_to_be_updated?
48
62
  !ticket_previously_replicated? || ticket_fields_changed?
49
63
  end
@@ -51,16 +51,18 @@ module Ticket
51
51
  end
52
52
 
53
53
  def self.fields_to_transform
54
- %i[ID Status Resolution Priority Team Summary]
54
+ %i[ID Status Resolution Priority Summary]
55
55
  end
56
56
 
57
57
  def mapped_value_for(field, extracted_value = remapped_field_extracted_value_for(field))
58
58
  mapping_for(field).fetch(extracted_value) do |key|
59
- unless mapping_for(field)["defaults_to"] == "keep_original_value"
59
+ case mapping_for(field)["defaults_to"]
60
+ when "keep_original_value" then extracted_value
61
+ when "unset_value" then nil
62
+ when "blank_value" then ""
63
+ else
60
64
  raise "No mapping found for #{field.inspect} = #{key.inspect} in #{mapping_for(field).inspect}"
61
65
  end
62
-
63
- extracted_value
64
66
  end
65
67
  end
66
68
 
@@ -57,6 +57,8 @@ module Ticket
57
57
  value.name
58
58
  elsif value.respond_to?(:value)
59
59
  value.value
60
+ elsif value.is_a?(Hash)
61
+ value.values_at("name", "value").compact.first
60
62
  else
61
63
  value.nil? ? "" : value.to_s
62
64
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Ticket
4
4
  class Replicator
5
- VERSION = "0.1.1"
5
+ VERSION = "1.0.0"
6
6
  end
7
7
  end
@@ -8,7 +8,7 @@ module Ticket
8
8
  RSpec.describe FileLoader do
9
9
  let(:loader) { described_class.send(:new, jira_project, "file.csv") }
10
10
  let(:jira_project) { instance_double(JiraProject) }
11
- let(:logger) { instance_double(Logger, info: nil) }
11
+ let(:logger) { instance_double(Logger, debug: nil) }
12
12
 
13
13
  describe ".run_on" do
14
14
  it "loads the given file" do
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Ticket
4
4
  class Replicator
5
- # rubocop:disable Metrics/ClassLength
6
5
  class FileReplicator
7
6
  RSpec.describe FileReplicator do
8
7
  let(:file_replicator) { described_class.send(:new, replicator, "extracted.csv") }
@@ -148,6 +147,5 @@ module Ticket
148
147
  end
149
148
  end
150
149
  end
151
- # rubocop:enable Metrics/ClassLength
152
150
  end
153
151
  end
@@ -43,7 +43,7 @@ module Ticket
43
43
 
44
44
  describe "#transformed_headers" do
45
45
  it "returns the headers" do
46
- expect(transformer.transformed_headers).to eq(%w[ID Status Resolution Priority Team Summary])
46
+ expect(transformer.transformed_headers).to eq(%w[ID Status Resolution Priority Summary])
47
47
  end
48
48
  end
49
49
 
@@ -28,6 +28,24 @@ module Ticket
28
28
  end
29
29
  end
30
30
 
31
+ describe "#resolutions" do
32
+ def build_resolution(name, id)
33
+ double(JIRA::Resource::Resolution, name: name, id: id)
34
+ end
35
+
36
+ let(:a_resolution) { build_resolution("a resolution", 1) }
37
+ let(:another_resolution) { build_resolution("another resolution", 2) }
38
+
39
+ let(:resolution_query) { double("jira_client.Resolution", all: [a_resolution, another_resolution]) }
40
+
41
+ before { allow(jira_client).to receive_messages(Resolution: resolution_query) }
42
+
43
+ it do
44
+ expect(project.resolutions)
45
+ .to eq({ "a resolution" => a_resolution, "another resolution" => another_resolution })
46
+ end
47
+ end
48
+
31
49
  describe "#ticket_type_name" do
32
50
  it do
33
51
  expect(ENV).to receive(:fetch).with("TICKET_REPLICATOR_JIRA_TICKET_TYPE_NAME").and_return("Ticket Type Name")
@@ -83,6 +101,7 @@ module Ticket
83
101
  build_expected_ticket("5", "SMAN-5 | a summary")
84
102
  ]
85
103
  end
104
+
86
105
  let(:actual_tickets) do
87
106
  [
88
107
  build_non_replicated_ticket("a non replicated ticket"),
@@ -20,7 +20,7 @@ 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 team summary]) }
23
+ it { expect(described_class.fields_to_load).to eq(%i[id status resolution priority summary]) }
24
24
  end
25
25
 
26
26
  describe "#run" do
@@ -56,6 +56,49 @@ module Ticket
56
56
  end
57
57
  end
58
58
 
59
+ describe "#jira_resolution_value" do
60
+ let(:loader) { described_class.send(:new, jira_project, row) }
61
+ let(:row) { { resolution: actual_resolution } }
62
+ let(:logger) { instance_double(Logger, info: nil) }
63
+ let(:resolutions) { { "Done" => double(id: "10004"), "Won't Fix" => double(id: "10005") } }
64
+
65
+ let(:jira_resolution_value) { loader.send(:jira_resolution_value) }
66
+
67
+ before do
68
+ allow(jira_project).to receive(:resolutions).and_return(resolutions)
69
+ allow(loader).to receive(:log).and_return(logger)
70
+ end
71
+
72
+ context "when the resolution is not set" do
73
+ let(:actual_resolution) { nil }
74
+ it { expect(jira_resolution_value).to be_nil }
75
+ end
76
+
77
+ context "when the resolution is an empty string" do
78
+ let(:actual_resolution) { "" }
79
+ it { expect(jira_resolution_value).to be_nil }
80
+ end
81
+
82
+ context "when the resolution is set to an existing value" do
83
+ let(:actual_resolution) { "Done" }
84
+ it { expect(jira_resolution_value).to eq({ name: "Done" }) }
85
+ end
86
+
87
+ context "when the resolution is set to an unknown value" do
88
+ let(:actual_resolution) { "an unknown resolution #{rand}" }
89
+
90
+ it do
91
+ expect(logger).to receive(:warn) do |&block|
92
+ expect(block.call)
93
+ .to eq("Setting resolution to unset " \
94
+ "since resolution #{actual_resolution.inspect} not found in #{resolutions.inspect}!")
95
+ end
96
+
97
+ expect(jira_resolution_value).to be_nil
98
+ end
99
+ end
100
+ end
101
+
59
102
  describe "#fetch_ticket" do
60
103
  let(:loader) { described_class.send(:new, jira_project, { id: "123" }) }
61
104
 
@@ -92,7 +135,8 @@ module Ticket
92
135
  let(:loader) { described_class.send(:new, jira_project, row) }
93
136
 
94
137
  let(:row) do
95
- { id: "123", priority: "Low", resolution: "", status: "Open", summary: "PREFIX | summary", team: "A Team" }
138
+ { id: "123", priority: "Low", resolution: "Done", status: "Open", summary: "PREFIX | summary",
139
+ team: "A Team" }
96
140
  end
97
141
 
98
142
  let(:ticket) { instance_double(Ticket, jira_ticket: jira_ticket) }
@@ -100,8 +144,15 @@ module Ticket
100
144
  let(:jira_ticket) { double(JIRA::Resource::Issue) }
101
145
 
102
146
  before do
103
- allow(loader).to receive_messages(ticket: ticket,
104
- :ticket_fields_need_to_be_updated? => ticket_fields_need_to_be_updated?)
147
+ allow(loader).to receive_messages(
148
+ ticket: ticket,
149
+ :ticket_fields_need_to_be_updated? => ticket_fields_need_to_be_updated?
150
+ )
151
+
152
+ allow(jira_project)
153
+ .to receive_messages(resolutions: {
154
+ "Done" => nil, "Won't Do" => nil, "Duplicate" => nil, "Cannot Reproduce" => nil
155
+ })
105
156
  end
106
157
 
107
158
  context "when the previously replicated needs to be updated " do
@@ -112,9 +163,8 @@ module Ticket
112
163
  fields: {
113
164
  project: { key: "PROJKEY" },
114
165
  issuetype: { name: "Bug" },
115
- # resolution: { name: "" },
166
+ resolution: { name: "Done" },
116
167
  priority: { name: "Low" },
117
- # team: { name: "A Team" },
118
168
  summary: "PREFIX | summary"
119
169
  }
120
170
  })
@@ -37,7 +37,7 @@ RSpec.describe Ticket::Replicator::RowTransformer do
37
37
  allow(transformer).to receive(:transformed_summary).and_return("transformed summary (123)")
38
38
 
39
39
  expect(transformer.run)
40
- .to eq(["123", "Open", "", "Low", "Transformed Team", "transformed summary (123)"])
40
+ .to eq(["123", "Open", "", "Low", "transformed summary (123)"])
41
41
  end
42
42
  end
43
43
 
@@ -92,7 +92,7 @@ RSpec.describe Ticket::Replicator::RowTransformer do
92
92
  {
93
93
  "field_mapping" => {
94
94
  "id" => "Defect", "priority" => "Defect Priority", "resolution" => "Defect (2)",
95
- "status" => "Defect status", "summary" => "Defect (2)", "team" => "Defect Team (2)"
95
+ "status" => "Defect status", "summary" => "Defect (2)"
96
96
  }
97
97
  }
98
98
  end
@@ -107,7 +107,7 @@ RSpec.describe Ticket::Replicator::RowTransformer do
107
107
  it do
108
108
  expect(transformer.remapped_field_extracted_row)
109
109
  .to eq({ "id" => "123", "priority" => "High", "resolution" => "a summary",
110
- "status" => "Open", "summary" => "a summary", "team" => "system team" })
110
+ "status" => "Open", "summary" => "a summary" })
111
111
  end
112
112
  end
113
113
 
@@ -155,7 +155,19 @@ RSpec.describe Ticket::Replicator::RowTransformer do
155
155
  it { expect(transformed_value).to eq(an_original_value) }
156
156
  end
157
157
 
158
- context "when the status is unexpected" do
158
+ context "when defaulting to unset value" do
159
+ let(:mappings) { { "#{field_name}_mapping" => { "defaults_to" => "unset_value" } } }
160
+
161
+ it { expect(transformed_value).to eq(nil) }
162
+ end
163
+
164
+ context "when defaulting to blank value" do
165
+ let(:mappings) { { "#{field_name}_mapping" => { "defaults_to" => "blank_value" } } }
166
+
167
+ it { expect(transformed_value).to eq("") }
168
+ end
169
+
170
+ context "when the value is unexpected" do
159
171
  let(:mappings) do
160
172
  { "#{field_name}_mapping" => { "extracted value" => "transformed value" } }
161
173
  end
@@ -238,7 +238,28 @@ module Ticket
238
238
  ticket.transition_to("Testing")
239
239
  end
240
240
  end
241
+
242
+ describe "#sanitize" do
243
+ let(:expectations) do
244
+ [
245
+ ["value as name attribute", double(name: "value as name attribute")],
246
+ ["value as value attribute", double(value: "value as value attribute")],
247
+ ["value from name entry in hash", { "name" => "value from name entry in hash" }],
248
+ ["value from value entry in hash", { "value" => "value from value entry in hash" }],
249
+ ["value as a string", "value as a string"],
250
+ ["125", 125],
251
+ ["object as a string", double(to_s: "object as a string")],
252
+ ["", nil]
253
+ ]
254
+ end
255
+
256
+ it do
257
+ expectations.each do |expected_sanitized_value, value|
258
+ expect(ticket.send(:sanitize, value)).to eq(expected_sanitized_value)
259
+ end
260
+ end
261
+ end
241
262
  end
242
263
  end
243
- # rubocop:enable Metrics/ClassLength
244
264
  end
265
+ # rubocop:enable Metrics/ClassLength
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ticket-replicator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christophe Broult