place 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Changelog ADDED
@@ -0,0 +1,11 @@
1
+ 2010-07-16 - Added memoization for total_on computing in WorkItem
2
+ 2010-07-14 - Added update* methods to Place: knowing where a repo is/was updated
3
+ 2010-06-25 - Tests refactored
4
+ 2010-06-25 - Added logging facility in collecting and retrieve
5
+ 2010-06-23 - Repository gathering reviewed, tests tuned.. and finally less code
6
+ 2010-06-21 - Added link workitems <-> projects
7
+ 2010-06-17 - Added links, watches and roles with testing
8
+ 2010-06-15 - Added comments with tests
9
+ 2010-06-15 - Added work record wirh testing
10
+ 2010-06-14 - Advanced on work_item testing
11
+ 2010-06-14 - Added users
data/LICENSE ADDED
@@ -0,0 +1,207 @@
1
+ Copyright (c) 2010 Carlo Pecchia (info@carlopecchia.eu)
2
+
3
+ This software is released under the condition of the Apache License:
4
+
5
+
6
+ Apache License
7
+ Version 2.0, January 2004
8
+ http://www.apache.org/licenses/
9
+
10
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
11
+
12
+ 1. Definitions.
13
+
14
+ "License" shall mean the terms and conditions for use, reproduction,
15
+ and distribution as defined by Sections 1 through 9 of this document.
16
+
17
+ "Licensor" shall mean the copyright owner or entity authorized by
18
+ the copyright owner that is granting the License.
19
+
20
+ "Legal Entity" shall mean the union of the acting entity and all
21
+ other entities that control, are controlled by, or are under common
22
+ control with that entity. For the purposes of this definition,
23
+ "control" means (i) the power, direct or indirect, to cause the
24
+ direction or management of such entity, whether by contract or
25
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
26
+ outstanding shares, or (iii) beneficial ownership of such entity.
27
+
28
+ "You" (or "Your") shall mean an individual or Legal Entity
29
+ exercising permissions granted by this License.
30
+
31
+ "Source" form shall mean the preferred form for making modifications,
32
+ including but not limited to software source code, documentation
33
+ source, and configuration files.
34
+
35
+ "Object" form shall mean any form resulting from mechanical
36
+ transformation or translation of a Source form, including but
37
+ not limited to compiled object code, generated documentation,
38
+ and conversions to other media types.
39
+
40
+ "Work" shall mean the work of authorship, whether in Source or
41
+ Object form, made available under the License, as indicated by a
42
+ copyright notice that is included in or attached to the work
43
+ (an example is provided in the Appendix below).
44
+
45
+ "Derivative Works" shall mean any work, whether in Source or Object
46
+ form, that is based on (or derived from) the Work and for which the
47
+ editorial revisions, annotations, elaborations, or other modifications
48
+ represent, as a whole, an original work of authorship. For the purposes
49
+ of this License, Derivative Works shall not include works that remain
50
+ separable from, or merely link (or bind by name) to the interfaces of,
51
+ the Work and Derivative Works thereof.
52
+
53
+ "Contribution" shall mean any work of authorship, including
54
+ the original version of the Work and any modifications or additions
55
+ to that Work or Derivative Works thereof, that is intentionally
56
+ submitted to Licensor for inclusion in the Work by the copyright owner
57
+ or by an individual or Legal Entity authorized to submit on behalf of
58
+ the copyright owner. For the purposes of this definition, "submitted"
59
+ means any form of electronic, verbal, or written communication sent
60
+ to the Licensor or its representatives, including but not limited to
61
+ communication on electronic mailing lists, source code control systems,
62
+ and issue tracking systems that are managed by, or on behalf of, the
63
+ Licensor for the purpose of discussing and improving the Work, but
64
+ excluding communication that is conspicuously marked or otherwise
65
+ designated in writing by the copyright owner as "Not a Contribution."
66
+
67
+ "Contributor" shall mean Licensor and any individual or Legal Entity
68
+ on behalf of whom a Contribution has been received by Licensor and
69
+ subsequently incorporated within the Work.
70
+
71
+ 2. Grant of Copyright License. Subject to the terms and conditions of
72
+ this License, each Contributor hereby grants to You a perpetual,
73
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
74
+ copyright license to reproduce, prepare Derivative Works of,
75
+ publicly display, publicly perform, sublicense, and distribute the
76
+ Work and such Derivative Works in Source or Object form.
77
+
78
+ 3. Grant of Patent License. Subject to the terms and conditions of
79
+ this License, each Contributor hereby grants to You a perpetual,
80
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
81
+ (except as stated in this section) patent license to make, have made,
82
+ use, offer to sell, sell, import, and otherwise transfer the Work,
83
+ where such license applies only to those patent claims licensable
84
+ by such Contributor that are necessarily infringed by their
85
+ Contribution(s) alone or by combination of their Contribution(s)
86
+ with the Work to which such Contribution(s) was submitted. If You
87
+ institute patent litigation against any entity (including a
88
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
89
+ or a Contribution incorporated within the Work constitutes direct
90
+ or contributory patent infringement, then any patent licenses
91
+ granted to You under this License for that Work shall terminate
92
+ as of the date such litigation is filed.
93
+
94
+ 4. Redistribution. You may reproduce and distribute copies of the
95
+ Work or Derivative Works thereof in any medium, with or without
96
+ modifications, and in Source or Object form, provided that You
97
+ meet the following conditions:
98
+
99
+ (a) You must give any other recipients of the Work or
100
+ Derivative Works a copy of this License; and
101
+
102
+ (b) You must cause any modified files to carry prominent notices
103
+ stating that You changed the files; and
104
+
105
+ (c) You must retain, in the Source form of any Derivative Works
106
+ that You distribute, all copyright, patent, trademark, and
107
+ attribution notices from the Source form of the Work,
108
+ excluding those notices that do not pertain to any part of
109
+ the Derivative Works; and
110
+
111
+ (d) If the Work includes a "NOTICE" text file as part of its
112
+ distribution, then any Derivative Works that You distribute must
113
+ include a readable copy of the attribution notices contained
114
+ within such NOTICE file, excluding those notices that do not
115
+ pertain to any part of the Derivative Works, in at least one
116
+ of the following places: within a NOTICE text file distributed
117
+ as part of the Derivative Works; within the Source form or
118
+ documentation, if provided along with the Derivative Works; or,
119
+ within a display generated by the Derivative Works, if and
120
+ wherever such third-party notices normally appear. The contents
121
+ of the NOTICE file are for informational purposes only and
122
+ do not modify the License. You may add Your own attribution
123
+ notices within Derivative Works that You distribute, alongside
124
+ or as an addendum to the NOTICE text from the Work, provided
125
+ that such additional attribution notices cannot be construed
126
+ as modifying the License.
127
+
128
+ You may add Your own copyright statement to Your modifications and
129
+ may provide additional or different license terms and conditions
130
+ for use, reproduction, or distribution of Your modifications, or
131
+ for any such Derivative Works as a whole, provided Your use,
132
+ reproduction, and distribution of the Work otherwise complies with
133
+ the conditions stated in this License.
134
+
135
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
136
+ any Contribution intentionally submitted for inclusion in the Work
137
+ by You to the Licensor shall be under the terms and conditions of
138
+ this License, without any additional terms or conditions.
139
+ Notwithstanding the above, nothing herein shall supersede or modify
140
+ the terms of any separate license agreement you may have executed
141
+ with Licensor regarding such Contributions.
142
+
143
+ 6. Trademarks. This License does not grant permission to use the trade
144
+ names, trademarks, service marks, or product names of the Licensor,
145
+ except as required for reasonable and customary use in describing the
146
+ origin of the Work and reproducing the content of the NOTICE file.
147
+
148
+ 7. Disclaimer of Warranty. Unless required by applicable law or
149
+ agreed to in writing, Licensor provides the Work (and each
150
+ Contributor provides its Contributions) on an "AS IS" BASIS,
151
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
152
+ implied, including, without limitation, any warranties or conditions
153
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
154
+ PARTICULAR PURPOSE. You are solely responsible for determining the
155
+ appropriateness of using or redistributing the Work and assume any
156
+ risks associated with Your exercise of permissions under this License.
157
+
158
+ 8. Limitation of Liability. In no event and under no legal theory,
159
+ whether in tort (including negligence), contract, or otherwise,
160
+ unless required by applicable law (such as deliberate and grossly
161
+ negligent acts) or agreed to in writing, shall any Contributor be
162
+ liable to You for damages, including any direct, indirect, special,
163
+ incidental, or consequential damages of any character arising as a
164
+ result of this License or out of the use or inability to use the
165
+ Work (including but not limited to damages for loss of goodwill,
166
+ work stoppage, computer failure or malfunction, or any and all
167
+ other commercial damages or losses), even if such Contributor
168
+ has been advised of the possibility of such damages.
169
+
170
+ 9. Accepting Warranty or Additional Liability. While redistributing
171
+ the Work or Derivative Works thereof, You may choose to offer,
172
+ and charge a fee for, acceptance of support, warranty, indemnity,
173
+ or other liability obligations and/or rights consistent with this
174
+ License. However, in accepting such obligations, You may act only
175
+ on Your own behalf and on Your sole responsibility, not on behalf
176
+ of any other Contributor, and only if You agree to indemnify,
177
+ defend, and hold each Contributor harmless for any liability
178
+ incurred by, or claims asserted against, such Contributor by reason
179
+ of your accepting any such warranty or additional liability.
180
+
181
+ END OF TERMS AND CONDITIONS
182
+
183
+ APPENDIX: How to apply the Apache License to your work.
184
+
185
+ To apply the Apache License to your work, attach the following
186
+ boilerplate notice, with the fields enclosed by brackets "[]"
187
+ replaced with your own identifying information. (Don't include
188
+ the brackets!) The text should be enclosed in the appropriate
189
+ comment syntax for the file format. We also recommend that a
190
+ file or class name and description of purpose be included on the
191
+ same "printed page" as the copyright notice for easier
192
+ identification within third-party archives.
193
+
194
+ Copyright 2010 Carlo Pecchia
195
+
196
+ Licensed under the Apache License, Version 2.0 (the "License");
197
+ you may not use this file except in compliance with the License.
198
+ You may obtain a copy of the License at
199
+
200
+ http://www.apache.org/licenses/LICENSE-2.0
201
+
202
+ Unless required by applicable law or agreed to in writing, software
203
+ distributed under the License is distributed on an "AS IS" BASIS,
204
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
205
+ See the License for the specific language governing permissions and
206
+ limitations under the License.
207
+
data/README.markdown ADDED
@@ -0,0 +1,96 @@
1
+
2
+ Place is a Ruby library aimed to gather and manage objects from [Polarion ALM](http://www.polarion.com/)&trade; repositories. Its name comes from the contraction of "**P**olarion **lace**".
3
+
4
+
5
+ # Intro
6
+
7
+ **Place** collects informations from *Polarion ALM &trade;* and turns it into easy manageable ruby objects, which are managed by excellent key-value store [Redis](http://code.google.com/p/redis/), via the Ruby library [Ohm](http://ohm.keyvalue.org/).
8
+
9
+ *Polarion &trade;* is an "Application Lifecycle Management" tool produced by *Polarion Software GmbH*. For more info on *Polarion ALM &trade;* please refers to <http://www.polarion.com/>.
10
+
11
+ # Why?
12
+
13
+ Basically I'd like to easy access to items inside a Polarion projects (namely "workitems"), as well as see relations among multiprojects workitems. That saved me a lot of time in extracting information and producing reports.
14
+
15
+
16
+ # Examples
17
+
18
+ First we need a local working copy of the repository. Notice we need only `.polarion` directories, not the WHOLE repository:
19
+
20
+ # obtain a local working copy of you Polarion repository
21
+ $ svn co http://your.polarion.server/repo/.polarion local_repo/.polarion
22
+ $ svn co http://your.polarion.server/repo/ProjectA/.polarion local_repo/ProjectA/.polarion
23
+ $ svn co http://your.polarion.server/repo/ProjectB/.polarion local_repo/ProjectB/.polarion
24
+
25
+ Then we go Ruby...
26
+
27
+
28
+ ## Gathering data
29
+
30
+ require 'place'
31
+ include Place
32
+
33
+ Place.setup('./local_repo')
34
+ Place.logger_setup('/dev/null')
35
+
36
+ Place.gather!
37
+ # This reset Redis db with a fresh new copy from the
38
+ # repository working copy (it's up to us update it).
39
+ # Of course is needed only when working copy is updated
40
+
41
+ ## Intro
42
+
43
+ require 'place'
44
+ include Place
45
+
46
+ Place.setup('./local_repo')
47
+ Place.logger_setup('/dev/null')
48
+
49
+ puts "Users: #{User.all.size}"
50
+ puts "Workitems: #{WorkItem.all.size}"
51
+
52
+ all_tasks = WorkItem.find_by_type(:task)
53
+
54
+ demo = Project.find_by_name('Demo')
55
+ demo_tasks = demo.workitems(:type => :taks)
56
+
57
+ t = demo_tasks.last
58
+ puts "Assignees for #{t.wid}: #{t.assignees.map{|u| u.name}.join(' ')}"
59
+
60
+
61
+ ## Assigned tasks
62
+
63
+ require 'place'
64
+ include Place
65
+
66
+ Place.setup('./local_repo')
67
+ Place.logger_setup('/dev/null')
68
+
69
+ tasks = WorkItem.fnid_by_type(:task)
70
+ assigned_tasks = tasks.reject{|wi| wi.assignees.empty? }
71
+ assigned_tasks.each do |wi|
72
+ puts "#{wi.wid} assigned to #{wi.assignees.map{|u| u.name}.join(' ')}"
73
+ end
74
+
75
+
76
+ ## Limitations
77
+
78
+ * **Place** does *not* work with LiveDocument workitems, that are workitems stored in Microsoft document rather than .xml files.
79
+ * The actual version was tested under *Linux* and *Mac OS X* only.
80
+
81
+ ## Performance
82
+
83
+ Retrieving data from a repository working copy takes not too much time. Assuming the time required grows with the numbers of workitems, we experienced a total retrieve time of 60 seconds with 1700 workitems.
84
+
85
+ ## Roadmap
86
+
87
+ * add more examples into documentation
88
+ * add hyperlinks for workitems (and votes, approvals, ...)
89
+ * (maybe) incremental update rather than one-shot gathering
90
+ * implement write back to repository
91
+ * callback for each workitem type (es: complex calculated fields)
92
+
93
+
94
+ ## Author
95
+
96
+ Place is written by [Carlo Pecchia](mailto:info@carlopecchia.eu) and released under the terms of Apache License (see LICENSE file).
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+
2
+ require 'rake/testtask'
3
+
4
+ desc "Run tests"
5
+ Rake::TestTask.new do |t|
6
+ t.test_files = FileList['test/test_*.rb']
7
+ end
8
+
9
+ task :default => [:test]
@@ -0,0 +1,29 @@
1
+ # Technical Info
2
+
3
+ ## Ratio
4
+
5
+ Polarion &trade; stores data under a [Subversion](http://subversion.apache.org/) repository - located on the server it runs on - encoded in XML files at two levels:
6
+
7
+ * Global level:
8
+ - .polarion/user-management/users/<name>/user.xml
9
+ * Project level:
10
+ - <prj>/.polarion/tracker/timepoints/<tid>.xml
11
+ - <prj>/.polarion/security/user-roles.xml
12
+ - <prj>/.polarion/tracker/workitems/**/<wid>/workitem.xml
13
+ - <prj>/.polarion/tracker/workitems/**/<wid>/workrecord-<N>.xml
14
+ - <prj>/.polarion/tracker/workitems/**/<wid>/comment-<N>.xml
15
+
16
+
17
+ ## Collecting & Retrieving sequence
18
+
19
+ In order to correctly build the "graph" of entities (work items, comments, work records, users, etc) we have to define a strict retrieve sequence:
20
+
21
+ projects
22
+ users
23
+ for each project:
24
+ timepoints
25
+ workitems
26
+ author, assignees, links, comments, workrecords
27
+ users' roles
28
+ users' watches
29
+
@@ -0,0 +1,34 @@
1
+
2
+ require 'rubygems'
3
+ require 'place'
4
+
5
+ include Place
6
+
7
+ # this path refers to (root) repository local working copy
8
+ Place.setup('../test/repo')
9
+
10
+ Place.logger_setup('/dev/null')
11
+
12
+ # that is not necessary each time!
13
+ Place.gather!
14
+
15
+ puts "Retrieved #{Project.all.size} projects."
16
+ puts "Retrieved #{WorkItem.all.size} workitems."
17
+
18
+ tasks = WorkItem.find_by_type :task
19
+ puts " tasks: #{tasks.size}"
20
+
21
+ puts "-" * 60
22
+
23
+ # for each task print: ID, title and list of linked in workitems
24
+ tasks.each do |t|
25
+ printf("[%4s] - %-10s (%s)\n", t.wid, t[:title], t.links_in.map{|l| l.from.wid}.join(', '))
26
+ end
27
+
28
+ puts "-" * 60
29
+
30
+ # do the same, but only in a project context
31
+ p = Project.find_by_name('P')
32
+ p.workitems(:type => :taks).each do |t|
33
+ printf("[%4s] - %-10s (%s)\n", t.wid, t[:title], t.links_in.map{|l| l.from.wid}.join(', '))
34
+ end
@@ -0,0 +1,76 @@
1
+ module Place
2
+
3
+ # Each Comment belongs to a WorkItem and is written by a User
4
+ class Comment < Ohm::Model
5
+ attribute :url
6
+ index :url
7
+
8
+ attribute :title
9
+ attribute :created
10
+ attribute :text
11
+ attribute :parentComment
12
+
13
+ collection :child, Comment, :parent
14
+
15
+ reference :parent, Comment
16
+ reference :author, User
17
+ reference :workitem, WorkItem
18
+
19
+ class << self; attr_accessor :rules end
20
+ @rules = {
21
+ 'title' => '//comment/field[@id="title"]',
22
+ 'author' => '//comment/field[@id="author"]',
23
+ 'text' => '//comment/field[@id="text"]',
24
+ 'created' => '//comment/field[@id="created"]',
25
+ 'parentComment' => '//comment/field[@id="parentComment"]'
26
+ }
27
+
28
+ # Retrieve a specific comment data
29
+ def retrieve
30
+ content = IO.readlines(url).join('')
31
+ doc = Nokogiri::XML(content)
32
+ self.class.rules.each_pair do |k,v|
33
+ tmp = doc.xpath(v)
34
+
35
+ case k
36
+ when 'author'
37
+ self.send("#{k}=", User.find_by_name(tmp[0].content))
38
+ else
39
+ self.send("#{k}=", tmp[0].content) unless tmp[0].nil?
40
+ end
41
+ end
42
+ self.workitem = WorkItem.find_by_wid(File.dirname(self.url).split(/\//).last)
43
+ self.parent = Comment.find_by_cid(self.parentComment) unless self.parentComment.nil?
44
+ Place.logger.info("retrieved comement for #{self.url}")
45
+ self.save
46
+ end
47
+
48
+ # Find a comment by a "comment-id" (es: P-1#3)
49
+ def self.find_by_cid(cid)
50
+ comments = self.all.select do |c|
51
+ chunks = c.url.split('/')
52
+ wid = chunks[-2]
53
+ comment_part = chunks[-1]
54
+ comment_part =~ /comment-(\d+).xml/
55
+ "#{wid}##{$1}" == cid
56
+ end
57
+ return comments.first if comments.size > 0
58
+ return nil
59
+ end
60
+
61
+ # Return a calculated cid for the comment
62
+ def cid
63
+ chunks = self.url.split('/')
64
+ wid = chunks[-2]
65
+ comment_part = chunks[-1]
66
+ comment_part =~ /comment-(\d+).xml/
67
+ "#{wid}#{$1}"
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+
75
+
76
+
data/lib/place/link.rb ADDED
@@ -0,0 +1,20 @@
1
+ module Place
2
+
3
+ class Link < Ohm::Model
4
+ attribute :role
5
+ index :role
6
+ attribute :suspect
7
+ attribute :revision
8
+
9
+ reference :from, WorkItem
10
+ reference :to, WorkItem
11
+
12
+ # added only for performance needs
13
+ attribute :from_wid
14
+ index :from_wid
15
+ attribute :to_wid
16
+ index :to_wid
17
+ end
18
+
19
+ end
20
+
@@ -0,0 +1,12 @@
1
+ module Place
2
+
3
+
4
+ class Participation < Ohm::Model
5
+ set :roles
6
+
7
+ reference :user, User
8
+ reference :project, Project
9
+ end
10
+
11
+
12
+ end
@@ -0,0 +1,159 @@
1
+ module Place
2
+
3
+ # Each project has a (name, url) from which (prefix, description) are derived
4
+ class Project < Ohm::Model
5
+ attribute :name
6
+ attribute :description
7
+ attribute :prefix
8
+ attribute :url
9
+
10
+ index :name
11
+ index :url
12
+ index :prefix
13
+
14
+ set :parent_roles
15
+
16
+ collection :participations, Participation, :project
17
+ collection :workitems, WorkItem, :project
18
+ collection :timepoints, TimePoint, :project
19
+
20
+ class << self; attr_accessor :rules end
21
+ @rules = {
22
+ 'name' => '//project/field[@id="name"]',
23
+ 'description' => '//project/field[@id="description"]',
24
+ 'prefix' => '//project/field[@id="trackerPrefix"]'
25
+ }
26
+
27
+ # Collect all projects (url) under a given repository url
28
+ def self.collect_all(base_url)
29
+ projects_path = base_url + '/**/.polarion'
30
+ Dir.glob(projects_path).each do |filename|
31
+ next if filename == base_url + '/.polarion'
32
+ Project.create(:url => filename)
33
+ Place.logger.info("created project with url #{filename}")
34
+ end
35
+ end
36
+
37
+ # Retrieve a specific project (based on url only)
38
+ def retrieve
39
+ start_time = Time.now.to_i
40
+
41
+ Dir.glob("#{url}/polarion-project.xml").each do |filename|
42
+ content = IO.readlines(filename).join('')
43
+ doc = Nokogiri::XML(content)
44
+
45
+ self.class.rules.each_pair do |k,v|
46
+ tmp = doc.xpath(v)
47
+ self.send("#{k}=", tmp[0].content) unless tmp[0].nil?
48
+ end
49
+ end
50
+ self.save
51
+ Place.logger.info("saved project with name #{self.name}")
52
+
53
+ retrieve_parent_roles
54
+
55
+ TimePoint.collect_all(url)
56
+ timepoints.all.each{|tp| tp.retrieve} if timepoints.size > 0
57
+
58
+ WorkItem.collect_all(url)
59
+ workitems.all.each{|wi| wi.retrieve} if workitems.size > 0
60
+
61
+ retrieve_participations
62
+
63
+ users.each do |u|
64
+ # ugly way to prevent multiple (global) data retrieve :(
65
+ u.retrieve if u.full_name.nil?
66
+ u.retrieve_watches
67
+ end
68
+
69
+ self.save
70
+ end
71
+
72
+ # Find a project by a given url (ending with +/.polarion+), +nil+ if not exists
73
+ def self.find_by_url(url)
74
+ projects = self.find(:url => url)
75
+ projects.nil? ? nil : projects[0]
76
+ end
77
+
78
+ # Find a project by a given name, +nil+ if not exists
79
+ def self.find_by_name(name)
80
+ projects = self.find(:name => name)
81
+ projects.nil? ? nil : projects[0]
82
+ end
83
+
84
+ # Find a project by a given perfix, +nil+ if not exists
85
+ def self.find_by_prefix(prefix)
86
+ projects = self.find(:prefix => prefix)
87
+ projects.nil? ? nil : projects[0]
88
+ end
89
+
90
+ # Find all users involved in the project, eventually with a given role
91
+ def users(with_role=nil)
92
+ user_set = []
93
+ if participations.size > 0
94
+ participations.all.each do |pt|
95
+ unless with_role.nil?
96
+ role = with_role.to_s
97
+ roles = pt.roles.size > 0 ? pt.roles.to_a : []
98
+ user_set << pt.user if roles.include?(role)
99
+ else
100
+ user_set << pt.user
101
+ end
102
+ end
103
+ end
104
+ user_set
105
+ end
106
+
107
+ # Find all roles used in the project
108
+ def roles
109
+ tmp = {}
110
+ participations.all.each do |pt|
111
+ if pt.roles.size > 0
112
+ pt.roles.all.each{|r| tmp[r] = true}
113
+ end
114
+ end
115
+ tmp.keys
116
+ end
117
+
118
+ private
119
+
120
+ # Retrieve all participation of users in project, with its own roles
121
+ def retrieve_participations
122
+ Dir.glob("#{url}/security/user-roles.xml").each do |filename|
123
+ content = IO.readlines(filename).join
124
+ doc = Nokogiri::XML(content)
125
+ doc.xpath('//user-roles/user').each do |udata|
126
+ u = User.find_by_name(udata['name'])
127
+ unless u.nil?
128
+ p = Participation.create(:project => self, :user => u)
129
+ udata.xpath('role').map{|i| i['name']}.each{|r| p.roles << r}
130
+ p.save
131
+ Place.logger.info("saved participation: #{u.name}, #{self.name}")
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ # Retrieve parent roles' id for the project
138
+ def retrieve_parent_roles
139
+ local_path = "#{url}/tracker/fields/workitem-link-role-enum.xml"
140
+ _retrieve_parent_roles(local_path)
141
+
142
+ # if they are not locally, find out globally
143
+ global_path = "#{Place.conf['base']}/.polarion/tracker/fields/workitem-link-role-enum.xml"
144
+ _retrieve_parent_roles(global_path) if parent_roles.empty?
145
+ end
146
+
147
+ def _retrieve_parent_roles(path)
148
+ Dir.glob(path).each do |filename|
149
+ content = IO.readlines(filename).join
150
+ doc = Nokogiri::XML(content)
151
+ doc.xpath('//enumeration/option[@parent="true"]').each do |data|
152
+ self.parent_roles << data.attributes['id'].to_s
153
+ end
154
+ end
155
+ end
156
+
157
+ end
158
+
159
+ end