embulk-input-mixpanel 0.3.4 → 0.4.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/.ruby-version +1 -1
- data/.travis.yml +13 -62
- data/.travis.yml.erb +10 -21
- data/CHANGELOG.md +11 -0
- data/embulk-input-mixpanel.gemspec +3 -2
- data/gemfiles/{embulk-0.6.0-latest → embulk-0.8.0-latest} +1 -1
- data/gemfiles/{embulk-0.7.0 → embulk-0.8.6} +1 -1
- data/gemfiles/embulk-latest +1 -1
- data/lib/embulk/input/mixpanel.rb +37 -7
- data/lib/embulk/input/mixpanel_api/client.rb +40 -28
- data/test/embulk/input/mixpanel_api/test_client.rb +18 -57
- data/test/embulk/input/test_mixpanel.rb +107 -10
- metadata +20 -24
- data/gemfiles/embulk-0.6.16 +0 -4
- data/gemfiles/embulk-0.6.17 +0 -4
- data/gemfiles/embulk-0.6.18 +0 -4
- data/gemfiles/embulk-0.6.19 +0 -4
- data/gemfiles/embulk-0.6.20 +0 -4
- data/gemfiles/embulk-0.6.21 +0 -4
- data/gemfiles/embulk-0.6.22 +0 -4
- data/gemfiles/embulk-0.6.23 +0 -4
- data/gemfiles/embulk-0.6.24 +0 -4
- data/gemfiles/embulk-0.6.25 +0 -4
- data/gemfiles/embulk-0.6.26 +0 -4
- data/gemfiles/embulk-0.6.27 +0 -4
- data/gemfiles/embulk-0.7.0-latest +0 -4
- data/gemfiles/embulk-0.7.1 +0 -4
- data/gemfiles/embulk-0.7.2 +0 -4
- data/gemfiles/embulk-0.7.3 +0 -4
- data/gemfiles/embulk-0.7.4 +0 -4
- data/gemfiles/embulk-0.7.5 +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0dedffafe59dd4e3dcbe23d13d3d2ae8f1a4046f
|
|
4
|
+
data.tar.gz: dad21a163d3dfe678e3b4d49531c476fe48af594
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0ac29f80faece33812fb85d48aed368398ea1fb2ee779cab01b7489ea1f171cfa7ea6aa9d017527d6ab8ca80b6966f29c22164ca0534f3878c1f94e2cd92b56c
|
|
7
|
+
data.tar.gz: c4a4382fd745a91c483ae5eff4b11e2aca0949a157ddcfb127d2430d273d4158c8087b350d0da5844e957a487a1c08e7bd0b1c07cef30900c23db883e870b566
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
jruby-9.0.
|
|
1
|
+
jruby-9.0.5.0
|
data/.travis.yml
CHANGED
|
@@ -1,84 +1,35 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
|
|
3
3
|
jdk: oraclejdk8
|
|
4
|
+
sudo: false
|
|
4
5
|
|
|
5
6
|
addons:
|
|
6
7
|
code_climate:
|
|
7
8
|
repo_token:
|
|
8
9
|
secure: "opE/ZhRzsEU2Fn6YEnItMD/rMs3O2OHVYQQ7Ly0dAkIc9ZrVMa//ogt4k7h0QGZUettRVV7kawCtRzde+QbOmezTRwWqQJ7Mi6D6qfwlYMz+D9FcufHaCJyLy+dYeBuQqr1d6n/3gVqVGh8MAMGHipYodudCub38DQ1sVWcCMDNNo4PMRFLS0pS839SC80HAS7tutOeaeohRc+Ct5yoY2ZDoTuGtNeJhwqmDAo13RwvVu9aZw97EZPvt8UcaW5oYDnx47kDpKi4XGrTPaWpSm/IitwW11FF+Kevt0RpUS0uVWqg4/6xTjDg++ETG+94ePYrOZGF4ne/CPtC0AtaWF1jgSlL9iu4IR/Awt+2BqawKzCnoSRgCGIHRZApErC3KacadJBaPCrKwf4xxxqRXex4lXcptKRygkG4ic2r+MblyPPwIsc1Wb1QYCeVjIEGWzOgKVEUpT8qN0DAj6KQe/HuyuXKE/FiPIRfkJkRY5oGCNZtzeCzXlC+IqhZYCg6HwcZuk3CbcxRrg5VFKDlL0VWacD/FQoGgfTp3SUmaL6NMcCKSrL0vjEgx98/yM9rsGZlZOU9ioN93PQVgqpI5dl+nm9vKkFyuzW07nNM+/6PNdHbbZBY1OLNd3RSpWVC9TDtZ3Q2gAx25+31TDzD2/3yjJjfdtwIH3bdyrO44MK8="
|
|
9
|
-
notifications:
|
|
10
|
-
slack:
|
|
11
|
-
secure: "cAAHcb/HdJK6elr6gfxlotUJdZys8nA/BUb1rKVt7T7EShOjqNOwHo0vZBG5fXQEbUJjHCFAl8tH1N8wz+KLoVErlMmD2OgBKGgvgm3fddkIgGRRvxe8yB0yEFy5yuvfgqJDlwPHZxbwj2Ddb8uTaLd8yzmRzGWNwLyRQTDaQbaKBaB+emP2t/1AilQHyItN02NuW3qcEGr7Hzg+IsKabDRzhMi89RV0xk2eP5iWTYW76ULbbfP3NqBpcVLskAqVQd1YOFUSEb2fdzRj7UuLUUp3C0Kb5gKfXPHb97XuMqwyviakTr02omdaM82NvB8GKn7QKBbcwA1Iz1euinxQQ7MTzJe8wLMH8q205lTpl96CANKwIxrk/HestgEboq97xSp5Wc1Qn1ynnrLOvBYW7EG/e6exguojQmkLkV9P6LW9g4nYsR8UEjyuRd252xch4+b4M3lxtlAXtpWguPfm5ZKhICBsJMlYm6//q1cBlNUOzR0cufCHDTNdlB/YLynvdg1ykFISYARP+5sV2YM9rD/1Rs/396qYr0mNbCh83P9GlZ5NZtWLQePJroHe3iQ18X3YHEcb50OTfRmKNoXTldQBD9iKNkwlFpWfruVdBWT+JRM77+yIV9ORjY7UE4ZtH8HxAg4bX+ey+C5axgxQk569h3CdLmVapFt6wovCSVk="
|
|
12
10
|
|
|
13
11
|
before_install:
|
|
12
|
+
- rvm list
|
|
14
13
|
- |
|
|
15
|
-
# Currently, Travis can't treat jruby 9.0.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
# Currently, Travis can't treat jruby 9.0.5.0
|
|
15
|
+
ruby -v
|
|
16
|
+
rvm get head
|
|
17
|
+
rvm use jruby-9.0.5.0 --install
|
|
18
|
+
gem install bundler
|
|
19
|
+
ruby -v
|
|
20
|
+
- gem i bundler
|
|
21
21
|
|
|
22
22
|
rvm:
|
|
23
|
-
- jruby-
|
|
24
|
-
- jruby-9.0.0.0
|
|
23
|
+
- jruby-9.0.5.0
|
|
25
24
|
|
|
26
25
|
gemfile:
|
|
27
|
-
- gemfiles/embulk-0.
|
|
28
|
-
- gemfiles/embulk-0.6
|
|
29
|
-
- gemfiles/embulk-0.6.17
|
|
30
|
-
- gemfiles/embulk-0.6.18
|
|
31
|
-
- gemfiles/embulk-0.6.19
|
|
32
|
-
- gemfiles/embulk-0.6.20
|
|
33
|
-
- gemfiles/embulk-0.6.21
|
|
34
|
-
- gemfiles/embulk-0.6.22
|
|
35
|
-
- gemfiles/embulk-0.6.23
|
|
36
|
-
- gemfiles/embulk-0.6.24
|
|
37
|
-
- gemfiles/embulk-0.6.25
|
|
38
|
-
- gemfiles/embulk-0.6.26
|
|
39
|
-
- gemfiles/embulk-0.6.27
|
|
40
|
-
- gemfiles/embulk-0.7.0
|
|
41
|
-
- gemfiles/embulk-0.7.0-latest
|
|
42
|
-
- gemfiles/embulk-0.7.1
|
|
43
|
-
- gemfiles/embulk-0.7.2
|
|
44
|
-
- gemfiles/embulk-0.7.3
|
|
45
|
-
- gemfiles/embulk-0.7.4
|
|
46
|
-
- gemfiles/embulk-0.7.5
|
|
26
|
+
- gemfiles/embulk-0.8.0-latest
|
|
27
|
+
- gemfiles/embulk-0.8.6
|
|
47
28
|
- gemfiles/embulk-latest
|
|
48
29
|
|
|
49
30
|
matrix:
|
|
50
|
-
exclude:
|
|
51
|
-
- jdk: oraclejdk8 # Ignore all matrix at first, use `include` to allow build
|
|
52
|
-
include:
|
|
53
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.0-latest}
|
|
54
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.16}
|
|
55
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.17}
|
|
56
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.18}
|
|
57
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.19}
|
|
58
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.20}
|
|
59
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.21}
|
|
60
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.22}
|
|
61
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.23}
|
|
62
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.24}
|
|
63
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.25}
|
|
64
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.26}
|
|
65
|
-
- {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.27}
|
|
66
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.0}
|
|
67
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.0-latest}
|
|
68
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.1}
|
|
69
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.2}
|
|
70
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.3}
|
|
71
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.4}
|
|
72
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.5}
|
|
73
|
-
- {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-latest}
|
|
74
|
-
|
|
75
|
-
|
|
76
31
|
allow_failures:
|
|
77
|
-
- gemfile: gemfiles/embulk-0.6.22
|
|
78
|
-
- gemfile: gemfiles/embulk-0.7.0
|
|
79
|
-
- gemfile: gemfiles/embulk-0.7.1
|
|
80
32
|
# Ignore failure for *-latest
|
|
81
|
-
- gemfile: embulk-0.
|
|
82
|
-
- gemfile: embulk-0.7.0-latest
|
|
33
|
+
- gemfile: embulk-0.8.0-latest
|
|
83
34
|
- gemfile: embulk-latest
|
|
84
35
|
|
data/.travis.yml.erb
CHANGED
|
@@ -1,27 +1,26 @@
|
|
|
1
1
|
language: ruby
|
|
2
2
|
|
|
3
3
|
jdk: oraclejdk8
|
|
4
|
+
sudo: false
|
|
4
5
|
|
|
5
6
|
addons:
|
|
6
7
|
code_climate:
|
|
7
8
|
repo_token:
|
|
8
9
|
secure: "opE/ZhRzsEU2Fn6YEnItMD/rMs3O2OHVYQQ7Ly0dAkIc9ZrVMa//ogt4k7h0QGZUettRVV7kawCtRzde+QbOmezTRwWqQJ7Mi6D6qfwlYMz+D9FcufHaCJyLy+dYeBuQqr1d6n/3gVqVGh8MAMGHipYodudCub38DQ1sVWcCMDNNo4PMRFLS0pS839SC80HAS7tutOeaeohRc+Ct5yoY2ZDoTuGtNeJhwqmDAo13RwvVu9aZw97EZPvt8UcaW5oYDnx47kDpKi4XGrTPaWpSm/IitwW11FF+Kevt0RpUS0uVWqg4/6xTjDg++ETG+94ePYrOZGF4ne/CPtC0AtaWF1jgSlL9iu4IR/Awt+2BqawKzCnoSRgCGIHRZApErC3KacadJBaPCrKwf4xxxqRXex4lXcptKRygkG4ic2r+MblyPPwIsc1Wb1QYCeVjIEGWzOgKVEUpT8qN0DAj6KQe/HuyuXKE/FiPIRfkJkRY5oGCNZtzeCzXlC+IqhZYCg6HwcZuk3CbcxRrg5VFKDlL0VWacD/FQoGgfTp3SUmaL6NMcCKSrL0vjEgx98/yM9rsGZlZOU9ioN93PQVgqpI5dl+nm9vKkFyuzW07nNM+/6PNdHbbZBY1OLNd3RSpWVC9TDtZ3Q2gAx25+31TDzD2/3yjJjfdtwIH3bdyrO44MK8="
|
|
9
|
-
notifications:
|
|
10
|
-
slack:
|
|
11
|
-
secure: "cAAHcb/HdJK6elr6gfxlotUJdZys8nA/BUb1rKVt7T7EShOjqNOwHo0vZBG5fXQEbUJjHCFAl8tH1N8wz+KLoVErlMmD2OgBKGgvgm3fddkIgGRRvxe8yB0yEFy5yuvfgqJDlwPHZxbwj2Ddb8uTaLd8yzmRzGWNwLyRQTDaQbaKBaB+emP2t/1AilQHyItN02NuW3qcEGr7Hzg+IsKabDRzhMi89RV0xk2eP5iWTYW76ULbbfP3NqBpcVLskAqVQd1YOFUSEb2fdzRj7UuLUUp3C0Kb5gKfXPHb97XuMqwyviakTr02omdaM82NvB8GKn7QKBbcwA1Iz1euinxQQ7MTzJe8wLMH8q205lTpl96CANKwIxrk/HestgEboq97xSp5Wc1Qn1ynnrLOvBYW7EG/e6exguojQmkLkV9P6LW9g4nYsR8UEjyuRd252xch4+b4M3lxtlAXtpWguPfm5ZKhICBsJMlYm6//q1cBlNUOzR0cufCHDTNdlB/YLynvdg1ykFISYARP+5sV2YM9rD/1Rs/396qYr0mNbCh83P9GlZ5NZtWLQePJroHe3iQ18X3YHEcb50OTfRmKNoXTldQBD9iKNkwlFpWfruVdBWT+JRM77+yIV9ORjY7UE4ZtH8HxAg4bX+ey+C5axgxQk569h3CdLmVapFt6wovCSVk="
|
|
12
10
|
|
|
13
11
|
before_install:
|
|
12
|
+
- rvm list
|
|
14
13
|
- |
|
|
15
|
-
# Currently, Travis can't treat jruby 9.0.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
# Currently, Travis can't treat jruby 9.0.5.0
|
|
15
|
+
ruby -v
|
|
16
|
+
rvm get head
|
|
17
|
+
rvm use jruby-9.0.5.0 --install
|
|
18
|
+
gem install bundler
|
|
19
|
+
ruby -v
|
|
20
|
+
- gem i bundler
|
|
21
21
|
|
|
22
22
|
rvm:
|
|
23
|
-
- jruby-
|
|
24
|
-
- jruby-9.0.0.0
|
|
23
|
+
- jruby-9.0.5.0
|
|
25
24
|
|
|
26
25
|
gemfile:
|
|
27
26
|
<% versions.each do |file| -%>
|
|
@@ -29,17 +28,7 @@ gemfile:
|
|
|
29
28
|
<% end -%>
|
|
30
29
|
|
|
31
30
|
matrix:
|
|
32
|
-
exclude:
|
|
33
|
-
- jdk: oraclejdk8 # Ignore all matrix at first, use `include` to allow build
|
|
34
|
-
include:
|
|
35
|
-
<% matrix.each do |m| -%>
|
|
36
|
-
<%= m %>
|
|
37
|
-
<% end %>
|
|
38
|
-
|
|
39
31
|
allow_failures:
|
|
40
|
-
- gemfile: gemfiles/embulk-0.6.22
|
|
41
|
-
- gemfile: gemfiles/embulk-0.7.0
|
|
42
|
-
- gemfile: gemfiles/embulk-0.7.1
|
|
43
32
|
# Ignore failure for *-latest
|
|
44
33
|
<% versions.find_all{|file| file.to_s.match(/-latest/)}.each do |file| -%>
|
|
45
34
|
- gemfile: <%= file %>
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## 0.4.0 - 2016-03-04
|
|
2
|
+
|
|
3
|
+
This version contains compatibility breaking. Only support Embulk 0.8 or later since this version, no longer support Embulk 0.7.x or earlier.
|
|
4
|
+
|
|
5
|
+
* [enhancement] Support json type [#35](https://github.com/treasure-data/embulk-input-mixpanel/pull/35)
|
|
6
|
+
* [enhancement] Check Mixpanel availability before run [#37](https://github.com/treasure-data/embulk-input-mixpanel/pull/37)
|
|
7
|
+
* [enhancement] Guessing time column as statically [#36](https://github.com/treasure-data/embulk-input-mixpanel/pull/36)
|
|
8
|
+
* [enhancement] Reduce guess and preview records [#34](https://github.com/treasure-data/embulk-input-mixpanel/pull/34)
|
|
9
|
+
* [maintenance] Use perfect_retry [#33](https://github.com/treasure-data/embulk-input-mixpanel/pull/33)
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
## 0.3.4 - 2015-11-02
|
|
2
13
|
|
|
3
14
|
* [enhancement] Create `unknown_columns` only when option is true [#32](https://github.com/treasure-data/embulk-input-mixpanel/pull/32)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
Gem::Specification.new do |spec|
|
|
3
3
|
spec.name = "embulk-input-mixpanel"
|
|
4
|
-
spec.version = "0.
|
|
4
|
+
spec.version = "0.4.0"
|
|
5
5
|
spec.authors = ["yoshihara", "uu59"]
|
|
6
6
|
spec.summary = "Mixpanel input plugin for Embulk"
|
|
7
7
|
spec.description = "Loads records from Mixpanel."
|
|
@@ -15,9 +15,10 @@ Gem::Specification.new do |spec|
|
|
|
15
15
|
|
|
16
16
|
spec.add_dependency 'httpclient'
|
|
17
17
|
spec.add_dependency 'tzinfo'
|
|
18
|
+
spec.add_dependency 'perfect_retry', ["~> 0.3"]
|
|
18
19
|
spec.add_development_dependency 'bundler', ['~> 1.0']
|
|
19
20
|
spec.add_development_dependency 'rake', ['>= 10.0']
|
|
20
|
-
spec.add_development_dependency 'embulk', ['>= 0.6
|
|
21
|
+
spec.add_development_dependency 'embulk', ['>= 0.8.6', '< 1.0']
|
|
21
22
|
spec.add_development_dependency 'pry'
|
|
22
23
|
spec.add_development_dependency 'test-unit'
|
|
23
24
|
spec.add_development_dependency 'test-unit-rr'
|
data/gemfiles/embulk-latest
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require "tzinfo"
|
|
2
|
+
require "perfect_retry"
|
|
2
3
|
require "embulk/input/mixpanel_api/client"
|
|
3
4
|
require "range_generator"
|
|
4
5
|
require "timezone_validator"
|
|
@@ -47,7 +48,7 @@ module Embulk
|
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
if fetch_unknown_columns
|
|
50
|
-
columns << Column.new(nil, "unknown_columns", :
|
|
51
|
+
columns << Column.new(nil, "unknown_columns", :json)
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
resume(task, columns, 1, &control)
|
|
@@ -66,17 +67,19 @@ module Embulk
|
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def self.guess(config)
|
|
70
|
+
giveup_when_mixpanel_is_down
|
|
71
|
+
|
|
69
72
|
client = MixpanelApi::Client.new(config.param(:api_key, :string), config.param(:api_secret, :string))
|
|
70
73
|
|
|
71
74
|
range = guess_range(config)
|
|
72
75
|
Embulk.logger.info "Guessing schema using #{range.first}..#{range.last} records"
|
|
73
76
|
|
|
74
77
|
params = export_params(config).merge(
|
|
75
|
-
from_date
|
|
76
|
-
to_date
|
|
78
|
+
"from_date" => range.first,
|
|
79
|
+
"to_date" => range.last,
|
|
77
80
|
)
|
|
78
81
|
|
|
79
|
-
columns = guess_from_records(client.
|
|
82
|
+
columns = guess_from_records(client.export_for_small_dataset(params))
|
|
80
83
|
return {"columns" => columns}
|
|
81
84
|
end
|
|
82
85
|
|
|
@@ -88,11 +91,23 @@ module Embulk
|
|
|
88
91
|
@schema = task[:schema]
|
|
89
92
|
@dates = task[:dates]
|
|
90
93
|
@fetch_unknown_columns = task[:fetch_unknown_columns]
|
|
94
|
+
@retryer = PerfectRetry.new do |config|
|
|
95
|
+
config.limit = task[:retry_limit]
|
|
96
|
+
config.sleep = proc{|n| task[:retry_initial_wait_sec] * (2 * (n - 1)) }
|
|
97
|
+
config.dont_rescues = [Embulk::ConfigError]
|
|
98
|
+
config.rescues = [RuntimeError]
|
|
99
|
+
config.log_level = nil
|
|
100
|
+
config.logger = Embulk.logger
|
|
101
|
+
end
|
|
91
102
|
end
|
|
92
103
|
|
|
93
104
|
def run
|
|
105
|
+
self.class.giveup_when_mixpanel_is_down
|
|
106
|
+
|
|
94
107
|
@dates.each_slice(SLICE_DAYS_COUNT) do |dates|
|
|
95
|
-
|
|
108
|
+
unless preview?
|
|
109
|
+
Embulk.logger.info "Fetching data from #{dates.first} to #{dates.last} ..."
|
|
110
|
+
end
|
|
96
111
|
|
|
97
112
|
fetch(dates).each do |record|
|
|
98
113
|
values = extract_values(record)
|
|
@@ -114,6 +129,12 @@ module Embulk
|
|
|
114
129
|
|
|
115
130
|
private
|
|
116
131
|
|
|
132
|
+
def self.giveup_when_mixpanel_is_down
|
|
133
|
+
unless MixpanelApi::Client.mixpanel_available?
|
|
134
|
+
raise Embulk::DataError.new("Mixpanel service is down. Please retry later.")
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
117
138
|
def extract_values(record)
|
|
118
139
|
@schema.map do |column|
|
|
119
140
|
extract_value(record, column["name"])
|
|
@@ -155,7 +176,14 @@ module Embulk
|
|
|
155
176
|
"to_date" => to_date,
|
|
156
177
|
)
|
|
157
178
|
client = MixpanelApi::Client.new(@api_key, @api_secret)
|
|
158
|
-
|
|
179
|
+
|
|
180
|
+
@retryer.with_retry do
|
|
181
|
+
if preview?
|
|
182
|
+
client.export_for_small_dataset(params)
|
|
183
|
+
else
|
|
184
|
+
client.export(params)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
159
187
|
end
|
|
160
188
|
|
|
161
189
|
def adjust_timezone(epoch)
|
|
@@ -204,14 +232,16 @@ module Embulk
|
|
|
204
232
|
sample_props = records.first(GUESS_RECORDS_COUNT).map{|r| r["properties"]}
|
|
205
233
|
schema = Guess::SchemaGuess.from_hash_records(sample_props)
|
|
206
234
|
columns = schema.map do |col|
|
|
235
|
+
next if col.name == "time"
|
|
207
236
|
result = {
|
|
208
237
|
name: col.name,
|
|
209
238
|
type: col.type,
|
|
210
239
|
}
|
|
211
240
|
result[:format] = col.format if col.format
|
|
212
241
|
result
|
|
213
|
-
end
|
|
242
|
+
end.compact
|
|
214
243
|
columns.unshift(name: NOT_PROPERTY_COLUMN, type: :string)
|
|
244
|
+
columns.unshift(name: "time", type: :long)
|
|
215
245
|
end
|
|
216
246
|
end
|
|
217
247
|
|
|
@@ -9,23 +9,55 @@ module Embulk
|
|
|
9
9
|
class Client
|
|
10
10
|
ENDPOINT_EXPORT = "https://data.mixpanel.com/api/2.0/export/".freeze
|
|
11
11
|
TIMEOUT_SECONDS = 3600
|
|
12
|
+
PING_TIMEOUT_SECONDS = 3
|
|
13
|
+
PING_RETRY_LIMIT = 3
|
|
14
|
+
PING_RETRY_WAIT = 2
|
|
15
|
+
|
|
16
|
+
def self.mixpanel_available?
|
|
17
|
+
retryer = PerfectRetry.new do |config|
|
|
18
|
+
config.limit = PING_RETRY_LIMIT
|
|
19
|
+
config.sleep = PING_RETRY_WAIT
|
|
20
|
+
config.logger = Embulk.logger
|
|
21
|
+
config.log_level = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
begin
|
|
25
|
+
retryer.with_retry do
|
|
26
|
+
client = HTTPClient.new
|
|
27
|
+
client.connect_timeout = PING_TIMEOUT_SECONDS
|
|
28
|
+
client.get("https://data.mixpanel.com")
|
|
29
|
+
end
|
|
30
|
+
true
|
|
31
|
+
rescue PerfectRetry::TooManyRetry
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
end
|
|
12
35
|
|
|
13
36
|
def initialize(api_key, api_secret)
|
|
14
37
|
@api_key = api_key
|
|
15
38
|
@api_secret = api_secret
|
|
16
39
|
end
|
|
17
40
|
|
|
18
|
-
def
|
|
19
|
-
body =
|
|
20
|
-
request(params)
|
|
21
|
-
end
|
|
22
|
-
|
|
41
|
+
def export(params = {})
|
|
42
|
+
body = request(params)
|
|
23
43
|
response_to_enum(body)
|
|
24
44
|
end
|
|
25
45
|
|
|
26
|
-
def
|
|
46
|
+
def export_for_small_dataset(params = {}, times = 0)
|
|
47
|
+
days = (1 * (10 ** times))
|
|
48
|
+
to_date = Date.parse(params["from_date"].to_s) + days
|
|
49
|
+
params["to_date"] = to_date.strftime("%Y-%m-%d")
|
|
50
|
+
|
|
27
51
|
body = request(params)
|
|
28
|
-
response_to_enum(body)
|
|
52
|
+
result = response_to_enum(body)
|
|
53
|
+
if result.to_a.length.zero?
|
|
54
|
+
if times >= 5
|
|
55
|
+
raise ConfigError.new "#{params["from_date"]} + #{days} days has no record. too old date?"
|
|
56
|
+
end
|
|
57
|
+
export_for_small_dataset(params, times + 1)
|
|
58
|
+
else
|
|
59
|
+
result
|
|
60
|
+
end
|
|
29
61
|
end
|
|
30
62
|
|
|
31
63
|
private
|
|
@@ -56,29 +88,9 @@ module Embulk
|
|
|
56
88
|
response.body
|
|
57
89
|
end
|
|
58
90
|
|
|
59
|
-
def with_retry(initial_wait, retry_limit, &block)
|
|
60
|
-
retry_count = 0
|
|
61
|
-
wait_sec = initial_wait
|
|
62
|
-
begin
|
|
63
|
-
yield
|
|
64
|
-
rescue Embulk::ConfigError => e # TODO: rescue Embulk::DataError for Embulk 0.7+
|
|
65
|
-
# Don't retry
|
|
66
|
-
raise e
|
|
67
|
-
rescue => e
|
|
68
|
-
if retry_limit <= retry_count
|
|
69
|
-
Embulk.logger.error "'#{e}(#{e.class})' error occured and reached retry limit (#{retry_limit} times)"
|
|
70
|
-
raise e
|
|
71
|
-
end
|
|
72
|
-
retry_count += 1
|
|
73
|
-
Embulk.logger.warn "Retrying after #{wait_sec} seconds [#{retry_count}/#{retry_limit}] '#{e}(#{e.class})' error occured"
|
|
74
|
-
sleep wait_sec
|
|
75
|
-
wait_sec *= 2
|
|
76
|
-
retry
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
91
|
def signature(params)
|
|
81
92
|
# https://mixpanel.com/docs/api-documentation/data-export-api#auth-implementation
|
|
93
|
+
params.delete(:sig)
|
|
82
94
|
sorted_keys = params.keys.map(&:to_s).sort
|
|
83
95
|
signature = sorted_keys.inject("") do |sig, key|
|
|
84
96
|
value = params[key] || params[key.to_sym]
|
|
@@ -89,69 +89,30 @@ module Embulk
|
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
|
|
92
|
-
class
|
|
93
|
-
def
|
|
94
|
-
|
|
95
|
-
@client
|
|
96
|
-
@retry_initial_wait_sec = 1
|
|
97
|
-
@retry_limit = 3
|
|
98
|
-
stub_client
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def test_retry_with_500
|
|
102
|
-
stub_response(failure_response(500))
|
|
103
|
-
|
|
104
|
-
@retry_limit.times do |n|
|
|
105
|
-
mock(@client).sleep(@retry_initial_wait_sec * (2**n))
|
|
106
|
-
end
|
|
107
|
-
mock(Embulk.logger).warn(/retry/i).times(@retry_limit)
|
|
108
|
-
mock(Embulk.logger).error(/retry/i).once
|
|
92
|
+
class ExportSmallDataset < self
|
|
93
|
+
def test_to_date_after_1_day
|
|
94
|
+
to = (Date.parse(params["from_date"]) + 1).to_s
|
|
95
|
+
mock(@client).request(params.merge("to_date" => to)) { jsonl_dummy_responses }
|
|
109
96
|
|
|
110
|
-
|
|
111
|
-
@client.export_with_retry(params, @retry_initial_wait_sec, @retry_limit)
|
|
112
|
-
end
|
|
97
|
+
@client.export_for_small_dataset(params)
|
|
113
98
|
end
|
|
114
99
|
|
|
115
|
-
def
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
@
|
|
119
|
-
|
|
120
|
-
end
|
|
121
|
-
mock(Embulk.logger).warn(/retry/i).times(@retry_limit)
|
|
122
|
-
mock(Embulk.logger).error(/retry/i).once
|
|
100
|
+
def test_to_date_after_1_day_after_10_days_if_empty
|
|
101
|
+
to1 = (Date.parse(params["from_date"]) + 1).to_s
|
|
102
|
+
to2 = (Date.parse(params["from_date"]) + 10).to_s
|
|
103
|
+
mock(@client).request(params.merge("to_date" => to1)) { "" }
|
|
104
|
+
mock(@client).request(params.merge("to_date" => to2)) { jsonl_dummy_responses }
|
|
123
105
|
|
|
124
|
-
|
|
125
|
-
@client.export_with_retry(params, @retry_initial_wait_sec, @retry_limit)
|
|
126
|
-
end
|
|
106
|
+
@client.export_for_small_dataset(params)
|
|
127
107
|
end
|
|
128
108
|
|
|
129
|
-
def
|
|
130
|
-
@
|
|
131
|
-
mock(Embulk.logger).warn(/retry/i).never
|
|
132
|
-
mock(Embulk.logger).error(/retry/i).never
|
|
109
|
+
def test_config_error_when_too_long_empty_dates
|
|
110
|
+
stub(@client).request(anything) { "" }
|
|
133
111
|
|
|
134
112
|
assert_raise(Embulk::ConfigError) do
|
|
135
|
-
@client.
|
|
136
|
-
record
|
|
137
|
-
end
|
|
113
|
+
@client.export_for_small_dataset(params)
|
|
138
114
|
end
|
|
139
115
|
end
|
|
140
|
-
|
|
141
|
-
def test_not_retry_with_invalid_json
|
|
142
|
-
omit "Embulk 0.6 or earlier has no DataError (enable to uncomment below code)"
|
|
143
|
-
|
|
144
|
-
# @httpclient.test_loopback_http_response << "HTTP/1.1 200\r\n\r\ninvalid json"
|
|
145
|
-
# mock(Embulk.logger).warn(/retry/i).never
|
|
146
|
-
# mock(Embulk.logger).error(/retry/i).never
|
|
147
|
-
|
|
148
|
-
# assert_raise(Embulk::DataError) do
|
|
149
|
-
# @client.export_with_retry(params, 0, 1).each do |record|
|
|
150
|
-
# # DataError will raised in each block
|
|
151
|
-
# record
|
|
152
|
-
# end
|
|
153
|
-
# end
|
|
154
|
-
end
|
|
155
116
|
end
|
|
156
117
|
|
|
157
118
|
private
|
|
@@ -176,10 +137,10 @@ module Embulk
|
|
|
176
137
|
|
|
177
138
|
def params
|
|
178
139
|
{
|
|
179
|
-
api_key
|
|
180
|
-
api_secret
|
|
181
|
-
from_date
|
|
182
|
-
to_date
|
|
140
|
+
"api_key" => API_KEY,
|
|
141
|
+
"api_secret" => API_SECRET,
|
|
142
|
+
"from_date" => "2015-01-01",
|
|
143
|
+
"to_date" => "2015-03-02",
|
|
183
144
|
}
|
|
184
145
|
end
|
|
185
146
|
|
|
@@ -24,6 +24,7 @@ module Embulk
|
|
|
24
24
|
def setup
|
|
25
25
|
setup_client
|
|
26
26
|
setup_logger
|
|
27
|
+
stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def setup_client
|
|
@@ -53,6 +54,7 @@ module Embulk
|
|
|
53
54
|
def setup
|
|
54
55
|
# Do nothing from parent
|
|
55
56
|
mute_warn
|
|
57
|
+
stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
|
|
56
58
|
end
|
|
57
59
|
|
|
58
60
|
def test_from_date_old_date
|
|
@@ -112,11 +114,33 @@ module Embulk
|
|
|
112
114
|
Mixpanel.guess(embulk_config(config))
|
|
113
115
|
end
|
|
114
116
|
|
|
117
|
+
def test_json_type
|
|
118
|
+
sample_records = records.map do |r|
|
|
119
|
+
r.merge("properties" => {"array" => [1,2], "hash" => {foo: "FOO"}})
|
|
120
|
+
end
|
|
121
|
+
actual = Mixpanel.guess_from_records(sample_records)
|
|
122
|
+
assert actual.include?(name: "array", type: :json)
|
|
123
|
+
assert actual.include?(name: "hash", type: :json)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def test_mixpanel_is_down
|
|
127
|
+
stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { false }
|
|
128
|
+
config = {
|
|
129
|
+
type: "mixpanel",
|
|
130
|
+
api_key: API_KEY,
|
|
131
|
+
api_secret: API_SECRET,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
assert_raise(Embulk::DataError) do
|
|
135
|
+
Mixpanel.guess(embulk_config(config))
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
115
139
|
private
|
|
116
140
|
|
|
117
141
|
def stub_export_all
|
|
118
142
|
any_instance_of(MixpanelApi::Client) do |klass|
|
|
119
|
-
stub(klass).
|
|
143
|
+
stub(klass).export_for_small_dataset(anything) { records }
|
|
120
144
|
end
|
|
121
145
|
end
|
|
122
146
|
|
|
@@ -131,9 +155,9 @@ module Embulk
|
|
|
131
155
|
def expected
|
|
132
156
|
{
|
|
133
157
|
"columns" => [
|
|
158
|
+
{name: "time", type: :long},
|
|
134
159
|
{name: "event", type: :string},
|
|
135
160
|
{name: "foo", type: :string},
|
|
136
|
-
{name: "time", type: :long},
|
|
137
161
|
{name: "int", type: :long},
|
|
138
162
|
]
|
|
139
163
|
}
|
|
@@ -364,6 +388,87 @@ module Embulk
|
|
|
364
388
|
assert_equal(expected, actual)
|
|
365
389
|
end
|
|
366
390
|
|
|
391
|
+
sub_test_case "retry" do
|
|
392
|
+
def setup
|
|
393
|
+
@page_builder = Object.new
|
|
394
|
+
@plugin = Mixpanel.new(task, nil, nil, @page_builder)
|
|
395
|
+
@plugin.init
|
|
396
|
+
@httpclient = HTTPClient.new
|
|
397
|
+
stub(HTTPClient).new { @httpclient }
|
|
398
|
+
stub(@page_builder).add {}
|
|
399
|
+
stub(@page_builder).finish {}
|
|
400
|
+
stub(Embulk.logger).warn {}
|
|
401
|
+
stub(Embulk.logger).info {}
|
|
402
|
+
stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
test "200" do
|
|
406
|
+
stub_response(200)
|
|
407
|
+
mock(Embulk.logger).warn(/Retrying/).never
|
|
408
|
+
mock(@page_builder).finish
|
|
409
|
+
@plugin.run
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
test "400" do
|
|
413
|
+
stub_response(400)
|
|
414
|
+
mock(Embulk.logger).warn(/Retrying/).never
|
|
415
|
+
assert_raise(Embulk::ConfigError) do
|
|
416
|
+
@plugin.run
|
|
417
|
+
end
|
|
418
|
+
end
|
|
419
|
+
|
|
420
|
+
test "401" do
|
|
421
|
+
stub_response(401)
|
|
422
|
+
mock(Embulk.logger).warn(/Retrying/).never
|
|
423
|
+
assert_raise(Embulk::ConfigError) do
|
|
424
|
+
@plugin.run
|
|
425
|
+
end
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
test "500" do
|
|
429
|
+
stub_response(500)
|
|
430
|
+
mock(Embulk.logger).warn(/Retrying/).times(task[:retry_limit])
|
|
431
|
+
assert_raise(PerfectRetry::TooManyRetry) do
|
|
432
|
+
@plugin.run
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
test "timeout" do
|
|
437
|
+
stub(@httpclient).get { raise HTTPClient::TimeoutError, "timeout" }
|
|
438
|
+
mock(Embulk.logger).warn(/Retrying/).times(task[:retry_limit])
|
|
439
|
+
|
|
440
|
+
assert_raise(PerfectRetry::TooManyRetry) do
|
|
441
|
+
@plugin.run
|
|
442
|
+
end
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
test "Mixpanel is down" do
|
|
446
|
+
stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { false }
|
|
447
|
+
|
|
448
|
+
assert_raise(Embulk::DataError) do
|
|
449
|
+
@plugin.run
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def stub_response(code)
|
|
454
|
+
stub(@httpclient.test_loopback_http_response).shift { "HTTP/1.1 #{code}\r\n\r\n" }
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def task
|
|
458
|
+
{
|
|
459
|
+
api_key: API_KEY,
|
|
460
|
+
api_secret: API_SECRET,
|
|
461
|
+
timezone: TIMEZONE,
|
|
462
|
+
schema: schema,
|
|
463
|
+
dates: DATES.to_a.map(&:to_s),
|
|
464
|
+
params: Mixpanel.export_params(embulk_config),
|
|
465
|
+
fetch_unknown_columns: false,
|
|
466
|
+
retry_initial_wait_sec: 0,
|
|
467
|
+
retry_limit: 3,
|
|
468
|
+
}
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
|
|
367
472
|
class RunTest < self
|
|
368
473
|
def setup_client
|
|
369
474
|
|
|
@@ -379,14 +484,6 @@ module Embulk
|
|
|
379
484
|
@plugin = Mixpanel.new(task, nil, nil, @page_builder)
|
|
380
485
|
end
|
|
381
486
|
|
|
382
|
-
def test_preview_check
|
|
383
|
-
mock(@plugin).preview? { true }
|
|
384
|
-
stub(@page_builder).add(anything)
|
|
385
|
-
stub(@page_builder).finish
|
|
386
|
-
|
|
387
|
-
@plugin.run
|
|
388
|
-
end
|
|
389
|
-
|
|
390
487
|
def test_preview
|
|
391
488
|
stub(@plugin).preview? { true }
|
|
392
489
|
mock(@page_builder).add(anything).times(records.length)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: embulk-input-mixpanel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- yoshihara
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date:
|
|
12
|
+
date: 2016-03-04 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -39,6 +39,20 @@ dependencies:
|
|
|
39
39
|
- - ">="
|
|
40
40
|
- !ruby/object:Gem::Version
|
|
41
41
|
version: '0'
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.3'
|
|
48
|
+
name: perfect_retry
|
|
49
|
+
prerelease: false
|
|
50
|
+
type: :runtime
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - "~>"
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0.3'
|
|
42
56
|
- !ruby/object:Gem::Dependency
|
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
|
44
58
|
requirements:
|
|
@@ -72,7 +86,7 @@ dependencies:
|
|
|
72
86
|
requirements:
|
|
73
87
|
- - ">="
|
|
74
88
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: 0.6
|
|
89
|
+
version: 0.8.6
|
|
76
90
|
- - "<"
|
|
77
91
|
- !ruby/object:Gem::Version
|
|
78
92
|
version: '1.0'
|
|
@@ -83,7 +97,7 @@ dependencies:
|
|
|
83
97
|
requirements:
|
|
84
98
|
- - ">="
|
|
85
99
|
- !ruby/object:Gem::Version
|
|
86
|
-
version: 0.6
|
|
100
|
+
version: 0.8.6
|
|
87
101
|
- - "<"
|
|
88
102
|
- !ruby/object:Gem::Version
|
|
89
103
|
version: '1.0'
|
|
@@ -175,26 +189,8 @@ files:
|
|
|
175
189
|
- README.md
|
|
176
190
|
- Rakefile
|
|
177
191
|
- embulk-input-mixpanel.gemspec
|
|
178
|
-
- gemfiles/embulk-0.
|
|
179
|
-
- gemfiles/embulk-0.6
|
|
180
|
-
- gemfiles/embulk-0.6.17
|
|
181
|
-
- gemfiles/embulk-0.6.18
|
|
182
|
-
- gemfiles/embulk-0.6.19
|
|
183
|
-
- gemfiles/embulk-0.6.20
|
|
184
|
-
- gemfiles/embulk-0.6.21
|
|
185
|
-
- gemfiles/embulk-0.6.22
|
|
186
|
-
- gemfiles/embulk-0.6.23
|
|
187
|
-
- gemfiles/embulk-0.6.24
|
|
188
|
-
- gemfiles/embulk-0.6.25
|
|
189
|
-
- gemfiles/embulk-0.6.26
|
|
190
|
-
- gemfiles/embulk-0.6.27
|
|
191
|
-
- gemfiles/embulk-0.7.0
|
|
192
|
-
- gemfiles/embulk-0.7.0-latest
|
|
193
|
-
- gemfiles/embulk-0.7.1
|
|
194
|
-
- gemfiles/embulk-0.7.2
|
|
195
|
-
- gemfiles/embulk-0.7.3
|
|
196
|
-
- gemfiles/embulk-0.7.4
|
|
197
|
-
- gemfiles/embulk-0.7.5
|
|
192
|
+
- gemfiles/embulk-0.8.0-latest
|
|
193
|
+
- gemfiles/embulk-0.8.6
|
|
198
194
|
- gemfiles/embulk-latest
|
|
199
195
|
- gemfiles/template.erb
|
|
200
196
|
- lib/embulk/input/mixpanel.rb
|
data/gemfiles/embulk-0.6.16
DELETED
data/gemfiles/embulk-0.6.17
DELETED
data/gemfiles/embulk-0.6.18
DELETED
data/gemfiles/embulk-0.6.19
DELETED
data/gemfiles/embulk-0.6.20
DELETED
data/gemfiles/embulk-0.6.21
DELETED
data/gemfiles/embulk-0.6.22
DELETED
data/gemfiles/embulk-0.6.23
DELETED
data/gemfiles/embulk-0.6.24
DELETED
data/gemfiles/embulk-0.6.25
DELETED
data/gemfiles/embulk-0.6.26
DELETED
data/gemfiles/embulk-0.6.27
DELETED
data/gemfiles/embulk-0.7.1
DELETED
data/gemfiles/embulk-0.7.2
DELETED
data/gemfiles/embulk-0.7.3
DELETED
data/gemfiles/embulk-0.7.4
DELETED
data/gemfiles/embulk-0.7.5
DELETED