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 +4 -4
- data/.rubocop.yml +3 -0
- data/config/examples/ticket-replicator.mappings.yml +1 -28
- data/cucumber.yml +1 -1
- data/features/load_tickets_in_jira.feature +65 -65
- data/features/setup_ticket_replicator.feature +1 -28
- data/features/step_definitions/load_tickets_in_jira_steps.rb +1 -1
- data/features/transform-solution-manager-tickets-into-jira-loadable-tickets.feature +49 -101
- data/features/transform_and_load_extracted_ticket_queue.feature +19 -46
- data/lib/ticket/replicator/file_loader.rb +1 -1
- data/lib/ticket/replicator/jira_project.rb +4 -0
- data/lib/ticket/replicator/row_loader.rb +16 -2
- data/lib/ticket/replicator/row_transformer.rb +6 -4
- data/lib/ticket/replicator/ticket.rb +2 -0
- data/lib/ticket/replicator/version.rb +1 -1
- data/spec/ticket/replicator/file_loader_spec.rb +1 -1
- data/spec/ticket/replicator/file_replicator_spec.rb +0 -2
- data/spec/ticket/replicator/file_transformer_spec.rb +1 -1
- data/spec/ticket/replicator/jira_project_spec.rb +19 -0
- data/spec/ticket/replicator/row_loader_spec.rb +56 -6
- data/spec/ticket/replicator/row_transformer_spec.rb +16 -4
- data/spec/ticket/replicator/ticket_spec.rb +22 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7606fa759b9d684b5f7ba6f51ae8492d0d75aa12f35aecf18dcacad00128d3ed
|
4
|
+
data.tar.gz: 31c447e651e6f1a3ee29f99d3ff5d82716f17ea2f26c0bcf99e120f73164695f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83564cefebd76b731d4bf201bf85aa076f11ad69344d8d6bc81ff43677946bc7050318f57fea6528ecf222a203a815e28dd8120b5fd4d9a2feb610c8e00a0a66
|
7
|
+
data.tar.gz: 9c7e90104e65a3ad37316714715c18ef83280b0d27feb272d73f110aeeda7d5cb47d22aaeff8a4c901ebd714115c9ae38078bdd9a1696c66eb46652466d1120b
|
data/.rubocop.yml
CHANGED
@@ -20,35 +20,8 @@ status_mapping:
|
|
20
20
|
defaults_to: keep_original_value
|
21
21
|
|
22
22
|
resolution_mapping:
|
23
|
-
defaults_to:
|
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","
|
17
|
-
"10001","Open","","Highest","
|
18
|
-
"10002","In Process","","Highest","
|
19
|
-
"10003","Confirmed","
|
20
|
-
"10004","Closed","Done","Low","
|
21
|
-
"10005","Open","","High","
|
22
|
-
"10006","Solution Proposal","","Medium","
|
23
|
-
"10007","Withdrawn","Won't Do","Low","
|
24
|
-
"10008","Open","","Highest","
|
25
|
-
"10009","Wait on External","","Medium","
|
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 |
|
30
|
-
| Open | | Highest |
|
31
|
-
| In Process | | Highest |
|
32
|
-
| Confirmed |
|
33
|
-
| Closed | Done | Low |
|
34
|
-
| Open | | High |
|
35
|
-
| Solution Proposal | | Medium |
|
36
|
-
| Withdrawn | Won't Do | Low |
|
37
|
-
| Open | | Highest |
|
38
|
-
| Wait on External | | Medium |
|
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","
|
45
|
-
"10001","Open","","Highest","
|
46
|
-
"10002","In Process","","Highest","
|
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","
|
51
|
-
"10001","Open","","Highest","
|
52
|
-
"10002","In Process","","Highest","
|
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 |
|
57
|
-
| Open | | Highest |
|
58
|
-
| In Process | | Highest |
|
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","
|
65
|
-
"10001","Open","","Highest","
|
66
|
-
"10002","In Process","","Medium","
|
67
|
-
"10016","Confirmed","
|
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","
|
73
|
-
"10001","Closed","","Highest","
|
74
|
-
"10002","In Process","","High","
|
75
|
-
"10008","Open","","Highest","
|
76
|
-
"10016","Confirmed","
|
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 |
|
81
|
-
| one update due to status change | Closed | | Highest |
|
82
|
-
| one update due to priority and summary updates
|
83
|
-
| two updates due to new ticket created (fields and status changes) | Open | | Highest |
|
84
|
-
| no update since no status or field change | Confirmed |
|
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","
|
91
|
-
"10001","Open","","Highest","
|
92
|
-
"10002","In Process","","Highest","
|
93
|
-
"10003","Confirmed","
|
94
|
-
"10004","____ INEXISTING STATUS ____","Done","Low","
|
95
|
-
"10005","Open","","High","
|
96
|
-
"10006","Solution Proposal","","Medium","
|
97
|
-
"10007","Withdrawn","Won't Do","Low","
|
98
|
-
"10008","Open","","Highest","
|
99
|
-
"10009","Wait on External","","Medium","
|
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"
|
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","
|
113
|
-
"10001","Open","","Highest","
|
114
|
-
"10002","In Process","","Highest","
|
115
|
-
"10003","Confirmed","
|
116
|
-
"10004","Closed","Done","Low","
|
117
|
-
"10005","Open","","High","
|
118
|
-
"10006","Solution Proposal","","Medium","
|
119
|
-
"10007","Withdrawn","Won't Do","Low","
|
120
|
-
"10008","Open","","____ UNEXPECTED PRIORITY ____","
|
121
|
-
"10009","Wait on External","","Medium","
|
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 ____"
|
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:
|
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"
|
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
|
-
"
|
43
|
-
"
|
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": "
|
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","
|
68
|
-
"10001","New","2-High","
|
69
|
-
"10002","In Progress","1-Critical","
|
70
|
-
"10003","Resolved","3-Medium","
|
71
|
-
"10004","Closed","4-Low","
|
72
|
-
"10005","Open","2-High","
|
73
|
-
"10006","In Review","3-Medium","
|
74
|
-
"10007","Rejected","4-Low","
|
75
|
-
"10008","Confirmed","1-Critical","
|
76
|
-
"10009","On Hold","3-Medium","
|
77
|
-
"10010","Fixed","2-High","
|
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","
|
83
|
-
"10001","Open","","High","
|
84
|
-
"10002","In Progress","","Highest","
|
85
|
-
"10003","Resolved","
|
86
|
-
"10004","Closed","Done","Low","
|
87
|
-
"10005","Open","","High","
|
88
|
-
"10006","In Review","","Medium","
|
89
|
-
"10007","Closed","Won't Do","Low","
|
90
|
-
"10008","Open","","Highest","
|
91
|
-
"10009","Blocked","","Medium","
|
92
|
-
"10010","Resolved","
|
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:
|
117
|
-
"
|
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": "
|
128
|
-
"
|
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","
|
174
|
-
"3000017049","Closed","Done","Medium","
|
175
|
-
"9400011377","Confirmed","","Low","
|
176
|
-
"3000016618","Defect Correction in Process","","Medium","
|
177
|
-
"9400013805","Deferred","","Medium","
|
178
|
-
"9400013816","Forwarded","","High","
|
179
|
-
"9400011382","In Process","","Medium","
|
180
|
-
"9400011393","Information Required","","Medium","
|
181
|
-
"9400011381","New","","Medium","
|
182
|
-
"3000016617","No Error","
|
183
|
-
"9400011372","Open","","Highest","
|
184
|
-
"9400011403","Solution Proposal","","Medium","
|
185
|
-
"9400011380","Tester Action","","Medium","
|
186
|
-
"9400011705","Wait for Defect Correction","","Medium","
|
187
|
-
"9400011437","Wait on External","","Medium","
|
188
|
-
"9400011466","Withdrawn","
|
189
|
-
"3000017667","Closed","Done","Medium","
|
190
|
-
"3000018423","No Error","
|
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:
|
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:
|
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:
|
32
|
-
"
|
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
|
-
"
|
42
|
-
"Resolved": "
|
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 |
|
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 |
|
88
|
-
| Closed | Done | Medium |
|
89
|
-
| Confirmed | | Low |
|
90
|
-
| Defect Correction in Process | | Medium |
|
91
|
-
| Deferred | | Medium |
|
92
|
-
| Forwarded | | High |
|
93
|
-
| In Process | | Medium |
|
94
|
-
| Information Required | | Medium |
|
95
|
-
|
|
96
|
-
| No Error | | Medium |
|
97
|
-
| Open | | Highest |
|
98
|
-
| Withdrawn | Won't Do | Medium |
|
99
|
-
| Closed | Done | Medium |
|
100
|
-
| No Error | | Medium |
|
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.
|
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
|
-
|
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
|
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
|
-
|
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
|
|
@@ -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,
|
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
|
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
|
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",
|
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(
|
104
|
-
|
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
|
-
|
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", "
|
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)"
|
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"
|
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
|
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
|