vigetlabs-unfuzzle 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +21 -1
- data/Rakefile +2 -2
- data/lib/unfuzzle.rb +13 -2
- data/lib/unfuzzle/component.rb +31 -0
- data/lib/unfuzzle/milestone.rb +17 -26
- data/lib/unfuzzle/priority.rb +30 -0
- data/lib/unfuzzle/project.rb +13 -20
- data/lib/unfuzzle/request.rb +5 -8
- data/lib/unfuzzle/response.rb +0 -7
- data/lib/unfuzzle/severity.rb +31 -0
- data/lib/unfuzzle/ticket.rb +58 -25
- data/lib/unfuzzle/version.rb +1 -1
- data/test/fixtures/component.xml +8 -0
- data/test/fixtures/components.xml +17 -0
- data/test/fixtures/milestone.xml +12 -0
- data/test/fixtures/milestones.xml +25 -0
- data/test/fixtures/project.xml +17 -0
- data/test/fixtures/projects.xml +35 -0
- data/test/fixtures/severities.xml +24 -0
- data/test/fixtures/severity.xml +8 -0
- data/test/fixtures/ticket.xml +25 -0
- data/test/fixtures/tickets.xml +51 -0
- data/test/test_helper.rb +5 -7
- data/test/unit/unfuzzle/component_test.rb +36 -0
- data/test/unit/unfuzzle/milestone_test.rb +12 -44
- data/test/unit/unfuzzle/priority_test.rb +25 -0
- data/test/unit/unfuzzle/project_test.rb +17 -37
- data/test/unit/unfuzzle/request_test.rb +3 -13
- data/test/unit/unfuzzle/response_test.rb +0 -28
- data/test/unit/unfuzzle/severity_test.rb +36 -0
- data/test/unit/unfuzzle/ticket_test.rb +108 -47
- metadata +21 -12
- data/lib/unfuzzle/model.rb +0 -56
- data/test/fixtures/milestone.json +0 -11
- data/test/fixtures/milestones.json +0 -22
- data/test/fixtures/project.json +0 -16
- data/test/fixtures/projects.json +0 -32
- data/test/fixtures/tickets.json +0 -44
- data/test/unit/unfuzzle/model_test.rb +0 -55
data/README.rdoc
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
== Description
|
4
4
|
|
5
|
-
The Unfuzzle gem provides an interface to the Unfuddle
|
5
|
+
The Unfuzzle gem provides an interface to the Unfuddle XML API
|
6
6
|
|
7
7
|
== Installation
|
8
8
|
|
@@ -81,8 +81,28 @@ And can also be associated to a milestone for the project:
|
|
81
81
|
ticket.description # => "Wash my car"
|
82
82
|
ticket.status # => "closed"
|
83
83
|
|
84
|
+
Unfuddle has additional associations for a ticket, including component, severity,
|
85
|
+
and priority:
|
86
|
+
|
87
|
+
ticket.component # => #<Unfuzzle::Component:0x12c5b54 ...>
|
88
|
+
ticket.component_name # => "User Accounts"
|
89
|
+
ticket.severity # => #<Unfuzzle::Severity:0x12a357c ...>
|
90
|
+
ticket.severity_name # => "Development"
|
91
|
+
ticket.priority # => #<Unfuzzle::Priority:0x12811fc @id=3>
|
92
|
+
ticket.priority_name # => "Normal"
|
93
|
+
|
84
94
|
See the Ticket documentation for more information.
|
85
95
|
|
96
|
+
== Updating
|
97
|
+
|
98
|
+
Currently, only ticket updating is supported and only for a subset of the data:
|
99
|
+
|
100
|
+
ticket.title = 'This is a new title' # => "This is a new title"
|
101
|
+
ticket.update # => #<Unfuzzle::Response:0x1275280 ...>
|
102
|
+
|
103
|
+
This will update the title of the ticket. Other fields that can be updated include
|
104
|
+
description and status.
|
105
|
+
|
86
106
|
== License
|
87
107
|
|
88
108
|
Copyright (c) 2009 Patrick Reagan of Viget Labs (mailto:patrick.reagan@viget.com)
|
data/Rakefile
CHANGED
@@ -12,13 +12,13 @@ spec = Gem::Specification.new do |s|
|
|
12
12
|
s.has_rdoc = true
|
13
13
|
s.extra_rdoc_files = %w(README.rdoc)
|
14
14
|
s.rdoc_options = %w(--main README.rdoc)
|
15
|
-
s.summary = "This gem provides an interface to the Unfuddle
|
15
|
+
s.summary = "This gem provides an interface to the Unfuddle XML API"
|
16
16
|
s.author = 'Patrick Reagan'
|
17
17
|
s.email = 'patrick.reagan@viget.com'
|
18
18
|
s.homepage = 'http://www.viget.com/extend'
|
19
19
|
s.files = %w(README.rdoc Rakefile) + Dir.glob("{lib,test}/**/*")
|
20
20
|
|
21
|
-
s.add_dependency('
|
21
|
+
s.add_dependency('graft', '>= 0.1.1')
|
22
22
|
end
|
23
23
|
|
24
24
|
Rake::GemPackageTask.new(spec) do |pkg|
|
data/lib/unfuzzle.rb
CHANGED
@@ -4,13 +4,16 @@ require 'uri'
|
|
4
4
|
require 'net/http'
|
5
5
|
require 'json'
|
6
6
|
require 'builder'
|
7
|
+
require 'graft'
|
7
8
|
|
8
9
|
require 'unfuzzle/request'
|
9
10
|
require 'unfuzzle/response'
|
10
|
-
require 'unfuzzle/model'
|
11
11
|
require 'unfuzzle/project'
|
12
12
|
require 'unfuzzle/milestone'
|
13
13
|
require 'unfuzzle/ticket'
|
14
|
+
require 'unfuzzle/severity'
|
15
|
+
require 'unfuzzle/priority'
|
16
|
+
require 'unfuzzle/component'
|
14
17
|
|
15
18
|
# = Unfuzzle: A simple wrapper around the Unfuddle JSON API
|
16
19
|
#
|
@@ -28,7 +31,15 @@ require 'unfuzzle/ticket'
|
|
28
31
|
#
|
29
32
|
# From there, you can start accessing a list of projects:
|
30
33
|
#
|
31
|
-
#
|
34
|
+
# >> Unfuzzle.projects
|
35
|
+
# => [#<Unfuzzle::Project:0x5f5c44 @id=1, @name="BlipCo", ...>, ... ]
|
36
|
+
#
|
37
|
+
# Or a specific project by its 'short name':
|
38
|
+
#
|
39
|
+
# >> Unfuzzle.project('sample')
|
40
|
+
# => #<Unfuzzle::Project:0x123f888 @id=2, @name="Sample Project", ... >
|
41
|
+
#
|
42
|
+
# For more usage documentation, see README.doc.
|
32
43
|
#
|
33
44
|
module Unfuzzle
|
34
45
|
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Component
|
4
|
+
#
|
5
|
+
# Represents a Component in an Unfuddle project. These are user-configurable
|
6
|
+
# and are custom for each project you have. Examples include 'Administration',
|
7
|
+
# 'User Registration', etc.. A component has the following attributes:
|
8
|
+
#
|
9
|
+
# [id] The unique id for this component
|
10
|
+
# [name] The name of this component (e.g User Registration)
|
11
|
+
# [created_at] The date/time that this component was created
|
12
|
+
# [updated_at] The date/time that this component was last updated
|
13
|
+
#
|
14
|
+
class Component
|
15
|
+
|
16
|
+
include Graft::Model
|
17
|
+
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :name
|
20
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
21
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
22
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
23
|
+
|
24
|
+
# Find a component by ID for a given project
|
25
|
+
def self.find_by_project_id_and_component_id(project_id, component_id)
|
26
|
+
response = Request.get("/projects/#{project_id}/components/#{component_id}")
|
27
|
+
new response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/unfuzzle/milestone.rb
CHANGED
@@ -6,28 +6,33 @@ module Unfuzzle
|
|
6
6
|
#
|
7
7
|
# [id] Unique identifier for this milestone
|
8
8
|
# [name] Name of the milestone
|
9
|
-
#
|
9
|
+
# [archived] The archived status of this milestone (see Milestone#archived?)
|
10
|
+
# [due_on] The due date for this milestone
|
11
|
+
# [created_at] The date/time that this milestone was created
|
12
|
+
# [updated_at] The date/time that this milestone was last updated
|
13
|
+
#
|
10
14
|
class Milestone
|
11
15
|
|
12
|
-
include
|
16
|
+
include Graft::Model
|
13
17
|
|
14
|
-
attribute :id
|
15
|
-
attribute :project_id
|
16
|
-
attribute :archived
|
17
|
-
attribute :name, :from =>
|
18
|
-
attribute :
|
19
|
-
attribute :
|
20
|
-
attribute :
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
20
|
+
attribute :archived, :type => :boolean
|
21
|
+
attribute :name, :from => 'title'
|
22
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
23
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
24
|
+
attribute :due_on, :from => 'due-on', :type => :date
|
21
25
|
|
22
26
|
# Return a list of all milestones for a given project
|
23
27
|
def self.find_all_by_project_id(project_id)
|
24
28
|
response = Request.get("/projects/#{project_id}/milestones")
|
25
|
-
response.
|
29
|
+
collection_from(response.body, 'milestones/milestone')
|
26
30
|
end
|
27
31
|
|
32
|
+
# Find a milestone by ID for a given project
|
28
33
|
def self.find_by_project_id_and_milestone_id(project_id, milestone_id)
|
29
34
|
response = Request.get("/projects/#{project_id}/milestones/#{milestone_id}")
|
30
|
-
new response.
|
35
|
+
new response.body
|
31
36
|
end
|
32
37
|
|
33
38
|
# Has this milestone been archived?
|
@@ -35,21 +40,7 @@ module Unfuzzle
|
|
35
40
|
archived == true
|
36
41
|
end
|
37
42
|
|
38
|
-
#
|
39
|
-
def created_at
|
40
|
-
DateTime.parse(created_timestamp)
|
41
|
-
end
|
42
|
-
|
43
|
-
# The DateTime that this milestone was last updated
|
44
|
-
def updated_at
|
45
|
-
DateTime.parse(updated_timestamp)
|
46
|
-
end
|
47
|
-
|
48
|
-
# The Date that this milestone is due
|
49
|
-
def due_on
|
50
|
-
Date.parse(due_datestamp) unless due_datestamp.nil?
|
51
|
-
end
|
52
|
-
|
43
|
+
# Does this milestone occur in the past?
|
53
44
|
def past?
|
54
45
|
due_on < Date.today
|
55
46
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Priority
|
4
|
+
#
|
5
|
+
# Represents a priority for a ticket.
|
6
|
+
#
|
7
|
+
class Priority
|
8
|
+
|
9
|
+
def initialize(id)
|
10
|
+
@id = id
|
11
|
+
end
|
12
|
+
|
13
|
+
# The name of the priority based on the supplied ID
|
14
|
+
def name
|
15
|
+
mapping[@id]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def mapping
|
20
|
+
{
|
21
|
+
5 => 'Highest',
|
22
|
+
4 => 'High',
|
23
|
+
3 => 'Normal',
|
24
|
+
2 => 'Low',
|
25
|
+
1 => 'Lowest'
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/unfuzzle/project.rb
CHANGED
@@ -8,35 +8,38 @@ module Unfuzzle
|
|
8
8
|
# [slug] The "short name" for this project
|
9
9
|
# [name] The name of this project
|
10
10
|
# [description] The description for the project
|
11
|
+
# [archived] The archived status of this project (see Project#archived?)
|
12
|
+
# [created_at] The date/time that this project was created
|
13
|
+
# [updated_at] The date/time that this project was last updated
|
11
14
|
#
|
12
15
|
class Project
|
13
16
|
|
14
|
-
include
|
17
|
+
include Graft::Model
|
15
18
|
|
16
|
-
attribute :id
|
17
|
-
attribute :slug, :from =>
|
18
|
-
attribute :archived
|
19
|
-
attribute :name, :from =>
|
19
|
+
attribute :id, :type => :integer
|
20
|
+
attribute :slug, :from => 'short-name'
|
21
|
+
attribute :archived, :type => :boolean
|
22
|
+
attribute :name, :from => 'title'
|
20
23
|
attribute :description
|
21
|
-
attribute :
|
22
|
-
attribute :
|
24
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
25
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
23
26
|
|
24
27
|
# Return a list of all projects to which the current user has access
|
25
28
|
def self.all
|
26
29
|
response = Request.get('/projects')
|
27
|
-
response.
|
30
|
+
collection_from(response.body, 'projects/project')
|
28
31
|
end
|
29
32
|
|
30
33
|
# Find a single project by its slug (short name)
|
31
34
|
def self.find_by_slug(slug)
|
32
35
|
response = Request.get("/projects/by_short_name/#{slug}")
|
33
|
-
new(response.
|
36
|
+
new(response.body)
|
34
37
|
end
|
35
38
|
|
36
39
|
# Find a single project by its ID
|
37
40
|
def self.find_by_id(id)
|
38
41
|
response = Request.get("/projects/#{id}")
|
39
|
-
new(response.
|
42
|
+
new(response.body)
|
40
43
|
end
|
41
44
|
|
42
45
|
# Has this project been archived?
|
@@ -44,16 +47,6 @@ module Unfuzzle
|
|
44
47
|
archived == true
|
45
48
|
end
|
46
49
|
|
47
|
-
# The DateTime that this project was created
|
48
|
-
def created_at
|
49
|
-
DateTime.parse(created_timestamp)
|
50
|
-
end
|
51
|
-
|
52
|
-
# The DateTime that this project was last updated
|
53
|
-
def updated_at
|
54
|
-
DateTime.parse(updated_timestamp)
|
55
|
-
end
|
56
|
-
|
57
50
|
# The collection of Milestones associated to this project
|
58
51
|
def milestones
|
59
52
|
Milestone.find_all_by_project_id(id)
|
data/lib/unfuzzle/request.rb
CHANGED
@@ -12,24 +12,20 @@ module Unfuzzle
|
|
12
12
|
request.get
|
13
13
|
end
|
14
14
|
|
15
|
+
# Send a PUT request with data and retrieve a Response
|
15
16
|
def self.put(resource_path, payload)
|
16
|
-
request = new(resource_path, payload
|
17
|
+
request = new(resource_path, payload)
|
17
18
|
request.put
|
18
19
|
end
|
19
20
|
|
20
21
|
# Create a new request for the given resource path
|
21
|
-
def initialize(resource_path, payload = nil
|
22
|
+
def initialize(resource_path, payload = nil)
|
22
23
|
@resource_path = resource_path
|
23
24
|
@payload = payload
|
24
|
-
@options = options
|
25
|
-
end
|
26
|
-
|
27
|
-
def request_format
|
28
|
-
(@options[:format] || 'json').to_s
|
29
25
|
end
|
30
26
|
|
31
27
|
def endpoint_uri # :nodoc:
|
32
|
-
URI.parse("http://#{Unfuzzle.subdomain}.unfuddle.com/api/v1#{@resource_path}
|
28
|
+
URI.parse("http://#{Unfuzzle.subdomain}.unfuddle.com/api/v1#{@resource_path}.xml")
|
33
29
|
end
|
34
30
|
|
35
31
|
def client # :nodoc:
|
@@ -44,6 +40,7 @@ module Unfuzzle
|
|
44
40
|
Response.new(client.request(request))
|
45
41
|
end
|
46
42
|
|
43
|
+
# Send a PUT request to the configured endpoint
|
47
44
|
def put
|
48
45
|
request = Net::HTTP::Put.new(endpoint_uri.path)
|
49
46
|
request.basic_auth Unfuzzle.username, Unfuzzle.password
|
data/lib/unfuzzle/response.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Severity
|
4
|
+
#
|
5
|
+
# Represents a Severity in an Unfuddle project. These are user-configurable
|
6
|
+
# and are custom for each project you have. Examples include 'Story',
|
7
|
+
# 'Defect', etc.. A severity has the following attributes:
|
8
|
+
#
|
9
|
+
# [id] The unique identifier for this severity
|
10
|
+
# [name] The name of this severity
|
11
|
+
# [created_at] The date/time that this severity was created
|
12
|
+
# [updated_at] The date/time that this severity was last updated
|
13
|
+
#
|
14
|
+
class Severity
|
15
|
+
|
16
|
+
include Graft::Model
|
17
|
+
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :name
|
20
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
21
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
22
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
23
|
+
|
24
|
+
# Find the severity by ID for a given project
|
25
|
+
def self.find_by_project_id_and_severity_id(project_id, severity_id)
|
26
|
+
response = Request.get("/projects/#{project_id}/severities/#{severity_id}")
|
27
|
+
new response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/unfuzzle/ticket.rb
CHANGED
@@ -10,56 +10,89 @@ module Unfuzzle
|
|
10
10
|
# [title] The title of the ticket (short)
|
11
11
|
# [description] The full description of the ticket
|
12
12
|
# [status] The ticket's status (new / accepted / resolved / closed)
|
13
|
+
# [due_on] The due date for this ticket
|
14
|
+
# [created_at] The date/time that this ticket was created
|
15
|
+
# [updated_at] The date/time that this ticket was last updated
|
13
16
|
#
|
14
17
|
class Ticket
|
15
18
|
|
16
|
-
include
|
19
|
+
include Graft::Model
|
17
20
|
|
18
|
-
attribute :id
|
19
|
-
attribute :project_id
|
20
|
-
attribute :milestone_id
|
21
|
+
attribute :id, :type => :integer
|
22
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
23
|
+
attribute :milestone_id, :from => 'milestone-id', :type => :integer
|
24
|
+
attribute :component_id, :from => 'component-id', :type => :integer
|
25
|
+
attribute :priority_id, :from => 'priority', :type => :integer
|
21
26
|
attribute :number
|
22
|
-
attribute :title, :from =>
|
27
|
+
attribute :title, :from => 'summary'
|
23
28
|
attribute :description
|
24
|
-
attribute :
|
25
|
-
attribute :
|
26
|
-
attribute :
|
29
|
+
attribute :due_on, :from => 'due-on', :type => :date
|
30
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
31
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
32
|
+
attribute :severity_id, :from => 'severity-id', :type => :integer
|
27
33
|
attribute :status
|
28
34
|
|
29
35
|
# Return a list of all tickets for an individual project
|
30
36
|
def self.find_all_by_project_id(project_id)
|
31
37
|
response = Request.get("/projects/#{project_id}/tickets")
|
32
|
-
response.
|
38
|
+
collection_from(response.body, 'tickets/ticket')
|
33
39
|
end
|
34
40
|
|
35
41
|
# Return a list of all tickets for a given milestone as part of a project
|
36
42
|
def self.find_all_by_project_id_and_milestone_id(project_id, milestone_id)
|
37
43
|
response = Request.get("/projects/#{project_id}/milestones/#{milestone_id}/tickets")
|
38
|
-
response.
|
44
|
+
collection_from(response.body, 'tickets/ticket')
|
39
45
|
end
|
40
46
|
|
41
|
-
# The
|
42
|
-
def
|
43
|
-
|
47
|
+
# The Milestone associated with this ticket
|
48
|
+
def milestone
|
49
|
+
Milestone.find_by_project_id_and_milestone_id(project_id, milestone_id)
|
44
50
|
end
|
45
|
-
|
46
|
-
# The
|
47
|
-
def
|
48
|
-
|
51
|
+
|
52
|
+
# The Severity associated with this ticket
|
53
|
+
def severity
|
54
|
+
Severity.find_by_project_id_and_severity_id(project_id, severity_id) unless severity_id.nil?
|
49
55
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
Date.parse(due_datestamp) unless due_datestamp.nil?
|
56
|
+
|
57
|
+
def severity_name
|
58
|
+
severity.name unless severity.nil?
|
54
59
|
end
|
55
|
-
|
56
|
-
|
57
|
-
|
60
|
+
|
61
|
+
# The Priority associated with this ticket
|
62
|
+
def priority
|
63
|
+
Priority.new(priority_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
def priority_name
|
67
|
+
priority.name
|
68
|
+
end
|
69
|
+
|
70
|
+
# The Component associated with this ticket
|
71
|
+
def component
|
72
|
+
Component.find_by_project_id_and_component_id(project_id, component_id) unless component_id.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
def component_name
|
76
|
+
component.name unless component.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
# Hash representation of this ticket's data (for updating)
|
80
|
+
def to_hash
|
81
|
+
{
|
82
|
+
'id' => id,
|
83
|
+
'project_id' => project_id,
|
84
|
+
'milestone_id' => milestone_id,
|
85
|
+
'number' => number,
|
86
|
+
'summary' => title,
|
87
|
+
'description' => description,
|
88
|
+
'status' => status
|
89
|
+
}
|
58
90
|
end
|
59
91
|
|
92
|
+
# Update the ticket's data in unfuddle
|
60
93
|
def update
|
61
94
|
resource_path = "/projects/#{project_id}/tickets/#{id}"
|
62
|
-
Request.put(resource_path, self.to_xml)
|
95
|
+
Request.put(resource_path, self.to_xml('ticket'))
|
63
96
|
end
|
64
97
|
|
65
98
|
end
|