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.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/Guardfile +158 -0
- data/LICENSE.txt +21 -0
- data/README.md +136 -0
- data/Rakefile +23 -0
- data/bin/ticket-replicator +67 -0
- data/config/examples/ticket-replicator.mappings.yml +54 -0
- data/cucumber.yml +7 -0
- data/features/extract-sap-solution-manager-defect-tickets.feature +45 -0
- data/features/load_tickets_in_jira.feature +129 -0
- data/features/setup_ticket_replicator.feature +85 -0
- data/features/step_definitions/anonymized_sample.xlsx +0 -0
- data/features/step_definitions/anonymized_sample.xlsx:Zone.Identifier +3 -0
- data/features/step_definitions/execution_context_steps.rb +13 -0
- data/features/step_definitions/extract_defect_tickets_from_sap_solution_manager_steps.rb.rb +29 -0
- data/features/step_definitions/load_tickets_in_jira_steps.rb +47 -0
- data/features/step_definitions/transform_solution_manager_tickets_steps.rb +21 -0
- data/features/support/10.setup_cucumber.rb +10 -0
- data/features/support/env.rb +15 -0
- data/features/support/hooks.rb +13 -0
- data/features/support/manage_mock_sap_solution_manager.rb.DISABLED +12 -0
- data/features/support/mocks/mock_defect_ticket_server.rb.DISABLED +251 -0
- data/features/support/setup_rspec.rb +15 -0
- data/features/support/setup_simplecov.rb +5 -0
- data/features/transform-solution-manager-tickets-into-jira-loadable-tickets.feature +313 -0
- data/features/transform_and_load_extracted_ticket_queue.feature +121 -0
- data/lib/tasks/version.rake +55 -0
- data/lib/ticket/replicator/defect_export_automation.rb.DISABLED +128 -0
- data/lib/ticket/replicator/file_loader.rb +46 -0
- data/lib/ticket/replicator/file_replicator.rb +67 -0
- data/lib/ticket/replicator/file_transformer/for_csv.rb +22 -0
- data/lib/ticket/replicator/file_transformer/for_xlsx.rb +34 -0
- data/lib/ticket/replicator/file_transformer.rb +70 -0
- data/lib/ticket/replicator/jira_project.rb +65 -0
- data/lib/ticket/replicator/replicated_summary.rb +73 -0
- data/lib/ticket/replicator/row_loader.rb +109 -0
- data/lib/ticket/replicator/row_transformer.rb +126 -0
- data/lib/ticket/replicator/s_a_p_solution_manager_client.rb.DISABLED +169 -0
- data/lib/ticket/replicator/setup.rb +49 -0
- data/lib/ticket/replicator/ticket.rb +70 -0
- data/lib/ticket/replicator/ticket_status_transitioner.rb +45 -0
- data/lib/ticket/replicator/version.rb +7 -0
- data/lib/ticket/replicator.rb +90 -0
- data/sig/ticket/replicator.rbs +6 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/ticket/replicator/file_loader_spec.rb +77 -0
- data/spec/ticket/replicator/file_replicator_spec.rb +153 -0
- data/spec/ticket/replicator/file_transformer/for_csv_spec.rb +52 -0
- data/spec/ticket/replicator/file_transformer/for_xlsx_spec.rb +52 -0
- data/spec/ticket/replicator/file_transformer_spec.rb +83 -0
- data/spec/ticket/replicator/jira_project_spec.rb +127 -0
- data/spec/ticket/replicator/replicated_summary_spec.rb +70 -0
- data/spec/ticket/replicator/row_loader_spec.rb +245 -0
- data/spec/ticket/replicator/row_transformer_spec.rb +234 -0
- data/spec/ticket/replicator/setup_spec.rb +80 -0
- data/spec/ticket/replicator/ticket_spec.rb +244 -0
- data/spec/ticket/replicator/ticket_status_transitioner_spec.rb +123 -0
- data/spec/ticket/replicator_spec.rb +137 -0
- data/transformed_file1 +1 -0
- 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,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
|
+
"""
|