vigetlabs-unfuzzle 0.1.1 → 0.1.2
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/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
|