mingle4r 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +40 -0
- data/MIT-LICENSE +21 -0
- data/README +227 -0
- data/TODO.txt +7 -0
- data/lib/mingle4r/api/v1/card/attachment.rb +51 -0
- data/lib/mingle4r/api/v1/card.rb +173 -0
- data/lib/mingle4r/api/v1/project.rb +71 -0
- data/lib/mingle4r/api/v1/property_definition.rb +16 -0
- data/lib/mingle4r/api/v1/transition_execution.rb +15 -0
- data/lib/mingle4r/api/v1/user.rb +9 -0
- data/lib/mingle4r/api/v1/wiki.rb +12 -0
- data/lib/mingle4r/api/v1.rb +25 -0
- data/lib/mingle4r/api/v2/card/attachment.rb +51 -0
- data/lib/mingle4r/api/v2/card/comment.rb +16 -0
- data/lib/mingle4r/api/v2/card/transition.rb +52 -0
- data/lib/mingle4r/api/v2/card.rb +157 -0
- data/lib/mingle4r/api/v2/murmur.rb +14 -0
- data/lib/mingle4r/api/v2/project.rb +90 -0
- data/lib/mingle4r/api/v2/property_definition.rb +14 -0
- data/lib/mingle4r/api/v2/user.rb +9 -0
- data/lib/mingle4r/api/v2/wiki.rb +12 -0
- data/lib/mingle4r/api/v2.rb +25 -0
- data/lib/mingle4r/api.rb +31 -0
- data/lib/mingle4r/common_class_methods.rb +220 -0
- data/lib/mingle4r/common_dyn_class_instance_methods.rb +5 -0
- data/lib/mingle4r/helpers.rb +33 -0
- data/lib/mingle4r/mingle_client.rb +91 -0
- data/lib/mingle4r/version.rb +11 -0
- data/lib/mingle4r.rb +41 -0
- data/lib/mingle_resource.rb +2 -0
- metadata +93 -0
data/History.txt
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
0.3.0
|
2
|
+
-----
|
3
|
+
|
4
|
+
* Major refactoring. The internal structure is completely changed
|
5
|
+
* supports both Mingle 2 and Mingle 3. Mingle 2 support is deprecated and will be removed in the next release.
|
6
|
+
* new Mingle 3 api features added - murmurs, comment
|
7
|
+
|
8
|
+
0.2.2
|
9
|
+
-----
|
10
|
+
|
11
|
+
* added add_comment to card class. allows adding comment to a card
|
12
|
+
|
13
|
+
0.2.1
|
14
|
+
-----
|
15
|
+
|
16
|
+
* added option to relationship methods(e.g. - cards, users, attachments) to return cached or
|
17
|
+
updated results
|
18
|
+
* property_definitions is a relationship method of project instead of mingle client.
|
19
|
+
|
20
|
+
0.2.0
|
21
|
+
-----
|
22
|
+
|
23
|
+
* added class method apply_filter to Card class. allows an MQL filter
|
24
|
+
* added instance method execute_transition to Card class. allows to execute a transition on a card.
|
25
|
+
|
26
|
+
0.1.6
|
27
|
+
-----
|
28
|
+
|
29
|
+
* added instance method at_version to Card class. gets the particular version for the card
|
30
|
+
|
31
|
+
0.1.5
|
32
|
+
-----
|
33
|
+
|
34
|
+
* Rest Api's added - wiki
|
35
|
+
|
36
|
+
0.0.1
|
37
|
+
-----
|
38
|
+
|
39
|
+
* Rest Api's - Card, Project, User, Attachment, Property Definition
|
40
|
+
* Mingle Client - supports getting cards, project etc.
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2009 Arusarka Haldar
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,227 @@
|
|
1
|
+
== mingle4r
|
2
|
+
|
3
|
+
http://github.com/arusarka/mingle4r/tree/master
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
This gem is a wrapper around active resource to access the rest api exposed by mingle
|
8
|
+
(http://studios.thoughtworks.com/mingle-agile-project-management).It provides a easy
|
9
|
+
way to communicate with mingle. For the library to work you need to enable basic authentication
|
10
|
+
(not enabled by default) in Mingle. See below to enable basic authentication in Mingle.
|
11
|
+
|
12
|
+
However if you are planning to connect and work with mingle from the terminal, then there
|
13
|
+
is another gem mingle-mingle which you should look at. This library provides a very easy
|
14
|
+
api to write code to work with mingle (see the examples below) but thats it.
|
15
|
+
|
16
|
+
Enable basic authentication in Mingle
|
17
|
+
-------------------------------------
|
18
|
+
|
19
|
+
1) Go to Mingle DataDir
|
20
|
+
|
21
|
+
2) Open YAML file <Mingle DataDir>/config/auth_config.yml
|
22
|
+
|
23
|
+
3) Set 'basic_authentication_enabled' to 'true' (without the quotes) if it is not so
|
24
|
+
|
25
|
+
== FEATURES/PROBLEMS:
|
26
|
+
|
27
|
+
It gives you access to projects in the mingle instance, cards under the project and also
|
28
|
+
attachments for a particular card.
|
29
|
+
|
30
|
+
== SYNOPSIS:
|
31
|
+
|
32
|
+
The api now supports both mingle 2 and mingle 3. The gem tries as much as possible to hide
|
33
|
+
away the internal details. But some api features are only supported in mingle 3 only (like
|
34
|
+
murmurs). For that check the api documentation for the mingle instance(located at
|
35
|
+
<mingle instance host>/help/index)
|
36
|
+
|
37
|
+
In all the documentation below you can replace Mingle4r::MingleClient with MingleClient.
|
38
|
+
Its an alias for easy use.
|
39
|
+
|
40
|
+
A) Getting all the projects for a particular instance
|
41
|
+
-----------------------------------------------------
|
42
|
+
|
43
|
+
Suppose you want to connect to the mingle instance hosted at http://localhost:8080 where the
|
44
|
+
username is 'testuser' and password is 'password'.
|
45
|
+
|
46
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
47
|
+
projs = m_c.projects
|
48
|
+
|
49
|
+
projs is an array of active resource objects
|
50
|
+
|
51
|
+
B) Getting a particular project
|
52
|
+
-------------------------------
|
53
|
+
|
54
|
+
Before you access a particular project you need to set the project id for the mingle client
|
55
|
+
object. You can do that in two ways. Supposing you are trying to access a project with an
|
56
|
+
identifier of 'great_mingle_project'
|
57
|
+
|
58
|
+
WARNING : project identifier and project name are different. If you named your project as
|
59
|
+
'Great Mingle Project' it's identifier is by default 'great_mingle_project'. To be sure what
|
60
|
+
the identifier of a project is you should look at the url in mingle in the particular project
|
61
|
+
you are trying to access. It should be something like 'http://localhost:8080/projects/great_mingle_project'
|
62
|
+
|
63
|
+
1) Set at initialize time
|
64
|
+
|
65
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password',
|
66
|
+
'great_mingle_project')
|
67
|
+
m_c.project
|
68
|
+
|
69
|
+
2) Set an attribute later
|
70
|
+
|
71
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
72
|
+
m_c.proj_id = 'great_mingle_project'
|
73
|
+
m_c.project
|
74
|
+
|
75
|
+
C) Getting cards for a particular project
|
76
|
+
--------------------------------------
|
77
|
+
|
78
|
+
Get a mingle client object initialized as in SECTION B. Then call the cards method.
|
79
|
+
|
80
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
81
|
+
m_c.proj_id = 'great_mingle_project'
|
82
|
+
m_c.project.cards
|
83
|
+
|
84
|
+
cards will be an array of activeresoure objects.
|
85
|
+
|
86
|
+
D) Getting custom properties for a card
|
87
|
+
---------------------------------------
|
88
|
+
|
89
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
90
|
+
m_c.proj_id = 'great_mingle_project'
|
91
|
+
card = m_c.project.cards[0]
|
92
|
+
card.custom_properties => returns an array of hashes, {property name => property value}
|
93
|
+
|
94
|
+
However this gives only custom properties, not all the properties.
|
95
|
+
|
96
|
+
E) Getting a particular property
|
97
|
+
--------------------------------
|
98
|
+
|
99
|
+
gets the value of a property. The property name given should be the same as seen in Mingle.
|
100
|
+
|
101
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
102
|
+
m_c.proj_id = 'great_mingle_project'
|
103
|
+
card = m_c.project.cards[0]
|
104
|
+
card.property_value('Status')
|
105
|
+
|
106
|
+
F) Setting a particular property
|
107
|
+
--------------------------------
|
108
|
+
|
109
|
+
sets the value of the property. The property name given should be the same as in Mingle and
|
110
|
+
the value given should be one of the values that Mingle accepts in case of a managed list
|
111
|
+
|
112
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
113
|
+
m_c.proj_id = 'great_mingle_project'
|
114
|
+
defect_card = m_c.project.cards.first
|
115
|
+
defect_card.property_value('Status', 'Closed')
|
116
|
+
|
117
|
+
G) Adding comment to a particular card
|
118
|
+
--------------------------------------
|
119
|
+
|
120
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
121
|
+
m_c.proj_id = 'great_mingle_project'
|
122
|
+
defect_card = m_c.project.cards[0]
|
123
|
+
defect_card.add_comment('Not able to reproduce')
|
124
|
+
|
125
|
+
H) Getting all comments for a card(only in mingle 3.0)
|
126
|
+
------------------------------------------------------
|
127
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
128
|
+
m_c.proj_id = 'great_mingle_project'
|
129
|
+
defect_card = m_c.project.cards.first
|
130
|
+
defect_cards.comments
|
131
|
+
|
132
|
+
I) Attachments
|
133
|
+
--------------
|
134
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
135
|
+
m_c.proj_id = 'great_mingle_project'
|
136
|
+
defect_card = m_c.project.cards.first
|
137
|
+
defect_card.attachments
|
138
|
+
|
139
|
+
1) Downloading a particular attachment
|
140
|
+
--------------------------------------
|
141
|
+
|
142
|
+
attachment = defect_card.attachments.first
|
143
|
+
attachment.save('page.css')
|
144
|
+
|
145
|
+
2) Uploading an attachment
|
146
|
+
--------------------------
|
147
|
+
|
148
|
+
defect_card.upload_attachment('page-screenshot.jpg')
|
149
|
+
|
150
|
+
J) Murmurs(only in Mingle 3.0)
|
151
|
+
------------------------------
|
152
|
+
|
153
|
+
1) Get the murmurs for a project
|
154
|
+
--------------------------------
|
155
|
+
|
156
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
157
|
+
m_c.proj_id = 'great_mingle_project'
|
158
|
+
project = m_c.project
|
159
|
+
project.murmurs
|
160
|
+
|
161
|
+
2) Get the murmurs associated with a card
|
162
|
+
-----------------------------------------
|
163
|
+
|
164
|
+
card = project.cards.first
|
165
|
+
card.murmurs
|
166
|
+
|
167
|
+
3) post a murmur(hooray!)
|
168
|
+
-------------------------
|
169
|
+
project.post_murmur('my first murmur, I am excited!')
|
170
|
+
|
171
|
+
K) Get all transitions for a card(only in Mingle 3.0)
|
172
|
+
-----------------------------------------------------
|
173
|
+
|
174
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
175
|
+
m_c.proj_id = 'great_mingle_project'
|
176
|
+
defect_card = m_c.project.cards.first
|
177
|
+
|
178
|
+
defect_card.transitions
|
179
|
+
|
180
|
+
L) Execute a transition on a card
|
181
|
+
---------------------------------
|
182
|
+
|
183
|
+
m_c = Mingle4r::MingleClient.new('http://localhost:8080', 'testuser', 'password')
|
184
|
+
m_c.proj_id = 'great_mingle_project'
|
185
|
+
defect_card = m_c.project.cards.first
|
186
|
+
|
187
|
+
defect_card.execute_transition(
|
188
|
+
'name'/'transition' => name of the transition to execute exactly s in Mingle(required in 2,3 but
|
189
|
+
not required in 3.0)
|
190
|
+
'comment' => comment for the transition, required only if the transition requires a comment
|
191
|
+
'Property Name as in Mingle exactly' => 'Property value to set for the property', required only
|
192
|
+
if the transition requires to be set manually.
|
193
|
+
)
|
194
|
+
|
195
|
+
== REQUIREMENTS:
|
196
|
+
|
197
|
+
1) active_resource gem, it would be automatically taken care of
|
198
|
+
during gem install.
|
199
|
+
|
200
|
+
== INSTALL:
|
201
|
+
|
202
|
+
sudo (not on windows) gem install mingle4r
|
203
|
+
|
204
|
+
== LICENSE:
|
205
|
+
|
206
|
+
(The MIT License)
|
207
|
+
|
208
|
+
Copyright (c) 2009 Arusarka Haldar
|
209
|
+
|
210
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
211
|
+
a copy of this software and associated documentation files (the
|
212
|
+
'Software'), to deal in the Software without restriction, including
|
213
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
214
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
215
|
+
permit persons to whom the Software is furnished to do so, subject to
|
216
|
+
the following conditions:
|
217
|
+
|
218
|
+
The above copyright notice and this permission notice shall be
|
219
|
+
included in all copies or substantial portions of the Software.
|
220
|
+
|
221
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
222
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
223
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
224
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
225
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
226
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
227
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/TODO.txt
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class API
|
3
|
+
class V1
|
4
|
+
class Card
|
5
|
+
class Attachment
|
6
|
+
module InstanceMethods
|
7
|
+
# downloads the attachment. It an additional file path is given it saves it at the
|
8
|
+
# given path. The given path should be writable
|
9
|
+
def download(file_name = nil)
|
10
|
+
collection_uri = self.class.site
|
11
|
+
rel_down_url = self.url
|
12
|
+
base_url = "#{collection_uri.scheme}://#{collection_uri.host}:#{collection_uri.port}/"
|
13
|
+
down_uri = URI.join(base_url, rel_down_url)
|
14
|
+
req = Net::HTTP::Get.new(down_uri.path)
|
15
|
+
req.basic_auth self.class.user, self.class.password
|
16
|
+
begin
|
17
|
+
res = Net::HTTP.start(down_uri.host, down_uri.port) { |http| http.request(req) }
|
18
|
+
file_name ||= self.file_name()
|
19
|
+
File.open(file_name, 'w') { |f| f.print(res.body) }
|
20
|
+
rescue Exception => e
|
21
|
+
e.message
|
22
|
+
end
|
23
|
+
end # download
|
24
|
+
|
25
|
+
# alias for file_name
|
26
|
+
def name
|
27
|
+
file_name()
|
28
|
+
end
|
29
|
+
|
30
|
+
# so that active resource tries to find by proper id
|
31
|
+
def id
|
32
|
+
name()
|
33
|
+
end
|
34
|
+
|
35
|
+
# This method had to be overriden.
|
36
|
+
# normal active resource destroy doesn't work as mingle site for deleting attachments doesn't end with .xml.
|
37
|
+
def destroy
|
38
|
+
connection = self.send(:connection)
|
39
|
+
# deletes the attachment by removing .xml at the end
|
40
|
+
connection.delete(self.send(:element_path).gsub(/\.xml\z/, ''))
|
41
|
+
end
|
42
|
+
alias_method :delete, :destroy
|
43
|
+
end #module InstanceMethods
|
44
|
+
|
45
|
+
extend Mingle4r::CommonClassMethods
|
46
|
+
|
47
|
+
end # class Attachment
|
48
|
+
end # class Card
|
49
|
+
end # class V1
|
50
|
+
end # class API
|
51
|
+
end # module Mingle4r
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class API
|
3
|
+
class V1
|
4
|
+
class Card
|
5
|
+
extend Mingle4r::CommonClassMethods
|
6
|
+
|
7
|
+
# overwrite the default find in CommonClassMethods
|
8
|
+
def self.find(*args)
|
9
|
+
scope = args.slice!(0)
|
10
|
+
options = args.slice!(0) || {}
|
11
|
+
@resource_class.find_without_pagination(scope, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def find_without_pagination(*args)
|
16
|
+
scope = args.slice!(0)
|
17
|
+
options = args.slice!(0) || {}
|
18
|
+
options[:params] ||= {}
|
19
|
+
options[:params].merge!({:page => 'all'})
|
20
|
+
|
21
|
+
# call ActiveResource::Base::find with proper options
|
22
|
+
find(scope, options)
|
23
|
+
end
|
24
|
+
|
25
|
+
# applies an mql filter on card types. Look at https://mingle05.thoughtworks.com/help/mql_reference.html
|
26
|
+
# for reference
|
27
|
+
def apply_filter(filter_string)
|
28
|
+
find_without_pagination(:all, :params => {'filters[mql]'.to_sym => filter_string})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module InstanceMethods
|
33
|
+
def attachments(refresh = false)
|
34
|
+
return @attachments if(!refresh && @attachments_cached)
|
35
|
+
attachment_site = File.join(self.class.site.to_s, "cards/#{self.number()}").to_s
|
36
|
+
Attachment.site = attachment_site
|
37
|
+
Attachment.user = self.class.user
|
38
|
+
Attachment.password = self.class.password
|
39
|
+
attachment_class = Attachment.send(:create_resource_class)
|
40
|
+
@attachments = attachment_class.find(:all)
|
41
|
+
@attachments_cached = true
|
42
|
+
@attachments
|
43
|
+
end
|
44
|
+
|
45
|
+
def upload_attachment(file_path)
|
46
|
+
attachment_uri = URI.parse(File.join(self.class.site.to_s, "cards/#{self.number()}/attachments.xml"))
|
47
|
+
http = Net::HTTP.new(attachment_uri.host, attachment_uri.port)
|
48
|
+
http.use_ssl = attachment_uri.is_a?(URI::HTTPS)
|
49
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
50
|
+
basic_encode = 'Basic ' + ["#{self.class.user}:#{self.class.password}"].pack('m').delete("\r\n")
|
51
|
+
|
52
|
+
post_headers = {
|
53
|
+
'Authorization' => basic_encode,
|
54
|
+
'Content-Type' => 'multipart/form-data; boundary=----------XnJLe9ZIbbGUYtzPQJ16u1'
|
55
|
+
}
|
56
|
+
|
57
|
+
file_content = IO.read(file_path)
|
58
|
+
|
59
|
+
post_body = <<EOS
|
60
|
+
------------XnJLe9ZIbbGUYtzPQJ16u1\r
|
61
|
+
Content-Disposition: form-data; name="file"; filename="#{File.basename(file_path)}"\r
|
62
|
+
Content-Type: application/octet-stream\r
|
63
|
+
Content-Length: #{file_content.size}\r
|
64
|
+
\r
|
65
|
+
#{file_content}\r
|
66
|
+
------------XnJLe9ZIbbGUYtzPQJ16u1--\r
|
67
|
+
EOS
|
68
|
+
|
69
|
+
http.post(attachment_uri.path, post_body, post_headers)
|
70
|
+
end
|
71
|
+
|
72
|
+
# returns back the version of the card given. If an invalid version is given, the latest
|
73
|
+
# version is returned, takes a number or :next or :before
|
74
|
+
def at_version(version_no)
|
75
|
+
version_2_find = 0
|
76
|
+
case version_no
|
77
|
+
when :before
|
78
|
+
version_2_find = self.version.to_i - 1
|
79
|
+
when :next
|
80
|
+
version_2_find = self.version.to_i + 1
|
81
|
+
else
|
82
|
+
version_2_find = version_no.to_i
|
83
|
+
end
|
84
|
+
self.class.find(self.number, :params => {:version => version_2_find})
|
85
|
+
end
|
86
|
+
|
87
|
+
# adds a comment to a card.
|
88
|
+
def add_comment(comment)
|
89
|
+
comment_uri = URI.parse(File.join(self.class.site.to_s, "cards/add_comment?card_id=#{self.id}"))
|
90
|
+
|
91
|
+
http = Net::HTTP.new(comment_uri.host, comment_uri.port)
|
92
|
+
http.use_ssl = comment_uri.is_a?(URI::HTTPS)
|
93
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if http.use_ssl
|
94
|
+
|
95
|
+
basic_encode = 'Basic ' + ["#{self.class.user}:#{self.class.password}"].pack('m').delete("\r\n")
|
96
|
+
|
97
|
+
post_headers = {
|
98
|
+
'Authorization' => basic_encode,
|
99
|
+
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
|
100
|
+
}
|
101
|
+
|
102
|
+
post_body = "comment=#{comment}&card_id=#{self.id}"
|
103
|
+
|
104
|
+
http.post(comment_uri.path, post_body, post_headers)
|
105
|
+
end
|
106
|
+
|
107
|
+
# Executes the given transition on the card.
|
108
|
+
# Example :
|
109
|
+
# defect_card.execute_transition(:name => 'Close Defect', :Owner => nil, :Status => 'Closed', :transition_comment => comment)
|
110
|
+
# transition_comment is mandatory if the transition is set that way.
|
111
|
+
# after transition 'Owner' would have value 'Not Set' and 'Status' would be 'Closed' for defect card
|
112
|
+
def execute_transition(args = {})
|
113
|
+
V1::TransitionExecution.site = self.class.site.to_s
|
114
|
+
V1::TransitionExecution.user = self.class.user
|
115
|
+
V1::TransitionExecution.password = self.class.password
|
116
|
+
|
117
|
+
args.symbolize_keys!
|
118
|
+
trans_hash = create_transition_exec_hash(args)
|
119
|
+
V1::TransitionExecution.new(trans_hash).execute
|
120
|
+
end
|
121
|
+
|
122
|
+
# gets the value of a property. The property name given should be the same name as
|
123
|
+
# the mingle property name
|
124
|
+
def property_value(name, val = nil)
|
125
|
+
set_property_definitions_attributes
|
126
|
+
column_name = PropertyDefinition.column_name_for(name.to_s)
|
127
|
+
val ? attributes[column_name] = val : attributes[column_name]
|
128
|
+
end
|
129
|
+
|
130
|
+
def custom_properties
|
131
|
+
set_property_definitions_attributes
|
132
|
+
custom_props = []
|
133
|
+
card_props = attributes.keys
|
134
|
+
PropertyDefinition.find(:all).each do |prop|
|
135
|
+
if(card_props.include?(prop.column_name))
|
136
|
+
custom_prop = {prop.name => attributes[prop.column_name]}
|
137
|
+
custom_props.push(custom_prop)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
custom_props
|
141
|
+
end
|
142
|
+
|
143
|
+
private
|
144
|
+
def boundary
|
145
|
+
'----------XnJLe9ZIbbGUYtzPQJ16u1'
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_transition_exec_hash(args)
|
149
|
+
transition_hash = {}
|
150
|
+
transition_hash['card'] = (args.delete(:card) || self.number).to_i
|
151
|
+
transition_hash['transition'] = (args.delete(:name) || args.delete(:transition))
|
152
|
+
|
153
|
+
comment = args.delete(:comment)
|
154
|
+
transition_hash['comment'] = comment if comment
|
155
|
+
properties = []
|
156
|
+
args.each do |name, value|
|
157
|
+
property = {'name' => name.to_s, 'value' => value}
|
158
|
+
properties.push(property)
|
159
|
+
end
|
160
|
+
transition_hash['properties'] = properties unless properties.empty?
|
161
|
+
transition_hash
|
162
|
+
end
|
163
|
+
|
164
|
+
def set_property_definitions_attributes
|
165
|
+
PropertyDefinition.site = self.class.site.to_s
|
166
|
+
PropertyDefinition.user = self.class.user
|
167
|
+
PropertyDefinition.password = self.class.password
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# require File.dirname(__FILE__) + '/../common/project'
|
2
|
+
module Mingle4r
|
3
|
+
class API
|
4
|
+
class V1
|
5
|
+
class Project
|
6
|
+
|
7
|
+
extend Mingle4r::CommonClassMethods
|
8
|
+
|
9
|
+
module InstanceMethods
|
10
|
+
# returns the cards for the project. To hit the resource server without returning
|
11
|
+
# cached results pass true as an argument.
|
12
|
+
def cards(refresh = false)
|
13
|
+
return @cards if(!refresh && @cards_cached)
|
14
|
+
cards_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
15
|
+
# card_class = API.new(self.class.site).card_class
|
16
|
+
Card.site = cards_site
|
17
|
+
Card.user = self.class.user
|
18
|
+
Card.password = self.class.password
|
19
|
+
# @cards = Card.send(:create_resource_class).find_without_pagination(:all)
|
20
|
+
@cards = Card.find_without_pagination(:all)
|
21
|
+
@cards_cached = true
|
22
|
+
@cards
|
23
|
+
end
|
24
|
+
|
25
|
+
# returns the users for the project. To hit the resource server without returning
|
26
|
+
# cached results pass true as an argument.
|
27
|
+
def users(refresh = false)
|
28
|
+
return @users if(!refresh && @users_cached)
|
29
|
+
users_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
30
|
+
User.site = users_site
|
31
|
+
User.user = self.class.user
|
32
|
+
User.password = self.class.password
|
33
|
+
User.element_name = nil # reset
|
34
|
+
user_class = User.send(:create_resource_class)
|
35
|
+
@users = user_class.find(:all)
|
36
|
+
@users_cached = true
|
37
|
+
@users
|
38
|
+
end
|
39
|
+
|
40
|
+
# returns the wikis for the project. To hit the resource server without returning
|
41
|
+
# cached results pass true as an argument.
|
42
|
+
def wikis(refresh = false)
|
43
|
+
return @wikis if(!refresh && @wikis_cached)
|
44
|
+
wiki_site = File.join(self.class.site.to_s, "projects/#{self.identifier()}")
|
45
|
+
Wiki.site = wiki_site
|
46
|
+
Wiki.user = self.class.user
|
47
|
+
Wiki.password = self.class.password
|
48
|
+
wiki_class = Wiki.send(:create_resource_class)
|
49
|
+
@wikis = wiki_class.find(:all)
|
50
|
+
@wikis_cached = true
|
51
|
+
@wikis
|
52
|
+
end
|
53
|
+
|
54
|
+
# returns the property definitions for the project. To hit the resource server
|
55
|
+
# pass true as an argument
|
56
|
+
def property_definitions(refresh = false)
|
57
|
+
return @prop_definitions if(!refresh && @prop_definitions_cached)
|
58
|
+
properties_site = File.join(self.class.site.to_s, "/projects/#{self.identifier}")
|
59
|
+
PropertyDefinition.site = properties_site
|
60
|
+
PropertyDefinition.user = self.class.user
|
61
|
+
PropertyDefinition.password = self.class.password
|
62
|
+
prop_defn_class = PropertyDefinition.send(:create_resource_class)
|
63
|
+
@prop_definitions = prop_defn_class.find(:all)
|
64
|
+
@prop_definitions_cached = true
|
65
|
+
@prop_definitions
|
66
|
+
end
|
67
|
+
end # module InstanceMethods
|
68
|
+
end # class Project
|
69
|
+
end # class V1
|
70
|
+
end # class API
|
71
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class API
|
3
|
+
class V1
|
4
|
+
class PropertyDefinition
|
5
|
+
extend Mingle4r::CommonClassMethods
|
6
|
+
|
7
|
+
def self.column_name_for(prop_name)
|
8
|
+
property_def = @resource_class.find(:all).detect { |prop| prop.name == prop_name }
|
9
|
+
property_def ? property_def.column_name : nil
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Mingle4r::API::V1::PropertyDefinition.element_name = 'record'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class API
|
3
|
+
class V1
|
4
|
+
class TransitionExecution
|
5
|
+
extend Mingle4r::CommonClassMethods
|
6
|
+
module InstanceMethods
|
7
|
+
def execute
|
8
|
+
conn = self.class.connection
|
9
|
+
conn.post(self.class.collection_path, encode, self.class.headers)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Mingle4r
|
2
|
+
class API
|
3
|
+
class V1
|
4
|
+
def initialize(host_url)
|
5
|
+
@host_uri = URI.parse(host_url)
|
6
|
+
end
|
7
|
+
|
8
|
+
def base_url
|
9
|
+
@host_uri.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def version
|
13
|
+
1
|
14
|
+
end
|
15
|
+
|
16
|
+
def project_class
|
17
|
+
Project
|
18
|
+
end
|
19
|
+
|
20
|
+
def user_class
|
21
|
+
User
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|