backlog-api 0.0.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.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +14 -0
- data/LICENSE.txt +20 -0
- data/README.md +22 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/backlog-api.gemspec +68 -0
- data/lib/backlog.rb +9 -0
- data/lib/backlog/api.rb +132 -0
- data/lib/backlog/client.rb +27 -0
- data/lib/backlog/object.rb +247 -0
- data/spec/backlog/api_spec.rb +519 -0
- data/spec/backlog/client_spec.rb +26 -0
- data/spec/backlog/object_spec.rb +22 -0
- data/spec/backlog_spec.rb +7 -0
- data/spec/spec_helper.rb +16 -0
- metadata +128 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
# Add dependencies required to use your gem here.
|
3
|
+
# Example:
|
4
|
+
# gem "activesupport", ">= 2.3.5"
|
5
|
+
|
6
|
+
# Add dependencies to develop your gem here.
|
7
|
+
# Include everything needed to run rake, tests, features, etc.
|
8
|
+
group :development do
|
9
|
+
gem 'rake', '0.8.7'
|
10
|
+
gem "rspec", "~> 2.3.0"
|
11
|
+
gem "bundler", "~> 1.0.0"
|
12
|
+
gem "jeweler", "~> 1.6.2"
|
13
|
+
gem "rcov", ">= 0"
|
14
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 yoppi
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# backlog-api
|
2
|
+
A library to Easy Access Backlog(http://www.backlog.jp) API from Ruby.
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
Ok, you just type
|
6
|
+
|
7
|
+
$ gem install backlog-api
|
8
|
+
|
9
|
+
## How to use
|
10
|
+
First, create backlog client to accessing API.
|
11
|
+
Second, call API
|
12
|
+
|
13
|
+
require 'backlog-api'
|
14
|
+
backlog = Backlog::Client.new("space", "user", "password")
|
15
|
+
# get Project List
|
16
|
+
projects = backlog.get_projects()
|
17
|
+
# get Issue
|
18
|
+
issue = backlog.get_issue("issue_key")
|
19
|
+
|
20
|
+
## Copyright
|
21
|
+
Copyright (c) 2011 yoppi. See LICENSE.txt for further details.
|
22
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "backlog-api"
|
18
|
+
gem.homepage = "http://github.com/yoppi/backlog-api"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{Backlog API}
|
21
|
+
gem.description = %Q{A library to Access Backlog Issue from Ruby}
|
22
|
+
gem.email = "y.hirokazu@gmail.com"
|
23
|
+
gem.authors = ["yoppi"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rspec/core'
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
31
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
32
|
+
end
|
33
|
+
|
34
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :default => :spec
|
40
|
+
|
41
|
+
require 'rake/rdoctask'
|
42
|
+
Rake::RDocTask.new do |rdoc|
|
43
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
44
|
+
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
46
|
+
rdoc.title = "backlog-api #{version}"
|
47
|
+
rdoc.rdoc_files.include('README*')
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
49
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.0
|
data/backlog-api.gemspec
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{backlog-api}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = [%q{yoppi}]
|
12
|
+
s.date = %q{2011-10-09}
|
13
|
+
s.description = %q{A library to Access Backlog Issue from Ruby}
|
14
|
+
s.email = %q{y.hirokazu@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
"Gemfile",
|
23
|
+
"LICENSE.txt",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"backlog-api.gemspec",
|
28
|
+
"lib/backlog.rb",
|
29
|
+
"lib/backlog/api.rb",
|
30
|
+
"lib/backlog/client.rb",
|
31
|
+
"lib/backlog/object.rb",
|
32
|
+
"spec/backlog/api_spec.rb",
|
33
|
+
"spec/backlog/client_spec.rb",
|
34
|
+
"spec/backlog/object_spec.rb",
|
35
|
+
"spec/backlog_spec.rb",
|
36
|
+
"spec/spec_helper.rb"
|
37
|
+
]
|
38
|
+
s.homepage = %q{http://github.com/yoppi/backlog-api}
|
39
|
+
s.licenses = [%q{MIT}]
|
40
|
+
s.require_paths = [%q{lib}]
|
41
|
+
s.rubygems_version = %q{1.8.7}
|
42
|
+
s.summary = %q{Backlog API}
|
43
|
+
|
44
|
+
if s.respond_to? :specification_version then
|
45
|
+
s.specification_version = 3
|
46
|
+
|
47
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
48
|
+
s.add_development_dependency(%q<rake>, ["= 0.8.7"])
|
49
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
50
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
51
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.2"])
|
52
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
55
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
56
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
58
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
59
|
+
end
|
60
|
+
else
|
61
|
+
s.add_dependency(%q<rake>, ["= 0.8.7"])
|
62
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
63
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
64
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.2"])
|
65
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
data/lib/backlog.rb
ADDED
data/lib/backlog/api.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Backlog
|
4
|
+
module API
|
5
|
+
class ArgumentError < StandardError ; end
|
6
|
+
|
7
|
+
def get_projects
|
8
|
+
self.call("backlog.getProjects").map {|project|
|
9
|
+
Backlog::Object::Project.new(project)
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
# String | Integer -> Backlog::Object::Project
|
14
|
+
def get_project(project_key)
|
15
|
+
Backlog::Object::Project.new(
|
16
|
+
self.call("backlog.getProject", conv_str_to_int(project_key))
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_components(project_id)
|
21
|
+
self.call("backlog.getComponents", project_id).map {|component|
|
22
|
+
Backlog::Object::Component.new(component)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_versions(project_id)
|
27
|
+
self.call("backlog.getVersions", project_id).map {|version|
|
28
|
+
Backlog::Object::Version.new(version)
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_users(project_id)
|
33
|
+
self.call("backlog.getUsers", project_id).map {|user|
|
34
|
+
Backlog::Object::User.new(user)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
# String | Integer -> Backlog::Object::DetailUser
|
39
|
+
def get_user(user_key)
|
40
|
+
Backlog::Object::DetailUser.new(
|
41
|
+
self.call("backlog.getUser", conv_str_to_int(user_key))
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
# String | Integer -> Backlog::Object::UserIcon
|
46
|
+
def get_user_icon(user_key)
|
47
|
+
Backlog::Object::UserIcon.new(
|
48
|
+
self.call("backlog.getUserIcon", conv_str_to_int(user_key))
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_issue_types(project_id)
|
53
|
+
self.call("backlog.getIssueTypes", project_id).map {|issue_type|
|
54
|
+
Backlog::Object::IssueType.new(issue_type)
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# String | Integer -> Backlog::Object::Issue
|
59
|
+
def get_issue(issue_key)
|
60
|
+
Backlog::Object::Issue.new(
|
61
|
+
self.call("backlog.getIssue", conv_str_to_int(issue_key))
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_comments(issue_id)
|
66
|
+
self.call("backlog.getComments", issue_id).map {|comment|
|
67
|
+
Backlog::Object::Comment.new(comment)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_timeline
|
72
|
+
self.call("backlog.getTimeline").map {|timeline|
|
73
|
+
Backlog::Object::Timeline.new(timeline)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
|
77
|
+
def get_activity_types
|
78
|
+
self.call("backlog.getActivityTypes").map {|activity_type|
|
79
|
+
Backlog::Object::ActivityType.new(activity_type)
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_statuses
|
84
|
+
self.call("backlog.getStatuses").map {|status|
|
85
|
+
Backlog::Object::Status.new(status)
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_resolutions
|
90
|
+
self.call("backlog.getResolutions").map {|resolution|
|
91
|
+
Backlog::Object::Resolution.new(resolution)
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_priorities
|
96
|
+
self.call("backlog.getPriorities").map {|priority|
|
97
|
+
Backlog::Object::Priority.new(priority)
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
# Integer -> (String|Integer) -> Backlog::Object::CustomFields
|
102
|
+
def get_custom_fields(project_id, issue_type=nil)
|
103
|
+
h = {"project_id" => project_id}
|
104
|
+
if issue_type.instance_of? String
|
105
|
+
h["issue_type"] = issue_type
|
106
|
+
elsif issue_type.instance_of? Integer
|
107
|
+
h["issue_type_id"] = isuissue_type
|
108
|
+
end
|
109
|
+
self.call("backlog.getCustomFields", h).map {|custom_field|
|
110
|
+
Backlog::Object::CustomField.new(custom_field)
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
# Hash -> Integer
|
115
|
+
def count_issue(condition)
|
116
|
+
raise Backlog::API::ArgumentError, "must specify 'projectId'" unless condition.has_key? "projectId"
|
117
|
+
condition = Backlog::Object::FindCondition.new(condition)
|
118
|
+
self.call("backlog.countIssue", condition.to_h)
|
119
|
+
end
|
120
|
+
|
121
|
+
# String(Integer) -> Integer
|
122
|
+
# String(String) -> String
|
123
|
+
# Integer -> Integer
|
124
|
+
def conv_str_to_int(x)
|
125
|
+
if x.instance_of? String
|
126
|
+
(x.to_i.zero? && x != "0") ? x : x.to_i
|
127
|
+
else
|
128
|
+
x
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'xmlrpc/client'
|
4
|
+
|
5
|
+
module Backlog
|
6
|
+
class Client
|
7
|
+
include API
|
8
|
+
|
9
|
+
BACKLOG_API = "https://%s:%s@%s.backlog.jp/XML-RPC"
|
10
|
+
|
11
|
+
def initialize(space, username, password)
|
12
|
+
@space = space
|
13
|
+
@username = username
|
14
|
+
@password = password
|
15
|
+
@client = XMLRPC::Client.new2(BACKLOG_API % [@username, @password, @space])
|
16
|
+
end
|
17
|
+
attr_reader :space, :username, :password, :client
|
18
|
+
|
19
|
+
def call(method, args=nil)
|
20
|
+
if args
|
21
|
+
@client.call(method, args)
|
22
|
+
else
|
23
|
+
@client.call(method)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,247 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
module Backlog
|
4
|
+
module Object
|
5
|
+
class Serializable
|
6
|
+
def to_h
|
7
|
+
self.instance_variables.inject({}) {|ret, v|
|
8
|
+
ret[v.to_s.gsub(/^@/, '')] = self.instance_variable_get(v.to_s)
|
9
|
+
ret
|
10
|
+
}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Project
|
15
|
+
def initialize(project)
|
16
|
+
@id = project['id']
|
17
|
+
@name = project['name']
|
18
|
+
@key = project['key']
|
19
|
+
@url = project['url']
|
20
|
+
@archived = project['archived']
|
21
|
+
end
|
22
|
+
attr_reader :id, :name, :key, :url, :archived
|
23
|
+
end
|
24
|
+
|
25
|
+
class Component
|
26
|
+
def initialize(component)
|
27
|
+
@id = component['id']
|
28
|
+
@name = component['name']
|
29
|
+
end
|
30
|
+
attr_reader :id, :name
|
31
|
+
end
|
32
|
+
|
33
|
+
class Version
|
34
|
+
def initialize(version)
|
35
|
+
@id = version['id']
|
36
|
+
@name = version['name']
|
37
|
+
@date = version['date']
|
38
|
+
end
|
39
|
+
attr_reader :id, :name, :date
|
40
|
+
end
|
41
|
+
|
42
|
+
class User
|
43
|
+
def initialize(user)
|
44
|
+
@id = user['id']
|
45
|
+
@name = user['name']
|
46
|
+
end
|
47
|
+
attr_reader :id, :name
|
48
|
+
end
|
49
|
+
|
50
|
+
class DetailUser < User
|
51
|
+
def initialize(user)
|
52
|
+
super(user)
|
53
|
+
@lang = user['lang']
|
54
|
+
@updated_on = user['updated_on']
|
55
|
+
end
|
56
|
+
attr_reader :lang, :updated_on
|
57
|
+
end
|
58
|
+
|
59
|
+
class UserIcon
|
60
|
+
def initialize(user_icon)
|
61
|
+
@id = user_icon['id']
|
62
|
+
@content_type = user_icon['content_type']
|
63
|
+
# backlog.getUserIcon['data'] isn't encoded, so encode here.
|
64
|
+
@data = XMLRPC::Base64.encode(user_icon['data']).delete("\n")
|
65
|
+
@updated_on = user_icon['updated_on']
|
66
|
+
end
|
67
|
+
attr_reader :id, :content_type, :data, :updated_on
|
68
|
+
end
|
69
|
+
|
70
|
+
class IssueType
|
71
|
+
def initialize(issue_type)
|
72
|
+
@id = issue_type['id']
|
73
|
+
@name = issue_type['name']
|
74
|
+
@color = issue_type['color']
|
75
|
+
end
|
76
|
+
attr_reader :id, :name, :color
|
77
|
+
end
|
78
|
+
|
79
|
+
class Issue
|
80
|
+
def initialize(issue)
|
81
|
+
@id = issue['id']
|
82
|
+
@key = issue['key']
|
83
|
+
@summary = issue['summary']
|
84
|
+
@description = issue['description']
|
85
|
+
@url = issue['url']
|
86
|
+
@due_date = issue['due_date']
|
87
|
+
@start_date = issue['start_date'],
|
88
|
+
@estimated_hours = issue['estimated_hours']
|
89
|
+
@actual_hours = issue['actual_hours']
|
90
|
+
@issue_type = issue['issue_type'] ? IssueType.new(issue['issue_type']) : nil
|
91
|
+
@priority = issue['priority'] ? Priority.new(issue['priority']) : nil
|
92
|
+
@resolution = issue['resolution'] ? Resolution.new(issue['resolution']) : nil
|
93
|
+
@status = issue['status'] ? Status.new(issue['status']) : nil
|
94
|
+
@components = issue['components'] ? issue['components'].map {|x| Component.new(x) } : []
|
95
|
+
@versions = issue['versions'] ? issue['versions'].map {|x| Version.new(x) } : []
|
96
|
+
@milestones = issue['milestone'] ? issue['milestones'].map {|x| Milestone.new(x)} : []
|
97
|
+
@created_user = issue['created_user'] ? User.new(issue['created_user']) : nil
|
98
|
+
@assigner = issue['assigner'] ? User.new(issue['assigner']) : nil
|
99
|
+
@created_on = issue['created_on']
|
100
|
+
@updated_on = issue['updated_on']
|
101
|
+
@custom_fields = issue['custom_fields']
|
102
|
+
end
|
103
|
+
attr_reader :id, :key, :summary, :description, :url,
|
104
|
+
:due_date, :start_date, :estimated_hours,
|
105
|
+
:actual_hours, :issue_type, :priority,
|
106
|
+
:resolution, :status, :components, :versions,
|
107
|
+
:milestones, :created_user, :assigner,
|
108
|
+
:created_on, :updated_on, :custom_fields
|
109
|
+
end
|
110
|
+
|
111
|
+
class Priority
|
112
|
+
def initialize(priority)
|
113
|
+
@id = priority['id']
|
114
|
+
@name = priority['name']
|
115
|
+
end
|
116
|
+
attr_reader :id, :name
|
117
|
+
end
|
118
|
+
|
119
|
+
class Resolution
|
120
|
+
def initialize(resolution)
|
121
|
+
@id = resolution['id']
|
122
|
+
@name = resolution['name']
|
123
|
+
end
|
124
|
+
attr_reader :id, :name
|
125
|
+
end
|
126
|
+
|
127
|
+
class Status
|
128
|
+
def initialize(status)
|
129
|
+
@id = status['id']
|
130
|
+
@name = status['name']
|
131
|
+
end
|
132
|
+
attr_reader :id, :name
|
133
|
+
end
|
134
|
+
|
135
|
+
class Item
|
136
|
+
def initialize(item)
|
137
|
+
@id = item['id']
|
138
|
+
@name = item['name']
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
class Milestone
|
143
|
+
def initialize(milestone)
|
144
|
+
@id = milestone['id']
|
145
|
+
@name = milestone['name']
|
146
|
+
@date = milestone['date']
|
147
|
+
end
|
148
|
+
attr_reader :id, :name, :date
|
149
|
+
end
|
150
|
+
|
151
|
+
class Comment
|
152
|
+
def initialize(comment)
|
153
|
+
@id = comment['id']
|
154
|
+
@content = comment['content']
|
155
|
+
@created_user = User.new(comment['created_user'])
|
156
|
+
@created_on = comment['created_on']
|
157
|
+
@updated_on = comment['updated_on']
|
158
|
+
end
|
159
|
+
attr_reader :id, :content, :created_user, :created_on, :updated_on
|
160
|
+
end
|
161
|
+
|
162
|
+
class Timeline
|
163
|
+
def initialize(timeline)
|
164
|
+
@type = timeline['type'] ? ActivityType.new(timeline['type']) : nil
|
165
|
+
@content = timeline['content']
|
166
|
+
@updated_on = timeline['updated_on']
|
167
|
+
@user = timeline['user'] ? User.new(timeline['user']) : nil
|
168
|
+
@issue = timeline['issue'] ? Issue.new(timeline['issue']) : nil
|
169
|
+
end
|
170
|
+
attr_reader :type, :content, :updated_on, :user, :issue
|
171
|
+
end
|
172
|
+
|
173
|
+
class ActivityType
|
174
|
+
def initialize(activity_type)
|
175
|
+
@id = activity_type['id']
|
176
|
+
@name = activity_type['name']
|
177
|
+
end
|
178
|
+
attr_reader :id, :name
|
179
|
+
end
|
180
|
+
|
181
|
+
class CustomField
|
182
|
+
def initialize(custom_field)
|
183
|
+
@id = custom_field['id']
|
184
|
+
@type_id = custom_field['type_id']
|
185
|
+
@name = custom_field['name']
|
186
|
+
@description = custom_field['description']
|
187
|
+
@required = custom_field['required']
|
188
|
+
if custom_field['issue_types']
|
189
|
+
@issue_types = custom_field['issue_types'].map {|issue_type| IssueType.new(issue_type) }
|
190
|
+
end
|
191
|
+
# custom_field type is Number(type_id = 3)
|
192
|
+
@min = custom_field['min']
|
193
|
+
@max = custom_field['max']
|
194
|
+
@initial_value = custom_field['initial_value']
|
195
|
+
@unit = custom_field['unit']
|
196
|
+
# custom_field type is Date(type_id = 4)
|
197
|
+
@initial_value_type = custom_field['initial_value_type']
|
198
|
+
@initial_shift = custom_field['initial_shift']
|
199
|
+
@initial_date = custom_field['initial_date']
|
200
|
+
# custom_field type is List(type_id = 5,6)
|
201
|
+
if custom_field['items']
|
202
|
+
@items = custom_field['items'].map {|item| Item.new(item)}
|
203
|
+
end
|
204
|
+
# custom_field type is CheckBox or RadioButton(type_id = 7,8)
|
205
|
+
@allow_input = custom_field['allow_input']
|
206
|
+
end
|
207
|
+
attr_reader :id, :type_id, :name, :description, :required,
|
208
|
+
:issue_types,
|
209
|
+
:min, :max, :initial_value, :unit,
|
210
|
+
:initial_value_type, :initial_shift, :initial_date,
|
211
|
+
:items,
|
212
|
+
:allow_input
|
213
|
+
end
|
214
|
+
|
215
|
+
class FindCondition < Serializable
|
216
|
+
CONDITION_KEYS = %w[
|
217
|
+
projectId
|
218
|
+
issueTypeId
|
219
|
+
issueType
|
220
|
+
componentId
|
221
|
+
versionId
|
222
|
+
milestoneId
|
223
|
+
statusId
|
224
|
+
priorityId
|
225
|
+
assignerId
|
226
|
+
createdUserId
|
227
|
+
resolutionId
|
228
|
+
created_on_min
|
229
|
+
created_on_max
|
230
|
+
updated_on_min
|
231
|
+
updated_on_max
|
232
|
+
].each {|k|
|
233
|
+
class_eval { attr_reader k.to_sym }
|
234
|
+
}
|
235
|
+
|
236
|
+
def initialize(condition)
|
237
|
+
condition.each {|k, v|
|
238
|
+
self.instance_eval %Q{
|
239
|
+
if CONDITION_KEYS.include? k
|
240
|
+
@#{k} = v
|
241
|
+
end
|
242
|
+
}
|
243
|
+
}
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,519 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
|
+
|
5
|
+
describe Backlog::API do
|
6
|
+
before(:each) do
|
7
|
+
@client = Backlog::Client.new("hoge", "yoppi", "test")
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "プロジェクトAPI" do
|
11
|
+
context "プロジェクトの一覧を取得する" do
|
12
|
+
let(:projects) {
|
13
|
+
[{"id" => 100,
|
14
|
+
"name" => "test",
|
15
|
+
"key" => "TEST",
|
16
|
+
"url" => "http://hoge.backlog.jp/TEST",
|
17
|
+
"archived" => false}]
|
18
|
+
}
|
19
|
+
|
20
|
+
before do
|
21
|
+
mock(@client).call.with_any_args { projects }
|
22
|
+
end
|
23
|
+
|
24
|
+
it "プロジェクトのリストを取得できる" do
|
25
|
+
@client.get_projects.class.should == Array
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "プロジェクトを取得する" do
|
30
|
+
let(:project) {
|
31
|
+
{"id" => 100,
|
32
|
+
"name" => "test",
|
33
|
+
"key" => "TEST",
|
34
|
+
"url" => "http://hoge.backlog.jp/TEST",
|
35
|
+
"archived" => false}
|
36
|
+
}
|
37
|
+
|
38
|
+
before do
|
39
|
+
mock(@client).call.with_any_args { project }
|
40
|
+
end
|
41
|
+
|
42
|
+
it "project_idを指定してプロジェクトを取得できる" do
|
43
|
+
@client.get_project(100).class.should == Backlog::Object::Project
|
44
|
+
end
|
45
|
+
|
46
|
+
it "keyを指定してプロジェクトを取得できる" do
|
47
|
+
@client.get_project("key").class.should == Backlog::Object::Project
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "カテゴリAPI" do
|
53
|
+
context "プロジェクトのカテゴリを取得する" do
|
54
|
+
let(:component) {
|
55
|
+
[{"id" => 100,
|
56
|
+
"name" => "カテゴリ名"}]
|
57
|
+
}
|
58
|
+
|
59
|
+
before do
|
60
|
+
mock(@client).call.with_any_args { component }
|
61
|
+
end
|
62
|
+
|
63
|
+
it "指定したプロジェクトのカテゴリが取得できる" do
|
64
|
+
@client.get_components(100).class.should == Array
|
65
|
+
end
|
66
|
+
|
67
|
+
it "取得したカテゴリはすべてカテゴリオブジェクトである" do
|
68
|
+
@client.get_components(100).each {|component|
|
69
|
+
component.class.should == Backlog::Object::Component
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "バージョンAPI" do
|
76
|
+
context "プロジェクトの発生バージョン/マイルストーンを取得する" do
|
77
|
+
let(:version) {
|
78
|
+
[{"id" => 733,
|
79
|
+
"name" => "サイトオープン",
|
80
|
+
"date" => "20110808"}]
|
81
|
+
}
|
82
|
+
|
83
|
+
before do
|
84
|
+
mock(@client).call.with_any_args { version }
|
85
|
+
end
|
86
|
+
|
87
|
+
it "プロジェクトを指定して発生バージョンが取得できる" do
|
88
|
+
@client.get_versions(100).class.should == Array
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "ユーザAPI" do
|
94
|
+
context "プロジェクトの参加メンバーを取得する" do
|
95
|
+
let(:user) {
|
96
|
+
[{"id" => 1000,
|
97
|
+
"name" => "yoppi"}]
|
98
|
+
}
|
99
|
+
|
100
|
+
before do
|
101
|
+
mock(@client).call.with_any_args{ user }
|
102
|
+
end
|
103
|
+
|
104
|
+
it "プロジェクトを指定してその参加メンバーを取得できる" do
|
105
|
+
@client.get_users(100).class.should == Array
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "特定のユーザの情報を取得する" do
|
110
|
+
let(:user) {
|
111
|
+
{"id" => 1000,
|
112
|
+
"name" => "yoppi",
|
113
|
+
"lang" => "ja",
|
114
|
+
"updated_on" => "20110807220000"}
|
115
|
+
}
|
116
|
+
|
117
|
+
before do
|
118
|
+
mock(@client).call.with_any_args { user }
|
119
|
+
end
|
120
|
+
|
121
|
+
it "ユーザIDを指定してそのユーザの情報を取得する" do
|
122
|
+
@client.get_user(100).class.should == Backlog::Object::DetailUser
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "特定のユーザのアイコンを取得する" do
|
127
|
+
let(:user_icon) {
|
128
|
+
{
|
129
|
+
"id" => 1000,
|
130
|
+
"content_type" => "image/gif",
|
131
|
+
"data" => "/9j/4AAQSkZJRgABAgAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAAgACADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDMvWNpEHL5ycCo00rV7+NZrOylkjI+WR2VB+GeTVhGjQj7UHlfP7uN+Ax/Ht7f4VPa+OjoupS2GrSRb5pEaKOINiFWHG7PUng8V51SpKWkS8Jg4RSnUMqa11OwkEd9ZmPJwr5DZP1FNMUjA5P4cf4VtJd6rHbyQa1HBcRnMnnRMeUyTg579uPSqTPAw2wENH2yBkd8E06NR35WZ47CRSdSI3QbG28NXD3K3VzdyyZUxTMNiruU9upwDzx19zXPa3px1DxAuoopQZU5LZ6etd/d2EUwIkwy9RkYwayZrRg4KuVRei8VsoPmuc7xb5bET6hBLZGOVH85YNkc0e5eSSWDAHG0/J2zwazrJVt1IjiOPUD7x/OtG437CAcA8deRTYLWadRicmNONoAGP0qPZ8slYcq7qQfMf//Z",
|
132
|
+
}
|
133
|
+
}
|
134
|
+
|
135
|
+
before do
|
136
|
+
mock(@client).call.with_any_args { user_icon }
|
137
|
+
end
|
138
|
+
|
139
|
+
it "ユーザを指定してそのユーザのアイコンが取得できる" do
|
140
|
+
@client.get_user_icon(100).class.should == Backlog::Object::UserIcon
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "イシューAPI" do
|
146
|
+
context "プロジェクトのイシュータイプを取得する" do
|
147
|
+
let(:issue_types) {
|
148
|
+
[{"id" => 2000,
|
149
|
+
"name" => "タスク",
|
150
|
+
"color" => "#7ea800"
|
151
|
+
}]
|
152
|
+
}
|
153
|
+
|
154
|
+
before do
|
155
|
+
mock(@client).call.with_any_args { issue_types }
|
156
|
+
end
|
157
|
+
|
158
|
+
it "プロジェクトを指定してそのイシュータイプのリストを取得する" do
|
159
|
+
@client.get_issue_types(100).class.should == Array
|
160
|
+
end
|
161
|
+
|
162
|
+
it "イシュータイプのリスト要素はすべてイシュータイプオブジェクトである" do
|
163
|
+
@client.get_issue_types(100).each {|issue_type|
|
164
|
+
issue_type.class.should == Backlog::Object::IssueType
|
165
|
+
}
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context "プロジェクトのイシューを取得する" do
|
170
|
+
let(:issue) {
|
171
|
+
{
|
172
|
+
"id" => 1617103,
|
173
|
+
"key" => "ISSUE-100",
|
174
|
+
"summary" => "トップページのデザイン決定",
|
175
|
+
"description" => "トップページのデザイン決定する",
|
176
|
+
"url" => "https://test.backog.jp/view/ISSUE-100",
|
177
|
+
"due_date" => "20110831",
|
178
|
+
"start_date" => "20110720",
|
179
|
+
"estimated_hours" => "100",
|
180
|
+
"actual_hours" => "200",
|
181
|
+
"issue_type" => {"id" => 2000,
|
182
|
+
"name" => "タスク",
|
183
|
+
"color" => "#7ea800"},
|
184
|
+
"priority" => {"id" => 300, "name" => "中"},
|
185
|
+
"resolution" => {"id" => 400, "name" => "対応済み"},
|
186
|
+
"status" => {"id" => 2, "name" => "処理中"},
|
187
|
+
"components" => [{"id" => 100,
|
188
|
+
"name" => "カテゴリ名"}],
|
189
|
+
"versions" => [{"id" => 733,
|
190
|
+
"name" => "サイトオープン",
|
191
|
+
"date" => "20110808"}],
|
192
|
+
"milestones" => [{"id" => 800,
|
193
|
+
"name" => "8/21リリース",
|
194
|
+
"date" => "20110821"}],
|
195
|
+
"created_user" => {"id" => 1000, "name" => "yoppi"},
|
196
|
+
"assigner" => {"id" => 1000, "name" => "yoppi"},
|
197
|
+
"created_on" => "20110701",
|
198
|
+
"updated_on" => "20110807",
|
199
|
+
"custom_fields" => []
|
200
|
+
}
|
201
|
+
}
|
202
|
+
|
203
|
+
before do
|
204
|
+
mock(@client).call.with_any_args { issue }
|
205
|
+
end
|
206
|
+
|
207
|
+
it "課題キーを指定してイシューを取得できる" do
|
208
|
+
@client.get_issue("ISSUE-100").class.should == Backlog::Object::Issue
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
describe "コメントAPI" do
|
214
|
+
context "イシューのコメントを取得する" do
|
215
|
+
let(:comments) {
|
216
|
+
[{"id" => "12889281",
|
217
|
+
"content" => "ここはもっとシンプルなデザインがいいと思いました。",
|
218
|
+
"created_user" => {"id" => 100, "name" => "yoppi"},
|
219
|
+
"created_on" => "20110808165300",
|
220
|
+
"updated_on" => "20110808165300"
|
221
|
+
}]
|
222
|
+
}
|
223
|
+
|
224
|
+
before do
|
225
|
+
mock(@client).call.with_any_args { comments }
|
226
|
+
end
|
227
|
+
|
228
|
+
it "指定したイシューのコメントが取得できる" do
|
229
|
+
@client.get_comments(1000).class.should == Array
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "タイムラインAPI" do
|
235
|
+
context "タイムライン(イシューの更新情報)の一覧を取得する" do
|
236
|
+
let(:timeline) {
|
237
|
+
[{
|
238
|
+
"type" => {"id" => 1, "name" => "更新"},
|
239
|
+
"content" => "着手しました",
|
240
|
+
"updated_on" => "20110807194600",
|
241
|
+
"user" => {"id" => 100, "name" => "yoppi"},
|
242
|
+
"issue" => {"id" => "73", "key" => "ISSUE-100",
|
243
|
+
"summary" => "トップページのデザイン決定",
|
244
|
+
"description" => "トップページのデザイン決定します",
|
245
|
+
"priority" => {"id" => 2, "name" => "中"}}
|
246
|
+
}]
|
247
|
+
}
|
248
|
+
|
249
|
+
before do
|
250
|
+
mock(@client).call.with_any_args { timeline }
|
251
|
+
end
|
252
|
+
|
253
|
+
it "タイムラインの一覧が取得できる" do
|
254
|
+
@client.get_timeline().class.should == Array
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe "イシューの更新情報の種別一覧API" do
|
260
|
+
let(:activity_types) {
|
261
|
+
[
|
262
|
+
{"id" => 100,
|
263
|
+
"name" => "課題"}
|
264
|
+
]
|
265
|
+
}
|
266
|
+
|
267
|
+
before do
|
268
|
+
mock(@client).call.with_any_args { activity_types }
|
269
|
+
end
|
270
|
+
|
271
|
+
it "イシューの更新情報の種別一覧を取得できる" do
|
272
|
+
@client.get_activity_types().class.should == Array
|
273
|
+
end
|
274
|
+
|
275
|
+
it "各種別のオブジェクトであること" do
|
276
|
+
@client.get_activity_types().each {|activity_type|
|
277
|
+
activity_type.class.should == Backlog::Object::ActivityType
|
278
|
+
}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe "イシュー状態API" do
|
283
|
+
let(:statuses) {
|
284
|
+
[{"id" => 4, "name" => "完了"}]
|
285
|
+
}
|
286
|
+
|
287
|
+
before do
|
288
|
+
mock(@client).call.with_any_args { statuses }
|
289
|
+
end
|
290
|
+
|
291
|
+
it "イシューの状態一覧を取得できる" do
|
292
|
+
@client.get_statuses().class.should == Array
|
293
|
+
end
|
294
|
+
|
295
|
+
it "取得したイシューの状態一覧の各状態はStatusオブジェクトであること" do
|
296
|
+
@client.get_statuses().each {|status|
|
297
|
+
status.class.should == Backlog::Object::Status
|
298
|
+
}
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "イシュー完了理由API" do
|
303
|
+
let(:resolutions) {
|
304
|
+
[{"id" => 0, "name" => "対応済み"}]
|
305
|
+
}
|
306
|
+
|
307
|
+
before do
|
308
|
+
mock(@client).call.with_any_args { resolutions }
|
309
|
+
end
|
310
|
+
|
311
|
+
it "イシューの完了理由一覧を取得できる" do
|
312
|
+
@client.get_resolutions().class.should == Array
|
313
|
+
end
|
314
|
+
|
315
|
+
it "取得したイシューの完了理由一覧はResolutionオブジェクトであること" do
|
316
|
+
@client.get_resolutions().each {|resolution|
|
317
|
+
resolution.class.should == Backlog::Object::Resolution
|
318
|
+
}
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "イシューの優先度一覧取得API" do
|
323
|
+
let(:priorities) {
|
324
|
+
[{"id" => 3, "name" => "中"}]
|
325
|
+
}
|
326
|
+
|
327
|
+
before do
|
328
|
+
mock(@client).call.with_any_args { priorities }
|
329
|
+
end
|
330
|
+
|
331
|
+
it "イシューの優先度一覧を取得できる" do
|
332
|
+
@client.get_priorities().class.should == Array
|
333
|
+
end
|
334
|
+
|
335
|
+
it "取得したイシューの各優先度はPriorityオブジェクトであること" do
|
336
|
+
@client.get_priorities().each {|priority|
|
337
|
+
priority.class.should == Backlog::Object::Priority
|
338
|
+
}
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
describe "カスタム属性の情報取得API" do
|
343
|
+
context "カスタム属性タイプが文字列の場合" do
|
344
|
+
let(:custom_fields_1) {
|
345
|
+
[{"id" => 4,
|
346
|
+
"type_id" => 1,
|
347
|
+
"name" => "OS",
|
348
|
+
"description" => "現象が発生したOS",
|
349
|
+
"required" => 1,
|
350
|
+
"issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}]}]
|
351
|
+
}
|
352
|
+
|
353
|
+
before do
|
354
|
+
mock(@client).call.with_any_args { custom_fields_1 }
|
355
|
+
end
|
356
|
+
|
357
|
+
it "プロジェクトIDを指定して登録しているカスタム属性の情報を取得できる" do
|
358
|
+
@client.get_custom_fields(100).class.should == Array
|
359
|
+
end
|
360
|
+
|
361
|
+
it "プロジェクトIDをissue_type_idを指定して登録しているカスタム属性の情報を取得できる" do
|
362
|
+
@client.get_custom_fields(100, 10).class.should == Array
|
363
|
+
end
|
364
|
+
|
365
|
+
it "プロジェクトIDをissue_typeを指定して登録しているカスタム属性の情報を取得できる" do
|
366
|
+
@client.get_custom_fields(100, "バグ").class.should == Array
|
367
|
+
end
|
368
|
+
|
369
|
+
it "取得したカスタム属性情報はCustomFieldsオブジェクトであること" do
|
370
|
+
@client.get_custom_fields(100).each {|custom_field|
|
371
|
+
custom_field.class.should == Backlog::Object::CustomField
|
372
|
+
custom_field.id.should == custom_fields_1.first["id"]
|
373
|
+
custom_field.type_id.should == custom_fields_1.first["type_id"]
|
374
|
+
custom_field.name.should == custom_fields_1.first["name"]
|
375
|
+
custom_field.description.should == custom_fields_1.first["description"]
|
376
|
+
custom_field.required.should == custom_fields_1.first["required"]
|
377
|
+
custom_field.issue_types.class.should == Array
|
378
|
+
custom_field.issue_types.each {|issue_type|
|
379
|
+
issue_type.class.should == Backlog::Object::IssueType
|
380
|
+
issue_type.id.should == custom_fields_1.first["issue_types"].first["id"]
|
381
|
+
issue_type.name.should == custom_fields_1.first["issue_types"].first["name"]
|
382
|
+
issue_type.color.should == custom_fields_1.first["issue_types"].first["color"]
|
383
|
+
}
|
384
|
+
}
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context "カスタム属性タイプが数値の場合" do
|
389
|
+
let(:custom_fields_3) {
|
390
|
+
[{"id" => 10,
|
391
|
+
"type_id" => 3,
|
392
|
+
"name" => "割合",
|
393
|
+
"description" => "発生した割合",
|
394
|
+
"required" => 1,
|
395
|
+
"issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
|
396
|
+
"min" => 0.0,
|
397
|
+
"max" => 100.0,
|
398
|
+
"initial_value" => 0.0,
|
399
|
+
"unit" => "%"
|
400
|
+
}]
|
401
|
+
}
|
402
|
+
|
403
|
+
before do
|
404
|
+
mock(@client).call.with_any_args { custom_fields_3 }
|
405
|
+
end
|
406
|
+
|
407
|
+
it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
|
408
|
+
@client.get_custom_fields(100).each {|custom_field|
|
409
|
+
custom_field.min.should == custom_fields_3.first["min"]
|
410
|
+
custom_field.max.should == custom_fields_3.first["max"]
|
411
|
+
custom_field.initial_value.should == custom_fields_3.first["initial_value"]
|
412
|
+
custom_field.unit.should == custom_fields_3.first["unit"]
|
413
|
+
}
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context "カスタム属性タイプが日付の場合" do
|
418
|
+
let(:custom_fields_4) {
|
419
|
+
[{"id" => 20,
|
420
|
+
"type_id" => 4,
|
421
|
+
"name" => "日付",
|
422
|
+
"description" => "発生した日付",
|
423
|
+
"required" => 1,
|
424
|
+
"issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
|
425
|
+
"initial_value_type" => 1,
|
426
|
+
"min" => 100.0,
|
427
|
+
"max" => 0.0,
|
428
|
+
}]
|
429
|
+
}
|
430
|
+
|
431
|
+
before do
|
432
|
+
mock(@client).call.with_any_args { custom_fields_4 }
|
433
|
+
end
|
434
|
+
|
435
|
+
it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
|
436
|
+
@client.get_custom_fields(100).each {|custom_field|
|
437
|
+
custom_field.initial_value_type.should == custom_fields_4.first["initial_value_type"]
|
438
|
+
custom_field.min.should == custom_fields_4.first["min"]
|
439
|
+
custom_field.max.should == custom_fields_4.first["max"]
|
440
|
+
}
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
context "カスタム属性タイプがリストの場合" do
|
445
|
+
let(:custom_fields_5) {
|
446
|
+
[{"id" => 20,
|
447
|
+
"type_id" => 5,
|
448
|
+
"name" => "OS",
|
449
|
+
"description" => "発生したOS",
|
450
|
+
"required" => 1,
|
451
|
+
"issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
|
452
|
+
"items" => [{"id" => 1, "name" => "windows"}]
|
453
|
+
}]
|
454
|
+
}
|
455
|
+
|
456
|
+
before do
|
457
|
+
mock(@client).call.with_any_args { custom_fields_5 }
|
458
|
+
end
|
459
|
+
|
460
|
+
it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
|
461
|
+
@client.get_custom_fields(100).each {|custom_field|
|
462
|
+
custom_field.items.class == Array
|
463
|
+
custom_field.items.each {|item|
|
464
|
+
item.class.should == Backlog::Object::Item
|
465
|
+
}
|
466
|
+
}
|
467
|
+
end
|
468
|
+
end
|
469
|
+
|
470
|
+
context "カスタム属性タイプがチェックボックスの場合" do
|
471
|
+
let(:custom_fields_7) {
|
472
|
+
[{"id" => 20,
|
473
|
+
"type_id" => 5,
|
474
|
+
"name" => "OS",
|
475
|
+
"description" => "発生したOS",
|
476
|
+
"required" => 1,
|
477
|
+
"issue_types" => [{"id" => 5, "name" => "バグ", "color" => "#990000"}],
|
478
|
+
"allow_input" => "1",
|
479
|
+
"items" => [{"id" => 1, "name" => "windows"}]
|
480
|
+
}]
|
481
|
+
}
|
482
|
+
|
483
|
+
before do
|
484
|
+
mock(@client).call.with_any_args { custom_fields_7 }
|
485
|
+
end
|
486
|
+
|
487
|
+
it "取得したカスタム属性情報はCustomFieldオブジェクトであること" do
|
488
|
+
@client.get_custom_fields(100).each {|custom_field|
|
489
|
+
custom_field.allow_input.should == custom_fields_7.first['allow_input']
|
490
|
+
}
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
describe "イシュー件数検索API" do
|
496
|
+
context "クエリにproject_idがない場合" do
|
497
|
+
let(:condition) {
|
498
|
+
{"issueTypeId" => 100}
|
499
|
+
}
|
500
|
+
it "例外が発生する" do
|
501
|
+
expect { @client.count_issue(condition) }.should raise_error(Backlog::API::ArgumentError)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
context "指定した検索条件で検索する" do
|
505
|
+
let(:condition) {
|
506
|
+
{
|
507
|
+
"projectId" => 100,
|
508
|
+
"issueTypeId" => 10
|
509
|
+
}
|
510
|
+
}
|
511
|
+
before do
|
512
|
+
mock(@client).call.with_any_args { 1 }
|
513
|
+
end
|
514
|
+
it "指定した検索条件で検索できる" do
|
515
|
+
@client.count_issue(condition).should == 1
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
|
+
|
5
|
+
describe Backlog::Client do
|
6
|
+
context "特定のユーザのプロジェクトでAPIにアクセスする" do
|
7
|
+
let(:space) { 'test' }
|
8
|
+
let(:username) { 'yoppi' }
|
9
|
+
let(:password) { 'hoge' }
|
10
|
+
let(:client) {
|
11
|
+
Backlog::Client.new(space, username, password)
|
12
|
+
}
|
13
|
+
|
14
|
+
it "Backlogにアクセスするクライアントオブジェクトが生成されること" do
|
15
|
+
client.should_not be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "ユーザ名が取得できること" do
|
19
|
+
client.username.should == username
|
20
|
+
end
|
21
|
+
|
22
|
+
it "スペース名が取得できること" do
|
23
|
+
client.space.should == space
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
|
4
|
+
|
5
|
+
describe Backlog::Object::FindCondition do
|
6
|
+
let(:params) {
|
7
|
+
{
|
8
|
+
"projectId" => 100,
|
9
|
+
"issueTypeId" => 10
|
10
|
+
}
|
11
|
+
}
|
12
|
+
it "指定したHashのパラメータが登録されていること" do
|
13
|
+
o = Backlog::Object::FindCondition.new(params)
|
14
|
+
o.projectId.should == params["projectId"]
|
15
|
+
o.issueTypeId.should == params["issueTypeId"]
|
16
|
+
end
|
17
|
+
it "Hashに変換できること" do
|
18
|
+
h = Backlog::Object::FindCondition.new(params).to_h
|
19
|
+
h["projectId"].should == params["projectId"]
|
20
|
+
h["issueTypeId"].should == params["issueTypeId"]
|
21
|
+
end
|
22
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$:.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
require 'rspec'
|
5
|
+
require 'rr'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
require 'backlog'
|
9
|
+
|
10
|
+
# Requires supporting files with custom matchers and macros, etc,
|
11
|
+
# in ./support/ and its subdirectories.
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
config.mock_with :rr
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,128 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backlog-api
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- yoppi
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-10-09 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rake
|
17
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - "="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 0.8.7
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rspec
|
28
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.0
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: bundler
|
39
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.0.0
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *id003
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: jeweler
|
50
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: 1.6.2
|
56
|
+
type: :development
|
57
|
+
prerelease: false
|
58
|
+
version_requirements: *id004
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rcov
|
61
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
62
|
+
none: false
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: "0"
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *id005
|
70
|
+
description: A library to Access Backlog Issue from Ruby
|
71
|
+
email: y.hirokazu@gmail.com
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files:
|
77
|
+
- LICENSE.txt
|
78
|
+
- README.md
|
79
|
+
files:
|
80
|
+
- .document
|
81
|
+
- .rspec
|
82
|
+
- Gemfile
|
83
|
+
- LICENSE.txt
|
84
|
+
- README.md
|
85
|
+
- Rakefile
|
86
|
+
- VERSION
|
87
|
+
- backlog-api.gemspec
|
88
|
+
- lib/backlog.rb
|
89
|
+
- lib/backlog/api.rb
|
90
|
+
- lib/backlog/client.rb
|
91
|
+
- lib/backlog/object.rb
|
92
|
+
- spec/backlog/api_spec.rb
|
93
|
+
- spec/backlog/client_spec.rb
|
94
|
+
- spec/backlog/object_spec.rb
|
95
|
+
- spec/backlog_spec.rb
|
96
|
+
- spec/spec_helper.rb
|
97
|
+
homepage: http://github.com/yoppi/backlog-api
|
98
|
+
licenses:
|
99
|
+
- MIT
|
100
|
+
post_install_message:
|
101
|
+
rdoc_options: []
|
102
|
+
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
hash: -1065371427
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
version: "0"
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ">="
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: "0"
|
120
|
+
requirements: []
|
121
|
+
|
122
|
+
rubyforge_project:
|
123
|
+
rubygems_version: 1.8.7
|
124
|
+
signing_key:
|
125
|
+
specification_version: 3
|
126
|
+
summary: Backlog API
|
127
|
+
test_files: []
|
128
|
+
|