taskmapper-mingle 0.2.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/.rvmrc +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +54 -0
- data/LICENSE.txt +20 -0
- data/README.md +77 -0
- data/Rakefile +35 -0
- data/VERSION +1 -0
- data/lib/mingle/mingle-api.rb +228 -0
- data/lib/provider/comment.rb +47 -0
- data/lib/provider/mingle.rb +38 -0
- data/lib/provider/project.rb +62 -0
- data/lib/provider/ticket.rb +102 -0
- data/lib/taskmapper-mingle.rb +5 -0
- data/spec/comments_spec.rb +40 -0
- data/spec/fixtures/cards.xml +83 -0
- data/spec/fixtures/cards/42.xml +41 -0
- data/spec/fixtures/cards/43.xml +42 -0
- data/spec/fixtures/cards/create.xml +42 -0
- data/spec/fixtures/comments.xml +20 -0
- data/spec/fixtures/comments/create.xml +10 -0
- data/spec/fixtures/projects.xml +57 -0
- data/spec/fixtures/projects/another_project_.xml +29 -0
- data/spec/fixtures/projects/create.xml +29 -0
- data/spec/fixtures/projects/test_project.xml +29 -0
- data/spec/projects_spec.rb +56 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/taskmapper-mingle_spec.rb +19 -0
- data/spec/tickets_spec.rb +72 -0
- data/taskmapper-mingle.gemspec +81 -0
- metadata +160 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
# This is the Mingle Provider for taskmapper
|
3
|
+
module Mingle
|
4
|
+
include TaskMapper::Provider::Base
|
5
|
+
TICKET_API = MingleAPI::Card # The class to access the api's cards
|
6
|
+
PROJECT_API = MingleAPI::Project # The class to access the api's projects
|
7
|
+
|
8
|
+
# This is for cases when you want to instantiate using TaskMapper::Provider::Mingle.new(auth)
|
9
|
+
def self.new(auth = {})
|
10
|
+
TaskMapper.new(:mingle, auth)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Providers must define an authorize method. This is used to initialize and set authentication
|
14
|
+
# parameters to access the API
|
15
|
+
|
16
|
+
def authorize(auth = {})
|
17
|
+
@authentication ||= TaskMapper::Authenticator.new(auth)
|
18
|
+
auth = @authentication
|
19
|
+
if auth.server.blank? and auth.login.blank? and auth.password.blank?
|
20
|
+
raise "Please provide server, login and password"
|
21
|
+
end
|
22
|
+
MingleAPI::Base.format = :xml
|
23
|
+
MingleAPI.authenticate(auth.server, auth.login, auth.password)
|
24
|
+
end
|
25
|
+
# declare needed overloaded methods here
|
26
|
+
def valid?
|
27
|
+
begin
|
28
|
+
PROJECT_API.find(:first)
|
29
|
+
true
|
30
|
+
rescue
|
31
|
+
false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Mingle
|
3
|
+
# Project class for taskmapper-mingle
|
4
|
+
#
|
5
|
+
#
|
6
|
+
class Project < TaskMapper::Provider::Base::Project
|
7
|
+
API = MingleAPI::Project # The class to access the api's projects
|
8
|
+
# declare needed overloaded methods here
|
9
|
+
|
10
|
+
def id
|
11
|
+
self[:identifier]
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(*options)
|
15
|
+
@system_data ||= {}
|
16
|
+
@cache ||= {}
|
17
|
+
first = options.first
|
18
|
+
case first
|
19
|
+
when Hash
|
20
|
+
super first.to_hash
|
21
|
+
else
|
22
|
+
@system_data[:client] = first
|
23
|
+
super first.attributes
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def tickets(*options)
|
28
|
+
begin
|
29
|
+
if options.first.is_a? Hash
|
30
|
+
#options[0].merge!(:params => {:id => id})
|
31
|
+
super(*options)
|
32
|
+
elsif options.empty?
|
33
|
+
tickets = MingleAPI::Card.find(:all, :params => {:identifier => id}).collect { |ticket| TaskMapper::Provider::Mingle::Ticket.new ticket }
|
34
|
+
else
|
35
|
+
super(*options)
|
36
|
+
end
|
37
|
+
rescue
|
38
|
+
[]
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def ticket!(*options)
|
43
|
+
options[0].merge!(:identifier => id) if options.first.is_a?(Hash)
|
44
|
+
provider_parent(self.class)::Ticket.create(*options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# copy from this.copy(that) copies that into this
|
48
|
+
def copy(project)
|
49
|
+
project.tickets.each do |ticket|
|
50
|
+
copy_ticket = self.ticket!(:name => ticket.title, :description => ticket.description)
|
51
|
+
ticket.comments.each do |comment|
|
52
|
+
copy_ticket.comment!(:content => comment.body)
|
53
|
+
sleep 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module TaskMapper::Provider
|
2
|
+
module Mingle
|
3
|
+
# Ticket class for taskmapper-mingle
|
4
|
+
#
|
5
|
+
API = MingleAPI::Card
|
6
|
+
|
7
|
+
class Ticket < TaskMapper::Provider::Base::Ticket
|
8
|
+
# declare needed overloaded methods herea
|
9
|
+
|
10
|
+
def initialize(*object)
|
11
|
+
if object.first
|
12
|
+
args = object
|
13
|
+
object = args.shift
|
14
|
+
identifier = args.shift
|
15
|
+
@system_data = {:client => object}
|
16
|
+
unless object.is_a? Hash
|
17
|
+
hash = {:number => object.number,
|
18
|
+
:name => object.name,
|
19
|
+
:description => object.description,
|
20
|
+
:card_type_name => object.card_type.nil? ? "Card" : object.card_type.name,
|
21
|
+
:identifier => identifier,
|
22
|
+
:created_on => object.created_on,
|
23
|
+
:modified_on => object.modified_on,
|
24
|
+
:properties => object.properties}
|
25
|
+
else
|
26
|
+
hash = object
|
27
|
+
end
|
28
|
+
super hash
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.create(*options)
|
33
|
+
card = API.new(*options)
|
34
|
+
ticket = self.new card
|
35
|
+
card.save
|
36
|
+
ticket
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.find_by_id(identifier, number)
|
40
|
+
self.search(identifier, {'number' => number}).first
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.search(identifier, options = {}, limit = 1000)
|
44
|
+
tickets = API.find(:all, :params => {:identifier => identifier}).collect { |ticket| self.new ticket, identifier }
|
45
|
+
search_by_attribute(tickets, options, limit)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find_by_attributes(identifier, attributes = {})
|
49
|
+
self.search(identifier, attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
def number
|
53
|
+
self[:number].to_i
|
54
|
+
end
|
55
|
+
|
56
|
+
def id
|
57
|
+
self[:id].to_i
|
58
|
+
end
|
59
|
+
|
60
|
+
def name
|
61
|
+
self[:name]
|
62
|
+
end
|
63
|
+
|
64
|
+
def identifier
|
65
|
+
self[:identifier]
|
66
|
+
end
|
67
|
+
|
68
|
+
def title
|
69
|
+
self[:name]
|
70
|
+
end
|
71
|
+
|
72
|
+
def description
|
73
|
+
self[:description]
|
74
|
+
end
|
75
|
+
|
76
|
+
def status
|
77
|
+
self.properties[1].value
|
78
|
+
end
|
79
|
+
|
80
|
+
def comments(*options)
|
81
|
+
begin
|
82
|
+
if options.empty?
|
83
|
+
comments = MingleAPI::Comment.find(:all, :params => {:identifier => identifier, :number => number}).collect { |comment| TaskMapper::Provider::Mingle::Comment.new comment }
|
84
|
+
else
|
85
|
+
super(*options)
|
86
|
+
end
|
87
|
+
rescue
|
88
|
+
[]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
#def comment(*options)
|
93
|
+
|
94
|
+
def comment!(*options)
|
95
|
+
options[0].update(:identifier => identifier, :number => number) if options.first.is_a?(Hash)
|
96
|
+
Comment.create(*options)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "TaskMapper::Provider::Mingle::Comment" do
|
4
|
+
before(:all) do
|
5
|
+
headers = {'Authorization' => 'Basic MDAwMDAwOg==', 'Accept' => 'application/xml'}
|
6
|
+
headers_post = {'Authorization' => 'Basic MDAwMDAwOg==', 'Content-Type' => 'application/xml'}
|
7
|
+
ActiveResource::HttpMock.respond_to do |mock|
|
8
|
+
mock.get '/api/v2/projects/test_project.xml', headers, fixture_for('projects/test_project'), 200
|
9
|
+
mock.get '/api/v2/projects/test_project/cards.xml', headers, fixture_for('cards'), 200
|
10
|
+
mock.get '/api/v2/projects/test_project/cards/42.xml', headers, fixture_for('cards/42'), 200
|
11
|
+
mock.get '/api/v2/projects/test_project/cards/42/comments.xml', headers, fixture_for('comments'), 200
|
12
|
+
mock.post '/api/v2/projects/test_project/cards/42/comments.xml?comment[content]=New%20comment%20created.', headers_post, fixture_for('comments/create'), 200
|
13
|
+
end
|
14
|
+
@identifier = 'test_project'
|
15
|
+
@number = 42
|
16
|
+
end
|
17
|
+
|
18
|
+
before(:each) do
|
19
|
+
@taskmapper = TaskMapper.new(:mingle, {:name => 'anymoto', :login => '000000', :server => 'localhost:8080'})
|
20
|
+
@project = @taskmapper.project(@identifier)
|
21
|
+
@ticket = @project.ticket(@number)
|
22
|
+
@ticket.identifier = @project.identifier
|
23
|
+
@klass = TaskMapper::Provider::Mingle::Comment
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should be able to load all comments" do
|
27
|
+
@comments = @ticket.comments
|
28
|
+
@comments.should be_an_instance_of(Array)
|
29
|
+
@comments.first.should be_an_instance_of(@klass)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the class" do
|
33
|
+
@ticket.comment.should == @klass
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should be able to create a comment" do
|
37
|
+
@comment = @ticket.comment!(:content => 'New comment created.')
|
38
|
+
@comment.should be_an_instance_of(@klass)
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<cards type="array">
|
3
|
+
<card>
|
4
|
+
<name>Ticket 1</name>
|
5
|
+
<description>
|
6
|
+
</description>
|
7
|
+
<card_type>
|
8
|
+
<name>Story</name>
|
9
|
+
</card_type>
|
10
|
+
<id type="integer">409</id>
|
11
|
+
<number type="integer">42</number>
|
12
|
+
<project url="http://myserver.com/api/v2/projects/test_project.xml">
|
13
|
+
<name>test project</name>
|
14
|
+
<identifier>test_project</identifier>
|
15
|
+
</project>
|
16
|
+
<version type="integer">1</version>
|
17
|
+
<project_card_rank type="integer">1</project_card_rank>
|
18
|
+
<created_on type="datetime">2009-10-14T09:14:54Z</created_on>
|
19
|
+
<modified_on type="datetime">2009-10-14T09:14:54Z</modified_on>
|
20
|
+
<modified_by url="http://myserver.com/api/v2/users/1.xml">
|
21
|
+
<name>anne</name>
|
22
|
+
<login>anne</login>
|
23
|
+
</modified_by>
|
24
|
+
<created_by url="http://myserver.com/api/v2/users/2.xml">
|
25
|
+
<name>jane</name>
|
26
|
+
<login>jane</login>
|
27
|
+
</created_by>
|
28
|
+
<properties type="array">
|
29
|
+
<property type_description="Managed text list" hidden="false">
|
30
|
+
<name>Status</name>
|
31
|
+
<value>Closed</value>
|
32
|
+
</property>
|
33
|
+
<property type_description="Managed number list" hidden="false">
|
34
|
+
<name>Estimate</name>
|
35
|
+
<value>4</value>
|
36
|
+
</property>
|
37
|
+
<property type_description="Managed text list" hidden="false">
|
38
|
+
<name>Priority</name>
|
39
|
+
<value nil="true"/>
|
40
|
+
</property>
|
41
|
+
</properties>
|
42
|
+
</card>
|
43
|
+
<card>
|
44
|
+
<name>Automatically update event status when event date has passed</name>
|
45
|
+
<description>
|
46
|
+
</description>
|
47
|
+
<card_type>
|
48
|
+
<name>Story</name>
|
49
|
+
</card_type>
|
50
|
+
<id type="integer">410</id>
|
51
|
+
<number type="integer">43</number>
|
52
|
+
<project url="http://myserver.com/api/v2/projects/test_project.xml">
|
53
|
+
<name>test project</name>
|
54
|
+
<identifier>test_project</identifier>
|
55
|
+
</project>
|
56
|
+
<version type="integer">1</version>
|
57
|
+
<project_card_rank type="integer">1</project_card_rank>
|
58
|
+
<created_on type="datetime">2009-10-14T09:14:54Z</created_on>
|
59
|
+
<modified_on type="datetime">2009-10-14T09:14:54Z</modified_on>
|
60
|
+
<modified_by url="http://myserver.com/api/v2/users/1.xml">
|
61
|
+
<name>anne</name>
|
62
|
+
<login>anne</login>
|
63
|
+
</modified_by>
|
64
|
+
<created_by url="http://myserver.com/api/v2/users/2.xml">
|
65
|
+
<name>jane</name>
|
66
|
+
<login>jane</login>
|
67
|
+
</created_by>
|
68
|
+
<properties type="array">
|
69
|
+
<property type_description="Managed text list" hidden="false">
|
70
|
+
<name>Status</name>
|
71
|
+
<value>Closed</value>
|
72
|
+
</property>
|
73
|
+
<property type_description="Managed number list" hidden="false">
|
74
|
+
<name>Estimate</name>
|
75
|
+
<value>4</value>
|
76
|
+
</property>
|
77
|
+
<property type_description="Managed text list" hidden="false">
|
78
|
+
<name>Priority</name>
|
79
|
+
<value nil="true"/>
|
80
|
+
</property>
|
81
|
+
</properties>
|
82
|
+
</card>
|
83
|
+
</cards>
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<card>
|
3
|
+
<name>As an API user, I would like to lookup a card in Mingle, given that I know the card number.</name>
|
4
|
+
<description>
|
5
|
+
</description>
|
6
|
+
<card_type>
|
7
|
+
<name>Story</name>
|
8
|
+
</card_type>
|
9
|
+
<number type="integer">42</number>
|
10
|
+
<project url="http://myserver.com/api/v2/projects/test_project.xml">
|
11
|
+
<name>test project</name>
|
12
|
+
<identifier>test_project</identifier>
|
13
|
+
</project>
|
14
|
+
<version type="integer">1</version>
|
15
|
+
<project_card_rank type="integer">1</project_card_rank>
|
16
|
+
<created_on type="datetime">2009-10-14T09:14:54Z</created_on>
|
17
|
+
<modified_on type="datetime">2009-10-14T09:14:54Z</modified_on>
|
18
|
+
<modified_by url="http://myserver.com/api/v2/users/1.xml">
|
19
|
+
<name>anne</name>
|
20
|
+
<login>anne</login>
|
21
|
+
</modified_by>
|
22
|
+
<created_by url="http://myserver.com/api/v2/users/2.xml">
|
23
|
+
<name>jane</name>
|
24
|
+
<login>jane</login>
|
25
|
+
</created_by>
|
26
|
+
<properties type="array">
|
27
|
+
<property type_description="Managed text list" hidden="false">
|
28
|
+
<name>Status</name>
|
29
|
+
<value>Closed</value>
|
30
|
+
</property>
|
31
|
+
<property type_description="Managed number list" hidden="false">
|
32
|
+
<name>Estimate</name>
|
33
|
+
<value>4</value>
|
34
|
+
</property>
|
35
|
+
<property type_description="Managed text list" hidden="false">
|
36
|
+
<name>Priority</name>
|
37
|
+
<value nil="true"/>
|
38
|
+
</property>
|
39
|
+
</properties>
|
40
|
+
</card>
|
41
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<card>
|
3
|
+
<name>Automatically update event status when event date has passed</name>
|
4
|
+
<description>
|
5
|
+
</description>
|
6
|
+
<card_type>
|
7
|
+
<name>Story</name>
|
8
|
+
</card_type>
|
9
|
+
<id type="integer">410</id>
|
10
|
+
<number type="integer">43</number>
|
11
|
+
<project url="http://localhost:8080/api/v2/projects/test_project.xml">
|
12
|
+
<name>test project</name>
|
13
|
+
<identifier>test_project</identifier>
|
14
|
+
</project>
|
15
|
+
<version type="integer">1</version>
|
16
|
+
<project_card_rank type="integer">1</project_card_rank>
|
17
|
+
<created_on type="datetime">2009-10-14T09:14:54Z</created_on>
|
18
|
+
<modified_on type="datetime">2009-10-14T09:14:54Z</modified_on>
|
19
|
+
<modified_by url="http://localhost:8080/api/v2/users/1.xml">
|
20
|
+
<name>anne</name>
|
21
|
+
<login>anne</login>
|
22
|
+
</modified_by>
|
23
|
+
<created_by url="http://localhost:8080/api/v2/users/2.xml">
|
24
|
+
<name>jane</name>
|
25
|
+
<login>jane</login>
|
26
|
+
</created_by>
|
27
|
+
<properties type="array">
|
28
|
+
<property type_description="Managed text list" hidden="false">
|
29
|
+
<name>Status</name>
|
30
|
+
<value>Closed</value>
|
31
|
+
</property>
|
32
|
+
<property type_description="Managed number list" hidden="false">
|
33
|
+
<name>Estimate</name>
|
34
|
+
<value>4</value>
|
35
|
+
</property>
|
36
|
+
<property type_description="Managed text list" hidden="false">
|
37
|
+
<name>Priority</name>
|
38
|
+
<value nil="true"/>
|
39
|
+
</property>
|
40
|
+
</properties>
|
41
|
+
</card>
|
42
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<card>
|
3
|
+
<name>Show event details in event list</name>
|
4
|
+
<description>
|
5
|
+
</description>
|
6
|
+
<card_type>
|
7
|
+
<name>Story</name>
|
8
|
+
</card_type>
|
9
|
+
<id type="integer">411</id>
|
10
|
+
<number type="integer">44</number>
|
11
|
+
<project url="http://localhost:8080/api/v2/projects/test_project.xml">
|
12
|
+
<name>test project</name>
|
13
|
+
<identifier>test_project</identifier>
|
14
|
+
</project>
|
15
|
+
<version type="integer">1</version>
|
16
|
+
<project_card_rank type="integer">1</project_card_rank>
|
17
|
+
<created_on type="datetime">2009-10-14T09:14:54Z</created_on>
|
18
|
+
<modified_on type="datetime">2009-10-14T09:14:54Z</modified_on>
|
19
|
+
<modified_by url="http://localhost:8080/api/v2/users/1.xml">
|
20
|
+
<name>anne</name>
|
21
|
+
<login>anne</login>
|
22
|
+
</modified_by>
|
23
|
+
<created_by url="http://localhost:8080/api/v2/users/2.xml">
|
24
|
+
<name>jane</name>
|
25
|
+
<login>jane</login>
|
26
|
+
</created_by>
|
27
|
+
<properties type="array">
|
28
|
+
<property type_description="Managed text list" hidden="false">
|
29
|
+
<name>Status</name>
|
30
|
+
<value>Closed</value>
|
31
|
+
</property>
|
32
|
+
<property type_description="Managed number list" hidden="false">
|
33
|
+
<name>Estimate</name>
|
34
|
+
<value>4</value>
|
35
|
+
</property>
|
36
|
+
<property type_description="Managed text list" hidden="false">
|
37
|
+
<name>Priority</name>
|
38
|
+
<value nil="true"/>
|
39
|
+
</property>
|
40
|
+
</properties>
|
41
|
+
</card>
|
42
|
+
|