mingle4r 0.3.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/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
|