kanbantool 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +59 -0
- data/Rakefile +9 -0
- data/kanbantool.gemspec +28 -0
- data/lib/kanbantool.rb +11 -0
- data/lib/kanbantool/board.rb +34 -0
- data/lib/kanbantool/client.rb +72 -0
- data/lib/kanbantool/task.rb +18 -0
- data/lib/kanbantool/version.rb +3 -0
- data/spec/cassettes/board.yml +50 -0
- data/spec/cassettes/boards.yml +59 -0
- data/spec/cassettes/tasks.yml +73 -0
- data/spec/lib/kanbantool/board_spec.rb +74 -0
- data/spec/lib/kanbantool/client_spec.rb +51 -0
- data/spec/lib/kanbantool/task_spec.rb +39 -0
- data/spec/spec_helper.rb +18 -0
- metadata +167 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Tim Blair
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Kanban Tool
|
2
|
+
|
3
|
+
A Ruby wrapper library for accessing the [Kanban Tool API][kt-api].
|
4
|
+
|
5
|
+
> Note: this is currently a limited, read-only interface. Contributions
|
6
|
+
> to extend the functionality are welcome.
|
7
|
+
|
8
|
+
## Installation
|
9
|
+
|
10
|
+
Add this line to your application's Gemfile:
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
gem 'kanbantool'
|
14
|
+
```
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
```sh
|
19
|
+
bundle
|
20
|
+
```
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
```sh
|
25
|
+
gem install kanbantool
|
26
|
+
```
|
27
|
+
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
Make sure you have an [API key][get-key], then create a client:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
client = KanbanTool::Client.new(SUBDOMAIN, API_KEY}
|
34
|
+
```
|
35
|
+
|
36
|
+
You can then call methods on the client to retrieve data from the API:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# Retrieve an array of all boards under this account
|
40
|
+
client.boards #=> [#<KanbanTool::Board:0x00 ...>, ...]
|
41
|
+
|
42
|
+
# Retrieve a single board, including stages
|
43
|
+
client.board(BOARD_ID) #=> #<KanbanTool::Board:0x00 ...>
|
44
|
+
|
45
|
+
# Retrieve an array of all tasks for a specific board
|
46
|
+
client.tasks(BOARD_ID) #=> [#<KanbanTool::Task:0x00 ...>, ... ]
|
47
|
+
```
|
48
|
+
|
49
|
+
## Contributing
|
50
|
+
|
51
|
+
1. [Fork it][fork-it]
|
52
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
53
|
+
3. Commit your changes and tests (`git commit -am 'Add some feature'`)
|
54
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
55
|
+
5. Create new Pull Request
|
56
|
+
|
57
|
+
[kt-api]: http://kanbantool.com/about/api
|
58
|
+
[get-key]: http://gppmt.kanbantool.com/profile/api_token
|
59
|
+
[fork-it]: https://github.com/timblair/kanbantool/fork
|
data/Rakefile
ADDED
data/kanbantool.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'kanbantool/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "kanbantool"
|
8
|
+
spec.version = KanbanTool::VERSION
|
9
|
+
spec.authors = ["Tim Blair"]
|
10
|
+
spec.email = ["tim@bla.ir"]
|
11
|
+
spec.description = %q{Easy access to Kanban Tool's API}
|
12
|
+
spec.summary = %q{Easy access to Kanban Tool's API}
|
13
|
+
spec.homepage = "https://github.com/timblair/kanbantool"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "httparty", "~> 0.11.0"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0.0"
|
26
|
+
spec.add_development_dependency "webmock", "< 1.10.0"
|
27
|
+
spec.add_development_dependency "vcr", "~> 2.4.0"
|
28
|
+
end
|
data/lib/kanbantool.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module KanbanTool
|
2
|
+
class Board
|
3
|
+
|
4
|
+
class Stage < Struct.new(:id, :name, :description, :position); end
|
5
|
+
|
6
|
+
FIELDS = %w{ id name description created_at version last_activity_on }
|
7
|
+
FIELDS.each { |f| attr_reader f.to_sym }
|
8
|
+
|
9
|
+
attr_reader :stages
|
10
|
+
|
11
|
+
def self.create_from_hash(hash)
|
12
|
+
board = self.new
|
13
|
+
board.load!(hash)
|
14
|
+
board.load_stages!(hash["workflow_stages"]) unless hash["workflow_stages"].nil?
|
15
|
+
board
|
16
|
+
end
|
17
|
+
|
18
|
+
def load!(hash)
|
19
|
+
FIELDS.each { |f| instance_variable_set("@#{f}".to_sym, hash[f]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_stages!(array)
|
23
|
+
@stages = []
|
24
|
+
array.each do |s|
|
25
|
+
@stages << Stage.new( s["id"], s["name"], s["description"], s["position"] ).freeze
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def stage(id)
|
30
|
+
stages.first { |s| s.id == id }
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "httparty"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module KanbanTool
|
5
|
+
class Client
|
6
|
+
include HTTParty
|
7
|
+
|
8
|
+
attr_reader :domain, :token
|
9
|
+
|
10
|
+
def initialize(domain, token)
|
11
|
+
@domain = domain
|
12
|
+
@token = token
|
13
|
+
end
|
14
|
+
|
15
|
+
def boards
|
16
|
+
get("boards").collect do |board|
|
17
|
+
Board.create_from_hash board
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def board(board_id)
|
22
|
+
Board.create_from_hash get("boards/#{board_id}")
|
23
|
+
end
|
24
|
+
|
25
|
+
def users(board_id)
|
26
|
+
get("boards/#{board_id}/users")
|
27
|
+
end
|
28
|
+
|
29
|
+
def tasks(board_id)
|
30
|
+
get("boards/#{board_id}/tasks").collect do |task|
|
31
|
+
Task.create_from_hash task
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def activity(board_id)
|
36
|
+
get("boards/#{board_id}/changelog")
|
37
|
+
end
|
38
|
+
|
39
|
+
def api_url
|
40
|
+
"https://#{domain}.#{KanbanTool::API_DOMAIN}#{KanbanTool::API_PATH}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def url_for(path)
|
44
|
+
"#{api_url}#{path}.json"
|
45
|
+
end
|
46
|
+
|
47
|
+
def headers
|
48
|
+
{ "X-KanbanToolToken" => token }
|
49
|
+
end
|
50
|
+
|
51
|
+
def params
|
52
|
+
{ :headers => headers }
|
53
|
+
end
|
54
|
+
|
55
|
+
def get(path)
|
56
|
+
r = HTTParty.get url_for(path), params
|
57
|
+
raise "Error: #{url_for(path)} => #{r.inspect}" if r.code != 200
|
58
|
+
unwrap JSON.parse(r.body)
|
59
|
+
end
|
60
|
+
|
61
|
+
def unwrap(data)
|
62
|
+
if data.is_a? Array
|
63
|
+
data.collect { |item| unwrap item }
|
64
|
+
else
|
65
|
+
keys = %w{ board task shared_item_user }
|
66
|
+
key = keys.find { |key| !data[key].nil? }
|
67
|
+
data.include?(key) ? data[key] : data
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module KanbanTool
|
2
|
+
class Task
|
3
|
+
|
4
|
+
FIELDS = %w{ id name description created_at updated_at archived_at assigned_user }
|
5
|
+
FIELDS.each { |f| attr_reader f.to_sym }
|
6
|
+
|
7
|
+
def self.create_from_hash(hash)
|
8
|
+
task = self.new
|
9
|
+
task.load!(hash)
|
10
|
+
task
|
11
|
+
end
|
12
|
+
|
13
|
+
def load!(hash)
|
14
|
+
FIELDS.each { |f| instance_variable_set("@#{f}".to_sym, hash[f]) }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://test.kanbantool.com/api/v1/boards/12345.json
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
X-Kanbantooltoken:
|
11
|
+
- 123456789ABC
|
12
|
+
response:
|
13
|
+
status:
|
14
|
+
code: 200
|
15
|
+
message: OK
|
16
|
+
headers:
|
17
|
+
Date:
|
18
|
+
- Fri, 10 May 2013 14:35:50 GMT
|
19
|
+
Content-Type:
|
20
|
+
- application/json; charset=utf-8
|
21
|
+
Transfer-Encoding:
|
22
|
+
- chunked
|
23
|
+
Connection:
|
24
|
+
- keep-alive
|
25
|
+
Status:
|
26
|
+
- '200'
|
27
|
+
X-Rack-Cache:
|
28
|
+
- miss
|
29
|
+
Cache-Control:
|
30
|
+
- max-age=0, private, must-revalidate
|
31
|
+
Etag:
|
32
|
+
- ! '"56215f2e9fdc84ee89170720de5cdfe9"'
|
33
|
+
X-Runtime:
|
34
|
+
- '0.095858'
|
35
|
+
X-Ua-Compatible:
|
36
|
+
- IE=Edge,chrome=1
|
37
|
+
Server:
|
38
|
+
- kanbantool.com
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: ! '{"board":{"swimlanes":[{"board_id":12345,"name":"Project status","id":77669,"limit":null,"position":1,"description":""}],"owner_id":22825,"created_at":"2013-05-02T15:01:16+01:00","cumulative_flow_updated_at":"2013-05-10T03:34:05+01:00","folder_id":null,"version":178,"board_template_id":"personal_basic","last_activity_on":"2013-05-10","deleted_at":null,"id":12345,"name":"Project
|
42
|
+
Status Board","workflow_stages":[{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":null,"id":284733,"parent_id":null,"limit":null,"position":1,"description":null},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Backlog","id":284735,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Briefing","id":286335,"parent_id":284733,"limit":null,"position":1,"description":"Actions
|
43
|
+
to be carried out outside of the project team prior to scheduling, requirements
|
44
|
+
gathering and development."},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Waiting
|
45
|
+
for resource","id":286337,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Functional
|
46
|
+
spec","id":284737,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Technical
|
47
|
+
spec","id":284755,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Development","id":284739,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"QA","id":284741,"parent_id":284733,"limit":null,"position":1,"description":""},{"board_id":12345,"lane_width":1,"lane_type_id":null,"name":"Live","id":284743,"parent_id":284733,"limit":null,"position":1,"description":""}],"external_id_sequence":1,"description":"","position":null,"card_types":[{"board_id":12345,"is_default":true,"color_ref":"yellow","name":"yellow","id":250943,"is_disabled":false,"position":1},{"board_id":12345,"is_default":false,"color_ref":"orange","name":"orange","id":250945,"is_disabled":false,"position":2},{"board_id":12345,"is_default":false,"color_ref":"red","name":"red","id":250947,"is_disabled":false,"position":3},{"board_id":12345,"is_default":false,"color_ref":"blue","name":"blue","id":250949,"is_disabled":false,"position":4},{"board_id":12345,"is_default":false,"color_ref":"green","name":"green","id":250951,"is_disabled":false,"position":5},{"board_id":12345,"is_default":false,"color_ref":"white","name":"white","id":250953,"is_disabled":false,"position":6}]}}'
|
48
|
+
http_version:
|
49
|
+
recorded_at: Fri, 10 May 2013 14:35:50 GMT
|
50
|
+
recorded_with: VCR 2.4.0
|
@@ -0,0 +1,59 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://test.kanbantool.com/api/v1/boards.json
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
X-Kanbantooltoken:
|
11
|
+
- 123456789ABC
|
12
|
+
response:
|
13
|
+
status:
|
14
|
+
code: 200
|
15
|
+
message: OK
|
16
|
+
headers:
|
17
|
+
Date:
|
18
|
+
- Fri, 10 May 2013 14:35:49 GMT
|
19
|
+
Content-Type:
|
20
|
+
- application/json; charset=utf-8
|
21
|
+
Transfer-Encoding:
|
22
|
+
- chunked
|
23
|
+
Connection:
|
24
|
+
- keep-alive
|
25
|
+
Status:
|
26
|
+
- '200'
|
27
|
+
X-Rack-Cache:
|
28
|
+
- miss
|
29
|
+
Cache-Control:
|
30
|
+
- max-age=0, private, must-revalidate
|
31
|
+
Etag:
|
32
|
+
- ! '"c3798def8ad2a5c47c71666aab890d61"'
|
33
|
+
X-Runtime:
|
34
|
+
- '2.177222'
|
35
|
+
X-Ua-Compatible:
|
36
|
+
- IE=Edge,chrome=1
|
37
|
+
Server:
|
38
|
+
- kanbantool.com
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: ! '[{ "board":{ "owner_id":
|
42
|
+
null,"created_at":"2013-04-05T14:49:07+01:00","cumulative_flow_updated_at":"2013-05-10T03:30:45+01:00","folder_id":
|
43
|
+
3029,"version":
|
44
|
+
620,"board_template_id":"team_basic","last_activity_on":"2013-05-10","deleted_at":
|
45
|
+
null,"id": 33223,"name":"Test Board
|
46
|
+
1","external_id_sequence": 1,"description":"My
|
47
|
+
description","position": null }},{ "board":{ "owner_id":
|
48
|
+
null,"created_at":"2013-04-05T14:49:07+01:00","cumulative_flow_updated_at":"2013-05-10T03:30:45+01:00","folder_id":
|
49
|
+
3029,"version":
|
50
|
+
620,"board_template_id":"team_basic","last_activity_on":"2013-05-10","deleted_at":
|
51
|
+
null,"id": 33223,"name":"Test Board
|
52
|
+
1","external_id_sequence": 1,"folder":{ "owner_id":
|
53
|
+
null,"created_at":"2013-02-07T14:45:54+00:00","deleted_at":
|
54
|
+
null,"name":"Some Folder","id": 3029,"position":
|
55
|
+
null,"description":""},"description":"My
|
56
|
+
description","position": null }}]'
|
57
|
+
http_version:
|
58
|
+
recorded_at: Fri, 10 May 2013 14:35:49 GMT
|
59
|
+
recorded_with: VCR 2.4.0
|
@@ -0,0 +1,73 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://test.kanbantool.com/api/v1/boards/12345/tasks.json
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
X-Kanbantooltoken:
|
11
|
+
- 123456789ABC
|
12
|
+
response:
|
13
|
+
status:
|
14
|
+
code: 200
|
15
|
+
message: OK
|
16
|
+
headers:
|
17
|
+
Date:
|
18
|
+
- Fri, 10 May 2013 14:35:52 GMT
|
19
|
+
Content-Type:
|
20
|
+
- application/json; charset=utf-8
|
21
|
+
Transfer-Encoding:
|
22
|
+
- chunked
|
23
|
+
Connection:
|
24
|
+
- keep-alive
|
25
|
+
Status:
|
26
|
+
- '200'
|
27
|
+
X-Rack-Cache:
|
28
|
+
- miss
|
29
|
+
Cache-Control:
|
30
|
+
- max-age=0, private, must-revalidate
|
31
|
+
Etag:
|
32
|
+
- ! '"c570831d8fdab2d078d64bbdb7162e1e"'
|
33
|
+
X-Runtime:
|
34
|
+
- '0.175887'
|
35
|
+
X-Ua-Compatible:
|
36
|
+
- IE=Edge,chrome=1
|
37
|
+
Server:
|
38
|
+
- kanbantool.com
|
39
|
+
body:
|
40
|
+
encoding: US-ASCII
|
41
|
+
string: ! '[{"task": {"archived_at": null,"assigned_user": {"initials": "TU","name": "Test
|
42
|
+
User"},"assigned_user_id": 2334,"block_reason": null,"card_type_id":
|
43
|
+
250953,"comments_count": 0,"created_at":
|
44
|
+
"2013-05-02T15:12:32+01:00","custom_field_1": null,"custom_field_2":
|
45
|
+
null,"custom_field_3": null,"custom_field_4": null,"custom_field_5":
|
46
|
+
null,"description": "","due_date": null,"external_id": null,"external_link":
|
47
|
+
null,"id": 1568915,"name": "Card 1","position": 4,"priority": 0,"size_estimate":
|
48
|
+
"1.0","subtask_search_tags": null,"subtasks_completed_count":
|
49
|
+
0,"subtasks_count": 0,"swimlane_id": 77669,"tags": "","updated_at":
|
50
|
+
"2013-05-02T16:19:34+01:00","workflow_stage_id": 284735}},{"task":
|
51
|
+
{"archived_at": null,"assigned_user": {"initials": "AU","name": "Another
|
52
|
+
User"},"assigned_user_id": 2344,"block_reason": null,"card_type_id":
|
53
|
+
250953,"comments_count": 0,"created_at":
|
54
|
+
"2013-05-02T15:12:46+01:00","custom_field_1": null,"custom_field_2":
|
55
|
+
null,"custom_field_3": null,"custom_field_4": null,"custom_field_5":
|
56
|
+
null,"description": "","due_date": null,"external_id": null,"external_link":
|
57
|
+
null,"id": 1568917,"name": "Card 2","position": 3,"priority": 0,"size_estimate":
|
58
|
+
"1.0","subtask_search_tags": null,"subtasks_completed_count":
|
59
|
+
0,"subtasks_count": 0,"swimlane_id": 77669,"tags": "","updated_at":
|
60
|
+
"2013-05-02T16:19:33+01:00","workflow_stage_id": 284735}},{"task":
|
61
|
+
{"archived_at": null,"assigned_user_id": null,"block_reason":
|
62
|
+
null,"card_type_id": 250953,"comments_count": 0,"created_at":
|
63
|
+
"2013-05-02T15:13:23+01:00","custom_field_1": null,"custom_field_2":
|
64
|
+
null,"custom_field_3": null,"custom_field_4": null,"custom_field_5":
|
65
|
+
null,"description": "","due_date": null,"external_id": null,"external_link":
|
66
|
+
null,"id": 1568919,"name": "Interests Searching/Niching","position":
|
67
|
+
1,"priority": 0,"size_estimate": "1.0","subtask_search_tags":
|
68
|
+
null,"subtasks_completed_count": 0,"subtasks_count": 0,"swimlane_id":
|
69
|
+
77669,"tags": "","updated_at": "2013-05-02T15:13:23+01:00","workflow_stage_id":
|
70
|
+
284735}}]'
|
71
|
+
http_version:
|
72
|
+
recorded_at: Fri, 10 May 2013 14:35:52 GMT
|
73
|
+
recorded_with: VCR 2.4.0
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require (File.expand_path('./../../../spec_helper', __FILE__))
|
2
|
+
|
3
|
+
describe KanbanTool::Board do
|
4
|
+
|
5
|
+
let(:board) { KanbanTool::Board.new }
|
6
|
+
let(:board_params) { KanbanTool::Board::FIELDS.inject({}) { |h,f| h[f] = f*3; h } }
|
7
|
+
let(:board_hash) { board_params }
|
8
|
+
let(:stage) { {"id" => "1", "name" => "foo", "description" => "bar", "position" => 1} }
|
9
|
+
let(:stages) { [stage, stage, stage] }
|
10
|
+
|
11
|
+
describe "#load!" do
|
12
|
+
let(:extra_hash_param) { board_hash.merge({ "foo" => "bar" }) }
|
13
|
+
|
14
|
+
it "loads the hash" do
|
15
|
+
board.load!(board_hash)
|
16
|
+
board_hash.each { |k,v| board.send("#{k}".to_sym).must_equal v }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "doesn't import unlisted fields" do
|
20
|
+
board.load!(extra_hash_param)
|
21
|
+
board.instance_variable_get(:@foo).must_be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "overwrites existing values" do
|
25
|
+
board.instance_variable_set(:@id, "x")
|
26
|
+
board.load!(board_hash)
|
27
|
+
board.id.must_equal board_hash["id"]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#load_stages!" do
|
32
|
+
before do
|
33
|
+
board.load_stages!(stages)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "loads all stages" do
|
37
|
+
board.stages.size.must_equal stages.size
|
38
|
+
end
|
39
|
+
|
40
|
+
it "creates Stage objects" do
|
41
|
+
board.stages.each { |s| s.must_be_instance_of KanbanTool::Board::Stage }
|
42
|
+
end
|
43
|
+
|
44
|
+
it "freezes all stages" do
|
45
|
+
board.stages.first.must_be :frozen?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe ".create_from_hash" do
|
50
|
+
let(:board) { KanbanTool::Board.create_from_hash(board_hash) }
|
51
|
+
|
52
|
+
context "without stages" do
|
53
|
+
it "returns a board instance" do
|
54
|
+
board.must_be_instance_of KanbanTool::Board
|
55
|
+
end
|
56
|
+
|
57
|
+
it "correctly loads the board data" do
|
58
|
+
board_hash.each { |k,v| board.send("#{k}".to_sym).must_equal v }
|
59
|
+
end
|
60
|
+
|
61
|
+
it "handles empty stages" do
|
62
|
+
board.stages.must_be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "with stages" do
|
67
|
+
let(:board_hash) { board_params.merge({"workflow_stages" => stages}) }
|
68
|
+
|
69
|
+
it "populates stages" do
|
70
|
+
board.stages.size.must_equal stages.size
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require (File.expand_path('./../../../spec_helper', __FILE__))
|
2
|
+
|
3
|
+
describe KanbanTool::Client do
|
4
|
+
|
5
|
+
let(:client) { KanbanTool::Client.new("test", "123456789ABC") }
|
6
|
+
|
7
|
+
after do
|
8
|
+
VCR.eject_cassette
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "#boards" do
|
12
|
+
before do
|
13
|
+
VCR.insert_cassette "boards"
|
14
|
+
end
|
15
|
+
|
16
|
+
subject { client.boards }
|
17
|
+
|
18
|
+
it "returns an array" do
|
19
|
+
subject.must_be_instance_of(Array)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "returns an array of boards" do
|
23
|
+
subject.each { |b| b.must_be_instance_of(KanbanTool::Board) }
|
24
|
+
end
|
25
|
+
|
26
|
+
it "populates all board objects" do
|
27
|
+
subject.each { |b| b.id.wont_be_nil }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#tasks" do
|
32
|
+
before do
|
33
|
+
VCR.insert_cassette "tasks"
|
34
|
+
end
|
35
|
+
|
36
|
+
subject { client.tasks(12345) }
|
37
|
+
|
38
|
+
it "returns an array" do
|
39
|
+
subject.must_be_instance_of(Array)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "returns an array of tasks" do
|
43
|
+
subject.each { |b| b.must_be_instance_of(KanbanTool::Task) }
|
44
|
+
end
|
45
|
+
|
46
|
+
it "populates all task objects" do
|
47
|
+
subject.each { |b| b.id.wont_be_nil }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require (File.expand_path('./../../../spec_helper', __FILE__))
|
2
|
+
|
3
|
+
describe KanbanTool::Task do
|
4
|
+
|
5
|
+
let(:task) { KanbanTool::Task.new }
|
6
|
+
let(:task_hash) { KanbanTool::Task::FIELDS.inject({}) { |h,f| h[f] = f*3; h } }
|
7
|
+
|
8
|
+
describe "#load!" do
|
9
|
+
let(:extra_hash_param) { task_hash.merge({ "foo" => "bar" }) }
|
10
|
+
|
11
|
+
it "loads the hash" do
|
12
|
+
task.load!(task_hash)
|
13
|
+
task_hash.each { |k,v| task.send("#{k}".to_sym).must_equal v }
|
14
|
+
end
|
15
|
+
|
16
|
+
it "doesn't import unlisted fields" do
|
17
|
+
task.load!(extra_hash_param)
|
18
|
+
task.instance_variable_get(:@foo).must_be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "overwrites existing values" do
|
22
|
+
task.instance_variable_set(:@id, "x")
|
23
|
+
task.load!(task_hash)
|
24
|
+
task.id.must_equal task_hash["id"]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".create_from_hash" do
|
29
|
+
let(:task) { KanbanTool::Task.create_from_hash(task_hash) }
|
30
|
+
|
31
|
+
it "returns a task instance" do
|
32
|
+
task.must_be_instance_of KanbanTool::Task
|
33
|
+
end
|
34
|
+
|
35
|
+
it "correctly loads the task data" do
|
36
|
+
task_hash.each { |k,v| task.send("#{k}".to_sym).must_equal v }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require(File.expand_path("../../lib/kanbantool", __FILE__))
|
2
|
+
|
3
|
+
require "minitest/autorun"
|
4
|
+
require "webmock/minitest"
|
5
|
+
require "vcr"
|
6
|
+
|
7
|
+
VCR.configure do |c|
|
8
|
+
c.cassette_library_dir = "spec/cassettes"
|
9
|
+
c.hook_into :webmock
|
10
|
+
end
|
11
|
+
|
12
|
+
module MiniTest
|
13
|
+
class Spec
|
14
|
+
class << self
|
15
|
+
alias_method :context, :describe
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: kanbantool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Tim Blair
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-05-13 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.11.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.11.0
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.3'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.3'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 5.0.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 5.0.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: webmock
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - <
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.10.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - <
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.10.0
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: vcr
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.4.0
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 2.4.0
|
110
|
+
description: Easy access to Kanban Tool's API
|
111
|
+
email:
|
112
|
+
- tim@bla.ir
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- Gemfile
|
119
|
+
- LICENSE.txt
|
120
|
+
- README.md
|
121
|
+
- Rakefile
|
122
|
+
- kanbantool.gemspec
|
123
|
+
- lib/kanbantool.rb
|
124
|
+
- lib/kanbantool/board.rb
|
125
|
+
- lib/kanbantool/client.rb
|
126
|
+
- lib/kanbantool/task.rb
|
127
|
+
- lib/kanbantool/version.rb
|
128
|
+
- spec/cassettes/board.yml
|
129
|
+
- spec/cassettes/boards.yml
|
130
|
+
- spec/cassettes/tasks.yml
|
131
|
+
- spec/lib/kanbantool/board_spec.rb
|
132
|
+
- spec/lib/kanbantool/client_spec.rb
|
133
|
+
- spec/lib/kanbantool/task_spec.rb
|
134
|
+
- spec/spec_helper.rb
|
135
|
+
homepage: https://github.com/timblair/kanbantool
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
none: false
|
144
|
+
requirements:
|
145
|
+
- - ! '>='
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
none: false
|
150
|
+
requirements:
|
151
|
+
- - ! '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
requirements: []
|
155
|
+
rubyforge_project:
|
156
|
+
rubygems_version: 1.8.23
|
157
|
+
signing_key:
|
158
|
+
specification_version: 3
|
159
|
+
summary: Easy access to Kanban Tool's API
|
160
|
+
test_files:
|
161
|
+
- spec/cassettes/board.yml
|
162
|
+
- spec/cassettes/boards.yml
|
163
|
+
- spec/cassettes/tasks.yml
|
164
|
+
- spec/lib/kanbantool/board_spec.rb
|
165
|
+
- spec/lib/kanbantool/client_spec.rb
|
166
|
+
- spec/lib/kanbantool/task_spec.rb
|
167
|
+
- spec/spec_helper.rb
|