embulk-input-jira 0.0.2 → 0.0.3
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/CHANGELOG.md +8 -3
- data/Rakefile +8 -4
- data/embulk-input-jira.gemspec +2 -1
- data/lib/embulk/input/jira/api.rb +54 -0
- data/lib/embulk/input/jira/issue.rb +67 -0
- data/lib/embulk/input/jira/version.rb +7 -0
- data/lib/embulk/input/jira.rb +3 -121
- data/lib/embulk/input/jira_input_plugin.rb +135 -0
- data/lib/embulk/input/{jira-input-plugin-utils.rb → jira_input_plugin_utils.rb} +0 -0
- data/spec/{jira_api_spec.rb → embulk/input/jira/api_spec.rb} +11 -14
- data/spec/{jira → embulk/input/jira}/issue_spec.rb +7 -8
- data/spec/embulk/input/jira-input-plugin-utils_spec.rb +0 -1
- data/spec/embulk/input/{jira_spec.rb → jira_input_plugin_spec.rb} +14 -22
- data/spec/embulk_spec.rb +1 -0
- data/spec/spec_helper.rb +1 -0
- metadata +13 -12
- data/VERSION +0 -1
- data/lib/jira/api.rb +0 -50
- data/lib/jira/issue.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e99c37b9c22a10ca74920b940eb2acf874d0676
|
4
|
+
data.tar.gz: b85987d31a8870a6136d14dd75f6b65605160211
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 010bff47e3e9c3a48c24d1da78ef835450f350d7b102969e5ab89c4847425e368719009bc70511f54d2f46347f70e9235883e3e383e3c54651fbfb5a86d193be
|
7
|
+
data.tar.gz: 6a99ada3fcfc2fc9d0b51484a40e85d6d51797a75964251714d9ebcc8d4f3b24f6f3e6f7af56097e329fd8647f9f7d9397587d827dfc10e1a273e658c9b32005
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
## 0.0.3 - 2015-06-12
|
2
|
+
* [enhancement] Limit records for guess and preview [#25](https://github.com/treasure-data/embulk-input-jira/pull/25)
|
3
|
+
* [maintenance] Define version number as constant [#24](https://github.com/treasure-data/embulk-input-jira/pull/24)
|
4
|
+
* [maintenance] Restructure file and class [#23](https://github.com/treasure-data/embulk-input-jira/pull/23)
|
5
|
+
|
1
6
|
## 0.0.2 - 2015-06-04
|
2
|
-
* [maintenance] Add release:prepare task for development [#21](https://github.com/treasure-data/embulk-input-jira/pull/21)
|
3
|
-
* [enhancement] Add timeout and retry for JIRA API search [#20](https://github.com/treasure-data/embulk-input-jira/pull/20)
|
7
|
+
* [maintenance] Add release:prepare task for development [#21](https://github.com/treasure-data/embulk-input-jira/pull/21)
|
8
|
+
* [enhancement] Add timeout and retry for JIRA API search [#20](https://github.com/treasure-data/embulk-input-jira/pull/20)
|
4
9
|
* [enhancement] Display progress [#19](https://github.com/treasure-data/embulk-input-jira/pull/19)
|
5
|
-
* [maintenance] Remove needless guessed config [#18](https://github.com/treasure-data/embulk-input-jira/pull/18)
|
10
|
+
* [maintenance] Remove needless guessed config [#18](https://github.com/treasure-data/embulk-input-jira/pull/18)
|
6
11
|
|
7
12
|
## 0.0.1 - 2015-05-28
|
8
13
|
|
data/Rakefile
CHANGED
@@ -3,6 +3,7 @@ require 'rspec/core/rake_task'
|
|
3
3
|
require "json"
|
4
4
|
require "pathname"
|
5
5
|
require "open-uri"
|
6
|
+
require File.expand_path("../lib/embulk/input/jira/version.rb", __FILE__)
|
6
7
|
|
7
8
|
|
8
9
|
task default: :spec
|
@@ -16,13 +17,12 @@ namespace :release do
|
|
16
17
|
desc "Add header of now version release to ChangeLog and bump up version"
|
17
18
|
task :prepare do
|
18
19
|
root_dir = Pathname.new(File.expand_path("../", __FILE__))
|
19
|
-
version_file = root_dir.join("VERSION")
|
20
20
|
changelog_file = root_dir.join("CHANGELOG.md")
|
21
21
|
|
22
22
|
system("git fetch origin")
|
23
23
|
|
24
24
|
# detect merged PR
|
25
|
-
old_version =
|
25
|
+
old_version = Embulk::Input::Jira::VERSION
|
26
26
|
pr_numbers = `git log v#{old_version}..origin/master --oneline`.scan(/#[0-9]+/)
|
27
27
|
|
28
28
|
if !$?.success? || pr_numbers.empty?
|
@@ -38,7 +38,7 @@ namespace :release do
|
|
38
38
|
pr_descriptions = pr_numbers.map do |number|
|
39
39
|
body = open("https://api.github.com/repos/treasure-data/embulk-input-jira/issues/#{number.gsub("#", "")}").read
|
40
40
|
payload = JSON.parse(body)
|
41
|
-
"* [] #{payload["title"]} [#{number}](https://github.com/treasure-data/embulk-input-jira/pull/#{number.gsub('#', '')})
|
41
|
+
"* [] #{payload["title"]} [#{number}](https://github.com/treasure-data/embulk-input-jira/pull/#{number.gsub('#', '')})"
|
42
42
|
end.join("\n")
|
43
43
|
|
44
44
|
new_changelog = <<-HEADER
|
@@ -51,7 +51,11 @@ HEADER
|
|
51
51
|
File.open(changelog_file, "w") {|f| f.write(new_changelog) }
|
52
52
|
|
53
53
|
# Update version.rb
|
54
|
-
|
54
|
+
version_file = root_dir.join("./lib/embulk/input/jira/version.rb")
|
55
|
+
old_content = version_file.read
|
56
|
+
File.open(version_file, "w") do |f|
|
57
|
+
f.write old_content.gsub(old_version, new_version)
|
58
|
+
end
|
55
59
|
|
56
60
|
# Update Gemfile.lock
|
57
61
|
system("bundle install")
|
data/embulk-input-jira.gemspec
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
+
require File.expand_path("../lib/embulk/input/jira/version.rb", __FILE__)
|
1
2
|
|
2
3
|
Gem::Specification.new do |spec|
|
3
4
|
spec.name = "embulk-input-jira"
|
4
|
-
spec.version =
|
5
|
+
spec.version = Embulk::Input::Jira::VERSION
|
5
6
|
spec.authors = ["uu59", "yoshihara"]
|
6
7
|
spec.summary = "Jira input plugin for Embulk"
|
7
8
|
spec.description = "Loads records from Jira."
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "jiralicious"
|
2
|
+
require "embulk/input/jira/issue"
|
3
|
+
require "timeout"
|
4
|
+
|
5
|
+
module Embulk
|
6
|
+
module Input
|
7
|
+
module Jira
|
8
|
+
class Api
|
9
|
+
SEARCH_TIMEOUT_SECONDS = 5
|
10
|
+
SEARCH_ISSUES_TIMEOUT_SECONDS = 60
|
11
|
+
DEFAULT_SEARCH_RETRY_TIMES = 10
|
12
|
+
|
13
|
+
def self.setup(&block)
|
14
|
+
Jiralicious.configure(&block)
|
15
|
+
new
|
16
|
+
end
|
17
|
+
|
18
|
+
def search_issues(jql, options={})
|
19
|
+
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS) do
|
20
|
+
search(jql, options).issues.map do |issue|
|
21
|
+
Jira::Issue.new(issue)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def search(jql, options={})
|
27
|
+
timeout_and_retry(SEARCH_TIMEOUT_SECONDS) do
|
28
|
+
Jiralicious.search(jql, options)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def total_count(jql)
|
33
|
+
search(jql, max_results: 1).num_results
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def timeout_and_retry(wait, retry_times = DEFAULT_SEARCH_RETRY_TIMES, &block)
|
39
|
+
count = 1
|
40
|
+
begin
|
41
|
+
Timeout.timeout(wait) do
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
rescue Timeout::Error => e
|
45
|
+
count += 1
|
46
|
+
sleep count # retry after some seconds for JIRA API perhaps under the overload
|
47
|
+
raise e if count > retry_times
|
48
|
+
retry
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Embulk
|
2
|
+
module Input
|
3
|
+
module Jira
|
4
|
+
class Issue
|
5
|
+
attr_reader :id, :key, :fields
|
6
|
+
|
7
|
+
def initialize(attributes)
|
8
|
+
@id = attributes.fetch("id")
|
9
|
+
|
10
|
+
# https://github.com/dorack/jiralicious/blob/404b7b6d5b7020f42064cf8d7a745ab02057e728/lib/jiralicious/issue.rb#L11-L12
|
11
|
+
@key = attributes.fetch("jira_key")
|
12
|
+
@fields = attributes.fetch("fields")
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](attribute)
|
16
|
+
case attribute
|
17
|
+
when "id"
|
18
|
+
return id
|
19
|
+
when "key"
|
20
|
+
return key
|
21
|
+
end
|
22
|
+
|
23
|
+
chunk = fields
|
24
|
+
attribute.split('.').each do |key|
|
25
|
+
chunk = chunk[key]
|
26
|
+
return chunk if chunk.nil?
|
27
|
+
end
|
28
|
+
|
29
|
+
if chunk.is_a?(Array) || chunk.is_a?(Hash)
|
30
|
+
chunk.to_json.to_s
|
31
|
+
else
|
32
|
+
chunk
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_record
|
37
|
+
record = {}
|
38
|
+
|
39
|
+
record["id"] = id
|
40
|
+
record["key"] = key
|
41
|
+
|
42
|
+
fields.each_pair do |key, value|
|
43
|
+
record_key = key
|
44
|
+
record_value = value.to_json.to_s
|
45
|
+
|
46
|
+
case value
|
47
|
+
when String
|
48
|
+
record_value = value
|
49
|
+
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"]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
record[record_key] = record_value
|
60
|
+
end
|
61
|
+
|
62
|
+
record
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/embulk/input/jira.rb
CHANGED
@@ -1,127 +1,9 @@
|
|
1
|
-
require "embulk/input/
|
2
|
-
require "jira/
|
3
|
-
require "logger"
|
4
|
-
require "time"
|
1
|
+
require "embulk/input/jira_input_plugin"
|
2
|
+
require "embulk/input/jira/version"
|
5
3
|
|
6
4
|
module Embulk
|
7
5
|
module Input
|
8
|
-
|
9
|
-
PER_PAGE = 50
|
10
|
-
|
11
|
-
Plugin.register_input("jira", self)
|
12
|
-
|
13
|
-
def self.version
|
14
|
-
File.read(File.expand_path("../../../../VERSION", __FILE__)).strip
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.transaction(config, &control)
|
18
|
-
task = {
|
19
|
-
"username" => config.param("username", :string),
|
20
|
-
"password" => config.param("password", :string),
|
21
|
-
"uri" => config.param("uri", :string),
|
22
|
-
"jql" => config.param("jql", :string),
|
23
|
-
}
|
24
|
-
|
25
|
-
attributes = {}
|
26
|
-
columns = config.param("columns", :array).map do |column|
|
27
|
-
name = column["name"]
|
28
|
-
type = column["type"].to_sym
|
29
|
-
attributes[name] = type
|
30
|
-
Column.new(nil, name, type, column["format"])
|
31
|
-
end
|
32
|
-
|
33
|
-
task["attributes"] = attributes
|
34
|
-
|
35
|
-
resume(task, columns, 1, &control)
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.resume(task, columns, count, &control)
|
39
|
-
commit_reports = yield(task, columns, count)
|
40
|
-
|
41
|
-
next_config_diff = {}
|
42
|
-
return next_config_diff
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.guess(config)
|
46
|
-
# TODO: api_version should be 2 (the latest version)
|
47
|
-
# auth_type should be specified from config. (The future task)
|
48
|
-
|
49
|
-
username = config.param("username", :string)
|
50
|
-
password = config.param("password", :string)
|
51
|
-
uri = config.param("uri", :string)
|
52
|
-
api_version = "latest"
|
53
|
-
auth_type = "basic"
|
54
|
-
jql = config.param("jql", :string)
|
55
|
-
|
56
|
-
jira = Jira::Api.setup do |jira_config|
|
57
|
-
jira_config.username = username
|
58
|
-
jira_config.password = password
|
59
|
-
jira_config.uri = uri
|
60
|
-
jira_config.api_version = api_version
|
61
|
-
jira_config.auth_type = auth_type
|
62
|
-
end
|
63
|
-
|
64
|
-
# TODO: we use 0..10 issues to guess config?
|
65
|
-
records = jira.search_issues(jql)[0..10].map do |issue|
|
66
|
-
issue.to_record
|
67
|
-
end
|
68
|
-
|
69
|
-
columns = JiraInputPluginUtils.guess_columns(records)
|
70
|
-
|
71
|
-
guessed_config = {
|
72
|
-
"columns" => columns,
|
73
|
-
}
|
74
|
-
|
75
|
-
return guessed_config
|
76
|
-
end
|
77
|
-
|
78
|
-
def init
|
79
|
-
@attributes = task["attributes"]
|
80
|
-
@jira = Jira::Api.setup do |config|
|
81
|
-
config.username = task["username"]
|
82
|
-
config.password = task["password"]
|
83
|
-
config.uri = task["uri"]
|
84
|
-
config.api_version = "latest"
|
85
|
-
config.auth_type = :basic
|
86
|
-
end
|
87
|
-
@jql = task["jql"]
|
88
|
-
end
|
89
|
-
|
90
|
-
def run
|
91
|
-
total_count = @jira.total_count(@jql)
|
92
|
-
last_page = (total_count.to_f / PER_PAGE).ceil
|
93
|
-
|
94
|
-
0.step(total_count, PER_PAGE).with_index(1) do |start_at, page|
|
95
|
-
logger.debug "Fetching #{page} / #{last_page} page"
|
96
|
-
@jira.search_issues(@jql, start_at: start_at).each do |issue|
|
97
|
-
values = @attributes.map do |(attribute_name, type)|
|
98
|
-
JiraInputPluginUtils.cast(issue[attribute_name], type)
|
99
|
-
end
|
100
|
-
|
101
|
-
page_builder.add(values)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
page_builder.finish
|
106
|
-
|
107
|
-
commit_report = {}
|
108
|
-
return commit_report
|
109
|
-
end
|
110
|
-
|
111
|
-
def self.logger
|
112
|
-
@logger ||=
|
113
|
-
begin
|
114
|
-
logger = Logger.new($stdout)
|
115
|
-
logger.formatter = proc do |severity, datetime, progname, msg|
|
116
|
-
"#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L %z")} [#{severity}] #{msg}\n"
|
117
|
-
end
|
118
|
-
logger
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def logger
|
123
|
-
self.class.logger
|
124
|
-
end
|
6
|
+
module Jira
|
125
7
|
end
|
126
8
|
end
|
127
9
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "embulk/input/jira_input_plugin_utils"
|
2
|
+
require "embulk/input/jira/api"
|
3
|
+
require "logger"
|
4
|
+
require "time"
|
5
|
+
|
6
|
+
module Embulk
|
7
|
+
module Input
|
8
|
+
class JiraInputPlugin < InputPlugin
|
9
|
+
PER_PAGE = 50
|
10
|
+
GUESS_RECORDS_COUNT = 10
|
11
|
+
PREVIEW_RECORDS_COUNT = 15
|
12
|
+
|
13
|
+
Plugin.register_input("jira", self)
|
14
|
+
|
15
|
+
def self.transaction(config, &control)
|
16
|
+
task = {
|
17
|
+
"username" => config.param("username", :string),
|
18
|
+
"password" => config.param("password", :string),
|
19
|
+
"uri" => config.param("uri", :string),
|
20
|
+
"jql" => config.param("jql", :string),
|
21
|
+
}
|
22
|
+
|
23
|
+
attributes = {}
|
24
|
+
columns = config.param("columns", :array).map do |column|
|
25
|
+
name = column["name"]
|
26
|
+
type = column["type"].to_sym
|
27
|
+
attributes[name] = type
|
28
|
+
Column.new(nil, name, type, column["format"])
|
29
|
+
end
|
30
|
+
|
31
|
+
task["attributes"] = attributes
|
32
|
+
|
33
|
+
resume(task, columns, 1, &control)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.resume(task, columns, count, &control)
|
37
|
+
commit_reports = yield(task, columns, count)
|
38
|
+
|
39
|
+
next_config_diff = {}
|
40
|
+
return next_config_diff
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.guess(config)
|
44
|
+
# TODO: api_version should be 2 (the latest version)
|
45
|
+
# auth_type should be specified from config. (The future task)
|
46
|
+
|
47
|
+
username = config.param("username", :string)
|
48
|
+
password = config.param("password", :string)
|
49
|
+
uri = config.param("uri", :string)
|
50
|
+
api_version = "latest"
|
51
|
+
auth_type = "basic"
|
52
|
+
jql = config.param("jql", :string)
|
53
|
+
|
54
|
+
jira = Jira::Api.setup do |jira_config|
|
55
|
+
jira_config.username = username
|
56
|
+
jira_config.password = password
|
57
|
+
jira_config.uri = uri
|
58
|
+
jira_config.api_version = api_version
|
59
|
+
jira_config.auth_type = auth_type
|
60
|
+
end
|
61
|
+
|
62
|
+
# TODO: we use 0..10 issues to guess config?
|
63
|
+
records = jira.search_issues(jql, max_results: GUESS_RECORDS_COUNT).map do |issue|
|
64
|
+
issue.to_record
|
65
|
+
end
|
66
|
+
|
67
|
+
columns = JiraInputPluginUtils.guess_columns(records)
|
68
|
+
|
69
|
+
guessed_config = {
|
70
|
+
"columns" => columns,
|
71
|
+
}
|
72
|
+
|
73
|
+
return guessed_config
|
74
|
+
end
|
75
|
+
|
76
|
+
def init
|
77
|
+
@attributes = task["attributes"]
|
78
|
+
@jira = Jira::Api.setup do |config|
|
79
|
+
config.username = task["username"]
|
80
|
+
config.password = task["password"]
|
81
|
+
config.uri = task["uri"]
|
82
|
+
config.api_version = "latest"
|
83
|
+
config.auth_type = :basic
|
84
|
+
end
|
85
|
+
@jql = task["jql"]
|
86
|
+
end
|
87
|
+
|
88
|
+
def run
|
89
|
+
# NOTE: This is workaround for "org.embulk.spi.Exec.isPreview"
|
90
|
+
# TODO: Extract process for preview command to method
|
91
|
+
if org.embulk.spi.Exec.session().isPreview()
|
92
|
+
options = {max_results: PREVIEW_RECORDS_COUNT}
|
93
|
+
total_count = PREVIEW_RECORDS_COUNT
|
94
|
+
last_page = 1
|
95
|
+
logger.debug "For preview mode, JIRA input plugin fetches records at most #{PREVIEW_RECORDS_COUNT}"
|
96
|
+
else
|
97
|
+
options = {}
|
98
|
+
total_count = @jira.total_count(@jql)
|
99
|
+
last_page = (total_count.to_f / PER_PAGE).ceil
|
100
|
+
end
|
101
|
+
|
102
|
+
0.step(total_count, PER_PAGE).with_index(1) do |start_at, page|
|
103
|
+
logger.debug "Fetching #{page} / #{last_page} page"
|
104
|
+
@jira.search_issues(@jql, options.merge(start_at: start_at)).each do |issue|
|
105
|
+
values = @attributes.map do |(attribute_name, type)|
|
106
|
+
JiraInputPluginUtils.cast(issue[attribute_name], type)
|
107
|
+
end
|
108
|
+
|
109
|
+
page_builder.add(values)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
page_builder.finish
|
114
|
+
|
115
|
+
commit_report = {}
|
116
|
+
return commit_report
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.logger
|
120
|
+
@logger ||=
|
121
|
+
begin
|
122
|
+
logger = Logger.new($stdout)
|
123
|
+
logger.formatter = proc do |severity, datetime, progname, msg|
|
124
|
+
"#{datetime.strftime("%Y-%m-%d %H:%M:%S.%L %z")} [#{severity}] #{msg}\n"
|
125
|
+
end
|
126
|
+
logger
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def logger
|
131
|
+
self.class.logger
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
File without changes
|
@@ -1,14 +1,11 @@
|
|
1
|
-
# TODO: move to spec/jira/api_spec.rb
|
2
|
-
|
3
1
|
require "spec_helper"
|
4
|
-
require "jira/api"
|
5
2
|
|
6
|
-
describe Jira::Api do
|
3
|
+
describe Embulk::Input::Jira::Api do
|
7
4
|
describe ".setup" do
|
8
|
-
subject { Jira::Api.setup {} }
|
5
|
+
subject { Embulk::Input::Jira::Api.setup {} }
|
9
6
|
|
10
|
-
it "returns Jira::Api instance" do
|
11
|
-
expect(subject.is_a?(Jira::Api)).to be_truthy
|
7
|
+
it "returns Embulk::Input::Jira::Api instance" do
|
8
|
+
expect(subject.is_a?(Embulk::Input::Jira::Api)).to be_truthy
|
12
9
|
end
|
13
10
|
|
14
11
|
it "calls Jiralicious.configure" do
|
@@ -18,7 +15,7 @@ describe Jira::Api do
|
|
18
15
|
|
19
16
|
describe "#search" do
|
20
17
|
let(:jql) { "project=FOO" }
|
21
|
-
let(:api) { Jira::Api.new }
|
18
|
+
let(:api) { Embulk::Input::Jira::Api.new }
|
22
19
|
|
23
20
|
subject { api.search(jql) }
|
24
21
|
|
@@ -33,7 +30,7 @@ describe Jira::Api do
|
|
33
30
|
end
|
34
31
|
|
35
32
|
it "retry DEFAULT_SEARCH_RETRY_TIMES times then raise error" do
|
36
|
-
expect(Timeout).to receive(:timeout).exactly(Jira::Api::DEFAULT_SEARCH_RETRY_TIMES)
|
33
|
+
expect(Timeout).to receive(:timeout).exactly(Embulk::Input::Jira::Api::DEFAULT_SEARCH_RETRY_TIMES)
|
37
34
|
expect { subject }.to raise_error
|
38
35
|
end
|
39
36
|
end
|
@@ -70,20 +67,20 @@ describe Jira::Api do
|
|
70
67
|
]
|
71
68
|
end
|
72
69
|
|
73
|
-
subject { Jira::Api.new.search_issues(jql) }
|
70
|
+
subject { Embulk::Input::Jira::Api.new.search_issues(jql) }
|
74
71
|
|
75
72
|
it do
|
76
73
|
allow(Jiralicious).to receive_message_chain(:search, :issues).and_return(results)
|
77
74
|
|
78
75
|
expect(subject).to be_kind_of Array
|
79
|
-
expect(subject.map(&:class)).to match_array [Jira::Issue, Jira::Issue]
|
76
|
+
expect(subject.map(&:class)).to match_array [Embulk::Input::Jira::Issue, Embulk::Input::Jira::Issue]
|
80
77
|
end
|
81
78
|
end
|
82
79
|
|
83
80
|
describe "#total_count" do
|
84
81
|
subject { jira_api.total_count(jql) }
|
85
82
|
|
86
|
-
let(:jira_api) { Jira::Api.new }
|
83
|
+
let(:jira_api) { Embulk::Input::Jira::Api.new }
|
87
84
|
let(:jql) { "project=FOO" }
|
88
85
|
let(:results) { Object.new } # add mock later
|
89
86
|
let(:results_count) { 5 }
|
@@ -92,7 +89,7 @@ describe Jira::Api do
|
|
92
89
|
allow(results).to receive(:num_results).and_return(results_count)
|
93
90
|
end
|
94
91
|
|
95
|
-
it "calls Jira::Api#search with proper arguments" do
|
92
|
+
it "calls Embulk::Input::Jira::Api#search with proper arguments" do
|
96
93
|
expect(jira_api).to receive(:search).with(jql, max_results: 1).and_return(results)
|
97
94
|
subject
|
98
95
|
end
|
@@ -106,7 +103,7 @@ describe Jira::Api do
|
|
106
103
|
describe "#timeout_and_retry" do
|
107
104
|
let(:wait) { 1 }
|
108
105
|
let(:retry_times) { 3 }
|
109
|
-
let(:jira_api) { Jira::Api.new }
|
106
|
+
let(:jira_api) { Embulk::Input::Jira::Api.new }
|
110
107
|
let(:block) { proc{ "it works" } }
|
111
108
|
|
112
109
|
subject { jira_api.send(:timeout_and_retry, wait, retry_times, &block) }
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "jira/issue"
|
3
2
|
|
4
|
-
describe Jira::Issue do
|
3
|
+
describe Embulk::Input::Jira::Issue do
|
5
4
|
describe ".initialize" do
|
6
5
|
context "when argument has 'fields' key" do
|
7
6
|
let(:issue_attributes) do
|
@@ -20,15 +19,15 @@ describe Jira::Issue do
|
|
20
19
|
end
|
21
20
|
|
22
21
|
it "has @id with argument['id']" do
|
23
|
-
expect(Jira::Issue.new(issue_attributes).id).to eq issue_attributes["id"]
|
22
|
+
expect(Embulk::Input::Jira::Issue.new(issue_attributes).id).to eq issue_attributes["id"]
|
24
23
|
end
|
25
24
|
|
26
25
|
it "has @key with argument['jira_key']" do
|
27
|
-
expect(Jira::Issue.new(issue_attributes).key).to eq issue_attributes["jira_key"]
|
26
|
+
expect(Embulk::Input::Jira::Issue.new(issue_attributes).key).to eq issue_attributes["jira_key"]
|
28
27
|
end
|
29
28
|
|
30
29
|
it "has @fields with argument['fields']" do
|
31
|
-
expect(Jira::Issue.new(issue_attributes).fields).to eq issue_attributes["fields"]
|
30
|
+
expect(Embulk::Input::Jira::Issue.new(issue_attributes).fields).to eq issue_attributes["fields"]
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
@@ -38,13 +37,13 @@ describe Jira::Issue do
|
|
38
37
|
end
|
39
38
|
|
40
39
|
it "raises error" do
|
41
|
-
expect { Jira::Issue.new(issue_attributes) }.to raise_error
|
40
|
+
expect { Embulk::Input::Jira::Issue.new(issue_attributes) }.to raise_error
|
42
41
|
end
|
43
42
|
end
|
44
43
|
end
|
45
44
|
|
46
45
|
describe "#[]" do
|
47
|
-
subject { Jira::Issue.new(issue_attributes)[attribute_name] }
|
46
|
+
subject { Embulk::Input::Jira::Issue.new(issue_attributes)[attribute_name] }
|
48
47
|
|
49
48
|
let(:issue_attributes) do
|
50
49
|
{
|
@@ -135,7 +134,7 @@ describe Jira::Issue do
|
|
135
134
|
|
136
135
|
describe "#to_record" do
|
137
136
|
subject do
|
138
|
-
Jira::Issue.new(issue_attributes).to_record
|
137
|
+
Embulk::Input::Jira::Issue.new(issue_attributes).to_record
|
139
138
|
end
|
140
139
|
|
141
140
|
let(:issue_attributes) do
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require "spec_helper"
|
2
|
-
require "embulk/input/jira"
|
3
2
|
|
4
3
|
describe Embulk::Input::JiraInputPlugin do
|
5
4
|
let(:username) { "jira-user" }
|
@@ -94,8 +93,8 @@ describe Embulk::Input::JiraInputPlugin do
|
|
94
93
|
|
95
94
|
let(:config) { Object.new } # add mock later
|
96
95
|
|
97
|
-
let(:jira_api) { Jira::Api.new }
|
98
|
-
let(:jira_issues) { [Jira::Issue.new(attributes)] }
|
96
|
+
let(:jira_api) { Embulk::Input::Jira::Api.new }
|
97
|
+
let(:jira_issues) { [Embulk::Input::Jira::Issue.new(attributes)] }
|
99
98
|
let(:attributes) do
|
100
99
|
{
|
101
100
|
"id" => "100",
|
@@ -126,7 +125,7 @@ describe Embulk::Input::JiraInputPlugin do
|
|
126
125
|
end
|
127
126
|
|
128
127
|
before do
|
129
|
-
allow(jira_api).to receive(:search_issues).and_return(jira_issues)
|
128
|
+
allow(jira_api).to receive(:search_issues).with(jql, max_results: Embulk::Input::JiraInputPlugin::GUESS_RECORDS_COUNT).and_return(jira_issues)
|
130
129
|
|
131
130
|
allow(config).to receive(:param).with("username", :string).and_return(username)
|
132
131
|
allow(config).to receive(:param).with("password", :string).and_return(password)
|
@@ -134,13 +133,13 @@ describe Embulk::Input::JiraInputPlugin do
|
|
134
133
|
allow(config).to receive(:param).with("jql", :string).and_return(jql)
|
135
134
|
end
|
136
135
|
|
137
|
-
it "setup Jira::Api" do
|
138
|
-
expect(Jira::Api).to receive(:setup).and_return(jira_api)
|
136
|
+
it "setup Embulk::Input::Jira::Api" do
|
137
|
+
expect(Embulk::Input::Jira::Api).to receive(:setup).and_return(jira_api)
|
139
138
|
subject
|
140
139
|
end
|
141
140
|
|
142
141
|
it "returns guessed config" do
|
143
|
-
allow(Jira::Api).to receive(:setup).and_return(jira_api)
|
142
|
+
allow(Embulk::Input::Jira::Api).to receive(:setup).and_return(jira_api)
|
144
143
|
|
145
144
|
expect(subject).to eq guessed_config
|
146
145
|
end
|
@@ -151,13 +150,13 @@ describe Embulk::Input::JiraInputPlugin do
|
|
151
150
|
|
152
151
|
subject { Embulk::Input::JiraInputPlugin.new({}, nil, nil, nil) }
|
153
152
|
|
154
|
-
it "setup Jira::Api" do
|
155
|
-
expect(Jira::Api).to receive(:setup)
|
153
|
+
it "setup Embulk::Input::Jira::Api" do
|
154
|
+
expect(Embulk::Input::Jira::Api).to receive(:setup)
|
156
155
|
subject
|
157
156
|
end
|
158
157
|
|
159
158
|
it "is a Embulk::InputPlugin" do
|
160
|
-
allow(Jira::Api).to receive(:setup)
|
159
|
+
allow(Embulk::Input::Jira::Api).to receive(:setup)
|
161
160
|
expect(subject).to be_a(Embulk::InputPlugin)
|
162
161
|
end
|
163
162
|
end
|
@@ -171,12 +170,12 @@ describe Embulk::Input::JiraInputPlugin do
|
|
171
170
|
result
|
172
171
|
end
|
173
172
|
|
174
|
-
let(:jira_api) { Jira::Api.new }
|
173
|
+
let(:jira_api) { Embulk::Input::Jira::Api.new }
|
175
174
|
let(:jira_issues) do
|
176
175
|
(1..total_count).map do |i|
|
177
176
|
attributes = fields.merge("id" => i.to_s, "jira_key" => "FOO-#{i}")
|
178
177
|
|
179
|
-
Jira::Issue.new(attributes)
|
178
|
+
Embulk::Input::Jira::Issue.new(attributes)
|
180
179
|
end
|
181
180
|
end
|
182
181
|
|
@@ -206,8 +205,10 @@ describe Embulk::Input::JiraInputPlugin do
|
|
206
205
|
let(:commit_report) { {} }
|
207
206
|
|
208
207
|
before do
|
208
|
+
allow(org.embulk.spi.Exec).to receive_message_chain(:session, :isPreview).and_return(false)
|
209
|
+
|
209
210
|
# TODO: create stubs without each `it` expected
|
210
|
-
allow(Jira::Api).to receive(:setup).and_return(jira_api)
|
211
|
+
allow(Embulk::Input::Jira::Api).to receive(:setup).and_return(jira_api)
|
211
212
|
|
212
213
|
0.step(total_count, max_result) do |start_at|
|
213
214
|
issues = jira_issues[start_at..(start_at + max_result - 1)]
|
@@ -235,15 +236,6 @@ describe Embulk::Input::JiraInputPlugin do
|
|
235
236
|
end
|
236
237
|
end
|
237
238
|
|
238
|
-
describe ".version" do
|
239
|
-
let(:version_file_path) { File.expand_path("../../../../VERSION", __FILE__) }
|
240
|
-
subject { Embulk::Input::JiraInputPlugin.version }
|
241
|
-
|
242
|
-
it "returns VERSION file content without line-break" do
|
243
|
-
expect(subject).to eq File.read(version_file_path).strip
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
239
|
describe ".logger" do
|
248
240
|
let(:logger) { Embulk::Input::JiraInputPlugin.logger }
|
249
241
|
|
data/spec/embulk_spec.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
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.
|
4
|
+
version: 0.0.3
|
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
|
+
date: 2015-06-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,17 +110,18 @@ files:
|
|
110
110
|
- LICENSE
|
111
111
|
- README.md
|
112
112
|
- Rakefile
|
113
|
-
- VERSION
|
114
113
|
- embulk-input-jira.gemspec
|
115
|
-
- lib/embulk/input/jira-input-plugin-utils.rb
|
116
114
|
- lib/embulk/input/jira.rb
|
117
|
-
- lib/jira/api.rb
|
118
|
-
- lib/jira/issue.rb
|
115
|
+
- lib/embulk/input/jira/api.rb
|
116
|
+
- lib/embulk/input/jira/issue.rb
|
117
|
+
- lib/embulk/input/jira/version.rb
|
118
|
+
- lib/embulk/input/jira_input_plugin.rb
|
119
|
+
- lib/embulk/input/jira_input_plugin_utils.rb
|
119
120
|
- spec/embulk/input/jira-input-plugin-utils_spec.rb
|
120
|
-
- spec/embulk/input/
|
121
|
+
- spec/embulk/input/jira/api_spec.rb
|
122
|
+
- spec/embulk/input/jira/issue_spec.rb
|
123
|
+
- spec/embulk/input/jira_input_plugin_spec.rb
|
121
124
|
- spec/embulk_spec.rb
|
122
|
-
- spec/jira/issue_spec.rb
|
123
|
-
- spec/jira_api_spec.rb
|
124
125
|
- spec/spec_helper.rb
|
125
126
|
- spec/support/prepare_embulk.rb
|
126
127
|
- spec/support/stdout_and_err_capture.rb
|
@@ -150,10 +151,10 @@ specification_version: 4
|
|
150
151
|
summary: Jira input plugin for Embulk
|
151
152
|
test_files:
|
152
153
|
- spec/embulk/input/jira-input-plugin-utils_spec.rb
|
153
|
-
- spec/embulk/input/
|
154
|
+
- spec/embulk/input/jira/api_spec.rb
|
155
|
+
- spec/embulk/input/jira/issue_spec.rb
|
156
|
+
- spec/embulk/input/jira_input_plugin_spec.rb
|
154
157
|
- spec/embulk_spec.rb
|
155
|
-
- spec/jira/issue_spec.rb
|
156
|
-
- spec/jira_api_spec.rb
|
157
158
|
- spec/spec_helper.rb
|
158
159
|
- spec/support/prepare_embulk.rb
|
159
160
|
- spec/support/stdout_and_err_capture.rb
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0.0.2
|
data/lib/jira/api.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require "jiralicious"
|
2
|
-
require "jira/issue"
|
3
|
-
require "timeout"
|
4
|
-
|
5
|
-
module Jira
|
6
|
-
class Api
|
7
|
-
SEARCH_TIMEOUT_SECONDS = 5
|
8
|
-
SEARCH_ISSUES_TIMEOUT_SECONDS = 60
|
9
|
-
DEFAULT_SEARCH_RETRY_TIMES = 10
|
10
|
-
|
11
|
-
def self.setup(&block)
|
12
|
-
Jiralicious.configure(&block)
|
13
|
-
new
|
14
|
-
end
|
15
|
-
|
16
|
-
def search_issues(jql, options={})
|
17
|
-
timeout_and_retry(SEARCH_ISSUES_TIMEOUT_SECONDS) do
|
18
|
-
search(jql, options).issues.map do |issue|
|
19
|
-
::Jira::Issue.new(issue)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def search(jql, options={})
|
25
|
-
timeout_and_retry(SEARCH_TIMEOUT_SECONDS) do
|
26
|
-
Jiralicious.search(jql, options)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def total_count(jql)
|
31
|
-
search(jql, max_results: 1).num_results
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def timeout_and_retry(wait, retry_times = DEFAULT_SEARCH_RETRY_TIMES, &block)
|
37
|
-
count = 1
|
38
|
-
begin
|
39
|
-
Timeout.timeout(wait) do
|
40
|
-
yield
|
41
|
-
end
|
42
|
-
rescue Timeout::Error => e
|
43
|
-
count += 1
|
44
|
-
sleep count # retry after some seconds for JIRA API perhaps under the overload
|
45
|
-
raise e if count > retry_times
|
46
|
-
retry
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
data/lib/jira/issue.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module Jira
|
2
|
-
class Issue
|
3
|
-
attr_reader :id, :key, :fields
|
4
|
-
|
5
|
-
def initialize(attributes)
|
6
|
-
@id = attributes.fetch("id")
|
7
|
-
|
8
|
-
# https://github.com/dorack/jiralicious/blob/404b7b6d5b7020f42064cf8d7a745ab02057e728/lib/jiralicious/issue.rb#L11-L12
|
9
|
-
@key = attributes.fetch("jira_key")
|
10
|
-
@fields = attributes.fetch("fields")
|
11
|
-
end
|
12
|
-
|
13
|
-
def [](attribute)
|
14
|
-
case attribute
|
15
|
-
when "id"
|
16
|
-
return id
|
17
|
-
when "key"
|
18
|
-
return key
|
19
|
-
end
|
20
|
-
|
21
|
-
chunk = fields
|
22
|
-
attribute.split('.').each do |key|
|
23
|
-
chunk = chunk[key]
|
24
|
-
return chunk if chunk.nil?
|
25
|
-
end
|
26
|
-
|
27
|
-
if chunk.is_a?(Array) || chunk.is_a?(Hash)
|
28
|
-
chunk.to_json.to_s
|
29
|
-
else
|
30
|
-
chunk
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_record
|
35
|
-
record = {}
|
36
|
-
|
37
|
-
record["id"] = id
|
38
|
-
record["key"] = key
|
39
|
-
|
40
|
-
fields.each_pair do |key, value|
|
41
|
-
record_key = key
|
42
|
-
record_value = value.to_json.to_s
|
43
|
-
|
44
|
-
case value
|
45
|
-
when String
|
46
|
-
record_value = value
|
47
|
-
when Hash
|
48
|
-
if value.keys.include?("name")
|
49
|
-
record_key += ".name"
|
50
|
-
record_value = value["name"]
|
51
|
-
elsif value.keys.include?("id")
|
52
|
-
record_key += ".id"
|
53
|
-
record_value = value["id"]
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
record[record_key] = record_value
|
58
|
-
end
|
59
|
-
|
60
|
-
record
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|