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.
@@ -8,7 +8,7 @@
8
8
 
9
9
  # Intro
10
10
 
11
- Often when using Polarion ALM and you refine (and redefine) step-by-step you process, or perhaps you need a fine-tune over the way you defines wor items the 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, etc).
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
- h.workitems.each do |wi|
34
- if wi['status'] == 'closed' and wi[:type] == 'action'
35
- wi[:resolution] = 'done'
36
- wi.save!
37
- end
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
- * it does work with Polarion 2011
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
-
@@ -7,6 +7,7 @@ end
7
7
 
8
8
  require 'powirb/workitem'
9
9
  require 'powirb/handler'
10
+ require 'powirb/version'
10
11
  require 'logger'
11
12
 
12
13
  # This module represent a container for Powirb classes.
@@ -14,35 +14,32 @@ class Handler
14
14
  # working copy)
15
15
  def initialize(project_path)
16
16
  unless File.exist?(project_path)
17
- msg = "Invalid project path '#{project_path}'"
18
- Powirb.log.error(msg)
19
- raise msg
20
- end
17
+ msg = "Invalid project path '#{project_path}'"
18
+ Powirb.log.error(msg)
19
+ raise msg
20
+ end
21
21
  @project_path = project_path
22
- Powirb.log.debug("Initialized handler for #{@project_path}")
22
+ Powirb.log.debug("Initialized handler for #{@project_path}")
23
23
 
24
- @workitems_count = 0
25
- self.workitems_paths.each do |path|
26
- @workitems_count += Dir[File.join(@project_path, path, "/**/workitem.xml")].size
27
- end
28
- Powirb.log.debug("Found #{@workitems_count} workitems.")
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
- tmp = []
34
- self.workitems_paths.each do |path|
35
- Dir[File.join(@project_path, path, "/**/workitem.xml")].each do |filename|
36
- tmp << Workitem.new(filename)
37
- Powirb.log.debug("Added workitem from #{filename}")
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
@@ -1,4 +1,4 @@
1
1
  module Powirb
2
- VERSION = '1.1'
2
+ VERSION = '1.2'
3
3
  end
4
4
 
@@ -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
- @doc = Nokogiri::XML(open(@filename))
26
- rescue Exception => e
27
- Powirb.log.error(e)
28
- end
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
- return nil if node.text.empty?
36
- node.text
31
+ return nil if node.text.empty?
32
+ node.text
37
33
  end
38
34
 
39
- # Set/remove a field
40
- def []=(fname, fvalue)
41
- fname = fname.to_s
42
- if self[fname].nil?
43
- # inserting new field
44
- Powirb.log.debug("[#{wid}] adding new field '#{fname}' with value '#{fvalue}'")
45
- @doc.xpath('//field[@id="type"]').last.add_next_sibling("\n <field id=\"#{fname}\">#{fvalue}</field>")
46
- else
47
- if fvalue.nil?
48
- # removing existing field
49
- Powirb.log.debug("[#{wid}] removing field '#{fname}'")
50
- @doc.xpath("//field[@id=\"#{fname}\"]").last.remove
51
- else
52
- # updating existing field
53
- Powirb.log.debug("[#{wid}] updating field '#{fname}' with value '#{fvalue}'")
54
- e = @doc.xpath("//field[@id=\"#{fname}\"]").last
55
- e.content = fvalue
56
- end
57
- end
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
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = "powirb"
5
- s.version = "1.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/handler.rb", "lib/powirb/version.rb", "lib/powirb/workitem.rb", "lib/powirb.rb", "powirb.gemspec", "test/test_helper.rb", "test/test_powirb.rb", "test/test_powirb_handler.rb", "test/test_powirb_workitem.rb"]
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
 
@@ -1,6 +1,5 @@
1
1
  require 'rubygems'
2
2
  require 'test/unit'
3
- #require 'ftools'
4
3
  require 'fileutils'
5
4
 
6
5
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__),'..','lib'))
@@ -12,4 +12,7 @@ class PowirbTest < Test::Unit::TestCase
12
12
  assert_not_nil Powirb.log
13
13
  end
14
14
 
15
+ def test_valid_version
16
+ assert_not_nil Powirb::VERSION
17
+ end
15
18
  end
@@ -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 Array, @h.workitems
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
- w = @h.workitems.first
71
- w.read
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: 13
4
+ hash: 11
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 1
9
- version: "1.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-04-18 00:00:00 +02:00
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/handler.rb
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: []