ticket-replicator 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +20 -0
  4. data/CHANGELOG.md +5 -0
  5. data/CODE_OF_CONDUCT.md +132 -0
  6. data/Guardfile +158 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +136 -0
  9. data/Rakefile +23 -0
  10. data/bin/ticket-replicator +67 -0
  11. data/config/examples/ticket-replicator.mappings.yml +54 -0
  12. data/cucumber.yml +7 -0
  13. data/features/extract-sap-solution-manager-defect-tickets.feature +45 -0
  14. data/features/load_tickets_in_jira.feature +129 -0
  15. data/features/setup_ticket_replicator.feature +85 -0
  16. data/features/step_definitions/anonymized_sample.xlsx +0 -0
  17. data/features/step_definitions/anonymized_sample.xlsx:Zone.Identifier +3 -0
  18. data/features/step_definitions/execution_context_steps.rb +13 -0
  19. data/features/step_definitions/extract_defect_tickets_from_sap_solution_manager_steps.rb.rb +29 -0
  20. data/features/step_definitions/load_tickets_in_jira_steps.rb +47 -0
  21. data/features/step_definitions/transform_solution_manager_tickets_steps.rb +21 -0
  22. data/features/support/10.setup_cucumber.rb +10 -0
  23. data/features/support/env.rb +15 -0
  24. data/features/support/hooks.rb +13 -0
  25. data/features/support/manage_mock_sap_solution_manager.rb.DISABLED +12 -0
  26. data/features/support/mocks/mock_defect_ticket_server.rb.DISABLED +251 -0
  27. data/features/support/setup_rspec.rb +15 -0
  28. data/features/support/setup_simplecov.rb +5 -0
  29. data/features/transform-solution-manager-tickets-into-jira-loadable-tickets.feature +313 -0
  30. data/features/transform_and_load_extracted_ticket_queue.feature +121 -0
  31. data/lib/tasks/version.rake +55 -0
  32. data/lib/ticket/replicator/defect_export_automation.rb.DISABLED +128 -0
  33. data/lib/ticket/replicator/file_loader.rb +46 -0
  34. data/lib/ticket/replicator/file_replicator.rb +67 -0
  35. data/lib/ticket/replicator/file_transformer/for_csv.rb +22 -0
  36. data/lib/ticket/replicator/file_transformer/for_xlsx.rb +34 -0
  37. data/lib/ticket/replicator/file_transformer.rb +70 -0
  38. data/lib/ticket/replicator/jira_project.rb +65 -0
  39. data/lib/ticket/replicator/replicated_summary.rb +73 -0
  40. data/lib/ticket/replicator/row_loader.rb +109 -0
  41. data/lib/ticket/replicator/row_transformer.rb +126 -0
  42. data/lib/ticket/replicator/s_a_p_solution_manager_client.rb.DISABLED +169 -0
  43. data/lib/ticket/replicator/setup.rb +49 -0
  44. data/lib/ticket/replicator/ticket.rb +70 -0
  45. data/lib/ticket/replicator/ticket_status_transitioner.rb +45 -0
  46. data/lib/ticket/replicator/version.rb +7 -0
  47. data/lib/ticket/replicator.rb +90 -0
  48. data/sig/ticket/replicator.rbs +6 -0
  49. data/spec/spec_helper.rb +19 -0
  50. data/spec/ticket/replicator/file_loader_spec.rb +77 -0
  51. data/spec/ticket/replicator/file_replicator_spec.rb +153 -0
  52. data/spec/ticket/replicator/file_transformer/for_csv_spec.rb +52 -0
  53. data/spec/ticket/replicator/file_transformer/for_xlsx_spec.rb +52 -0
  54. data/spec/ticket/replicator/file_transformer_spec.rb +83 -0
  55. data/spec/ticket/replicator/jira_project_spec.rb +127 -0
  56. data/spec/ticket/replicator/replicated_summary_spec.rb +70 -0
  57. data/spec/ticket/replicator/row_loader_spec.rb +245 -0
  58. data/spec/ticket/replicator/row_transformer_spec.rb +234 -0
  59. data/spec/ticket/replicator/setup_spec.rb +80 -0
  60. data/spec/ticket/replicator/ticket_spec.rb +244 -0
  61. data/spec/ticket/replicator/ticket_status_transitioner_spec.rb +123 -0
  62. data/spec/ticket/replicator_spec.rb +137 -0
  63. data/transformed_file1 +1 -0
  64. metadata +235 -0
@@ -0,0 +1,251 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "sinatra"
4
+ require "json"
5
+ require "securerandom"
6
+ require "csv"
7
+
8
+ # Store mock data in memory
9
+ class MockDataStore
10
+ @instance = new
11
+
12
+ private_class_method :new
13
+
14
+ class << self
15
+ attr_reader :instance
16
+ end
17
+
18
+ def initialize
19
+ @defect_tickets = {}
20
+ seed_sample_data
21
+ end
22
+
23
+ def seed_sample_data
24
+ # Create some initial sample defect tickets
25
+ 5.times do |i|
26
+ id = "DEFECT-#{1000 + i}"
27
+ @defect_tickets[id] = {
28
+ ticket_id: id,
29
+ status: %w[NEW IN_PROGRESS RESOLVED CLOSED].sample,
30
+ priority: %w[LOW MEDIUM HIGH CRITICAL].sample,
31
+ description: "Sample defect ticket #{i + 1}",
32
+ created_at: Time.now - (rand(10) * 86_400), # Random days ago
33
+ modified_at: Time.now - (rand(5) * 86_400),
34
+ assigned_to: %w[USER1 USER2 USER3].sample,
35
+ components: %w[UI Backend Database].sample(rand(1..3)),
36
+ customer_id: "CUST-#{rand(100..999)}"
37
+ }
38
+ end
39
+ end
40
+
41
+ def all_tickets
42
+ @defect_tickets.values
43
+ end
44
+
45
+ def find_ticket(id)
46
+ @defect_tickets[id]
47
+ end
48
+
49
+ def create_ticket(attributes)
50
+ id = "DEFECT-#{1000 + @defect_tickets.size}"
51
+ ticket = {
52
+ ticket_id: id,
53
+ created_at: Time.now,
54
+ modified_at: Time.now
55
+ }.merge(attributes)
56
+
57
+ @defect_tickets[id] = ticket
58
+ ticket
59
+ end
60
+
61
+ def update_ticket(id, attributes)
62
+ return nil unless @defect_tickets[id]
63
+
64
+ @defect_tickets[id] = @defect_tickets[id].merge(attributes)
65
+ @defect_tickets[id][:modified_at] = Time.now
66
+ @defect_tickets[id]
67
+ end
68
+
69
+ def delete_ticket(id)
70
+ @defect_tickets.delete(id)
71
+ end
72
+
73
+ def search_tickets(params)
74
+ result = @defect_tickets.values
75
+
76
+ # Filter by status if provided
77
+ result = result.select { |t| t[:status] == params[:status] } if params[:status]
78
+
79
+ # Filter by priority if provided
80
+ result = result.select { |t| t[:priority] == params[:priority] } if params[:priority]
81
+
82
+ # Filter by assigned_to if provided
83
+ result = result.select { |t| t[:assigned_to] == params[:assigned_to] } if params[:assigned_to]
84
+
85
+ # Filter by component if provided
86
+ result = result.select { |t| t[:components]&.include?(params[:component]) } if params[:component]
87
+
88
+ # Filter by customer_id if provided
89
+ result = result.select { |t| t[:customer_id] == params[:customer_id] } if params[:customer_id]
90
+
91
+ result
92
+ end
93
+ end
94
+
95
+ # Configure Sinatra
96
+ configure do
97
+ set :bind, "0.0.0.0"
98
+ set :port, 4567
99
+ set :show_exceptions, false
100
+ end
101
+
102
+ # Error handling
103
+ error do
104
+ content_type :json
105
+ status :internal_server_error
106
+
107
+ { error: env["sinatra.error"].message }.to_json
108
+ end
109
+
110
+ # Authentication middleware (simulates SAP authentication)
111
+ before do
112
+ # Skip authentication for the auth endpoint itself
113
+ return if request.path_info == "/api/auth"
114
+
115
+ auth_token = request.env["HTTP_AUTHORIZATION"]&.split&.last
116
+
117
+ # Simple token validation (in a real app, you'd validate against a token store)
118
+ if auth_token.nil? || auth_token != "valid_mock_token"
119
+ halt :unauthorized, { error: "Unauthorized. Please provide valid authentication token." }.to_json
120
+ end
121
+ end
122
+
123
+ # Authentication endpoint
124
+ post "/api/auth" do
125
+ content_type :json
126
+
127
+ data = JSON.parse(request.body.read, symbolize_names: true)
128
+
129
+ if data[:username] == "test_user" && data[:password] == "test_password"
130
+ { token: "valid_mock_token", expires_at: (Time.now + 3600).iso8601 }.to_json
131
+ else
132
+ status :unauthorized
133
+ { error: "Invalid credentials" }.to_json
134
+ end
135
+ end
136
+
137
+ # Endpoints for defect tickets
138
+
139
+ # Get all tickets with optional filtering
140
+ get "/api/defect_tickets" do
141
+ content_type :json
142
+
143
+ tickets = MockDataStore.instance.search_tickets(params)
144
+ { tickets: tickets, total: tickets.size }.to_json
145
+ end
146
+
147
+ # Get a specific ticket
148
+ get "/api/defect_tickets/:id" do
149
+ content_type :json
150
+
151
+ ticket = MockDataStore.instance.find_ticket(params[:id])
152
+
153
+ if ticket
154
+ ticket.to_json
155
+ else
156
+ status :not_found
157
+ { error: "Ticket #{params[:id]} not found" }.to_json
158
+ end
159
+ end
160
+
161
+ # Create a new ticket
162
+ post "/api/defect_tickets" do
163
+ content_type :json
164
+
165
+ begin
166
+ data = JSON.parse(request.body.read, symbolize_names: true)
167
+
168
+ # Validate required fields
169
+ required_fields = %i[description status priority]
170
+ missing_fields = required_fields.select { |field| data[field].nil? || data[field].to_s.strip.empty? }
171
+
172
+ unless missing_fields.empty?
173
+ status :bad_request
174
+ return { error: "Missing required fields: #{missing_fields.join(", ")}" }.to_json
175
+ end
176
+
177
+ ticket = MockDataStore.instance.create_ticket(data)
178
+ status :created
179
+ ticket.to_json
180
+ rescue JSON::ParserError
181
+ status :bad_request
182
+ { error: "Invalid JSON format" }.to_json
183
+ end
184
+ end
185
+
186
+ # Update an existing ticket
187
+ put "/api/defect_tickets/:id" do
188
+ content_type :json
189
+
190
+ begin
191
+ data = JSON.parse(request.body.read, symbolize_names: true)
192
+ ticket = MockDataStore.instance.update_ticket(params[:id], data)
193
+
194
+ if ticket
195
+ ticket.to_json
196
+ else
197
+ status Sinatra::HTTP_STATUS_CODES[:not_found]
198
+ { error: "Ticket #{params[:id]} not found" }.to_json
199
+ end
200
+ rescue JSON::ParserError
201
+ status :bad_request
202
+ { error: "Invalid JSON format" }.to_json
203
+ end
204
+ end
205
+
206
+ # Delete a ticket
207
+ delete "/api/defect_tickets/:id" do
208
+ content_type :json
209
+
210
+ if MockDataStore.instance.find_ticket(params[:id])
211
+ MockDataStore.instance.delete_ticket(params[:id])
212
+ status :no_content
213
+ else
214
+ status :not_found
215
+ { error: "Ticket #{params[:id]} not found" }.to_json
216
+ end
217
+ end
218
+
219
+ def handle_json_export(tickets)
220
+ content_type :json
221
+ { tickets: tickets }.to_json
222
+ end
223
+
224
+ def handle_csv_export(tickets)
225
+ content_type "text/csv"
226
+ headers["Content-Disposition"] = 'attachment; filename="defect_tickets.csv"'
227
+
228
+ CSV.generate do |csv|
229
+ headers = %i[ticket_id status priority description created_at modified_at assigned_to customer_id]
230
+ csv << headers.map { |h| h.to_s.split("_").map(&:capitalize).join(" ") }
231
+ tickets.each do |ticket|
232
+ csv << ticket.values_at(*headers)
233
+ end
234
+ end
235
+ end
236
+
237
+ # Export defect tickets
238
+ get "/api/export/defect_tickets" do
239
+ format = params[:format] || "json"
240
+ tickets = MockDataStore.instance.search_tickets(params)
241
+
242
+ case format
243
+ when "json"
244
+ handle_json_export(tickets)
245
+ when "csv"
246
+ handle_csv_export(tickets)
247
+ else
248
+ status :bad_request
249
+ { error: "Unsupported export format: #{format}" }.to_json
250
+ end
251
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec"
4
+
5
+ RSpec.configure do |config|
6
+ config.expect_with :rspec do |expectations|
7
+ expectations.syntax = :expect
8
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
9
+ expectations.max_formatted_output_length = nil
10
+ end
11
+
12
+ config.mock_with :rspec do |mocks|
13
+ mocks.verify_partial_doubles = true
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "simplecov"
4
+
5
+ SimpleCov.start
@@ -0,0 +1,313 @@
1
+ Feature: Transform SAP tickets to Jira format
2
+ As an integration system
3
+ I want to transform SAP ticket data
4
+ So that it matches Jira's required format
5
+
6
+ Background:
7
+ Given the following environment variables have been set:
8
+ | name | value |
9
+ | TICKET_REPLICATOR_SOURCE_TICKET_BASE_URL_ERB | http://url/to/source/ticket/<%= source_id %> |
10
+
11
+
12
+ Scenario: Transform valid ticket CSV
13
+ Given a file named "config/ticket-replicator.mappings.yml" with:
14
+ """
15
+ field_mapping:
16
+ id: ID
17
+ summary: Summary
18
+ priority: Priority
19
+ resolution: Status
20
+ status: Status
21
+ team: Team
22
+
23
+ priority_mapping:
24
+ "1-Critical": "Highest"
25
+ "2-High": "High"
26
+ "3-Medium": "Medium"
27
+ "4-Low": "Low"
28
+
29
+ status_mapping:
30
+ "New": "Open"
31
+ "Open": "Open"
32
+ "In Progress": "In Progress"
33
+ "In Review": "In Review"
34
+ "On Hold": "Blocked"
35
+ "Resolved": "Resolved"
36
+ "Fixed": "Resolved"
37
+ "Closed": "Closed"
38
+ "Rejected": "Closed"
39
+ "Confirmed": "Open"
40
+
41
+ resolution_mapping:
42
+ "New": ""
43
+ "Open": ""
44
+ "In Progress": ""
45
+ "In Review": ""
46
+ "On Hold": ""
47
+ "Fixed": "Fixed"
48
+ "Closed": "Done"
49
+ "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"
64
+ """
65
+ Given a file named "queue/10.extracted/sap_solution_manager_defects.csv" with:
66
+ """
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)"
78
+ """
79
+ When I successfully run `ticket-replicator --transform`
80
+ Then a file named "queue/20.transformed/sap_solution_manager_defects.csv" should contain exactly:
81
+ """
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)"
93
+ """
94
+
95
+ Scenario: Transform valid ticket Excel
96
+ Given a file named "config/ticket-replicator.mappings.yml" with:
97
+ """
98
+ field_mapping:
99
+ id: Defect
100
+ summary: Defect (2)
101
+ priority: Defect Priority
102
+ resolution: Defect Status
103
+ status: Defect Status
104
+ team: Defect Support Team (2)
105
+
106
+ priority_mapping:
107
+ "1: Critical": "Highest"
108
+ "2: High": "High"
109
+ "3: Medium": "Medium"
110
+ "4: Low": "Low"
111
+
112
+ status_mapping:
113
+ defaults_to: keep_original_value
114
+
115
+ 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"
125
+ "Closed": "Done"
126
+ "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"
148
+ """
149
+ And an Excel file named "queue/10.extracted/sap_solution_manager_defects.xlsx"
150
+ And it has a tab named "SAP Document Export" with the following rows:
151
+ | Defect | Defect (2) | Defect Priority | Defect Status | Defect Support Team (2) |
152
+ | 3000017049 | Summary | 3: Medium | Closed | A Team |
153
+ | 9400011377 | Summary | 4: Low | Confirmed | A Team |
154
+ | 3000016618 | Summary | 3: Medium | Defect Correction in Process | A Team |
155
+ | 9400013805 | Summary | 3: Medium | Deferred | A Team |
156
+ | 9400013816 | Summary | 2: High | Forwarded | A Team |
157
+ | 9400011382 | Summary | 3: Medium | In Process | A Team |
158
+ | 9400011393 | Summary | 3: Medium | Information Required | A Team |
159
+ | 9400011381 | Summary | 3: Medium | New | A Team |
160
+ | 3000016617 | Summary | 3: Medium | No Error | A Team |
161
+ | 9400011372 | Summary | 1: Critical | Open | A Team |
162
+ | 9400011403 | Summary | 3: Medium | Solution Proposal | A Team |
163
+ | 9400011380 | Summary | 3: Medium | Tester Action | A Team |
164
+ | 9400011705 | Summary | 3: Medium | Wait for Defect Correction | A Team |
165
+ | 9400011437 | Summary | 3: Medium | Wait on External | A Team |
166
+ | 9400011466 | Summary | 3: Medium | Withdrawn | A Team |
167
+ | 3000017667 | Summary | 3: Medium | Closed | Another Team |
168
+ | 3000018423 | Summary | 3: Medium | No Error | A Team |
169
+ Then a file named "queue/10.extracted/sap_solution_manager_defects.xlsx" should exist
170
+ When I successfully run `ticket-replicator --transform`
171
+ Then a file named "queue/20.transformed/sap_solution_manager_defects.csv" should contain exactly:
172
+ """
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"
191
+ """
192
+
193
+ Scenario: Processing an invalid Excel file generates an error with relevant information
194
+ Given a file named "config/ticket-replicator.mappings.yml" with:
195
+ """
196
+ field_mapping:
197
+ id: Defect
198
+ summary: Defect (2)
199
+ priority: Defect Priority
200
+ resolution: Defect Status
201
+ status: Defect Status
202
+ team: Defect Support Team (2)
203
+
204
+ priority_mapping:
205
+ "1: Critical": "Highest"
206
+ "2: High": "High"
207
+ "3: Medium": "Medium"
208
+ "4: Low": "Low"
209
+
210
+ status_mapping:
211
+ defaults_to: keep_original_value
212
+
213
+ resolution_mapping:
214
+ defaults_to: keep_original_value
215
+
216
+ team_mapping:
217
+ defaults_to: keep_original_value
218
+
219
+ """
220
+ And a file named "queue/10.extracted/invalid_file.xlsx" with:
221
+ """
222
+ BOGUS EXCEL File content
223
+ """
224
+ When I run `ticket-replicator --transform`
225
+ Then it should fail with:
226
+ """
227
+ ERROR Object : Ticket::Replicator::FileTransformer::ForXLSX::XLSXReaderError: queue/10.extracted/invalid_file.xlsx:1: error while reading XLSX file:
228
+ Zip end of central directory signature not found
229
+ """
230
+
231
+ Scenario: Processing a file with missing columns generates an error with relevant information
232
+ Given a file named "config/ticket-replicator.mappings.yml" with:
233
+ """
234
+ field_mapping:
235
+ id: Defect
236
+ summary: Defect (2)
237
+ priority: Defect Priority
238
+ resolution: Defect Status
239
+ status: Defect Status
240
+ team: Defect Support Team (2)
241
+
242
+ priority_mapping:
243
+ "1: Critical": "Highest"
244
+ "2: High": "High"
245
+ "3: Medium": "Medium"
246
+ "4: Low": "Low"
247
+
248
+ status_mapping:
249
+ defaults_to: keep_original_value
250
+
251
+ resolution_mapping:
252
+ defaults_to: keep_original_value
253
+
254
+ team_mapping:
255
+ defaults_to: keep_original_value
256
+
257
+ """
258
+ And an Excel file named "queue/10.extracted/sap_solution_manager_defects_with_missing_priority_column.xlsx"
259
+ And it has a tab named "SAP Document Export" with the following rows:
260
+ | Defect | Defect (2) | Defect Status | Defect Support Team (2) |
261
+ | 3000017049 | Summary | Closed | A Team |
262
+ | 9400011377 | Summary | Confirmed | A Team |
263
+ | 3000016618 | Summary | Defect Correction in Process | A Team |
264
+ Then a file named "queue/10.extracted/sap_solution_manager_defects_with_missing_priority_column.xlsx" should exist
265
+ When I run `ticket-replicator --transform`
266
+ Then it should fail with:
267
+ """
268
+ ERROR Object : Ticket::Replicator::FileTransformer::TransformError: queue/10.extracted/sap_solution_manager_defects_with_missing_priority_column.xlsx:2: error while transforming row:
269
+ No value found for "priority" as "defect priority" in {"defect" => "3000017049", "defect (2)" => "Summary", "defect status" => "Closed", "defect support team (2)" => "A Team"}:
270
+ {"defect" => "3000017049", "defect (2)" => "Summary", "defect status" => "Closed", "defect support team (2)" => "A Team"}
271
+ """
272
+
273
+ Scenario: Processing a file with an unexpected priority generates an error with relevant information
274
+ Given a file named "config/ticket-replicator.mappings.yml" with:
275
+ """
276
+ field_mapping:
277
+ id: Defect
278
+ summary: Defect (2)
279
+ priority: Defect Priority
280
+ resolution: Defect Status
281
+ status: Defect Status
282
+ team: Defect Support Team (2)
283
+
284
+ priority_mapping:
285
+ "1: Critical": "Highest"
286
+ "2: High": "High"
287
+ "3: Medium": "Medium"
288
+ "4: Low": "Low"
289
+
290
+ status_mapping:
291
+ defaults_to: keep_original_value
292
+
293
+ resolution_mapping:
294
+ defaults_to: keep_original_value
295
+
296
+ team_mapping:
297
+ defaults_to: keep_original_value
298
+
299
+ """
300
+ And an Excel file named "queue/10.extracted/sap_solution_manager_defects.xlsx"
301
+ And it has a tab named "SAP Document Export" with the following rows:
302
+ | Defect | Defect (2) | Defect Priority | Defect Status | Defect Support Team (2) |
303
+ | 3000017049 | Summary | 3: Medium | Closed | A Team |
304
+ | 9400011377 | Summary | 4: Low | Confirmed | A Team |
305
+ | 3000016618 | Summary | ____ UNKNOWN PRIORITY ____ | Defect Correction in Process | A Team |
306
+ Then a file named "queue/10.extracted/sap_solution_manager_defects.xlsx" should exist
307
+ When I run `ticket-replicator --transform`
308
+ Then it should fail with:
309
+ """
310
+ ERROR Object : Ticket::Replicator::FileTransformer::TransformError: queue/10.extracted/sap_solution_manager_defects.xlsx:4: error while transforming row:
311
+ No mapping found for :priority = "____ UNKNOWN PRIORITY ____" in {"1: Critical" => "Highest", "2: High" => "High", "3: Medium" => "Medium", "4: Low" => "Low"}:
312
+ {"defect" => "3000016618", "defect (2)" => "Summary", "defect priority" => "____ UNKNOWN PRIORITY ____", "defect status" => "Defect Correction in Process", "defect support team (2)" => "A Team"}
313
+ """