embulk-input-jira 0.2.4 → 0.2.5
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/.gitignore +1 -0
- data/CHANGELOG.md +4 -0
- data/embulk-input-jira.gemspec +2 -1
- data/lib/embulk/input/jira.rb +1 -1
- data/lib/embulk/input/jira_api/client.rb +73 -30
- data/spec/embulk/input/jira_api/client_spec.rb +80 -5
- metadata +47 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f18cc941dfa5acf3d4042b5bf94be8f56f839874
|
4
|
+
data.tar.gz: fe29da077a7423972da281afd02d9818ddbb1214
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c65a216e19e5117bafc0b72a460c8705e19249aecfb5869cf92d2ee5f120d438f1dedcc34a947b92388b1c236542da39fbfcdc66d44a1c335662c4837dbac0a4
|
7
|
+
data.tar.gz: 1791e18b0d566961f64dfa20c854dfba3aa712732cf28974577e3ac903c6fcd9be287eab04279eefc8e3bc452e0ad73dae7a3da4de36de123a9c90422c9bbee1
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
## 0.2.5 - 2018-11-27
|
2
|
+
|
3
|
+
* [fixed] Fix infinitive 401 errors and dynamically adjust parallel threads [#52](https://github.com/treasure-data/embulk-input-jira/pull/52)
|
4
|
+
|
1
5
|
## 0.2.4 - 2017-11-17
|
2
6
|
|
3
7
|
* [fixed] Fixed checking credentials by `Jiralicious User` [#51](https://github.com/treasure-data/embulk-input-jira/pull/51)
|
data/embulk-input-jira.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "embulk-input-jira"
|
3
|
-
spec.version = "0.2.
|
3
|
+
spec.version = "0.2.5"
|
4
4
|
spec.authors = ["uu59", "yoshihara"]
|
5
5
|
spec.summary = "Jira input plugin for Embulk"
|
6
6
|
spec.description = "Loads records from Jira."
|
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|
14
14
|
|
15
15
|
spec.add_dependency 'jiralicious', ['~> 0.5.0']
|
16
16
|
spec.add_dependency 'parallel', ['~> 1.6.0']
|
17
|
+
spec.add_dependency 'ruby-limiter', ['~> 1.0']
|
17
18
|
spec.add_dependency 'perfect_retry', ['~> 0.3']
|
18
19
|
spec.add_development_dependency 'bundler', ['~> 1.0']
|
19
20
|
spec.add_development_dependency 'rake', ['< 11.0']
|
data/lib/embulk/input/jira.rb
CHANGED
@@ -103,7 +103,7 @@ module Embulk
|
|
103
103
|
last_page = (total_count.to_f / PER_PAGE).ceil
|
104
104
|
|
105
105
|
0.step(total_count, PER_PAGE).with_index(1) do |start_at, page|
|
106
|
-
logger.
|
106
|
+
logger.info "Fetching #{page} / #{last_page} page"
|
107
107
|
@retryer.with_retry do
|
108
108
|
@jira.search_issues(@jql, options.merge(start_at: start_at)).each do |issue|
|
109
109
|
values = @attributes.map do |(attribute_name, type)|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "jiralicious"
|
2
2
|
require "parallel"
|
3
|
+
require "limiter"
|
3
4
|
require "embulk/input/jira_api/issue"
|
4
5
|
require "timeout"
|
5
6
|
|
@@ -7,31 +8,68 @@ module Embulk
|
|
7
8
|
module Input
|
8
9
|
module JiraApi
|
9
10
|
class Client
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
MAX_RATE_LIMIT = 50
|
12
|
+
MIN_RATE_LIMIT = 2
|
13
|
+
# Normal http request timeout is 300s
|
14
|
+
SEARCH_ISSUES_TIMEOUT_SECONDS = 300
|
13
15
|
DEFAULT_SEARCH_RETRY_TIMES = 10
|
14
16
|
|
17
|
+
def initialize
|
18
|
+
@rate_limiter = Limiter::RateQueue.new(MAX_RATE_LIMIT, interval: 2)
|
19
|
+
end
|
20
|
+
|
15
21
|
def self.setup(&block)
|
16
22
|
Jiralicious.configure(&block)
|
17
23
|
new
|
18
24
|
end
|
19
25
|
|
20
26
|
def search_issues(jql, options={})
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
issues_raw = search(jql, options).issues_raw
|
28
|
+
# Maximum number of issues to retrieve is 50
|
29
|
+
rate_limit = MAX_RATE_LIMIT
|
30
|
+
success_items = []
|
31
|
+
fail_items = []
|
32
|
+
error_object = nil
|
33
|
+
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS * MAX_RATE_LIMIT ) do
|
34
|
+
retry_count = 0
|
35
|
+
semaphore = Mutex.new
|
36
|
+
@rate_limiter = Limiter::RateQueue.new(rate_limit, interval: 2)
|
37
|
+
error_object = nil
|
38
|
+
while issues_raw.length > 0 && retry_count <= DEFAULT_SEARCH_RETRY_TIMES do
|
39
|
+
Parallel.each(issues_raw, in_threads: rate_limit) do |issue_raw|
|
40
|
+
# https://github.com/dorack/jiralicious/blob/v0.4.0/lib/jiralicious/search_result.rb#L32-34
|
41
|
+
begin
|
42
|
+
issue = find_issue(issue_raw["key"])
|
43
|
+
semaphore.synchronize {
|
44
|
+
success_items.push(JiraApi::Issue.new(issue))
|
45
|
+
}
|
46
|
+
rescue MultiJson::ParseError => e
|
47
|
+
html = e.message
|
48
|
+
title = html[%r|<title>(.*?)</title>|, 1]
|
49
|
+
# 401 due to high number of concurrent requests with current account
|
50
|
+
# The number of concurrent requests is not fixed by every account
|
51
|
+
# Hence catch the error item and retry later
|
52
|
+
raise title if title != "Unauthorized (401)"
|
53
|
+
semaphore.synchronize {
|
54
|
+
fail_items.push(issue_raw)
|
55
|
+
error_object = e
|
56
|
+
}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
retry_count += 1
|
60
|
+
rate_limit = calculate_rate_limit(rate_limit, issues_raw.length, fail_items.length, retry_count)
|
61
|
+
issues_raw = fail_items
|
62
|
+
fail_items = []
|
63
|
+
raise error_object if retry_count > DEFAULT_SEARCH_RETRY_TIMES && !error_object.nil?
|
64
|
+
# Sleep after some seconds for JIRA API perhaps under the overload
|
65
|
+
sleep retry_count if fail_items.length > 0
|
29
66
|
end
|
67
|
+
success_items
|
30
68
|
end
|
31
69
|
end
|
32
70
|
|
33
71
|
def search(jql, options={})
|
34
|
-
timeout_and_retry(
|
72
|
+
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS) do
|
35
73
|
Jiralicious.search(jql, options)
|
36
74
|
end
|
37
75
|
end
|
@@ -53,10 +91,19 @@ module Embulk
|
|
53
91
|
raise ConfigError.new("Can not authorize with your credential.") if title == 'Unauthorized (401)'
|
54
92
|
end
|
55
93
|
|
94
|
+
# Calculate rate limit based on previous run result
|
95
|
+
# Return 2 MIN_RATE_LIMIT in case turning from the 5th times or success_items is less than 2
|
96
|
+
# Otherwise return the min number between fail_items, success_items and current_limit
|
97
|
+
def calculate_rate_limit(current_limit, all_items, fail_items, times)
|
98
|
+
success_items = all_items - fail_items
|
99
|
+
return MIN_RATE_LIMIT if times >= DEFAULT_SEARCH_RETRY_TIMES/2 || success_items < MIN_RATE_LIMIT
|
100
|
+
return [fail_items, success_items, current_limit].min
|
101
|
+
end
|
102
|
+
|
56
103
|
private
|
57
104
|
|
58
105
|
def timeout_and_retry(wait, retry_times = DEFAULT_SEARCH_RETRY_TIMES, &block)
|
59
|
-
count =
|
106
|
+
count = 0
|
60
107
|
begin
|
61
108
|
Timeout.timeout(wait) do
|
62
109
|
yield
|
@@ -72,29 +119,25 @@ module Embulk
|
|
72
119
|
# And (b) `search_issues` method has race-condition bug. If it occurred, MultiJson::ParseError raised too.
|
73
120
|
html = e.message
|
74
121
|
title = html[%r|<title>(.*?)</title>|, 1] #=> e.g. "Unauthorized (401)"
|
75
|
-
if title
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
when "Unauthorized (401)"
|
82
|
-
Embulk.logger.warn "JIRA returns error: #{title}. Will go to retry"
|
83
|
-
count += 1
|
84
|
-
retry
|
85
|
-
end
|
86
|
-
else
|
87
|
-
# (b)
|
88
|
-
count += 1
|
89
|
-
retry
|
90
|
-
end
|
122
|
+
raise title if title == "Atlassian Cloud Notifications - Page Unavailable"
|
123
|
+
count += 1
|
124
|
+
raise title.nil? ? "Unknown Error" : title if count > retry_times
|
125
|
+
Embulk.logger.warn "JIRA returns error: #{title == 'Unauthorized (401)' ? title + " due to overloading API requests. Retrying on failed items only" : title}."
|
126
|
+
sleep count
|
127
|
+
retry
|
91
128
|
rescue Timeout::Error => e
|
92
129
|
count += 1
|
93
|
-
sleep count # retry after some seconds for JIRA API perhaps under the overload
|
94
130
|
raise e if count > retry_times
|
131
|
+
Embulk.logger.warn "Time out error."
|
132
|
+
sleep count # retry after some seconds for JIRA API perhaps under the overload
|
95
133
|
retry
|
96
134
|
end
|
97
135
|
end
|
136
|
+
|
137
|
+
def find_issue(issue_key)
|
138
|
+
@rate_limiter.shift
|
139
|
+
Jiralicious::Issue.find(issue_key)
|
140
|
+
end
|
98
141
|
end
|
99
142
|
end
|
100
143
|
end
|
@@ -30,7 +30,7 @@ describe Embulk::Input::JiraApi::Client do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it "retry DEFAULT_SEARCH_RETRY_TIMES times then raise error" do
|
33
|
-
expect(Timeout).to receive(:timeout).exactly(Embulk::Input::JiraApi::Client::DEFAULT_SEARCH_RETRY_TIMES)
|
33
|
+
expect(Timeout).to receive(:timeout).exactly(Embulk::Input::JiraApi::Client::DEFAULT_SEARCH_RETRY_TIMES + 1)
|
34
34
|
expect { subject }.to raise_error
|
35
35
|
end
|
36
36
|
end
|
@@ -38,6 +38,9 @@ describe Embulk::Input::JiraApi::Client do
|
|
38
38
|
|
39
39
|
describe "#search_issues" do
|
40
40
|
let(:jql) { "project=FOO" }
|
41
|
+
let(:jira_api) { Embulk::Input::JiraApi::Client.new }
|
42
|
+
let(:title_401) { "Unauthorized (401)"}
|
43
|
+
let(:multi_json_error) {MultiJson::ParseError.build(StandardError.new("<title>#{title_401}</title>"), {})}
|
41
44
|
let(:results) do
|
42
45
|
[
|
43
46
|
{
|
@@ -67,15 +70,39 @@ describe Embulk::Input::JiraApi::Client do
|
|
67
70
|
]
|
68
71
|
end
|
69
72
|
|
70
|
-
subject {
|
73
|
+
subject { jira_api.search_issues(jql) }
|
71
74
|
|
72
|
-
it do
|
75
|
+
it "Search issues successfully" do
|
76
|
+
allow(Jiralicious).to receive_message_chain(:search, :issues_raw).and_return(results)
|
77
|
+
allow(jira_api).to receive(:find_issue).and_return(results.first)
|
78
|
+
|
79
|
+
expect(subject).to be_kind_of Array
|
80
|
+
expect(subject.map(&:class)).to match_array [Embulk::Input::JiraApi::Issue, Embulk::Input::JiraApi::Issue]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "Search issues successfully when first item success - 401 - second items success" do
|
73
84
|
allow(Jiralicious).to receive_message_chain(:search, :issues_raw).and_return(results)
|
74
|
-
allow(
|
85
|
+
allow(jira_api).to receive(:find_issue).and_return(results.first).and_raise(multi_json_error).and_return(results.first)
|
75
86
|
|
76
87
|
expect(subject).to be_kind_of Array
|
77
88
|
expect(subject.map(&:class)).to match_array [Embulk::Input::JiraApi::Issue, Embulk::Input::JiraApi::Issue]
|
78
89
|
end
|
90
|
+
|
91
|
+
it "Search issues successfully when 401 - first and second items success" do
|
92
|
+
allow(Jiralicious).to receive_message_chain(:search, :issues_raw).and_return(results)
|
93
|
+
allow(jira_api).to receive(:find_issue).and_raise(multi_json_error).and_return(results.first)
|
94
|
+
|
95
|
+
expect(subject).to be_kind_of Array
|
96
|
+
expect(subject.map(&:class)).to match_array [Embulk::Input::JiraApi::Issue, Embulk::Input::JiraApi::Issue]
|
97
|
+
end
|
98
|
+
|
99
|
+
it "Search issues got 401 due to high concurrent load issues" do
|
100
|
+
allow(Jiralicious).to receive_message_chain(:search, :issues_raw).and_return(results)
|
101
|
+
allow(jira_api).to receive(:find_issue).and_raise(multi_json_error)
|
102
|
+
allow(jira_api).to receive(:sleep)
|
103
|
+
|
104
|
+
expect { subject }.to raise_error(StandardError, title_401)
|
105
|
+
end
|
79
106
|
end
|
80
107
|
|
81
108
|
describe "#total_count" do
|
@@ -120,7 +147,7 @@ describe Embulk::Input::JiraApi::Client do
|
|
120
147
|
it "Always timeout, raise error after N times retry" do
|
121
148
|
allow(Timeout).to receive(:timeout) { raise Timeout::Error }
|
122
149
|
|
123
|
-
expect(Timeout).to receive(:timeout).with(wait).exactly(retry_times).times
|
150
|
+
expect(Timeout).to receive(:timeout).with(wait).exactly(retry_times + 1).times
|
124
151
|
expect { subject }.to raise_error(Timeout::Error)
|
125
152
|
end
|
126
153
|
|
@@ -146,4 +173,52 @@ describe Embulk::Input::JiraApi::Client do
|
|
146
173
|
end
|
147
174
|
end
|
148
175
|
end
|
176
|
+
|
177
|
+
describe "#calculate_rate_limit" do
|
178
|
+
let(:jira_api) { Embulk::Input::JiraApi::Client.new }
|
179
|
+
it "current_limit = 50, all_items = 50, fail_items=50, times=1" do
|
180
|
+
current_limit = 50
|
181
|
+
all_items = 50
|
182
|
+
fail_items = 50
|
183
|
+
times = 1
|
184
|
+
expected_result = Embulk::Input::JiraApi::Client::MIN_RATE_LIMIT
|
185
|
+
expect(jira_api.calculate_rate_limit(current_limit, all_items, fail_items, times)).to eq expected_result
|
186
|
+
end
|
187
|
+
|
188
|
+
it "current_limit = 50, all_items = 50, fail_items=20, times=1" do
|
189
|
+
current_limit = 50
|
190
|
+
all_items = 50
|
191
|
+
fail_items = 20
|
192
|
+
times = 1
|
193
|
+
expected_result = 20
|
194
|
+
expect(jira_api.calculate_rate_limit(current_limit, all_items, fail_items, times)).to eq expected_result
|
195
|
+
end
|
196
|
+
|
197
|
+
it "current_limit = MIN_RATE_LIMIT, all_items = 50, fail_items=20, times=2" do
|
198
|
+
current_limit = Embulk::Input::JiraApi::Client::MIN_RATE_LIMIT
|
199
|
+
all_items = 50
|
200
|
+
fail_items = 20
|
201
|
+
times = 2
|
202
|
+
expected_result = Embulk::Input::JiraApi::Client::MIN_RATE_LIMIT
|
203
|
+
expect(jira_api.calculate_rate_limit(current_limit, all_items, fail_items, times)).to eq expected_result
|
204
|
+
end
|
205
|
+
|
206
|
+
it "current_limit = 10, all_items = 30, fail_items=25, times=2" do
|
207
|
+
current_limit = 10
|
208
|
+
all_items = 30
|
209
|
+
fail_items = 25
|
210
|
+
times = 2
|
211
|
+
expected_result = 5
|
212
|
+
expect(jira_api.calculate_rate_limit(current_limit, all_items, fail_items, times)).to eq expected_result
|
213
|
+
end
|
214
|
+
|
215
|
+
it "current_limit = 50, all_items = 50, fail_items=20, times=DEFAULT_SEARCH_RETRY_TIMES/2" do
|
216
|
+
current_limit = 50
|
217
|
+
all_items = 50
|
218
|
+
fail_items = 20
|
219
|
+
times = Embulk::Input::JiraApi::Client::DEFAULT_SEARCH_RETRY_TIMES/2
|
220
|
+
expected_result = Embulk::Input::JiraApi::Client::MIN_RATE_LIMIT
|
221
|
+
expect(jira_api.calculate_rate_limit(current_limit, all_items, fail_items, times)).to eq expected_result
|
222
|
+
end
|
223
|
+
end
|
149
224
|
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.2.
|
4
|
+
version: 0.2.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- uu59
|
@@ -9,162 +9,176 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2018-11-23 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
name: jiralicious
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
16
|
requirements:
|
18
17
|
- - "~>"
|
19
18
|
- !ruby/object:Gem::Version
|
20
19
|
version: 0.5.0
|
20
|
+
name: jiralicious
|
21
|
+
prerelease: false
|
22
|
+
type: :runtime
|
21
23
|
version_requirements: !ruby/object:Gem::Requirement
|
22
24
|
requirements:
|
23
25
|
- - "~>"
|
24
26
|
- !ruby/object:Gem::Version
|
25
27
|
version: 0.5.0
|
26
|
-
prerelease: false
|
27
|
-
type: :runtime
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
|
-
name: parallel
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
31
|
- - "~>"
|
33
32
|
- !ruby/object:Gem::Version
|
34
33
|
version: 1.6.0
|
34
|
+
name: parallel
|
35
|
+
prerelease: false
|
36
|
+
type: :runtime
|
35
37
|
version_requirements: !ruby/object:Gem::Requirement
|
36
38
|
requirements:
|
37
39
|
- - "~>"
|
38
40
|
- !ruby/object:Gem::Version
|
39
41
|
version: 1.6.0
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
name: ruby-limiter
|
40
49
|
prerelease: false
|
41
50
|
type: :runtime
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - "~>"
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.0'
|
42
56
|
- !ruby/object:Gem::Dependency
|
43
|
-
name: perfect_retry
|
44
57
|
requirement: !ruby/object:Gem::Requirement
|
45
58
|
requirements:
|
46
59
|
- - "~>"
|
47
60
|
- !ruby/object:Gem::Version
|
48
61
|
version: '0.3'
|
62
|
+
name: perfect_retry
|
63
|
+
prerelease: false
|
64
|
+
type: :runtime
|
49
65
|
version_requirements: !ruby/object:Gem::Requirement
|
50
66
|
requirements:
|
51
67
|
- - "~>"
|
52
68
|
- !ruby/object:Gem::Version
|
53
69
|
version: '0.3'
|
54
|
-
prerelease: false
|
55
|
-
type: :runtime
|
56
70
|
- !ruby/object:Gem::Dependency
|
57
|
-
name: bundler
|
58
71
|
requirement: !ruby/object:Gem::Requirement
|
59
72
|
requirements:
|
60
73
|
- - "~>"
|
61
74
|
- !ruby/object:Gem::Version
|
62
75
|
version: '1.0'
|
76
|
+
name: bundler
|
77
|
+
prerelease: false
|
78
|
+
type: :development
|
63
79
|
version_requirements: !ruby/object:Gem::Requirement
|
64
80
|
requirements:
|
65
81
|
- - "~>"
|
66
82
|
- !ruby/object:Gem::Version
|
67
83
|
version: '1.0'
|
68
|
-
prerelease: false
|
69
|
-
type: :development
|
70
84
|
- !ruby/object:Gem::Dependency
|
71
|
-
name: rake
|
72
85
|
requirement: !ruby/object:Gem::Requirement
|
73
86
|
requirements:
|
74
87
|
- - "<"
|
75
88
|
- !ruby/object:Gem::Version
|
76
89
|
version: '11.0'
|
90
|
+
name: rake
|
91
|
+
prerelease: false
|
92
|
+
type: :development
|
77
93
|
version_requirements: !ruby/object:Gem::Requirement
|
78
94
|
requirements:
|
79
95
|
- - "<"
|
80
96
|
- !ruby/object:Gem::Version
|
81
97
|
version: '11.0'
|
82
|
-
prerelease: false
|
83
|
-
type: :development
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
|
-
name: rspec
|
86
99
|
requirement: !ruby/object:Gem::Requirement
|
87
100
|
requirements:
|
88
101
|
- - "~>"
|
89
102
|
- !ruby/object:Gem::Version
|
90
103
|
version: 3.2.0
|
104
|
+
name: rspec
|
105
|
+
prerelease: false
|
106
|
+
type: :development
|
91
107
|
version_requirements: !ruby/object:Gem::Requirement
|
92
108
|
requirements:
|
93
109
|
- - "~>"
|
94
110
|
- !ruby/object:Gem::Version
|
95
111
|
version: 3.2.0
|
96
|
-
prerelease: false
|
97
|
-
type: :development
|
98
112
|
- !ruby/object:Gem::Dependency
|
99
|
-
name: embulk
|
100
113
|
requirement: !ruby/object:Gem::Requirement
|
101
114
|
requirements:
|
102
115
|
- - "~>"
|
103
116
|
- !ruby/object:Gem::Version
|
104
117
|
version: 0.8.7
|
118
|
+
name: embulk
|
119
|
+
prerelease: false
|
120
|
+
type: :development
|
105
121
|
version_requirements: !ruby/object:Gem::Requirement
|
106
122
|
requirements:
|
107
123
|
- - "~>"
|
108
124
|
- !ruby/object:Gem::Version
|
109
125
|
version: 0.8.7
|
110
|
-
prerelease: false
|
111
|
-
type: :development
|
112
126
|
- !ruby/object:Gem::Dependency
|
113
|
-
name: simplecov
|
114
127
|
requirement: !ruby/object:Gem::Requirement
|
115
128
|
requirements:
|
116
129
|
- - ">="
|
117
130
|
- !ruby/object:Gem::Version
|
118
131
|
version: '0'
|
132
|
+
name: simplecov
|
133
|
+
prerelease: false
|
134
|
+
type: :development
|
119
135
|
version_requirements: !ruby/object:Gem::Requirement
|
120
136
|
requirements:
|
121
137
|
- - ">="
|
122
138
|
- !ruby/object:Gem::Version
|
123
139
|
version: '0'
|
124
|
-
prerelease: false
|
125
|
-
type: :development
|
126
140
|
- !ruby/object:Gem::Dependency
|
127
|
-
name: pry
|
128
141
|
requirement: !ruby/object:Gem::Requirement
|
129
142
|
requirements:
|
130
143
|
- - ">="
|
131
144
|
- !ruby/object:Gem::Version
|
132
145
|
version: '0'
|
146
|
+
name: pry
|
147
|
+
prerelease: false
|
148
|
+
type: :development
|
133
149
|
version_requirements: !ruby/object:Gem::Requirement
|
134
150
|
requirements:
|
135
151
|
- - ">="
|
136
152
|
- !ruby/object:Gem::Version
|
137
153
|
version: '0'
|
138
|
-
prerelease: false
|
139
|
-
type: :development
|
140
154
|
- !ruby/object:Gem::Dependency
|
141
|
-
name: codeclimate-test-reporter
|
142
155
|
requirement: !ruby/object:Gem::Requirement
|
143
156
|
requirements:
|
144
157
|
- - ">="
|
145
158
|
- !ruby/object:Gem::Version
|
146
159
|
version: '0'
|
160
|
+
name: codeclimate-test-reporter
|
161
|
+
prerelease: false
|
162
|
+
type: :development
|
147
163
|
version_requirements: !ruby/object:Gem::Requirement
|
148
164
|
requirements:
|
149
165
|
- - ">="
|
150
166
|
- !ruby/object:Gem::Version
|
151
167
|
version: '0'
|
152
|
-
prerelease: false
|
153
|
-
type: :development
|
154
168
|
- !ruby/object:Gem::Dependency
|
155
|
-
name: everyleaf-embulk_helper
|
156
169
|
requirement: !ruby/object:Gem::Requirement
|
157
170
|
requirements:
|
158
171
|
- - ">="
|
159
172
|
- !ruby/object:Gem::Version
|
160
173
|
version: '0'
|
174
|
+
name: everyleaf-embulk_helper
|
175
|
+
prerelease: false
|
176
|
+
type: :development
|
161
177
|
version_requirements: !ruby/object:Gem::Requirement
|
162
178
|
requirements:
|
163
179
|
- - ">="
|
164
180
|
- !ruby/object:Gem::Version
|
165
181
|
version: '0'
|
166
|
-
prerelease: false
|
167
|
-
type: :development
|
168
182
|
description: Loads records from Jira.
|
169
183
|
email:
|
170
184
|
- k@uu59.org
|