powirb 1.1 → 1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.markdown +15 -13
- data/lib/powirb.rb +1 -0
- data/lib/powirb/handler.rb +22 -25
- data/lib/powirb/version.rb +1 -1
- data/lib/powirb/workitem.rb +99 -31
- data/powirb.gemspec +2 -2
- data/test/test_helper.rb +0 -1
- data/test/test_powirb.rb +3 -0
- data/test/test_powirb_handler.rb +13 -2
- data/test/test_powirb_workitem.rb +41 -8
- metadata +7 -7
data/README.markdown
CHANGED
@@ -8,7 +8,7 @@
|
|
8
8
|
|
9
9
|
# Intro
|
10
10
|
|
11
|
-
Often when using Polarion ALM
|
11
|
+
Often when using Polarion ALM you refine (and redefine) step-by-step your process, or perhaps you need a fine-tune over the way you defines work items, workflows and so and so. Other time you need to import data from other tools and - again - you need an adjustment on some workitems (eg: author name, status, external references, etc).
|
12
12
|
|
13
13
|
I've fonud extremely valuable and fast to do all this operation in [CLI](http://en.wikipedia.org/wiki/Command-line_interface) with ruby.
|
14
14
|
|
@@ -29,21 +29,26 @@ Only basic operation on workitems are implemented, see the example above:
|
|
29
29
|
|
30
30
|
# this referes to a project working copy of the subversion repository
|
31
31
|
h = Powirb::Handler.new('./SampleProject')
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
32
|
+
# now the handler has loaded all workitems data in memory (very fast)
|
33
|
+
|
34
|
+
# we can access a particular workitem with its "wid"
|
35
|
+
wi = h.workitems['WI-1234']
|
36
|
+
|
37
|
+
# or by and AND'ed set of conditions, eg: all closed requirements
|
38
|
+
h.workitems(:type => 'requirements', :status => 'closed').each do |wid,wi|
|
39
|
+
puts "#{wid} - #{wi[:title]}"
|
40
|
+
wi[:resolution] = 'done'
|
41
|
+
wi.save!
|
38
42
|
end
|
39
43
|
|
40
|
-
Please, *remember*: In order to "save" the modification we have to hit a commit with subversion.
|
44
|
+
Please, *remember*: In order to "save" the modification we have to hit a subsequent *commit* with subversion.
|
41
45
|
|
42
46
|
|
43
47
|
# Notes
|
44
48
|
|
45
|
-
*
|
46
|
-
* it does **not** support the "old" *LiveDoc* technology
|
49
|
+
* Powirb can't create new workitems, only updating on existing ones is allowed
|
50
|
+
* it does **not** support the "old" *LiveDoc* technology, but it's ok with the new one
|
51
|
+
* the only fields you can change are "string/text" (more work have to be done here!)
|
47
52
|
* the actual version was tested under Linux and Mac OS X only
|
48
53
|
|
49
54
|
|
@@ -51,7 +56,4 @@ Please, *remember*: In order to "save" the modification we have to hit a commit
|
|
51
56
|
|
52
57
|
**Powirb** is written by [Carlo Pecchia](mailto:info@carlopecchia.eu) and released under the terms of Apache License (see LICENSE file).
|
53
58
|
|
54
|
-
|
55
59
|
----
|
56
|
-
|
57
|
-
|
data/lib/powirb.rb
CHANGED
data/lib/powirb/handler.rb
CHANGED
@@ -14,35 +14,32 @@ class Handler
|
|
14
14
|
# working copy)
|
15
15
|
def initialize(project_path)
|
16
16
|
unless File.exist?(project_path)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
msg = "Invalid project path '#{project_path}'"
|
18
|
+
Powirb.log.error(msg)
|
19
|
+
raise msg
|
20
|
+
end
|
21
21
|
@project_path = project_path
|
22
|
-
|
22
|
+
Powirb.log.debug("Initialized handler for #{@project_path}")
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
24
|
+
# workitems are stored in a big hash, indexed by 'wid's
|
25
|
+
@space = {}
|
26
|
+
self.workitems_paths.each do |path|
|
27
|
+
Dir[File.join(@project_path, path, "/**/workitem.xml")].each do |filename|
|
28
|
+
wid = File.dirname(filename).split(/\//).last
|
29
|
+
@space[wid] = Workitem.new(filename)
|
30
|
+
Powirb.log.debug("Added workitem from #{filename}")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
Powirb.log.debug("Found #{@space.keys.size} workitems.")
|
29
34
|
end
|
30
|
-
|
35
|
+
|
31
36
|
# Return all workitems in the project
|
32
|
-
def workitems
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
tmp
|
41
|
-
end
|
42
|
-
|
43
|
-
# Return the number of total workitems found in the project
|
44
|
-
def workitems_count
|
45
|
-
@workitems_count
|
37
|
+
def workitems(conditions=nil)
|
38
|
+
return @space if conditions.nil?
|
39
|
+
# Return only workitems for which *all* specified conditions are true
|
40
|
+
@space.select do |wid,wi|
|
41
|
+
conditions.map{|k,v| wi[k] == v}.reduce(:&)
|
42
|
+
end
|
46
43
|
end
|
47
44
|
|
48
45
|
# Returns the path for workitems in the specified project
|
data/lib/powirb/version.rb
CHANGED
data/lib/powirb/workitem.rb
CHANGED
@@ -10,51 +10,110 @@ module Powirb
|
|
10
10
|
# Copyright:: Copyright (c) 2011 Carlo Pecchia
|
11
11
|
# License:: See LICENSE file
|
12
12
|
class Workitem
|
13
|
+
attr_reader :filename
|
13
14
|
|
14
15
|
# Create a new instance of a workitem belonging to its representation
|
15
16
|
# in the standard way Polarion does it
|
16
17
|
def initialize(filename)
|
17
18
|
@filename = filename
|
18
|
-
Powirb.log.debug("Initializing workitem with #{filename}")
|
19
|
-
end
|
20
|
-
|
21
|
-
# Read workitem content
|
22
|
-
def read
|
23
19
|
Powirb.log.debug("Retrieving workitem from #{@filename}")
|
24
20
|
begin
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
21
|
+
@doc = Nokogiri::XML(open(@filename))
|
22
|
+
rescue Exception => e
|
23
|
+
Powirb.log.error(e)
|
24
|
+
end
|
29
25
|
end
|
30
26
|
|
31
27
|
# Return a field value
|
32
28
|
def [](fname)
|
33
29
|
fname = fname.to_s
|
34
30
|
node = @doc.xpath("//field[@id=\"#{fname}\"]")
|
35
|
-
|
36
|
-
|
31
|
+
return nil if node.text.empty?
|
32
|
+
node.text
|
37
33
|
end
|
38
34
|
|
39
|
-
# Set/remove a field
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
35
|
+
# Set/remove a field, optionally is possible to specify a 'type'
|
36
|
+
# eg: wi[:foo] = nil -> remove the field 'foo'
|
37
|
+
# wi[:foo] = 'bar' -> add/update the field 'foo'
|
38
|
+
# wi[:foo] = {:value => 'bar', :type => 'enum:foo'} -> the same as above
|
39
|
+
def []=(f,v)
|
40
|
+
f = f.to_s
|
41
|
+
|
42
|
+
# with a null value we remove and existing field
|
43
|
+
if v.nil?
|
44
|
+
# Delete
|
45
|
+
Powirb.log.debug("[#{wid}] removing field '#{f}'")
|
46
|
+
@doc.xpath("//field[@id=\"#{f}\"]").last.remove
|
47
|
+
return
|
48
|
+
end
|
49
|
+
# assert: v is defined (String or Hash)
|
50
|
+
|
51
|
+
# retrieve the 'value' and the optional 'type'
|
52
|
+
if v.instance_of?(Hash)
|
53
|
+
value = v[:value]
|
54
|
+
type = v[:type]
|
55
|
+
else
|
56
|
+
value = v
|
57
|
+
type = nil
|
58
|
+
end
|
59
|
+
# assert: 'value' and 'type' are defined
|
60
|
+
|
61
|
+
if self[f].nil?
|
62
|
+
# Create: the field is not already present
|
63
|
+
Powirb.log.debug("[#{wid}] adding new field '#{f}' with value '#{value}'")
|
64
|
+
e = Nokogiri::XML::Node.new('field', @doc)
|
65
|
+
e['id'] = f
|
66
|
+
e['type'] = type unless type.nil?
|
67
|
+
e.content = value
|
68
|
+
# we are sure the 'type' field always exists for any workitem, so attach after that
|
69
|
+
@doc.xpath('//field[@id="type"]').last.add_next_sibling(e)
|
70
|
+
else
|
71
|
+
# Update: the field is already present
|
72
|
+
Powirb.log.debug("[#{wid}] updating existing field '#{f}' with value '#{value}'")
|
73
|
+
e = @doc.xpath("//field[@id=\"#{f}\"]").last
|
74
|
+
e['type'] = type unless type.nil?
|
75
|
+
e.content = value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# Return the list of linked workitems ['role1:wid1', ..., 'roleN:widN']
|
81
|
+
def links
|
82
|
+
tmp = []
|
83
|
+
@doc.xpath('//field[@id="linkedWorkItems"]/list/struct').each do |struct|
|
84
|
+
linked_wid = struct.xpath('item[@id="workItem"]').text
|
85
|
+
role = struct.xpath('item[@id="role"]').text
|
86
|
+
tmp << "#{role}:#{linked_wid}"
|
87
|
+
end
|
88
|
+
return tmp
|
89
|
+
end
|
90
|
+
|
91
|
+
# Add a link to another workitem with specified role
|
92
|
+
def add_link(lh)
|
93
|
+
lnk_wid = lh[:wid]
|
94
|
+
lnk_role = lh[:role]
|
95
|
+
|
96
|
+
# find or create the attach node
|
97
|
+
if @doc.xpath('//field[@id="linkedWorkItems"]/list').last.nil?
|
98
|
+
Nokogiri::XML::Builder.with(@doc.xpath('//work-item').last) do
|
99
|
+
field(:id => 'linkedWorkItems') {
|
100
|
+
list {}
|
101
|
+
}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# build and attach the link struct
|
106
|
+
Nokogiri::XML::Builder.with(@doc.xpath('//field[@id="linkedWorkItems"]/list').last) do
|
107
|
+
struct {
|
108
|
+
item(:id => 'revision')
|
109
|
+
item(:id => 'workItem') {
|
110
|
+
text lnk_wid
|
111
|
+
}
|
112
|
+
item(:id => 'role') {
|
113
|
+
text lnk_role
|
114
|
+
}
|
115
|
+
}
|
116
|
+
end
|
58
117
|
end
|
59
118
|
|
60
119
|
# Save workitem on filesystem
|
@@ -76,7 +135,16 @@ class Workitem
|
|
76
135
|
# Return a list with all field names
|
77
136
|
def fields
|
78
137
|
@doc.xpath("//field").map{|node| node['id']}.sort
|
79
|
-
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return the "space" under which the workitem lives (tracker xor document)
|
141
|
+
def space
|
142
|
+
if @filename.include?('/.polarion/tracker/')
|
143
|
+
return 'tracker'
|
144
|
+
else
|
145
|
+
File.dirname(@filename).split(/\//)[4]
|
146
|
+
end
|
147
|
+
end
|
80
148
|
end
|
81
149
|
|
82
150
|
end
|
data/powirb.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "powirb"
|
5
|
-
s.version = "1.
|
5
|
+
s.version = "1.2"
|
6
6
|
s.summary = "POlarion WorkItems handling with RuBy"
|
7
7
|
s.description = <<-EOF
|
8
8
|
Ruby interface to Polarion workitems content, for fast manipulation.
|
@@ -11,6 +11,6 @@ EOF
|
|
11
11
|
s.email = ["info@carlopecchia.eu"]
|
12
12
|
s.homepage = "http://github.com/carlopecchia/powirb"
|
13
13
|
s.add_dependency('nokogiri')
|
14
|
-
s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/powirb
|
14
|
+
s.files = ["LICENSE", "README.markdown", "Rakefile", "lib/powirb.rb", "lib/powirb/version.rb", "lib/powirb/handler.rb", "lib/powirb/workitem.rb", "powirb.gemspec", "test/test_helper.rb", "test/test_powirb_workitem.rb", "test/test_powirb.rb", "test/test_powirb_handler.rb"]
|
15
15
|
end
|
16
16
|
|
data/test/test_helper.rb
CHANGED
data/test/test_powirb.rb
CHANGED
data/test/test_powirb_handler.rb
CHANGED
@@ -19,10 +19,21 @@ class PowirbHandlerTest < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
def test_wired_workitems_sources
|
23
|
+
assert_not_nil @h.workitems_paths
|
24
|
+
assert_kind_of Array, @h.workitems_paths
|
25
|
+
end
|
26
|
+
|
22
27
|
def test_workitems
|
23
|
-
assert_kind_of
|
24
|
-
assert @h.workitems_count == 4
|
28
|
+
assert_kind_of Hash, @h.workitems
|
25
29
|
assert @h.workitems.size == 4
|
30
|
+
|
31
|
+
assert_equal 1, @h.workitems(:type => 'task').size
|
32
|
+
assert_equal 3, @h.workitems(:type => 'action').size
|
33
|
+
assert_equal 0, @h.workitems(:type => 'fooz').size
|
34
|
+
|
35
|
+
assert_not_nil @h.workitems['WI-1']
|
36
|
+
assert_nil @h.workitems['non existant wid']
|
26
37
|
end
|
27
38
|
|
28
39
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
|
-
require 'Nokogiri'
|
2
|
+
#require 'Nokogiri'
|
3
3
|
|
4
4
|
class PowirbWorkitemTest < Test::Unit::TestCase
|
5
5
|
|
@@ -9,11 +9,10 @@ class PowirbWorkitemTest < Test::Unit::TestCase
|
|
9
9
|
FileUtils.rm_rf dst
|
10
10
|
FileUtils.cp_r src, dst
|
11
11
|
|
12
|
-
pp = File.join(File.dirname(__FILE__),'sample_project')
|
12
|
+
@pp = File.join(File.dirname(__FILE__),'sample_project')
|
13
13
|
Powirb.set_logger(:debug,'/dev/null')
|
14
|
-
@h = Powirb::Handler.new(pp)
|
15
|
-
@wi = @h.workitems.first
|
16
|
-
@wi.read
|
14
|
+
@h = Powirb::Handler.new(@pp)
|
15
|
+
@wi = @h.workitems[@h.workitems.keys.first]
|
17
16
|
end
|
18
17
|
|
19
18
|
def teardown
|
@@ -36,12 +35,18 @@ class PowirbWorkitemTest < Test::Unit::TestCase
|
|
36
35
|
@wi['foo'] = 'bar'
|
37
36
|
assert @wi['foo'] == 'bar'
|
38
37
|
assert @wi[:foo] == 'bar'
|
38
|
+
|
39
|
+
@wi['foo'] = {:value => 'new foo', :type => 'enum:fooz'}
|
40
|
+
assert @wi.to_xml.include?("id=\"foo\" type=\"enum:fooz\"")
|
39
41
|
end
|
40
|
-
|
42
|
+
|
41
43
|
def test_updating_existing_field
|
42
44
|
assert_not_nil @wi['title']
|
43
45
|
@wi['title'] = 'Some silly Title here...'
|
44
46
|
assert @wi['title'] == 'Some silly Title here...'
|
47
|
+
|
48
|
+
@wi['title'] = {:value => 'new title', :type => 'text/plain'}
|
49
|
+
assert @wi.to_xml.include?("id=\"title\" type=\"text/plain\"")
|
45
50
|
end
|
46
51
|
|
47
52
|
def test_remove_field
|
@@ -67,8 +72,8 @@ class PowirbWorkitemTest < Test::Unit::TestCase
|
|
67
72
|
assert_nil @wi['priority']
|
68
73
|
@wi.save!
|
69
74
|
|
70
|
-
|
71
|
-
w.
|
75
|
+
h2 = Powirb::Handler.new(@pp)
|
76
|
+
w = h2.workitems[@wi.wid]
|
72
77
|
assert_nil w['priority']
|
73
78
|
end
|
74
79
|
|
@@ -84,4 +89,32 @@ class PowirbWorkitemTest < Test::Unit::TestCase
|
|
84
89
|
assert fields.include?('title')
|
85
90
|
assert !fields.include?('foo')
|
86
91
|
end
|
92
|
+
|
93
|
+
def test_space
|
94
|
+
assert_not_nil @wi.space
|
95
|
+
assert_kind_of String, @wi.space
|
96
|
+
assert_equal 'tracker', @wi.space
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_links
|
100
|
+
wi = @h.workitems['WI-2']
|
101
|
+
assert_not_nil wi.links
|
102
|
+
assert_equal 1, wi.links.size
|
103
|
+
assert_equal 'parent:WI-1', wi.links.first
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_add_link
|
107
|
+
wi1 = @h.workitems['WI-1']
|
108
|
+
assert_not_nil wi1
|
109
|
+
wi2 = @h.workitems['WI-2']
|
110
|
+
assert_not_nil wi2
|
111
|
+
|
112
|
+
# to empty link set
|
113
|
+
wi1.add_link(:wid => 'WI-2', :role => 'relates_to')
|
114
|
+
assert wi1.links.include?('relates_to:WI-2')
|
115
|
+
|
116
|
+
# to non empty links set
|
117
|
+
wi2.add_link(:wid => 'WI-1', :role => 'relates_to')
|
118
|
+
assert wi2.links.include?('relates_to:WI-1')
|
119
|
+
end
|
87
120
|
end
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: powirb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 11
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: "1.
|
8
|
+
- 2
|
9
|
+
version: "1.2"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Carlo Pecchia
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-08-08 00:00:00 +02:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -44,15 +44,15 @@ files:
|
|
44
44
|
- LICENSE
|
45
45
|
- README.markdown
|
46
46
|
- Rakefile
|
47
|
-
- lib/powirb
|
47
|
+
- lib/powirb.rb
|
48
48
|
- lib/powirb/version.rb
|
49
|
+
- lib/powirb/handler.rb
|
49
50
|
- lib/powirb/workitem.rb
|
50
|
-
- lib/powirb.rb
|
51
51
|
- powirb.gemspec
|
52
52
|
- test/test_helper.rb
|
53
|
+
- test/test_powirb_workitem.rb
|
53
54
|
- test/test_powirb.rb
|
54
55
|
- test/test_powirb_handler.rb
|
55
|
-
- test/test_powirb_workitem.rb
|
56
56
|
has_rdoc: true
|
57
57
|
homepage: http://github.com/carlopecchia/powirb
|
58
58
|
licenses: []
|