ticket-replicator 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -0
- data/.ruby-version +1 -0
- data/README.md +9 -9
- data/config/examples/ticket-replicator.mappings.yml +3 -1
- data/features/load_tickets_in_jira.feature +82 -69
- data/features/setup_ticket_replicator.feature +3 -1
- data/features/transform-solution-manager-tickets-into-jira-loadable-tickets.feature +86 -32
- data/features/transform_and_load_extracted_ticket_queue.feature +18 -14
- data/lib/ticket/replicator/file_transformer.rb +1 -0
- data/lib/ticket/replicator/row_loader.rb +73 -16
- data/lib/ticket/replicator/row_transformer.rb +47 -4
- data/lib/ticket/replicator/ticket.rb +17 -0
- data/lib/ticket/replicator/version.rb +1 -1
- data/spec/ticket/replicator/file_transformer_spec.rb +5 -6
- data/spec/ticket/replicator/row_loader_spec.rb +270 -40
- data/spec/ticket/replicator/row_transformer_spec.rb +280 -185
- data/spec/ticket/replicator/ticket_spec.rb +50 -1
- metadata +2 -1
@@ -2,245 +2,340 @@
|
|
2
2
|
|
3
3
|
require "ticket/replicator/row_transformer"
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
module Ticket
|
6
|
+
class Replicator
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
8
|
+
class RowTransformer
|
9
|
+
RSpec.describe RowTransformer do
|
10
|
+
let(:transformer) { described_class.send(:new, extracted_row) }
|
7
11
|
|
8
|
-
|
9
|
-
|
12
|
+
describe ".run_on" do
|
13
|
+
let(:extracted_row) { :a_row_to_transform }
|
10
14
|
|
11
|
-
|
12
|
-
|
15
|
+
it "transforms the given file" do
|
16
|
+
expect(described_class).to receive(:new).with(:a_row_to_transform).and_return(transformer)
|
13
17
|
|
14
|
-
|
18
|
+
expect(transformer).to receive(:run)
|
15
19
|
|
16
|
-
|
17
|
-
|
18
|
-
|
20
|
+
described_class.run_on(:a_row_to_transform)
|
21
|
+
end
|
22
|
+
end
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
describe "#run" do
|
25
|
+
let(:extracted_row) do
|
26
|
+
{
|
27
|
+
id: "123",
|
28
|
+
status: "Open",
|
29
|
+
priority: "4 - Low",
|
30
|
+
team: "Source Team",
|
31
|
+
summary: "summary"
|
32
|
+
}
|
33
|
+
end
|
30
34
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
it "transforms a row" do
|
36
|
+
allow(transformer).to receive(:transformed_id).and_return("123")
|
37
|
+
allow(transformer).to receive(:transformed_status).and_return("Open")
|
38
|
+
allow(transformer).to receive(:transformed_resolution).and_return("")
|
39
|
+
allow(transformer).to receive(:transformed_priority).and_return("Low")
|
40
|
+
allow(transformer).to receive(:transformed_summary).and_return("transformed summary (123)")
|
41
|
+
allow(transformer).to receive(:transformed_source_ticket_url).and_return("url/to/source/ticket/123")
|
38
42
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
+
expect(transformer.run)
|
44
|
+
.to eq(["123", "Open", "", "Low", "transformed summary (123)", "url/to/source/ticket/123"])
|
45
|
+
end
|
46
|
+
end
|
43
47
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
48
|
+
describe "#mappings" do
|
49
|
+
let(:mappings_yaml) do
|
50
|
+
<<~'YAML'
|
51
|
+
field_mapping:
|
52
|
+
id: Defect
|
53
|
+
summary: Defect (2)
|
54
|
+
id_extraction_regex: "\\((?<id>\\d+)\\)$"
|
55
|
+
status_mapping:
|
56
|
+
defaults_to: keep_original_value
|
57
|
+
Open: Open
|
58
|
+
Closed: Closed
|
59
|
+
resolution_mapping:
|
60
|
+
Closed: Done
|
61
|
+
Rejected: Won't Fix
|
62
|
+
team_mapping:
|
63
|
+
Source Team: Transformed Team
|
64
|
+
Front End: Web Team
|
65
|
+
priority_mapping:
|
66
|
+
1 - Critical: Critical
|
67
|
+
2 - High: High
|
68
|
+
3 - Medium: Medium
|
69
|
+
4 - Low: Low
|
70
|
+
YAML
|
71
|
+
end
|
67
72
|
|
68
|
-
|
73
|
+
let(:extracted_row) { {} }
|
74
|
+
|
75
|
+
let(:file_io) { instance_double(IO) }
|
76
|
+
|
77
|
+
it "loads the mappings from the mappings.yml file" do
|
78
|
+
expect(IO).to receive(:open).with("config/ticket-replicator.mappings.yml",
|
79
|
+
"r:bom|utf-8").and_yield(mappings_yaml)
|
80
|
+
|
81
|
+
expect(transformer.mappings)
|
82
|
+
.to eq(
|
83
|
+
"field_mapping" => { "id" => "Defect", "summary" => "Defect (2)" },
|
84
|
+
"id_extraction_regex" => "\\((?<id>\\d+)\\)$",
|
85
|
+
"status_mapping" => { "defaults_to" => "keep_original_value", "Open" => "Open",
|
86
|
+
"Closed" => "Closed" },
|
87
|
+
"resolution_mapping" => { "Closed" => "Done", "Rejected" => "Won't Fix" },
|
88
|
+
"team_mapping" => { "Source Team" => "Transformed Team", "Front End" => "Web Team" },
|
89
|
+
"priority_mapping" =>
|
90
|
+
{ "1 - Critical" => "Critical", "2 - High" => "High", "3 - Medium" => "Medium",
|
91
|
+
"4 - Low" => "Low" }
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
69
95
|
|
70
|
-
|
96
|
+
describe "#ticket_replicator_source_ticket_url" do
|
97
|
+
let(:extracted_row) { {} }
|
71
98
|
|
72
|
-
|
73
|
-
|
99
|
+
context "when the source ticket url is set in the environment" do
|
100
|
+
before do
|
101
|
+
allow(ENV)
|
102
|
+
.to receive(:fetch).with("TICKET_REPLICATOR_SOURCE_TICKET_URL").and_return("url/to/source/ticket")
|
103
|
+
end
|
74
104
|
|
75
|
-
|
76
|
-
|
77
|
-
"field_mapping" => { "id" => "Defect", "summary" => "Defect (2)" },
|
78
|
-
"status_mapping" => { "defaults_to" => "keep_original_value", "Open" => "Open", "Closed" => "Closed" },
|
79
|
-
"resolution_mapping" => { "Closed" => "Done", "Rejected" => "Won't Fix" },
|
80
|
-
"team_mapping" => { "Source Team" => "Transformed Team", "Front End" => "Web Team" },
|
81
|
-
"priority_mapping" =>
|
82
|
-
{ "1 - Critical" => "Critical", "2 - High" => "High", "3 - Medium" => "Medium", "4 - Low" => "Low" }
|
83
|
-
)
|
84
|
-
end
|
85
|
-
end
|
105
|
+
it { expect(transformer.ticket_replicator_source_ticket_url).to eq("url/to/source/ticket") }
|
106
|
+
end
|
86
107
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
"id" => "Defect", "priority" => "Defect Priority", "resolution" => "Defect (2)",
|
95
|
-
"status" => "Defect status", "summary" => "Defect (2)"
|
96
|
-
}
|
97
|
-
}
|
98
|
-
end
|
108
|
+
context "when the source ticket url is not set in the environment" do
|
109
|
+
it do
|
110
|
+
expect { transformer.ticket_replicator_source_ticket_url }
|
111
|
+
.to raise_error("TICKET_REPLICATOR_SOURCE_TICKET_URL: not set in environment!")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
99
115
|
|
100
|
-
|
101
|
-
|
102
|
-
"defect (2)" => "a summary", "defect priority" => "High", "defect status" => "Open",
|
103
|
-
"defect team (2)" => "system team", "defect" => "123"
|
104
|
-
}
|
105
|
-
end
|
116
|
+
describe "#source_ticket_url_builder" do
|
117
|
+
let(:extracted_row) { {} }
|
106
118
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
end
|
112
|
-
end
|
119
|
+
before do
|
120
|
+
allow(transformer)
|
121
|
+
.to receive_messages(ticket_replicator_source_ticket_url: ticket_replicator_source_ticket_url)
|
122
|
+
end
|
113
123
|
|
114
|
-
|
115
|
-
|
116
|
-
let(:extracted_row) { { :extracted_row => "should not be used in this context but the remapped version" } }
|
124
|
+
context "when the URL has no syntax error" do
|
125
|
+
let(:ticket_replicator_source_ticket_url) { "http://url/to/source/ticket/<%= source_ticket_id %>" }
|
117
126
|
|
118
|
-
|
127
|
+
it { expect(transformer.source_ticket_url_builder("123")).to eq("http://url/to/source/ticket/123") }
|
128
|
+
end
|
119
129
|
|
120
|
-
|
121
|
-
|
122
|
-
let(:mappings) { {} }
|
130
|
+
context "when the URL has a syntax error" do
|
131
|
+
let(:ticket_replicator_source_ticket_url) { "http://url/to/source/ticket/<%= missing_variable %>" }
|
123
132
|
|
124
|
-
|
125
|
-
|
133
|
+
it { expect { transformer.source_ticket_url_builder("123") }.to raise_error(StandardError) }
|
134
|
+
end
|
126
135
|
end
|
127
|
-
end
|
128
136
|
|
129
|
-
|
130
|
-
|
131
|
-
|
137
|
+
describe "using mappings" do
|
138
|
+
before { allow(transformer).to receive_messages(mappings: mappings) }
|
139
|
+
|
140
|
+
describe "#remapped_field_extracted_row" do
|
141
|
+
let(:mappings) do
|
142
|
+
{
|
143
|
+
"field_mapping" => {
|
144
|
+
"id" => "Defect", "priority" => "Defect Priority", "resolution" => "Defect (2)",
|
145
|
+
"status" => "Defect status", "summary" => "Defect (2)"
|
146
|
+
}
|
147
|
+
}
|
148
|
+
end
|
149
|
+
|
150
|
+
let(:extracted_row) do
|
151
|
+
{
|
152
|
+
"defect (2)" => "a summary", "defect priority" => "High", "defect status" => "Open",
|
153
|
+
"defect team (2)" => "system team", "defect" => "123"
|
154
|
+
}
|
155
|
+
end
|
156
|
+
|
157
|
+
it do
|
158
|
+
expect(transformer.remapped_field_extracted_row)
|
159
|
+
.to eq({ "id" => "123", "priority" => "High", "resolution" => "a summary",
|
160
|
+
"status" => "Open", "summary" => "a summary" })
|
161
|
+
end
|
162
|
+
end
|
132
163
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
end
|
164
|
+
# rubocop:disable Metrics/BlockLength
|
165
|
+
context "when remapped field extracted row used" do
|
166
|
+
let(:extracted_row) { { :extracted_row => "should not be used in this context but the remapped version" } }
|
137
167
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
end
|
168
|
+
before do
|
169
|
+
allow(transformer).to receive_messages(remapped_field_extracted_row: remapped_field_extracted_row)
|
170
|
+
end
|
142
171
|
|
143
|
-
|
144
|
-
|
172
|
+
describe "#transformed_id" do
|
173
|
+
context "when using the ID value as is" do
|
174
|
+
let(:mappings) { {} }
|
175
|
+
let(:remapped_field_extracted_row) { { "id" => "123" } }
|
145
176
|
|
146
|
-
|
177
|
+
it "returns the ID" do
|
178
|
+
expect(transformer.transformed_id).to eq("123")
|
179
|
+
end
|
180
|
+
end
|
147
181
|
|
148
|
-
|
182
|
+
context "when extracting the ID from the string" do
|
183
|
+
let(:remapped_field_extracted_row) { { "id" => "also (85)73 in summary (123456)" } }
|
184
|
+
let(:mappings) { { "id_extraction_regex" => "\\((?<id>\\d+)\\)$" } }
|
149
185
|
|
150
|
-
|
186
|
+
it { expect(transformer.transformed_id).to eq("123456") }
|
151
187
|
|
152
|
-
|
153
|
-
|
188
|
+
context "when the regex does not match" do
|
189
|
+
let(:remapped_field_extracted_row) { { "id" => "summary (non numeric)" } }
|
154
190
|
|
155
|
-
|
156
|
-
|
191
|
+
it "raises an error" do
|
192
|
+
expect { transformer.transformed_id }
|
193
|
+
.to raise_error(FileTransformer::TransformError,
|
194
|
+
%(No match found for :id in "summary (non numeric)") +
|
195
|
+
" using /\\((?<id>\\d+)\\)$/")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
157
200
|
|
158
|
-
|
159
|
-
|
201
|
+
describe "#transformed_source_ticket_url" do
|
202
|
+
let(:remapped_field_extracted_row) { { "id" => "123" } }
|
203
|
+
let(:mappings) { {} }
|
160
204
|
|
161
|
-
|
162
|
-
|
205
|
+
before do
|
206
|
+
allow(transformer)
|
207
|
+
.to receive_messages(
|
208
|
+
transformed_id: "123",
|
209
|
+
ticket_replicator_source_ticket_url: "url/to/source/ticket/<%= source_ticket_id %>"
|
210
|
+
)
|
211
|
+
end
|
163
212
|
|
164
|
-
|
165
|
-
|
213
|
+
it "returns the source ticket url" do
|
214
|
+
expect(transformer.transformed_source_ticket_url).to eq("url/to/source/ticket/123")
|
215
|
+
end
|
216
|
+
end
|
166
217
|
|
167
|
-
|
168
|
-
|
218
|
+
describe "#transformed_summary" do
|
219
|
+
let(:remapped_field_extracted_row) { { "id" => "426", "summary" => "a summary" } }
|
220
|
+
let(:mappings) { {} }
|
169
221
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
end
|
222
|
+
before do
|
223
|
+
allow(ReplicatedSummary).to receive(:build).with("426", "a summary").and_return("replicated_summary")
|
224
|
+
end
|
174
225
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
"in #{mappings["#{field_name}_mapping"].inspect}")
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
226
|
+
it "returns the summary" do
|
227
|
+
expect(transformer.transformed_summary).to eq("replicated_summary")
|
228
|
+
end
|
229
|
+
end
|
183
230
|
|
184
|
-
|
185
|
-
|
186
|
-
{ "status_mapping" => { "Open" => "Open", "Closed" => "Closed" } }
|
187
|
-
end
|
231
|
+
shared_examples "an unmapped value handler" do |field_name, source_field|
|
232
|
+
source_field ||= field_name
|
188
233
|
|
189
|
-
|
234
|
+
let(:remapped_field_extracted_row) { { source_field.to_s => an_original_value } }
|
190
235
|
|
191
|
-
|
192
|
-
expect(transformer.transformed_status).to eq("Open")
|
193
|
-
end
|
236
|
+
let(:an_original_value) { "any #{field_name} #{rand}" }
|
194
237
|
|
195
|
-
|
196
|
-
end
|
238
|
+
let(:transformed_value) { transformer.send("transformed_#{field_name}") }
|
197
239
|
|
198
|
-
|
199
|
-
|
240
|
+
context "when defaulting to original value" do
|
241
|
+
let(:mappings) { { "#{field_name}_mapping" => { "defaults_to" => "keep_original_value" } } }
|
200
242
|
|
201
|
-
|
202
|
-
|
243
|
+
it { expect(transformed_value).to eq(an_original_value) }
|
244
|
+
end
|
203
245
|
|
204
|
-
|
205
|
-
|
206
|
-
end
|
207
|
-
end
|
246
|
+
context "when defaulting to unset value" do
|
247
|
+
let(:mappings) { { "#{field_name}_mapping" => { "defaults_to" => "unset_value" } } }
|
208
248
|
|
209
|
-
|
210
|
-
|
249
|
+
it { expect(transformed_value).to eq(nil) }
|
250
|
+
end
|
211
251
|
|
212
|
-
|
213
|
-
|
214
|
-
end
|
215
|
-
end
|
252
|
+
context "when defaulting to blank value" do
|
253
|
+
let(:mappings) { { "#{field_name}_mapping" => { "defaults_to" => "blank_value" } } }
|
216
254
|
|
217
|
-
|
218
|
-
|
255
|
+
it { expect(transformed_value).to eq("") }
|
256
|
+
end
|
219
257
|
|
220
|
-
|
221
|
-
|
258
|
+
context "when the value is unexpected" do
|
259
|
+
let(:mappings) do
|
260
|
+
{ "#{field_name}_mapping" => { "extracted value" => "transformed value" } }
|
261
|
+
end
|
222
262
|
|
223
|
-
|
263
|
+
it do
|
264
|
+
expect { transformed_value }
|
265
|
+
.to raise_error(RuntimeError,
|
266
|
+
"No mapping found for #{field_name.inspect} = #{an_original_value.inspect} " \
|
267
|
+
"in #{mappings["#{field_name}_mapping"].inspect}")
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
224
271
|
|
225
|
-
|
226
|
-
|
227
|
-
|
272
|
+
describe "#transformed_status" do
|
273
|
+
let(:mappings) do
|
274
|
+
{ "status_mapping" => { "Open" => "Open", "Closed" => "Closed" } }
|
275
|
+
end
|
228
276
|
|
229
|
-
|
230
|
-
end
|
277
|
+
let(:remapped_field_extracted_row) { { "status" => "Open" } }
|
231
278
|
|
232
|
-
|
233
|
-
|
279
|
+
it "returns the status" do
|
280
|
+
expect(transformer.transformed_status).to eq("Open")
|
281
|
+
end
|
234
282
|
|
235
|
-
|
283
|
+
it_behaves_like "an unmapped value handler", :status
|
284
|
+
end
|
236
285
|
|
237
|
-
|
238
|
-
|
239
|
-
|
286
|
+
describe "#transformed_resolution" do
|
287
|
+
let(:mappings) { { "resolution_mapping" => { "Closed" => "Done", "Rejected" => "Won't Fix" } } }
|
288
|
+
|
289
|
+
context "when the status is Closed" do
|
290
|
+
let(:remapped_field_extracted_row) { { "status" => "Closed" } }
|
291
|
+
|
292
|
+
it "returns the resolution" do
|
293
|
+
expect(transformer.transformed_resolution).to eq("Done")
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
context "when the status is Rejected" do
|
298
|
+
let(:remapped_field_extracted_row) { { "status" => "Rejected" } }
|
299
|
+
|
300
|
+
it "returns the resolution" do
|
301
|
+
expect(transformer.transformed_resolution).to eq("Won't Fix")
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
it_behaves_like "an unmapped value handler", :resolution, :status
|
306
|
+
end
|
307
|
+
|
308
|
+
describe "#transformed_team" do
|
309
|
+
let(:mappings) do
|
310
|
+
{ "team_mapping" => { "Source Team" => "Transformed Team", "Front End" => "Web Team" } }
|
311
|
+
end
|
312
|
+
|
313
|
+
let(:remapped_field_extracted_row) { { "team" => "Source Team" } }
|
240
314
|
|
241
|
-
|
315
|
+
it "returns the team" do
|
316
|
+
expect(transformer.transformed_team).to eq("Transformed Team")
|
317
|
+
end
|
318
|
+
|
319
|
+
it_behaves_like "an unmapped value handler", :team
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "#transformed_priority" do
|
323
|
+
let(:mappings) { { "priority_mapping" => { "1 - Critical" => "Critical", "2 - High" => "High" } } }
|
324
|
+
|
325
|
+
let(:remapped_field_extracted_row) { { "priority" => "1 - Critical" } }
|
326
|
+
|
327
|
+
it "returns the priority" do
|
328
|
+
expect(transformer.transformed_priority).to eq("Critical")
|
329
|
+
end
|
330
|
+
|
331
|
+
it_behaves_like "an unmapped value handler", :priority
|
332
|
+
end
|
333
|
+
end
|
334
|
+
# rubocop:enable Metrics/BlockLength
|
335
|
+
end
|
242
336
|
end
|
243
337
|
end
|
244
|
-
|
338
|
+
|
339
|
+
# rubocop:enable Metrics/ClassLength
|
245
340
|
end
|
246
341
|
end
|
@@ -136,7 +136,6 @@ module Ticket
|
|
136
136
|
let(:jira_auto_tool) { instance_double(Jira::Auto::Tool) }
|
137
137
|
let(:jira_client) { instance_double(JIRA::Client, Field: field_navigator) }
|
138
138
|
|
139
|
-
# let(:jira_ticket) { OpenStruct.new(jira_ticket_properties_hash["fields"]) }
|
140
139
|
let(:jira_ticket) { JIRA::Resource::Issue.build(jira_client, jira_ticket_properties_hash) }
|
141
140
|
|
142
141
|
let(:ticket) { described_class.new(jira_auto_tool, jira_ticket) }
|
@@ -149,6 +148,56 @@ module Ticket
|
|
149
148
|
it { expect(ticket.summary).to eq("SMAN-16384 | Login page randomly fails to load CSS assets (10001)") }
|
150
149
|
end
|
151
150
|
|
151
|
+
def build_ticket_link(url, title, application = Ticket::SOURCE_TICKET_REMOTE_LINK_APPLICATION)
|
152
|
+
double(JIRA::Resource::Remotelink, attrs: RowLoader.build_ticket_link_attributes(url, title, application))
|
153
|
+
end
|
154
|
+
|
155
|
+
describe "#source_ticket_link" do
|
156
|
+
let(:ticket_links) { [double(JIRA::Resource::Remotelink, attrs: {}), source_ticket_jira_link].compact }
|
157
|
+
|
158
|
+
before { allow(jira_ticket).to receive_messages(remotelink: double(all: ticket_links)) }
|
159
|
+
|
160
|
+
let(:source_ticket_jira_link) { build_ticket_link("https://ur/to/source/ticket/16384", "Source Ticket 16384") }
|
161
|
+
|
162
|
+
it { expect(ticket.source_ticket_link).to eq(source_ticket_jira_link) }
|
163
|
+
|
164
|
+
context "when no source ticket is linked" do
|
165
|
+
let(:source_ticket_jira_link) { nil }
|
166
|
+
it { expect(ticket.source_ticket_link).to be_nil }
|
167
|
+
end
|
168
|
+
|
169
|
+
context "when the existing remote link is not a ticket source link (no application specified)" do
|
170
|
+
let(:source_ticket_jira_link) do
|
171
|
+
build_ticket_link("https://ur/to/source/ticket/16384", "Source Ticket 16384", nil)
|
172
|
+
end
|
173
|
+
|
174
|
+
it { expect(ticket.source_ticket_link).to be_nil }
|
175
|
+
end
|
176
|
+
|
177
|
+
context "when the existing remote link is not a ticket source link (another application specified)" do
|
178
|
+
let(:source_ticket_jira_link) do
|
179
|
+
build_ticket_link("https://ur/to/source/ticket/16384", "Source Ticket 16384", "Another application")
|
180
|
+
end
|
181
|
+
|
182
|
+
it { expect(ticket.source_ticket_link).to be_nil }
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#source_ticket_url" do
|
187
|
+
before do
|
188
|
+
allow(ticket).to receive_messages(source_ticket_link: source_ticket_jira_link)
|
189
|
+
end
|
190
|
+
|
191
|
+
let(:source_ticket_jira_link) { build_ticket_link("https://ur/to/source/ticket/16384", "Source Ticket 16384") }
|
192
|
+
|
193
|
+
it { expect(ticket.source_ticket_url).to eq("https://ur/to/source/ticket/16384") }
|
194
|
+
|
195
|
+
context "when no source ticket is linked" do
|
196
|
+
let(:source_ticket_jira_link) { nil }
|
197
|
+
it { expect(ticket.source_ticket_url).to be_nil }
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
152
201
|
describe "replicated?" do
|
153
202
|
let(:ticket) { described_class.new(jira_auto_tool, jira_ticket) }
|
154
203
|
let(:jira_ticket) { double(JIRA::Resource::Issue, summary: actual_summary) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ticket-replicator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Christophe Broult
|
@@ -146,6 +146,7 @@ extra_rdoc_files: []
|
|
146
146
|
files:
|
147
147
|
- ".rspec"
|
148
148
|
- ".rubocop.yml"
|
149
|
+
- ".ruby-version"
|
149
150
|
- CHANGELOG.md
|
150
151
|
- CODE_OF_CONDUCT.md
|
151
152
|
- Guardfile
|