mingle_events 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +3 -4
- data/lib/mingle_events/feed.rb +1 -1
- data/lib/mingle_events/feed/author.rb +21 -9
- data/lib/mingle_events/feed/category.rb +13 -1
- data/lib/mingle_events/feed/changes.rb +76 -0
- data/lib/mingle_events/feed/entry.rb +22 -8
- data/lib/mingle_events/feed/page.rb +4 -25
- data/lib/mingle_events/project_event_fetcher.rb +4 -12
- data/test/mingle_events/feed/author_test.rb +10 -9
- data/test/mingle_events/feed/category_test.rb +4 -0
- data/test/mingle_events/feed/changes_test.rb +344 -0
- data/test/mingle_events/feed/entry_test.rb +23 -36
- data/test/mingle_events/feed/page_test.rb +2 -51
- data/test/mingle_events/project_event_fetcher_test.rb +1 -1
- metadata +5 -4
- data/lib/mingle_events/feed/element_support.rb +0 -19
data/README.textile
CHANGED
@@ -123,12 +123,11 @@ One of the great usages of event playback is historical analysis. E.g., if you w
|
|
123
123
|
It is possible to repeatedly run analysis against previously fetched events using the ProjectEventFetcher class that is only used in the internals of the standard polling mechanism. ProjectEventFetcher does most of the real work of reading new events from the server and making them available for local processing, so it's not a bad class to get to know.
|
124
124
|
|
125
125
|
<pre>
|
126
|
-
event_fetcher = MingleEvents::ProjectEventFetcher.new('
|
127
|
-
processor = MingleEvents::Processors::PutsPublisher.new
|
126
|
+
event_fetcher = MingleEvents::ProjectEventFetcher.new('my_project', mingle_access)
|
128
127
|
event_fetcher.all_fetched_entries.each do |e|
|
129
|
-
|
128
|
+
# do something interesting with each event
|
130
129
|
end
|
131
130
|
</pre>
|
132
131
|
|
133
|
-
|
132
|
+
Until there's time for further documentation take a look at card_count_by_day.rb and story_count_by_day.rb in the examples folder.
|
134
133
|
|
data/lib/mingle_events/feed.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'element_support'))
|
2
1
|
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'author'))
|
3
2
|
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'category'))
|
4
3
|
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'entry'))
|
5
4
|
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'page'))
|
5
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'feed', 'changes'))
|
@@ -3,9 +3,7 @@ module MingleEvents
|
|
3
3
|
|
4
4
|
# The user who's Mingle activity triggered this event
|
5
5
|
class Author
|
6
|
-
|
7
|
-
include ElementSupport
|
8
|
-
|
6
|
+
|
9
7
|
# The name of the author
|
10
8
|
attr_reader :name
|
11
9
|
# The email address of the author
|
@@ -16,13 +14,27 @@ module MingleEvents
|
|
16
14
|
attr_reader :icon_uri
|
17
15
|
|
18
16
|
def initialize(author_element)
|
19
|
-
@name =
|
20
|
-
@email =
|
21
|
-
@uri =
|
22
|
-
@icon_uri =
|
17
|
+
@name = author_element.at("name").inner_text
|
18
|
+
@email = optional_element_text(author_element, 'email')
|
19
|
+
@uri = optional_element_text(author_element, 'uri')
|
20
|
+
@icon_uri = optional_element_text(author_element, 'icon')
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.from_snippet(entry_xml)
|
24
|
+
self.new(Nokogiri::XML(entry_xml))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def optional_element_text(parent_element, element_name)
|
30
|
+
element = parent_element.at(element_name)
|
31
|
+
element.nil? ? nil : element.inner_text
|
23
32
|
end
|
24
33
|
|
25
34
|
end
|
26
|
-
|
35
|
+
|
27
36
|
end
|
28
|
-
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
@@ -6,6 +6,8 @@ module MingleEvents
|
|
6
6
|
# All current Mingle categories are also defined here, as constants.
|
7
7
|
class Category
|
8
8
|
|
9
|
+
@@categories_by_mingle_term = {}
|
10
|
+
|
9
11
|
# The category's term
|
10
12
|
attr_reader :term
|
11
13
|
# The category's scheme
|
@@ -14,6 +16,16 @@ module MingleEvents
|
|
14
16
|
def initialize(term, scheme)
|
15
17
|
@term = term
|
16
18
|
@scheme = scheme
|
19
|
+
@@categories_by_mingle_term[term] = self
|
20
|
+
end
|
21
|
+
|
22
|
+
# lookup a category by the text value of the term (mingle scheme is assumed)
|
23
|
+
def self.for_mingle_term(mingle_term)
|
24
|
+
@@categories_by_mingle_term[mingle_term]
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
term
|
17
29
|
end
|
18
30
|
|
19
31
|
def ==(other)
|
@@ -30,7 +42,7 @@ module MingleEvents
|
|
30
42
|
|
31
43
|
# The Atom category scheme for all Mingle categories
|
32
44
|
MINGLE_SCHEME = 'http://www.thoughtworks-studios.com/ns/mingle#categories'
|
33
|
-
|
45
|
+
|
34
46
|
# Category for any event sourced by a card
|
35
47
|
CARD = Category.new('card', MINGLE_SCHEME)
|
36
48
|
# Category for any event that is the creation of a new card
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module MingleEvents
|
2
|
+
module Feed
|
3
|
+
|
4
|
+
# Enumerable detail for each change specified in the entry's content section
|
5
|
+
class Changes
|
6
|
+
|
7
|
+
include Enumerable
|
8
|
+
|
9
|
+
def initialize(changes_element)
|
10
|
+
@changes_element = changes_element
|
11
|
+
end
|
12
|
+
|
13
|
+
def each
|
14
|
+
(@changes ||= parse_changes).each{|c| yield c}
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def parse_changes
|
20
|
+
changes = []
|
21
|
+
@changes_element.search("change").map do |change_element|
|
22
|
+
category = Category.for_mingle_term(change_element["type"])
|
23
|
+
changes << Change.new(category).build(change_element)
|
24
|
+
end
|
25
|
+
changes
|
26
|
+
end
|
27
|
+
|
28
|
+
class Change
|
29
|
+
|
30
|
+
def initialize(category)
|
31
|
+
@category = category
|
32
|
+
end
|
33
|
+
|
34
|
+
def build(element)
|
35
|
+
element_to_hash(element)
|
36
|
+
|
37
|
+
raw_hash_from_xml = element_to_hash(element)
|
38
|
+
|
39
|
+
raw_hash_from_xml[:change].merge({
|
40
|
+
:category => @category,
|
41
|
+
:type => @category
|
42
|
+
})
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def element_to_hash(element, hash = {})
|
48
|
+
hash_for_element = (hash[element.name.to_sym] ||= {})
|
49
|
+
|
50
|
+
element.attribute_nodes.each do |a|
|
51
|
+
hash_for_element[a.name.to_sym] = a.value
|
52
|
+
end
|
53
|
+
|
54
|
+
element.children.each do |child|
|
55
|
+
next unless child.is_a?(Nokogiri::XML::Element)
|
56
|
+
|
57
|
+
if child.children.count{|c| c.is_a?(Nokogiri::XML::Element)} > 0
|
58
|
+
element_to_hash(child, hash_for_element)
|
59
|
+
else
|
60
|
+
hash_for_element[child.name.to_sym] = if child["nil"] && child["nil"] == "true"
|
61
|
+
nil
|
62
|
+
else
|
63
|
+
child.inner_text
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
hash
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -9,6 +9,10 @@ module MingleEvents
|
|
9
9
|
def initialize(entry_element)
|
10
10
|
@entry_element = entry_element
|
11
11
|
end
|
12
|
+
|
13
|
+
def self.from_snippet(entry_xml)
|
14
|
+
self.new(Nokogiri::XML(entry_xml).remove_namespaces!)
|
15
|
+
end
|
12
16
|
|
13
17
|
# The raw entry XML from the Atom feed
|
14
18
|
def raw_xml
|
@@ -18,7 +22,7 @@ module MingleEvents
|
|
18
22
|
# The Atom entry's id value. This is the one true identifier for the entry,
|
19
23
|
# and therefore the event.
|
20
24
|
def entry_id
|
21
|
-
@entry_id ||= @entry_element.at(
|
25
|
+
@entry_id ||= @entry_element.at("id").inner_text
|
22
26
|
end
|
23
27
|
alias :event_id :entry_id
|
24
28
|
|
@@ -29,20 +33,30 @@ module MingleEvents
|
|
29
33
|
|
30
34
|
# The time at which entry was created, i.e., the event was triggered
|
31
35
|
def updated
|
32
|
-
@updated ||= Time.parse(@entry_element.at(
|
36
|
+
@updated ||= Time.parse(@entry_element.at("updated").inner_text)
|
33
37
|
end
|
34
38
|
|
35
39
|
# The user who created the entry (triggered the event), i.e., changed project data in Mingle
|
36
40
|
def author
|
37
|
-
@author ||= Author.new(@entry_element.at(
|
41
|
+
@author ||= Author.new(@entry_element.at("author"))
|
38
42
|
end
|
39
43
|
|
40
44
|
# The set of Atom categoies describing the entry
|
41
45
|
def categories
|
42
|
-
@categories ||= @entry_element.search(
|
43
|
-
Category.new(category_element
|
46
|
+
@categories ||= @entry_element.search("category").map do |category_element|
|
47
|
+
Category.new(category_element["term"], category_element["scheme"])
|
44
48
|
end
|
45
49
|
end
|
50
|
+
|
51
|
+
# The array of changes for this entry. Each change is a hash with redundant :type and
|
52
|
+
# :category entries specifying the category to which the change maps.
|
53
|
+
# Change detail is contained in nested hashes with keys mapping exactly to the XML
|
54
|
+
# as described in http://www.thoughtworks-studios.com/mingle/3.3/help/mingle_api_events.html.
|
55
|
+
# The data in the change hashes reflect only what is in the XML as encriching them would
|
56
|
+
# require potentially many calls to the Mingle server resulting in very slow processing.
|
57
|
+
def changes
|
58
|
+
@changes ||= Changes.new(@entry_element.at("content/changes"))
|
59
|
+
end
|
46
60
|
|
47
61
|
# Whether the entry/event was sourced by a Mingle card
|
48
62
|
def card?
|
@@ -60,7 +74,7 @@ module MingleEvents
|
|
60
74
|
# The version number of the card or page that was created by this event. (For now, only
|
61
75
|
# working with cards.)
|
62
76
|
def version
|
63
|
-
@version ||= CGI.parse(URI.parse(card_version_resource_uri).query)[
|
77
|
+
@version ||= CGI.parse(URI.parse(card_version_resource_uri).query)["version"].first.to_i
|
64
78
|
end
|
65
79
|
|
66
80
|
# The resource URI for the card version that was created by this event. Throws error if not card event.
|
@@ -94,14 +108,14 @@ module MingleEvents
|
|
94
108
|
"link[@rel='http://www.thoughtworks-studios.com/ns/mingle#event-source'][@type='application/vnd.mingle+xml']"
|
95
109
|
)
|
96
110
|
# TODO: improve this bit of parsing :)
|
97
|
-
card_number_element
|
111
|
+
card_number_element["href"].split('/').last.split('.')[0..-2].join.to_i
|
98
112
|
end
|
99
113
|
|
100
114
|
def parse_card_version_resource_uri
|
101
115
|
card_number_element = @entry_element.at(
|
102
116
|
"link[@rel='http://www.thoughtworks-studios.com/ns/mingle#version'][@type='application/vnd.mingle+xml']"
|
103
117
|
)
|
104
|
-
card_number_element
|
118
|
+
card_number_element["href"]
|
105
119
|
end
|
106
120
|
|
107
121
|
end
|
@@ -14,45 +14,24 @@ module MingleEvents
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def entries
|
17
|
-
@entries ||= page_as_document.search('
|
17
|
+
@entries ||= page_as_document.search('entry').map do |entry_element|
|
18
18
|
Entry.new(entry_element)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
def next
|
23
|
-
next_url_element = page_as_document.at("
|
23
|
+
next_url_element = page_as_document.at("link[@rel='next']")
|
24
24
|
if next_url_element.nil?
|
25
25
|
nil
|
26
26
|
else
|
27
|
-
Page.new(next_url_element
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def previous
|
32
|
-
previous_url_element = page_as_document.at("feed/link[@rel='previous']")
|
33
|
-
if previous_url_element.nil?
|
34
|
-
nil
|
35
|
-
else
|
36
|
-
Page.new(previous_url_element.attribute('href').text, @mingle_access)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def archived?
|
41
|
-
URI.parse(url).query && url == page_as_document.at("feed/link[@rel='self']").attribute('href').text
|
42
|
-
end
|
43
|
-
|
44
|
-
def closest_archived_page
|
45
|
-
if archived?
|
46
|
-
self
|
47
|
-
else
|
48
|
-
self.next
|
27
|
+
Page.new(next_url_element["href"], @mingle_access)
|
49
28
|
end
|
50
29
|
end
|
51
30
|
|
52
31
|
private
|
53
32
|
|
54
33
|
def page_as_document
|
55
|
-
@page_as_document ||= Nokogiri::XML(@mingle_access.fetch_page(@url))
|
34
|
+
@page_as_document ||= Nokogiri::XML(@mingle_access.fetch_page(@url)).remove_namespaces!
|
56
35
|
end
|
57
36
|
|
58
37
|
end
|
@@ -81,7 +81,7 @@ module MingleEvents
|
|
81
81
|
|
82
82
|
def current_state_entry(info_file_key)
|
83
83
|
if info_file = load_current_state[info_file_key]
|
84
|
-
|
84
|
+
Feed::Entry.from_snippet(YAML.load(File.new(info_file))[:entry_xml])
|
85
85
|
else
|
86
86
|
nil
|
87
87
|
end
|
@@ -106,7 +106,7 @@ module MingleEvents
|
|
106
106
|
current_state = load_current_state
|
107
107
|
last_fetched_entry = if current_state[:last_fetched_entry_info_file]
|
108
108
|
last_fetched_entry_info = YAML.load(File.new(current_state[:last_fetched_entry_info_file]))
|
109
|
-
Feed::Entry.
|
109
|
+
Feed::Entry.from_snippet(last_fetched_entry_info[:entry_xml])
|
110
110
|
else
|
111
111
|
nil
|
112
112
|
end
|
@@ -120,10 +120,6 @@ module MingleEvents
|
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
-
def entry_for_xml(entry_xml)
|
124
|
-
Feed::Entry.new(Nokogiri::XML(entry_xml).at('/entry'))
|
125
|
-
end
|
126
|
-
|
127
123
|
class Entries
|
128
124
|
|
129
125
|
include Enumerable
|
@@ -132,16 +128,12 @@ module MingleEvents
|
|
132
128
|
@first_info_file = first_info_file
|
133
129
|
@last_info_file = last_info_file
|
134
130
|
end
|
135
|
-
|
136
|
-
def entry_for_xml(entry_xml)
|
137
|
-
Feed::Entry.new(Nokogiri::XML(entry_xml).at('/entry'))
|
138
|
-
end
|
139
|
-
|
131
|
+
|
140
132
|
def each(&block)
|
141
133
|
current_file = @first_info_file
|
142
134
|
while current_file
|
143
135
|
current_entry_info = YAML.load(File.new(current_file))
|
144
|
-
yield(
|
136
|
+
yield(Feed::Entry.from_snippet(current_entry_info[:entry_xml]))
|
145
137
|
break if File.expand_path(current_file) == File.expand_path(@last_info_file)
|
146
138
|
current_file = current_entry_info[:next_entry_file_path]
|
147
139
|
end
|
@@ -6,15 +6,15 @@ module MingleEvents
|
|
6
6
|
class AuthorTest < Test::Unit::TestCase
|
7
7
|
|
8
8
|
def test_parse_attributes
|
9
|
-
|
10
|
-
<author
|
9
|
+
author_xml = %{
|
10
|
+
<author >
|
11
11
|
<name>Sammy Soso</name>
|
12
12
|
<email>sammy@example.com</email>
|
13
13
|
<uri>https://mingle.example.com/api/v2/users/233.xml</uri>
|
14
14
|
<mingle:icon>https://mingle.example.com/user/icon/233/profile.jpg</mingle:icon>
|
15
|
-
</author>
|
16
|
-
|
17
|
-
author = Author.
|
15
|
+
</author>
|
16
|
+
}
|
17
|
+
author = Author.from_snippet(author_xml)
|
18
18
|
assert_equal("Sammy Soso", author.name)
|
19
19
|
assert_equal("sammy@example.com", author.email)
|
20
20
|
assert_equal("https://mingle.example.com/api/v2/users/233.xml", author.uri)
|
@@ -22,11 +22,12 @@ module MingleEvents
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_parse_attributes_when_no_optional_fields
|
25
|
-
|
26
|
-
<author
|
25
|
+
author_xml = %{
|
26
|
+
<author>
|
27
27
|
<name>Sammy Soso</name>
|
28
|
-
</author>
|
29
|
-
|
28
|
+
</author>
|
29
|
+
}
|
30
|
+
author = Author.from_snippet(author_xml)
|
30
31
|
assert_equal("Sammy Soso", author.name)
|
31
32
|
assert_nil(author.email)
|
32
33
|
assert_nil(author.uri)
|
@@ -13,6 +13,10 @@ module MingleEvents
|
|
13
13
|
assert_not_equal(Category::CARD, Object.new)
|
14
14
|
assert_equal(:foo, {Category::CARD => :foo}[Category.new('card', 'http://www.thoughtworks-studios.com/ns/mingle#categories')])
|
15
15
|
end
|
16
|
+
|
17
|
+
def test_can_lookup_by_mingle_term
|
18
|
+
assert_equal(Category::CARD_CREATION, Category.for_mingle_term('card-creation'))
|
19
|
+
end
|
16
20
|
|
17
21
|
end
|
18
22
|
|
@@ -0,0 +1,344 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'test_helper'))
|
2
|
+
|
3
|
+
module MingleEvents
|
4
|
+
module Feed
|
5
|
+
|
6
|
+
class ChangesTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_parse_multiple_changes
|
9
|
+
element_xml_text = %{
|
10
|
+
<entry>
|
11
|
+
<content type="application/vnd.mingle+xml">
|
12
|
+
<changes>
|
13
|
+
<change type="card-creation"/>
|
14
|
+
<change type="card-type-change">
|
15
|
+
<old_value nil="true"></old_value>
|
16
|
+
<new_value>
|
17
|
+
<card_type url="https://mingle.example.com/api/v2/projects/atlas/card_types/27.xml">
|
18
|
+
<name>Defect</name>
|
19
|
+
</card_type>
|
20
|
+
</new_value>
|
21
|
+
</change>
|
22
|
+
<change type="name-change">
|
23
|
+
<old_value nil="true"></old_value>
|
24
|
+
<new_value>A New Card</new_value>
|
25
|
+
</change>
|
26
|
+
</changes>
|
27
|
+
</content>
|
28
|
+
</entry>}
|
29
|
+
entry = Entry.from_snippet(element_xml_text)
|
30
|
+
|
31
|
+
# check that all the changes are built
|
32
|
+
assert_equal 3, entry.changes.count
|
33
|
+
[Category::CARD_CREATION, Category::CARD_TYPE_CHANGE, Category::NAME_CHANGE].each do |change_type|
|
34
|
+
assert entry.changes.find{|c| c[:category] == change_type}
|
35
|
+
end
|
36
|
+
|
37
|
+
# check that a change's detail is built
|
38
|
+
card_type_change = entry.changes.find{|c| c[:category] == Category::CARD_TYPE_CHANGE}
|
39
|
+
assert_equal('Defect', card_type_change[:new_value][:card_type][:name])
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_parse_name_change_from_nil
|
43
|
+
element_xml_text = %{
|
44
|
+
<entry>
|
45
|
+
<content type="application/vnd.mingle+xml">
|
46
|
+
<changes>
|
47
|
+
<change type="name-change">
|
48
|
+
<old_value nil="true" />
|
49
|
+
<new_value>Basic email integration</new_value>
|
50
|
+
</change
|
51
|
+
</changes>
|
52
|
+
</content>
|
53
|
+
</entry>}
|
54
|
+
entry = Entry.from_snippet(element_xml_text)
|
55
|
+
|
56
|
+
change = entry.changes.first
|
57
|
+
assert_equal(Category::NAME_CHANGE, change[:type])
|
58
|
+
assert_equal(Category::NAME_CHANGE, change[:category])
|
59
|
+
assert_nil change[:old_value]
|
60
|
+
assert_equal("Basic email integration", change[:new_value])
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_parse_name_change
|
64
|
+
element_xml_text = %{
|
65
|
+
<entry>
|
66
|
+
<content type="application/vnd.mingle+xml">
|
67
|
+
<changes>
|
68
|
+
<change type="name-change">
|
69
|
+
<old_value>Work with email</old_value>
|
70
|
+
<new_value>Basic email integration</new_value>
|
71
|
+
</change>
|
72
|
+
</changes>
|
73
|
+
</content>
|
74
|
+
</entry>}
|
75
|
+
entry = Entry.from_snippet(element_xml_text)
|
76
|
+
|
77
|
+
change = entry.changes.first
|
78
|
+
assert_equal(Category::NAME_CHANGE, change[:type])
|
79
|
+
assert_equal(Category::NAME_CHANGE, change[:category])
|
80
|
+
assert_equal("Work with email", change[:old_value])
|
81
|
+
assert_equal("Basic email integration", change[:new_value])
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_parse_type_info_when_no_custom_builder_specified
|
85
|
+
element_xml_text = %{
|
86
|
+
<entry>
|
87
|
+
<content type="application/vnd.mingle+xml">
|
88
|
+
<changes>
|
89
|
+
<change type="card-creation"/>
|
90
|
+
</changes>
|
91
|
+
</content>
|
92
|
+
</entry>}
|
93
|
+
entry = Entry.from_snippet(element_xml_text)
|
94
|
+
|
95
|
+
assert_equal(Category::CARD_CREATION, entry.changes.first[:type])
|
96
|
+
assert_equal(Category::CARD_CREATION, entry.changes.first[:category])
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_parse_card_type_change_from_nil
|
100
|
+
element_xml_text = %{
|
101
|
+
<entry>
|
102
|
+
<content type="application/vnd.mingle+xml">
|
103
|
+
<changes>
|
104
|
+
<change type="card-type-change">
|
105
|
+
<old_value nil="true"></old_value>
|
106
|
+
<new_value>
|
107
|
+
<card_type url="https://mingle.example.com/api/v2/projects/atlas/card_types/27.xml">
|
108
|
+
<name>Defect</name>
|
109
|
+
</card_type>
|
110
|
+
</new_value>
|
111
|
+
</change>
|
112
|
+
</changes>
|
113
|
+
</content>
|
114
|
+
</entry>}
|
115
|
+
entry = Entry.from_snippet(element_xml_text)
|
116
|
+
|
117
|
+
change = entry.changes.first
|
118
|
+
|
119
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:type])
|
120
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:category])
|
121
|
+
assert_nil change[:old_value]
|
122
|
+
assert_equal("Defect", change[:new_value][:card_type][:name])
|
123
|
+
assert_equal("https://mingle.example.com/api/v2/projects/atlas/card_types/27.xml", change[:new_value][:card_type][:url])
|
124
|
+
end
|
125
|
+
|
126
|
+
def test_parse_card_type_change
|
127
|
+
element_xml_text = %{
|
128
|
+
<entry>
|
129
|
+
<content type="application/vnd.mingle+xml">
|
130
|
+
<changes>
|
131
|
+
<change type="card-type-change">
|
132
|
+
<old_value>
|
133
|
+
<card_type url="https://mingle.example.com/api/v2/projects/atlas/card_types/30.xml">
|
134
|
+
<name>Story</name
|
135
|
+
</card_type>
|
136
|
+
</old_value>
|
137
|
+
<new_value>
|
138
|
+
<card_type url="https://mingle.example.com/api/v2/projects/atlas/card_types/27.xml">
|
139
|
+
<name>Defect</name>
|
140
|
+
</card_type>
|
141
|
+
</new_value>
|
142
|
+
</change>
|
143
|
+
</changes>
|
144
|
+
</content>
|
145
|
+
</entry>}
|
146
|
+
entry = Entry.from_snippet(element_xml_text)
|
147
|
+
|
148
|
+
change = entry.changes.first
|
149
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:type])
|
150
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:category])
|
151
|
+
assert_equal("Story", change[:old_value][:card_type][:name])
|
152
|
+
assert_equal("https://mingle.example.com/api/v2/projects/atlas/card_types/30.xml", change[:old_value][:card_type][:url])
|
153
|
+
assert_equal("Defect", change[:new_value][:card_type][:name])
|
154
|
+
assert_equal("https://mingle.example.com/api/v2/projects/atlas/card_types/27.xml", change[:new_value][:card_type][:url])
|
155
|
+
end
|
156
|
+
|
157
|
+
def test_parse_card_type_change_to_deleted_type
|
158
|
+
element_xml_text = %{
|
159
|
+
<entry>
|
160
|
+
<content type="application/vnd.mingle+xml">
|
161
|
+
<changes>
|
162
|
+
<change type="card-type-change">
|
163
|
+
<old_value>
|
164
|
+
<card_type url="https://mingle.example.com/api/v2/projects/atlas/card_types/30.xml">
|
165
|
+
<name>Story</name>
|
166
|
+
</card_type>
|
167
|
+
</old_value>
|
168
|
+
<new_value>
|
169
|
+
<deleted_card_type>
|
170
|
+
<name>Card</name>
|
171
|
+
</deleted_card_type>
|
172
|
+
</new_value>
|
173
|
+
</change>
|
174
|
+
</changes>
|
175
|
+
</content>
|
176
|
+
</entry>}
|
177
|
+
entry = Entry.from_snippet(element_xml_text)
|
178
|
+
|
179
|
+
change = entry.changes.first
|
180
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:type])
|
181
|
+
assert_equal(Category::CARD_TYPE_CHANGE, change[:category])
|
182
|
+
assert_equal("Story", change[:old_value][:card_type][:name])
|
183
|
+
assert_equal("https://mingle.example.com/api/v2/projects/atlas/card_types/30.xml", change[:old_value][:card_type][:url])
|
184
|
+
assert_equal("Card", change[:new_value][:deleted_card_type][:name])
|
185
|
+
assert_equal(nil, change[:new_value][:deleted_card_type][:url])
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_parse_card_property_change
|
189
|
+
element_xml_text = %{
|
190
|
+
<entry>
|
191
|
+
<content type="application/vnd.mingle+xml">
|
192
|
+
<changes>
|
193
|
+
<change type="property-change">
|
194
|
+
<property_definition
|
195
|
+
url="http://mingle.example.com/api/v2/projects/atlas/property_definitions/10418.xml">
|
196
|
+
<name>Priority</name>
|
197
|
+
<position nil="true"></position>
|
198
|
+
<data_type>string</data_type>
|
199
|
+
<is_numeric type="boolean">false</is_numeric>
|
200
|
+
</property_definition>
|
201
|
+
<old_value>nice</old_value>
|
202
|
+
<new_value>must</new_value>
|
203
|
+
</change>
|
204
|
+
</changes>
|
205
|
+
</content>
|
206
|
+
</entry>}
|
207
|
+
entry = Entry.from_snippet(element_xml_text)
|
208
|
+
|
209
|
+
change = entry.changes.first
|
210
|
+
assert_equal(Category::PROPERTY_CHANGE, change[:type])
|
211
|
+
assert_equal(Category::PROPERTY_CHANGE, change[:category])
|
212
|
+
assert_equal(
|
213
|
+
"http://mingle.example.com/api/v2/projects/atlas/property_definitions/10418.xml",
|
214
|
+
change[:property_definition][:url]
|
215
|
+
)
|
216
|
+
assert_equal("Priority", change[:property_definition][:name])
|
217
|
+
assert_equal("nice", change[:old_value])
|
218
|
+
assert_equal("must", change[:new_value])
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_parse_card_property_change_from_nil
|
222
|
+
element_xml_text = %{
|
223
|
+
<entry>
|
224
|
+
<content type="application/vnd.mingle+xml">
|
225
|
+
<changes>
|
226
|
+
<change type="property-change">
|
227
|
+
<property_definition
|
228
|
+
url="http://mingle.example.com/api/v2/projects/atlas/property_definitions/10418.xml">
|
229
|
+
<name>Priority</name>
|
230
|
+
<position nil="true"></position>
|
231
|
+
<data_type>string</data_type>
|
232
|
+
<is_numeric type="boolean">false</is_numeric>
|
233
|
+
</property_definition>
|
234
|
+
<old_value nil="true"></old_value>
|
235
|
+
<new_value>must</new_value>
|
236
|
+
</change>
|
237
|
+
</changes>
|
238
|
+
</content>
|
239
|
+
</entry>}
|
240
|
+
entry = Entry.from_snippet(element_xml_text)
|
241
|
+
|
242
|
+
change = entry.changes.first
|
243
|
+
assert_nil(change[:old_value])
|
244
|
+
assert_equal("must", change[:new_value])
|
245
|
+
end
|
246
|
+
|
247
|
+
def test_parse_card_property_change_to_nil
|
248
|
+
element_xml_text = %{
|
249
|
+
<entry>
|
250
|
+
<content type="application/vnd.mingle+xml">
|
251
|
+
<changes>
|
252
|
+
<change type="property-change">
|
253
|
+
<property_definition
|
254
|
+
url="http://mingle.example.com/api/v2/projects/atlas/property_definitions/10418.xml">
|
255
|
+
<name>Priority</name>
|
256
|
+
<position nil="true"></position>
|
257
|
+
<data_type>string</data_type>
|
258
|
+
<is_numeric type="boolean">false</is_numeric>
|
259
|
+
</property_definition>
|
260
|
+
<old_value>nice</old_value>
|
261
|
+
<new_value nil="true"></new_value>
|
262
|
+
</change>
|
263
|
+
</changes>
|
264
|
+
</content>
|
265
|
+
</entry>}
|
266
|
+
entry = Entry.from_snippet(element_xml_text)
|
267
|
+
|
268
|
+
change = entry.changes.first
|
269
|
+
assert_equal("nice", change[:old_value])
|
270
|
+
assert_nil(change[:new_value])
|
271
|
+
end
|
272
|
+
|
273
|
+
def test_foo
|
274
|
+
foo = %{
|
275
|
+
<entry>
|
276
|
+
<id>https://mingle09.thoughtworks.com/projects/mingle/events/index/1344945</id>
|
277
|
+
<title>story #67 CRUD Project created</title>
|
278
|
+
<updated>2006-11-13T05:45:06Z</updated>
|
279
|
+
<author>
|
280
|
+
<name>Jon Tirsen</name>
|
281
|
+
<email>jtirsen@thoughtworks.com</email>
|
282
|
+
<uri>https://mingle09.thoughtworks.com/api/v2/users/10040.xml</uri>
|
283
|
+
</author>
|
284
|
+
<link href="https://mingle09.thoughtworks.com/api/v2/projects/mingle/cards/67.xml" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="application/vnd.mingle+xml" title="story #67"/>
|
285
|
+
<link href="https://mingle09.thoughtworks.com/projects/mingle/cards/67" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="text/html" title="story #67"/>
|
286
|
+
<link href="https://mingle09.thoughtworks.com/api/v2/projects/mingle/cards/67.xml?version=1" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="application/vnd.mingle+xml" title="story #67 (v1)"/>
|
287
|
+
<link href="https://mingle09.thoughtworks.com/projects/mingle/cards/67?version=1" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="text/html" title="story #67 (v1)"/>
|
288
|
+
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
289
|
+
<category term="card-creation" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
290
|
+
<category term="card-type-change" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
291
|
+
<category term="description-change" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
292
|
+
<category term="name-change" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
293
|
+
<category term="property-change" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
294
|
+
<content type="application/vnd.mingle+xml">
|
295
|
+
<changes xmlns="http://www.thoughtworks-studios.com/ns/mingle">
|
296
|
+
<change type="card-creation"/>
|
297
|
+
<change type="card-type-change">
|
298
|
+
<old_value nil="true"/>
|
299
|
+
<new_value>
|
300
|
+
<card_type url="https://mingle09.thoughtworks.com/api/v2/projects/mingle/card_types/10134.xml">
|
301
|
+
<name>story</name>
|
302
|
+
</card_type>
|
303
|
+
</new_value>
|
304
|
+
</change>
|
305
|
+
<change type="description-change">
|
306
|
+
</change>
|
307
|
+
<change type="name-change">
|
308
|
+
<old_value nil="true"/>
|
309
|
+
<new_value>CRUD Project</new_value>
|
310
|
+
</change>
|
311
|
+
<change type="property-change">
|
312
|
+
<property_definition url="https://mingle09.thoughtworks.com/api/v2/projects/mingle/property_definitions/10380.xml">
|
313
|
+
<name>release</name>
|
314
|
+
<position nil="true"/>
|
315
|
+
<data_type>string</data_type>
|
316
|
+
<is_numeric type="boolean">false</is_numeric>
|
317
|
+
</property_definition>
|
318
|
+
<old_value nil="true"/>
|
319
|
+
<new_value>0.92</new_value>
|
320
|
+
</change>
|
321
|
+
<change type="property-change">
|
322
|
+
<property_definition url="https://mingle09.thoughtworks.com/api/v2/projects/mingle/property_definitions/10381.xml">
|
323
|
+
<name>Priority</name>
|
324
|
+
<position nil="true"/>
|
325
|
+
<data_type>string</data_type>
|
326
|
+
<is_numeric type="boolean">false</is_numeric>
|
327
|
+
</property_definition>
|
328
|
+
<old_value nil="true"/>
|
329
|
+
<new_value>Should</new_value>
|
330
|
+
</change>
|
331
|
+
</changes>
|
332
|
+
</content>
|
333
|
+
</entry>
|
334
|
+
}
|
335
|
+
|
336
|
+
entry = Entry.from_snippet(foo)
|
337
|
+
entry.changes.each do |c|
|
338
|
+
puts c
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
@@ -7,7 +7,7 @@ module MingleEvents
|
|
7
7
|
|
8
8
|
def test_parse_basic_attributes
|
9
9
|
element_xml_text = %{
|
10
|
-
<entry
|
10
|
+
<entry>
|
11
11
|
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
12
12
|
<title>Page Special:HeaderActions changed</title>
|
13
13
|
<updated>2011-02-03T08:12:42Z</updated>
|
@@ -16,10 +16,9 @@ module MingleEvents
|
|
16
16
|
<email>sammy@example.com</email>
|
17
17
|
<uri>https://mingle.example.com/api/v2/users/233.xml</uri>
|
18
18
|
</author>
|
19
|
-
</entry>
|
20
|
-
|
21
|
-
|
22
|
-
entry = Entry.new(element)
|
19
|
+
</entry>
|
20
|
+
}
|
21
|
+
entry = Entry.from_snippet(element_xml_text)
|
23
22
|
# assert_equal(element_xml_text.inspect, entry.raw_xml.inspect)
|
24
23
|
assert_equal("https://mingle.example.com/projects/mingle/events/index/234443", entry.entry_id)
|
25
24
|
assert_equal("Page Special:HeaderActions changed", entry.title)
|
@@ -29,13 +28,11 @@ module MingleEvents
|
|
29
28
|
|
30
29
|
def test_parse_categories
|
31
30
|
element_xml_text = %{
|
32
|
-
<entry
|
31
|
+
<entry>
|
33
32
|
<category term="foo" scheme='http://tws.com/ns#mingle' />
|
34
33
|
<category term="bar" scheme="http://tws.com/ns#go" />
|
35
34
|
</entry>}
|
36
|
-
|
37
|
-
|
38
|
-
entry = Entry.new(element)
|
35
|
+
entry = Entry.from_snippet(element_xml_text)
|
39
36
|
assert_equal(
|
40
37
|
[Category.new('foo', 'http://tws.com/ns#mingle'), Category.new('bar', 'http://tws.com/ns#go')],
|
41
38
|
entry.categories
|
@@ -48,29 +45,25 @@ module MingleEvents
|
|
48
45
|
# that the card number is derived from a single, precise position
|
49
46
|
|
50
47
|
element_xml_text = %{
|
51
|
-
<entry
|
48
|
+
<entry>
|
52
49
|
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
53
50
|
<link href="https://mingle.example.com/projects/atlas/cards/102" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="text/html" title="bug #103"/>
|
54
51
|
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="application/vnd.mingle+xml" title="bug #105 (v7)"/>
|
55
52
|
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/106.xml" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="application/vnd.mingle+xml" title="bug #107"/>
|
56
53
|
<link href="https://mingle.example.com/projects/atlas/cards/108?version=17" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="text/html" title="bug #109 (v7)"/>
|
57
54
|
</entry>}
|
58
|
-
|
59
|
-
|
60
|
-
entry = Entry.new(element)
|
55
|
+
entry = Entry.from_snippet(element_xml_text)
|
61
56
|
assert_equal(106, entry.card_number)
|
62
57
|
assert_equal(7, entry.version)
|
63
58
|
end
|
64
59
|
|
65
60
|
def test_card_number_and_version_throws_error_when_event_not_related_to_a_card
|
66
61
|
element_xml_text = %{
|
67
|
-
<entry
|
62
|
+
<entry>
|
68
63
|
<category term="page" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
69
64
|
</entry>}
|
70
|
-
|
71
|
-
|
72
|
-
entry = Entry.new(element)
|
73
|
-
|
65
|
+
entry = Entry.from_snippet(element_xml_text)
|
66
|
+
|
74
67
|
begin
|
75
68
|
entry.card_number
|
76
69
|
fail("Should not have been able to retrieve a card number for non card-related event!")
|
@@ -93,27 +86,23 @@ module MingleEvents
|
|
93
86
|
# that the card number is derived from a single, precise position
|
94
87
|
|
95
88
|
element_xml_text = %{
|
96
|
-
<entry
|
89
|
+
<entry>
|
97
90
|
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
98
91
|
<link href="https://mingle.example.com/projects/atlas/cards/102" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="text/html" title="bug #103"/>
|
99
92
|
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="application/vnd.mingle+xml" title="bug #105 (v7)"/>
|
100
93
|
<link href="https://mingle.example.com/api/v2/projects/atlas/cards/106.xml" rel="http://www.thoughtworks-studios.com/ns/mingle#event-source" type="application/vnd.mingle+xml" title="bug #107"/>
|
101
94
|
<link href="https://mingle.example.com/projects/atlas/cards/108?version=7" rel="http://www.thoughtworks-studios.com/ns/mingle#version" type="text/html" title="bug #109 (v7)"/>
|
102
95
|
</entry>}
|
103
|
-
|
104
|
-
|
105
|
-
entry = Entry.new(element)
|
96
|
+
entry = Entry.from_snippet(element_xml_text)
|
106
97
|
assert_equal('https://mingle.example.com/api/v2/projects/atlas/cards/104.xml?version=7', entry.card_version_resource_uri)
|
107
98
|
end
|
108
99
|
|
109
100
|
def test_card_version_resource_uri_throws_error_when_not_card_event
|
110
101
|
element_xml_text = %{
|
111
|
-
<entry
|
102
|
+
<entry>
|
112
103
|
<category term="page" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
113
104
|
</entry>}
|
114
|
-
|
115
|
-
|
116
|
-
entry = Entry.new(element)
|
105
|
+
entry = Entry.from_snippet(element_xml_text)
|
117
106
|
begin
|
118
107
|
entry.card_version_resource_uri
|
119
108
|
fail("Should not have been able to retrieve a card version resource URI for non card-related event!")
|
@@ -124,37 +113,35 @@ module MingleEvents
|
|
124
113
|
|
125
114
|
def test_entry_id_aliased_as_event_id
|
126
115
|
element_xml_text = %{
|
127
|
-
<entry
|
116
|
+
<entry>
|
128
117
|
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
129
118
|
</entry>}
|
130
|
-
|
131
|
-
|
132
|
-
entry = Entry.new(element)
|
119
|
+
entry = Entry.from_snippet(element_xml_text)
|
133
120
|
assert_equal('https://mingle.example.com/projects/mingle/events/index/234443', entry.event_id)
|
134
121
|
assert_equal(entry.entry_id, entry.event_id)
|
135
122
|
end
|
136
123
|
|
137
124
|
def test_entry_id_determines_equality
|
138
125
|
element_xml_text_1 = %{
|
139
|
-
<entry
|
126
|
+
<entry>
|
140
127
|
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
141
128
|
<category term="page" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
142
129
|
</entry>}
|
143
|
-
entry_1 = Entry.
|
130
|
+
entry_1 = Entry.from_snippet(element_xml_text_1)
|
144
131
|
|
145
132
|
element_xml_text_2 = %{
|
146
|
-
<entry
|
133
|
+
<entry>
|
147
134
|
<id>https://mingle.example.com/projects/mingle/events/index/234443</id>
|
148
135
|
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
149
136
|
</entry>}
|
150
|
-
entry_2 = Entry.
|
137
|
+
entry_2 = Entry.from_snippet(element_xml_text_2)
|
151
138
|
|
152
139
|
element_xml_text_3 = %{
|
153
|
-
<entry
|
140
|
+
<entry>
|
154
141
|
<id>https://mingle.example.com/projects/mingle/events/index/234</id>
|
155
142
|
<category term="card" scheme="http://www.thoughtworks-studios.com/ns/mingle#categories"/>
|
156
143
|
</entry>}
|
157
|
-
entry_3 = Entry.
|
144
|
+
entry_3 = Entry.from_snippet(element_xml_text_3)
|
158
145
|
|
159
146
|
assert entry_1.eql?(entry_2)
|
160
147
|
assert entry_1 == entry_2
|
@@ -7,7 +7,7 @@ module MingleEvents
|
|
7
7
|
|
8
8
|
def test_entries_are_enumerable
|
9
9
|
latest_entries_page = Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml', stub_mingle_access)
|
10
|
-
|
10
|
+
|
11
11
|
assert_equal([
|
12
12
|
'https://mingle.example.com/projects/atlas/events/index/103',
|
13
13
|
'https://mingle.example.com/projects/atlas/events/index/101',
|
@@ -26,56 +26,7 @@ module MingleEvents
|
|
26
26
|
last_page = Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=1', stub_mingle_access)
|
27
27
|
assert_nil(last_page.next)
|
28
28
|
end
|
29
|
-
|
30
|
-
def test_previous_page_returns_the_page_of_entries_as_specified_by_previous_link
|
31
|
-
current_page = Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=1', stub_mingle_access)
|
32
|
-
previous_page = current_page.previous
|
33
|
-
assert_equal('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=2', previous_page.url)
|
34
|
-
assert_equal('https://mingle.example.com/projects/atlas/events/index/99', previous_page.entries.first.entry_id)
|
35
|
-
end
|
36
|
-
|
37
|
-
def test_previous_page_when_on_latest_entries
|
38
|
-
latest_entries_page = Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml', stub_mingle_access)
|
39
|
-
assert_nil(latest_entries_page.previous)
|
40
|
-
end
|
41
|
-
|
42
|
-
def test_can_determine_whether_archived
|
43
|
-
assert !Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml', stub_mingle_access).archived?
|
44
|
-
assert !Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=3', stub_mingle_access).archived?
|
45
|
-
assert Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=1', stub_mingle_access).archived?
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_can_determine_closest_archived_page
|
49
|
-
assert_equal 'https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=2',
|
50
|
-
Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml', stub_mingle_access).closest_archived_page.url
|
51
|
-
assert_equal 'https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=2',
|
52
|
-
Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=2', stub_mingle_access).closest_archived_page.url
|
53
|
-
end
|
54
|
-
|
55
|
-
def test_can_determine_when_there_is_no_closest_archived_page
|
56
|
-
mingle_access = StubMingleAccess.new
|
57
|
-
mingle_access.register_page_content('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=1',
|
58
|
-
%{
|
59
|
-
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:mingle="http://www.thoughtworks-studios.com/ns/mingle">
|
60
|
-
<link href="https://mingle.example.com/api/v2/projects/event_tester/feeds/events.xml" rel="current"/>
|
61
|
-
<link href="https://mingle.example.com/api/v2/projects/event_tester/feeds/events.xml" rel="self"/>
|
62
|
-
<entry>
|
63
|
-
<id>https://mingle.example.com/projects/event_tester/events/index/390</id>
|
64
|
-
<title>Card #2 Card Two created</title>
|
65
|
-
<updated>2011-08-02T22:27:38Z</updated>
|
66
|
-
<author><name>David</name></author>
|
67
|
-
</entry>
|
68
|
-
<entry>
|
69
|
-
<id>https://mingle.example.com/projects/event_tester/events/index/389</id>
|
70
|
-
<title>Card #1 Card One created</title>
|
71
|
-
<updated>2011-08-02T22:27:36Z</updated>
|
72
|
-
<author><name>David</name></author>
|
73
|
-
</entry>
|
74
|
-
</feed>
|
75
|
-
})
|
76
|
-
assert_nil Page.new('https://mingle.example.com/api/v2/projects/atlas/feeds/events.xml?page=1', mingle_access).closest_archived_page
|
77
|
-
end
|
78
|
-
|
29
|
+
|
79
30
|
end
|
80
31
|
|
81
32
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mingle_events
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- David Rice
|
@@ -59,7 +59,7 @@ files:
|
|
59
59
|
- Gemfile
|
60
60
|
- lib/mingle_events/feed/author.rb
|
61
61
|
- lib/mingle_events/feed/category.rb
|
62
|
-
- lib/mingle_events/feed/
|
62
|
+
- lib/mingle_events/feed/changes.rb
|
63
63
|
- lib/mingle_events/feed/entry.rb
|
64
64
|
- lib/mingle_events/feed/page.rb
|
65
65
|
- lib/mingle_events/feed.rb
|
@@ -83,6 +83,7 @@ files:
|
|
83
83
|
- README.textile
|
84
84
|
- test/mingle_events/feed/author_test.rb
|
85
85
|
- test/mingle_events/feed/category_test.rb
|
86
|
+
- test/mingle_events/feed/changes_test.rb
|
86
87
|
- test/mingle_events/feed/entry_test.rb
|
87
88
|
- test/mingle_events/feed/page_test.rb
|
88
89
|
- test/mingle_events/poller_test.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module MingleEvents
|
2
|
-
module Feed
|
3
|
-
|
4
|
-
# Provides some helpers for pulling values from Nokogiri Elems
|
5
|
-
module ElementSupport
|
6
|
-
|
7
|
-
def element_text(parent_element, element_name, optional = false)
|
8
|
-
element = parent_element.at(".//#{element_name}")
|
9
|
-
if optional && element.nil?
|
10
|
-
nil
|
11
|
-
else
|
12
|
-
element.inner_text
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
19
|
-
end
|