embulk-input-jira 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5e99c37b9c22a10ca74920b940eb2acf874d0676
4
- data.tar.gz: b85987d31a8870a6136d14dd75f6b65605160211
3
+ metadata.gz: c3c5410e3708624d8c297422cbe1e1551964fd41
4
+ data.tar.gz: b29d96f3a03d59786269c4e1799888761f3afb95
5
5
  SHA512:
6
- metadata.gz: 010bff47e3e9c3a48c24d1da78ef835450f350d7b102969e5ab89c4847425e368719009bc70511f54d2f46347f70e9235883e3e383e3c54651fbfb5a86d193be
7
- data.tar.gz: 6a99ada3fcfc2fc9d0b51484a40e85d6d51797a75964251714d9ebcc8d4f3b24f6f3e6f7af56097e329fd8647f9f7d9397587d827dfc10e1a273e658c9b32005
6
+ metadata.gz: 76b46642effb1df89e29d8a2cd7fd60ac2321dd2f0f5736fff448836d11f427239d8c829ffdd3635965a82b3e3d95b5492a4e82180cb52de3a19f92e2201e40c
7
+ data.tar.gz: 1a292c77fa20cef49500dadc2dde6929f6aa7bdf0be8f732e3e32049664c6eeb1815293443aa006b5546681fbde876817f667f90ff3f24dc5d7ee485a2d69ca8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ ## 0.0.4 - 2015-06-22
2
+ * [enhancement] Add more schema generated by guess command [#27](https://github.com/treasure-data/embulk-input-jira/pull/27)
3
+
1
4
  ## 0.0.3 - 2015-06-12
2
5
  * [enhancement] Limit records for guess and preview [#25](https://github.com/treasure-data/embulk-input-jira/pull/25)
3
6
  * [maintenance] Define version number as constant [#24](https://github.com/treasure-data/embulk-input-jira/pull/24)
@@ -20,46 +20,112 @@ module Embulk
20
20
  return key
21
21
  end
22
22
 
23
- chunk = fields
24
- attribute.split('.').each do |key|
25
- chunk = chunk[key]
26
- return chunk if chunk.nil?
27
- end
23
+ attribute_keys = attribute.split('.')
28
24
 
29
- if chunk.is_a?(Array) || chunk.is_a?(Hash)
30
- chunk.to_json.to_s
31
- else
32
- chunk
33
- end
25
+ fetch(fields, attribute_keys)
34
26
  end
35
27
 
36
28
  def to_record
37
- record = {}
29
+ @record = {}
38
30
 
39
- record["id"] = id
40
- record["key"] = key
31
+ @record["id"] = id
32
+ @record["key"] = key
41
33
 
42
- fields.each_pair do |key, value|
43
- record_key = key
44
- record_value = value.to_json.to_s
34
+ generate_record(fields, "")
35
+
36
+ @record
37
+ end
38
+
39
+ private
40
+
41
+ def fetch(fields, keys)
42
+ return fields if fields.nil? || (fields.is_a?(Array) && fields.empty?)
43
+
44
+ if keys.empty?
45
+ case fields
46
+ when Array
47
+ values = fields.map do |field|
48
+ if field.is_a?(String)
49
+ field.to_s
50
+ else
51
+ field.to_json
52
+ end
53
+ end
45
54
 
46
- case value
47
- when String
48
- record_value = value
55
+ return values.join(",")
49
56
  when Hash
50
- if value.keys.include?("name")
51
- record_key += ".name"
52
- record_value = value["name"]
53
- elsif value.keys.include?("id")
54
- record_key += ".id"
55
- record_value = value["id"]
57
+ return fields.to_json
58
+ else
59
+ return fields
60
+ end
61
+ end
62
+
63
+ target_key = keys.shift
64
+ if fields.is_a?(Array)
65
+ values = fields.map do |field|
66
+ if field.is_a?(Hash)
67
+ field[target_key]
68
+ else
69
+ field.to_json
56
70
  end
57
71
  end
58
72
 
59
- record[record_key] = record_value
73
+ fetch(values, keys)
74
+ else
75
+ fetch(fields[target_key], keys)
60
76
  end
77
+ end
78
+
79
+ def generate_record(value, prefix_key)
80
+ case value
81
+ when Hash
82
+ # NOTE: If you want to flatten JSON completely, please
83
+ # remove this if...end and #add_heuristic_value.
84
+ if prefix_key.count(".") > 1
85
+ add_heuristic_value(value, prefix_key)
86
+ return
87
+ end
61
88
 
62
- record
89
+ value.each_pair do |_key, _value|
90
+ generate_record(_value, record_key(prefix_key, _key))
91
+ end
92
+ when Array
93
+ if value.empty? || value.any? {|v| !v.is_a?(Hash) }
94
+ @record[prefix_key] = "\"#{value.map(&:to_s).join(',')}\""
95
+ return
96
+ end
97
+
98
+ # gathering values from each Hash
99
+ keys = value.map(&:keys).inject([]) {|sum, key| sum + key }.uniq
100
+ values = value.inject({}) do |sum, elem|
101
+ keys.each {|key| sum[key] = (sum[key] || []) << elem[key] }
102
+ sum
103
+ end
104
+
105
+ generate_record(values, prefix_key)
106
+ else
107
+ @record[prefix_key] = value
108
+ end
109
+ end
110
+
111
+ def record_key(prefix, key)
112
+ return key if prefix.empty?
113
+
114
+ "#{prefix}.#{key}"
115
+ end
116
+
117
+ def add_heuristic_value(hash, prefix_key)
118
+ heuristic_values = hash.select do |key, value|
119
+ ["name", "key", "id"].include?(key) && !value.nil?
120
+ end
121
+
122
+ if heuristic_values.empty?
123
+ @record[prefix_key] = hash.to_json
124
+ else
125
+ heuristic_values.each do |key, value|
126
+ @record[record_key(prefix_key, key)] = value
127
+ end
128
+ end
63
129
  end
64
130
  end
65
131
  end
@@ -1,7 +1,7 @@
1
1
  module Embulk
2
2
  module Input
3
3
  module Jira
4
- VERSION = "0.0.3".freeze
4
+ VERSION = "0.0.4".freeze
5
5
  end
6
6
  end
7
7
  end
@@ -1,5 +1,27 @@
1
1
  # This module contains methods for Plugin.
2
2
 
3
+ module Embulk::Guess
4
+ module SchemaGuess
5
+ class << self
6
+
7
+ # NOTE: Original #from_hash_records uses keys of the first record only,
8
+ # but JSON from JIRA API has fields which of value is sometimes nil,
9
+ # sometimes JSON,
10
+ # so the first record doesn't have all key for guess always.
11
+ # original Embulk::Guess::SchemaGuess is https://github.com/embulk/embulk/blob/57b42c31d1d539177e1e818f294550cde5b69e1f/lib/embulk/guess/schema_guess.rb#L16-L24
12
+ def from_hash_records(array_of_hash)
13
+ array_of_hash = Array(array_of_hash)
14
+ if array_of_hash.empty?
15
+ raise "SchemaGuess Can't guess schema from no records"
16
+ end
17
+ column_names = array_of_hash.map(&:keys).inject([]) {|r, a| r + a }.uniq.sort
18
+ samples = array_of_hash.to_a.map {|hash| column_names.map {|name| hash[name] } }
19
+ from_array_records(column_names, samples)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
3
25
  module Embulk
4
26
  module Input
5
27
  module JiraInputPluginUtils
@@ -49,85 +49,139 @@ describe Embulk::Input::Jira::Issue do
49
49
  {
50
50
  "id" => "1",
51
51
  "jira_key" => "FOO-1",
52
- "fields" => {
53
- "summary" => "jira issue",
54
- "project" => project_attribute,
55
- "labels" =>
56
- [
57
- "Feature",
58
- "WantTo"
59
- ],
60
- "priority" => {
61
- "iconUrl" => "https://jira-api/images/icon.png",
62
- "name" => "Must",
63
- "id" => "1"
64
- },
65
- "customfield_1" => nil,
66
- }
52
+ "fields" => fields_attributes
67
53
  }
68
54
  end
69
55
 
70
- let(:project_attribute) do
71
- {
72
- "key" => "FOO",
73
- }
56
+ context "when target attribute_name is especially key" do
57
+ let(:fields_attributes) { {} }
58
+
59
+ context 'id' do
60
+ let(:attribute_name) { 'id' }
61
+
62
+ it "returns issue id" do
63
+ expect(subject).to eq "1"
64
+ end
65
+ end
66
+
67
+ context 'key' do
68
+ let(:attribute_name) { 'key' }
69
+
70
+ it "returns issue key" do
71
+ expect(subject).to eq "FOO-1"
72
+ end
73
+ end
74
74
  end
75
75
 
76
- context 'id' do
77
- let(:attribute_name) { 'id' }
76
+ context "when fields_attributes is empty Hash" do
77
+ let(:fields_attributes) { {} }
78
+
79
+ let(:attribute_name) { 'key1' }
80
+
81
+ it "returns nil" do
82
+ expect(subject).to eq nil
83
+ end
84
+ end
85
+
86
+ context "when fields_attributes is empty Hash including Array" do
87
+ let(:fields_attributes) { { 'key1' => [] } }
88
+
89
+ let(:attribute_name) { 'key1' }
78
90
 
79
- it "returns issue id" do
80
- expect(subject).to eq "1"
91
+ it "returns empty Array" do
92
+ expect(subject).to eq []
81
93
  end
82
94
  end
83
95
 
84
- context 'key' do
96
+ context "when fields_attributes is Hash" do
97
+ let(:fields_attributes) do
98
+ {'key' => 'value'}
99
+ end
100
+
85
101
  let(:attribute_name) { 'key' }
86
102
 
87
- it "returns issue key" do
103
+ it "returns 'value'" do
88
104
  expect(subject).to eq "FOO-1"
89
105
  end
90
106
  end
91
107
 
92
- context 'summary' do
93
- let(:attribute_name) { 'summary' }
108
+ context "when fields_attributes is `{'key1' => {'key2' => 'value2', 'key3' => 'value3'}}`" do
109
+ let(:fields_attributes) do
110
+ {'key1' => {'key2' => 'value2', 'key3' => 'value3'}}
111
+ end
94
112
 
95
- it "returns issue summary" do
96
- expect(subject).to eq 'jira issue'
113
+ context "when attribute_name is 'key1'" do
114
+ let(:attribute_name) { 'key1' }
115
+
116
+ it "returns key1's JSON" do
117
+ expect(subject).to eq({'key2' => 'value2', 'key3' => 'value3'}.to_json)
118
+ end
119
+ end
120
+
121
+ context "when attribute_name is 'key1.key2'" do
122
+ let(:attribute_name) { 'key1.key2' }
123
+
124
+ it "returns 'value2'" do
125
+ expect(subject).to eq 'value2'
126
+ end
97
127
  end
98
128
  end
99
129
 
100
- context 'project.key' do
101
- let(:attribute_name) { 'project.key' }
130
+ context "when fields_attributes is `{'key1' => [{'key2' => 'value2-1'}, {'key2' => 'value2-2'}]}`" do
131
+ let(:fields_attributes) do
132
+ {'key1' => [{'key2' => 'value2-1'}, {'key2' => 'value2-2'}]}
133
+ end
134
+
135
+ context "when attribute_name is 'key1'" do
136
+ let(:attribute_name) { 'key1' }
102
137
 
103
- context "when project is not nil" do
104
- it "returns issue's project key" do
105
- expect(subject).to eq 'FOO'
138
+ it "returns JSON array" do
139
+ expect(subject).to eq '{"key2":"value2-1"},{"key2":"value2-2"}'
106
140
  end
107
141
  end
108
142
 
109
- context "when project is nil" do
110
- let(:project_attribute) { nil }
143
+ context "when attribute_name is 'key1.key2'" do
144
+ let(:attribute_name) { 'key1.key2' }
111
145
 
112
- it "returns nil" do
113
- expect(subject).to be_nil
146
+ it "returns CSV values assigned by 'key2' key" do
147
+ expect(subject).to eq 'value2-1,value2-2'
114
148
  end
115
149
  end
116
150
  end
117
151
 
118
- context 'labels' do
119
- let(:attribute_name) { 'labels' }
152
+ context "when fields_attributes is `{'key1' => [{'key2' => 'value2-1'}, nil]}`" do
153
+ let(:fields_attributes) do
154
+ {'key1' => [{'key2' => 'value2-1'}, nil]}
155
+ end
156
+
157
+ context "when attribute_name is 'key1'" do
158
+ let(:attribute_name) { 'key1' }
159
+
160
+ it "returns CSV value including null" do
161
+ expect(subject).to eq '{"key2":"value2-1"},null'
162
+ end
163
+ end
164
+
165
+ context "when attribute_name is 'key1.key2'" do
166
+ let(:attribute_name) { 'key1.key2' }
120
167
 
121
- it "returns issue's labels JSON string" do
122
- expect(subject).to eq '["Feature","WantTo"]'
168
+ it "returns JSON array including null" do
169
+ expect(subject).to eq 'value2-1,null'
170
+ end
123
171
  end
124
172
  end
125
173
 
126
- context 'priority' do
127
- let(:attribute_name) { 'priority' }
174
+ context "when fields_attributes is `{'key1' => ['element1', 'element2', 'element3']}`" do
175
+ let(:fields_attributes) do
176
+ {
177
+ 'key1' => ['element1', 'element2', 'element3'],
178
+ }
179
+ end
180
+
181
+ let(:attribute_name) { 'key1' }
128
182
 
129
- it "returns issue's priority JSON string" do
130
- expect(subject).to eq '{"iconUrl":"https://jira-api/images/icon.png","name":"Must","id":"1"}'
183
+ it "returns CSV values assigned by 'key1'" do
184
+ expect(subject).to eq 'element1,element2,element3'
131
185
  end
132
186
  end
133
187
  end
@@ -137,44 +191,204 @@ describe Embulk::Input::Jira::Issue do
137
191
  Embulk::Input::Jira::Issue.new(issue_attributes).to_record
138
192
  end
139
193
 
194
+ shared_examples 'return guessed record' do
195
+ it do
196
+ expect(subject).to eq expected_record
197
+ end
198
+ end
199
+
140
200
  let(:issue_attributes) do
201
+ {"jira_key" => "FOO-1", "id" => "1", "fields" => fields_attributes}
202
+ end
203
+
204
+ let(:expected_record) do
141
205
  {
142
- "id" => 1,
143
- "jira_key" => "FOO-1",
144
- "fields" => {
145
- "summary" => "jira issue",
146
- "project" => {
147
- "id" => "FOO",
148
- },
149
- "labels" =>
206
+ "key" => "FOO-1",
207
+ "id" => "1"
208
+ }.merge(exptected_record_from_fields)
209
+ end
210
+
211
+ context "when fields_attributes is `{'key' => 'value'}`" do
212
+ let(:fields_attributes) do
213
+ {'key' => 'value'}
214
+ end
215
+
216
+ let(:exptected_record_from_fields) do
217
+ {'key' => 'value'}
218
+ end
219
+
220
+ it_behaves_like "return guessed record"
221
+ end
222
+
223
+ context "when fields_attributes is `{'key1' => {'key2' => 'value2', 'key3' => 'value3'}}`" do
224
+ let(:fields_attributes) do
225
+ {
226
+ 'key1' => {
227
+ 'key2' => 'value2',
228
+ 'key3' => 'value3',
229
+ }
230
+ }
231
+ end
232
+
233
+ let(:exptected_record_from_fields) do
234
+ {
235
+ "key1.key2" => "value2",
236
+ "key1.key3" => "value3"
237
+ }
238
+ end
239
+
240
+ it_behaves_like "return guessed record"
241
+ end
242
+
243
+ context "when fields_attributes is `{'key1' => {'key2' => {'key3' => last_child}}}`" do
244
+ let(:fields_attributes) do
245
+ {'key1' => {'key2' => {'key3' => last_child}}}
246
+ end
247
+
248
+ context "when last_child is String" do
249
+ let(:last_child) do
250
+ "String"
251
+ end
252
+
253
+ let(:exptected_record_from_fields) do
254
+ {"key1.key2.key3" => "String"}
255
+ end
256
+
257
+ it_behaves_like "return guessed record"
258
+ end
259
+
260
+ context "when last_child has 'key' key" do
261
+ let(:last_child) do
262
+ {"key" => "BAR-1"}
263
+ end
264
+
265
+ let(:exptected_record_from_fields) do
266
+ {"key1.key2.key3.key" => "BAR-1"}
267
+ end
268
+
269
+ it_behaves_like "return guessed record"
270
+ end
271
+
272
+ context "when last_child has 'id' key" do
273
+ let(:last_child) do
274
+ {"id" => "20"}
275
+ end
276
+
277
+ let(:exptected_record_from_fields) do
278
+ {"key1.key2.key3.id" => "20"}
279
+ end
280
+
281
+ it_behaves_like "return guessed record"
282
+ end
283
+
284
+ context "when last_child has 'name' key" do
285
+ let(:last_child) do
286
+ {"name" => "Foo name"}
287
+ end
288
+
289
+ let(:exptected_record_from_fields) do
290
+ {"key1.key2.key3.name" => "Foo name"}
291
+ end
292
+
293
+ it_behaves_like "return guessed record"
294
+ end
295
+
296
+ context "when last_child has another key except 'key', 'id', 'name'" do
297
+ let(:last_child) do
298
+ {"customfield_0001" => "value0001"}
299
+ end
300
+
301
+ let(:exptected_record_from_fields) do
302
+ {"key1.key2.key3" => "{\"customfield_0001\":\"value0001\"}"}
303
+ end
304
+
305
+ it_behaves_like "return guessed record"
306
+ end
307
+
308
+ context "when last_child Hash Array" do
309
+ let(:last_child) do
150
310
  [
151
- "Feature",
152
- "WantTo"
153
- ],
154
- "priority" => {
155
- "iconUrl" => "https://jira-api/images/icon.png",
156
- "name" => "Must",
157
- "id" => "1"
158
- },
159
- "customfield_1" => nil,
311
+ {"key4" => "value4", "key5" => "value5-1"},
312
+ {"key6" => "value6", "key5" => "value5-2"},
313
+ ]
314
+ end
315
+
316
+ let(:exptected_record_from_fields) do
317
+ {"key1.key2.key3" => '{"key4":["value4",null],"key5":["value5-1","value5-2"],"key6":[null,"value6"]}'}
318
+ end
319
+
320
+ it_behaves_like "return guessed record"
321
+ end
322
+ end
323
+
324
+ context "when fields_attributes is `{'key1' => ['element1-1', 'element1-2', 'element1-3'], 'key2' => ['element2-1', 'element2-2', 'element2-3']}`" do
325
+ let(:fields_attributes) do
326
+ {
327
+ 'key1' => ['element1-1', 'element1-2', 'element1-3'],
328
+ 'key2' => ['element2-1', 'element2-2', 'element2-3'],
160
329
  }
161
- }
330
+ end
331
+
332
+ let(:exptected_record_from_fields) do
333
+ {
334
+ 'key1' => '"element1-1,element1-2,element1-3"',
335
+ 'key2' => '"element2-1,element2-2,element2-3"',
336
+ }
337
+ end
338
+
339
+ it_behaves_like "return guessed record"
162
340
  end
163
341
 
164
- let(:expected) do
165
- {
166
- "id" => 1,
167
- "key" => "FOO-1",
168
- "summary" => "jira issue",
169
- "project.id" => "FOO",
170
- "labels" => "[\"Feature\",\"WantTo\"]",
171
- "priority.name" => "Must",
172
- "customfield_1" => "null"
173
- }
342
+ context "when fields_attributes is `{'key' => []}`" do
343
+ let(:fields_attributes) do
344
+ {'key' => []}
345
+ end
346
+
347
+ let(:exptected_record_from_fields) do
348
+ {"key" => '""'}
349
+ end
350
+
351
+ it_behaves_like "return guessed record"
174
352
  end
175
353
 
176
- it 'return guessed record' do
177
- expect(subject).to eq expected
354
+ context "when fields_attributes is `{'key1' => { 'key2' => [{'key3' => 'value3-1'}, {'key3'=> 'value3-2'}]}}`" do
355
+ let(:fields_attributes) do
356
+ {
357
+ 'key1' => {
358
+ 'key2' => [
359
+ {'key3' => 'value3-1'}, {'key3'=> 'value3-2'},
360
+ ]
361
+ }
362
+ }
363
+ end
364
+
365
+ let(:exptected_record_from_fields) do
366
+ {
367
+ "key1.key2.key3" => '"value3-1,value3-2"',
368
+ }
369
+ end
370
+
371
+ it_behaves_like "return guessed record"
372
+ end
373
+
374
+ context "when fields_attributes is `{'key1' => { 'key2' => ['element2-1', 'element2-2', 'element2-3'], 'key3' => ['element3-1', 'element3-2', 'element3-3']}}`" do
375
+ let(:fields_attributes) do
376
+ {
377
+ 'key1' => {
378
+ 'key2' => ['element2-1', 'element2-2', 'element2-3'],
379
+ 'key3' => ['element3-1', 'element3-2', 'element3-3']
380
+ }
381
+ }
382
+ end
383
+
384
+ let(:exptected_record_from_fields) do
385
+ {
386
+ "key1.key2" => '"element2-1,element2-2,element2-3"',
387
+ "key1.key3" => '"element3-1,element3-2,element3-3"',
388
+ }
389
+ end
390
+
391
+ it_behaves_like "return guessed record"
178
392
  end
179
393
  end
180
394
  end
@@ -8,15 +8,17 @@ describe Embulk::Input::JiraInputPluginUtils do
8
8
 
9
9
  let(:records) do
10
10
  [
11
- {"project_key" => "FOO", "comment.total" => 3, "created" => "2015-03-01T00:12:00"}
11
+ {"project.key" => "FOO-1", "comment.total" => 3, "created" => "2015-03-01T00:12:00"},
12
+ {"project.id" => "1", "project.key" => "FOO", "comment.total" => 3, "created" => "2015-03-01T00:12:00"}
12
13
  ]
13
14
  end
14
15
 
15
16
  let(:expected) do
16
17
  [
17
- {name: "project_key", type: :string},
18
18
  {name: "comment.total", type: :long},
19
- {name: "created", type: :timestamp, format: "%Y-%m-%dT%H:%M:%S"}
19
+ {name: "created", type: :timestamp, format: "%Y-%m-%dT%H:%M:%S"},
20
+ {name: "project.id", type: :long},
21
+ {name: "project.key", type: :string},
20
22
  ]
21
23
  end
22
24
 
@@ -116,10 +116,12 @@ describe Embulk::Input::JiraInputPlugin do
116
116
  let(:guessed_config) do
117
117
  {
118
118
  "columns" => [
119
+ {name: "comment.comments", type: :string},
120
+ {name: "comment.total", type: :long},
119
121
  {name: "id", type: :long},
120
122
  {name: "key", type: :string},
123
+ {name: "project.key", type: :string},
121
124
  {name: "project.name", type: :string},
122
- {name: "comment", type: :string}
123
125
  ]
124
126
  }
125
127
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-input-jira
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - uu59
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-06-12 00:00:00.000000000 Z
12
+ date: 2015-06-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  requirement: !ruby/object:Gem::Requirement