clubhouse.io-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +70 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/clubhouse.io-ruby.gemspec +26 -0
- data/docs/comments.md +64 -0
- data/docs/epics.md +64 -0
- data/docs/files.md +48 -0
- data/docs/labels.md +49 -0
- data/docs/linked_files.md +64 -0
- data/docs/projects.md +74 -0
- data/docs/stories.md +96 -0
- data/docs/story_links.md +39 -0
- data/docs/tasks.md +66 -0
- data/docs/users.md +26 -0
- data/docs/workflows.md +17 -0
- data/lib/clubhouse.rb +34 -0
- data/lib/clubhouse/api_actions.rb +10 -0
- data/lib/clubhouse/base_resource.rb +108 -0
- data/lib/clubhouse/client.rb +83 -0
- data/lib/clubhouse/comment.rb +45 -0
- data/lib/clubhouse/epic.rb +38 -0
- data/lib/clubhouse/ext/string.rb +9 -0
- data/lib/clubhouse/file.rb +19 -0
- data/lib/clubhouse/label.rb +18 -0
- data/lib/clubhouse/linked_file.rb +13 -0
- data/lib/clubhouse/project.rb +20 -0
- data/lib/clubhouse/story.rb +70 -0
- data/lib/clubhouse/story_link.rb +17 -0
- data/lib/clubhouse/task.rb +45 -0
- data/lib/clubhouse/user.rb +34 -0
- data/lib/clubhouse/version.rb +3 -0
- data/lib/clubhouse/workflow.rb +42 -0
- metadata +137 -0
data/docs/projects.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Projects
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client.
|
4
|
+
|
5
|
+
## Creating
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
project = Clubhouse::Project.new(
|
9
|
+
name: "Project One",
|
10
|
+
description: 'Project description',
|
11
|
+
color: '#222'
|
12
|
+
)
|
13
|
+
|
14
|
+
project.save
|
15
|
+
```
|
16
|
+
|
17
|
+
Once saved the project object will be reloaded with the response from clubhouse so now your new
|
18
|
+
object will have the created_at and updated_at time that is returned from the API.
|
19
|
+
|
20
|
+
### Required Fields
|
21
|
+
* name
|
22
|
+
|
23
|
+
|
24
|
+
## Updating
|
25
|
+
|
26
|
+
```ruby
|
27
|
+
project = Clubhouse::Project.find(8)
|
28
|
+
|
29
|
+
project.archived = true
|
30
|
+
project.save # Save works for both creating and updating
|
31
|
+
|
32
|
+
=> <#Clubhouse::Project... >
|
33
|
+
|
34
|
+
```
|
35
|
+
|
36
|
+
## Finding by id
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
project = Clubhouse::Project.find(8)
|
40
|
+
|
41
|
+
=> #<Clubhouse::Project:0x007ffcd58002d0 @archived=true, @id=8 ... >
|
42
|
+
```
|
43
|
+
|
44
|
+
## Deleting by id
|
45
|
+
|
46
|
+
When an empty hash is returned this means it was successfull otherwise it will raise an exception
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
Clubhouse::Project.delete(8)
|
50
|
+
|
51
|
+
=> {}
|
52
|
+
```
|
53
|
+
|
54
|
+
## Listing
|
55
|
+
|
56
|
+
Returns a list of all projects
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
Clubhouse::Project.all
|
60
|
+
|
61
|
+
=> [#<Clubhouse::Project:0x007fb142440458 @abbreviation="PT"...>]
|
62
|
+
```
|
63
|
+
|
64
|
+
## Listing all stories for a project
|
65
|
+
|
66
|
+
Returns all the stories for the current project
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
project = Clubhouse::Project.find(8)
|
70
|
+
|
71
|
+
project.stories
|
72
|
+
|
73
|
+
=> [#<Clubhouse::Story:0x007fb144089178 @archived=false, @comments=[{"...>, #<Clubhouse::Story>]
|
74
|
+
```
|
data/docs/stories.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# Stories
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client check out the README if you haven't already.
|
4
|
+
|
5
|
+
## Creating
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
story = Clubhouse::Story.new(
|
9
|
+
comments:[ {text: 'A comment to start the story'} ],
|
10
|
+
deadline: '2016-12-31T12:30:00Z',
|
11
|
+
estimate: 8,
|
12
|
+
labels: [ {name: 'High'}, {name: :bug } ],
|
13
|
+
name: "Can't login and get 503",
|
14
|
+
project_id: 17,
|
15
|
+
story_type: :bug,
|
16
|
+
tasks: [ {description: 'Monitor server load' } ],
|
17
|
+
workflow_state_id: 2
|
18
|
+
)
|
19
|
+
|
20
|
+
story.save
|
21
|
+
```
|
22
|
+
|
23
|
+
Once saved the story object will be reloaded with the response from clubhouse so now your new object will have the created_at and updated_at time that is returned from the API.
|
24
|
+
|
25
|
+
### Required Fields
|
26
|
+
* name
|
27
|
+
* project_id
|
28
|
+
|
29
|
+
|
30
|
+
## Updating
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
story = Clubhouse::Story.new(name: "Can't login and get 503", project_id: 17).save
|
34
|
+
|
35
|
+
story.story_type = 'bug'
|
36
|
+
story.save # Save works for both creating and updating and only sends the attributes which are permitted
|
37
|
+
|
38
|
+
=> <#Clubhouse::Story... >
|
39
|
+
|
40
|
+
```
|
41
|
+
|
42
|
+
## Finding by id
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
story = Clubhouse::Story.find(696)
|
46
|
+
|
47
|
+
=> #<Clubhouse::Story:0x007ffcd58002d0 @archived=false, @id=696 ... >
|
48
|
+
```
|
49
|
+
|
50
|
+
## Deleting by id
|
51
|
+
|
52
|
+
When an empty hash is returned this means it was successfull otherwise it will raise an exception
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
Clubhouse::Story.delete(696)
|
56
|
+
|
57
|
+
=> {}
|
58
|
+
```
|
59
|
+
|
60
|
+
## Adding comments and tasks quickly
|
61
|
+
|
62
|
+
Once you have saved your story or you find a story and want to add a comment or task quickly. You can do so with the following method calls
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
|
66
|
+
story = Clubhouse::Story.find(696)
|
67
|
+
|
68
|
+
story.add_comment('My comment here')
|
69
|
+
=> [#<Clubhouse::Comment:0x007ffcd41518b8 @text="My comment here", @story_id=696, @author_id="57c75ddd-ad27-4531-8c7d-368d8702cc0d", @created_at... >, <#Clubhouse::Comment>]
|
70
|
+
|
71
|
+
story.add_task('Add acceptance spec')
|
72
|
+
=> [#<Clubhouse::Task:0x007ffcd434efd0 @complete=false, @created_at="2016-09-25T16:44:35Z", @description="Write acceptance spec"...>, <#Clubhouse::Task>]
|
73
|
+
|
74
|
+
```
|
75
|
+
|
76
|
+
When you add a comment or a task it will return an array of all the comments or tasks that exist
|
77
|
+
on that story, you can access all the comments and task and modify them by calling comments or tasks on the story object.
|
78
|
+
|
79
|
+
## Searching
|
80
|
+
|
81
|
+
Searching for stories is open and not restricted. It takes a hash of key, value.
|
82
|
+
You can check which search attributes are valid [here](https://clubhouse.io/api/v1/#search-stories)
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
Clubhouse::Story.search(project_id: 17, estimate: 5, epic_id: 1)
|
86
|
+
|
87
|
+
=> [#<Clubhouse::Story:0x007ffcd58002d0 @archived=false, @id=696 ... >]
|
88
|
+
```
|
89
|
+
|
90
|
+
## Failure
|
91
|
+
All the request calls can fail and if they do you will be presented with an exception.
|
92
|
+
The exception will be explanatory of the issue with the full body content response of the problem from Clubhouse API
|
93
|
+
|
94
|
+
```
|
95
|
+
Clubhouse::BadRequestError: {"message":"The request included invalid or missing parameters.","errors":{"name":"missing-required-key","project_id":"missing-required-key"}
|
96
|
+
```
|
data/docs/story_links.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# StoryLinks
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client.
|
4
|
+
|
5
|
+
## Creating
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
story_link = Clubhouse::StoryLink.new(
|
9
|
+
subject_id: 3,
|
10
|
+
object_id: 2,
|
11
|
+
verb: 'blocks'
|
12
|
+
)
|
13
|
+
|
14
|
+
story_link.save
|
15
|
+
```
|
16
|
+
|
17
|
+
Once saved the story link object will be reloaded with the response from clubhouse so now your new
|
18
|
+
object will have the created_at and updated_at time that is returned from the API.
|
19
|
+
|
20
|
+
### Required Fields
|
21
|
+
* subject_id
|
22
|
+
* object_id
|
23
|
+
* verb (blocks, duplicates, relates to)
|
24
|
+
|
25
|
+
|
26
|
+
## Updating
|
27
|
+
|
28
|
+
You can't update a story link best thing is to delete and recreate
|
29
|
+
|
30
|
+
|
31
|
+
## Deleting by id
|
32
|
+
|
33
|
+
When an empty hash is returned this means it was successfull otherwise it will raise an exception
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
Clubhouse::StoryLink.delete(8)
|
37
|
+
|
38
|
+
=> {}
|
39
|
+
```
|
data/docs/tasks.md
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
# Tasks
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client.
|
4
|
+
|
5
|
+
It is recommended to create tasks from a story object as described [here](stories.md)
|
6
|
+
|
7
|
+
## Creating
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
task = Clubhouse::Task.new(
|
11
|
+
story_id: 34,
|
12
|
+
description: 'My task',
|
13
|
+
complete: false
|
14
|
+
)
|
15
|
+
|
16
|
+
task.save
|
17
|
+
```
|
18
|
+
|
19
|
+
Once saved the task object will be reloaded with the response from clubhouse so now your new
|
20
|
+
object will have the created_at and updated_at time that is returned from the API.
|
21
|
+
|
22
|
+
### Required Fields
|
23
|
+
* story_id
|
24
|
+
* description
|
25
|
+
|
26
|
+
|
27
|
+
## Updating
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
task = Clubhouse::Task.find(34, 9)
|
31
|
+
|
32
|
+
task.description = "My task"
|
33
|
+
task.complete = true
|
34
|
+
task.save # Save works for both creating and updating
|
35
|
+
|
36
|
+
=> <#Clubhouse::Task... >
|
37
|
+
|
38
|
+
```
|
39
|
+
|
40
|
+
## Finding by id
|
41
|
+
|
42
|
+
Finding a task is different to all other resources the find method takes two arguments
|
43
|
+
|
44
|
+
* story_id
|
45
|
+
* task_id
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
task = Clubhouse::Task.find(34, 8)
|
49
|
+
|
50
|
+
=> #<Clubhouse::Task:0x007ffcd58002d0 @description="Updated task", @id=9, @complete=true ... >
|
51
|
+
```
|
52
|
+
|
53
|
+
## Deleting by id
|
54
|
+
|
55
|
+
Deleting a task is different to all other resources the delete method takes two arguments
|
56
|
+
|
57
|
+
* story_id
|
58
|
+
* task_id
|
59
|
+
|
60
|
+
When an empty hash is returned this means it was successfull otherwise it will raise an exception
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
Clubhouse::Task.delete(34, 8)
|
64
|
+
|
65
|
+
=> {}
|
66
|
+
```
|
data/docs/users.md
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Users
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client.
|
4
|
+
|
5
|
+
## Creating, Updating, Deleting
|
6
|
+
|
7
|
+
You can't create, update or delete users via the API this needs to happen only via Clubhouse web
|
8
|
+
|
9
|
+
|
10
|
+
## Finding by id
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
epic = Clubhouse::User.find(3)
|
14
|
+
|
15
|
+
=> #<Clubhouse::User:0x007ffcd58002d0 @disabled=false, @id=3 ... >
|
16
|
+
```
|
17
|
+
|
18
|
+
## Listing
|
19
|
+
|
20
|
+
Returns a list of all users
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
Clubhouse::User.all
|
24
|
+
|
25
|
+
=> [#<Clubhouse::User:0x007fb142170e58 @name="Tester", @deactivated=false,..>, #<Clubhouse::User...>]
|
26
|
+
```
|
data/docs/workflows.md
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Workflows
|
2
|
+
|
3
|
+
This assumes that you have setup the default client, or will inject your own client.
|
4
|
+
|
5
|
+
## Creating, Updating, Deleting
|
6
|
+
|
7
|
+
You can't create, update or delete workflows via the API this needs to happen only via Clubhouse web
|
8
|
+
|
9
|
+
## Listing
|
10
|
+
|
11
|
+
Returns a list of all workflows
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
Clubhouse::Workflow.all
|
15
|
+
|
16
|
+
=> [#<Clubhouse::Workflow:0x007fb142034030 @default_state_id=500000011, @id=500000009...>]
|
17
|
+
```
|
data/lib/clubhouse.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
require 'clubhouse/version'
|
5
|
+
require 'clubhouse/ext/string'
|
6
|
+
require 'clubhouse/api_actions'
|
7
|
+
require 'clubhouse/client'
|
8
|
+
require 'clubhouse/base_resource'
|
9
|
+
|
10
|
+
require 'clubhouse/story'
|
11
|
+
require 'clubhouse/label'
|
12
|
+
require 'clubhouse/user'
|
13
|
+
require 'clubhouse/workflow'
|
14
|
+
require 'clubhouse/project'
|
15
|
+
require 'clubhouse/epic'
|
16
|
+
require 'clubhouse/file'
|
17
|
+
require 'clubhouse/linked_file'
|
18
|
+
require 'clubhouse/task'
|
19
|
+
require 'clubhouse/comment'
|
20
|
+
require 'clubhouse/story_link'
|
21
|
+
|
22
|
+
module Clubhouse
|
23
|
+
class NotSupportedByAPIError < StandardError; end
|
24
|
+
class MissingStoryIDError < StandardError; end
|
25
|
+
class StoryNotSavedError < StandardError; end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
attr_accessor :default_client
|
29
|
+
|
30
|
+
def configure
|
31
|
+
yield self if block_given?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Clubhouse
|
2
|
+
class InvalidKeyAssignment < StandardError; end
|
3
|
+
class ClientNotSetup < StandardError; end
|
4
|
+
|
5
|
+
class BaseResource
|
6
|
+
attr_writer :client
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_reader :endpoint
|
10
|
+
|
11
|
+
def resource(name)
|
12
|
+
@endpoint = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def client
|
16
|
+
Clubhouse.default_client
|
17
|
+
end
|
18
|
+
|
19
|
+
def find(id)
|
20
|
+
client.find(self, self.endpoint, id)
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete(id)
|
24
|
+
client.delete("#{self.endpoint}/#{id}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def all
|
28
|
+
payload = client.get(self.endpoint)
|
29
|
+
payload.collect{|h| self.new.update_object_from_payload(h) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def initialize(attr = {})
|
34
|
+
attr.each do |key, value|
|
35
|
+
begin
|
36
|
+
send("#{key}=", value)
|
37
|
+
rescue NoMethodError
|
38
|
+
raise InvalidKeyAssignment, "You can't assign value to #{key}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.attributes(*keys, **opts)
|
44
|
+
readonly = Array(opts[:readonly])
|
45
|
+
|
46
|
+
class_eval do
|
47
|
+
define_method(:attribute_keys) { (keys + readonly) }
|
48
|
+
|
49
|
+
(keys + readonly).each do |key|
|
50
|
+
define_method(:"#{key}") { instance_variable_get("@#{key}") }
|
51
|
+
|
52
|
+
if !readonly.include?(key)
|
53
|
+
define_method(:"#{key}=") {|v| instance_variable_set("@#{key}", v) }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.attributes_for_update(*keys)
|
60
|
+
class_eval do
|
61
|
+
define_method :update_attributes do
|
62
|
+
keys.reduce({}) do |h, k|
|
63
|
+
h.merge(k => instance_variable_get("@#{k}"))
|
64
|
+
end.reject{|k,v| v.nil?}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.attributes_for_create(*keys)
|
70
|
+
class_eval do
|
71
|
+
define_method :create_attributes do
|
72
|
+
keys.reduce({}) do |h, k|
|
73
|
+
h.merge(k => instance_variable_get("@#{k}"))
|
74
|
+
end.reject{|k,v| v.nil?}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def client
|
80
|
+
@client ||= Clubhouse.default_client
|
81
|
+
end
|
82
|
+
|
83
|
+
def update_object_from_payload(payload)
|
84
|
+
attribute_keys.each do |k|
|
85
|
+
self.instance_variable_set("@#{k}", payload[k.to_s])
|
86
|
+
end
|
87
|
+
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
91
|
+
def reload
|
92
|
+
payload = client.get("#{self.class.endpoint}/#{id}")
|
93
|
+
update_object_from_payload(payload)
|
94
|
+
end
|
95
|
+
|
96
|
+
def save
|
97
|
+
raise ClientNotSetup, "A default client or instance client is not setup" unless client
|
98
|
+
|
99
|
+
payload = if id
|
100
|
+
client.put("#{self.class.endpoint}/#{id}", update_attributes)
|
101
|
+
else
|
102
|
+
client.post(self.class.endpoint, create_attributes)
|
103
|
+
end
|
104
|
+
|
105
|
+
update_object_from_payload(payload)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|