trello_effort_tracker 0.0.3 → 0.0.4
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/.gitignore +2 -1
- data/.travis.yml +0 -1
- data/CHANGELOG +17 -0
- data/Gemfile +7 -4
- data/Gemfile.lock +27 -13
- data/README.md +106 -36
- data/Rakefile +1 -1
- data/config/config.template.yml +0 -1
- data/config/config.yml.trackinguser_for_test +7 -0
- data/lib/patches/trello/card.rb +19 -0
- data/lib/patches/trello/member.rb +5 -5
- data/lib/trello_effort_tracker/tracked_card.rb +17 -10
- data/lib/trello_effort_tracker/tracking/base.rb +82 -0
- data/lib/trello_effort_tracker/tracking/card_done_tracking.rb +10 -0
- data/lib/trello_effort_tracker/tracking/effort_tracking.rb +45 -0
- data/lib/trello_effort_tracker/tracking/estimate_tracking.rb +23 -0
- data/lib/trello_effort_tracker/tracking/invalid_tracking.rb +19 -0
- data/lib/trello_effort_tracker/tracking_factory.rb +22 -0
- data/lib/trello_effort_tracker/trello_authorize.rb +4 -20
- data/lib/trello_effort_tracker/trello_tracker.rb +5 -10
- data/lib/trello_effort_tracker/version.rb +1 -1
- data/lib/trello_effort_tracker.rb +7 -1
- data/spec/integration/trello_tracker_spec.rb +69 -0
- data/spec/patches/trello/card_spec.rb +25 -0
- data/spec/spec_helper.rb +46 -1
- data/spec/support/database_cleaner.rb +12 -0
- data/spec/tracked_card_spec.rb +56 -5
- data/spec/tracking/card_done_tracking_spec.rb +18 -0
- data/spec/tracking/effort_tracking_spec.rb +114 -0
- data/spec/tracking/estimate_tracking_spec.rb +44 -0
- data/spec/tracking_factory_spec.rb +42 -0
- data/spec/trello_authorize_spec.rb +10 -16
- data/spec/trello_configuration_spec.rb +2 -2
- data/trello_effort_tracker.gemspec +12 -0
- metadata +131 -5
- data/lib/trello_effort_tracker/tracking.rb +0 -130
- data/spec/tracking_spec.rb +0 -236
@@ -0,0 +1,23 @@
|
|
1
|
+
module Tracking
|
2
|
+
class EstimateTracking
|
3
|
+
include Base
|
4
|
+
|
5
|
+
#TODO: rename to 'amount' ?
|
6
|
+
#TODO: avoid recomputing estimate every time using a lazy instance variable
|
7
|
+
def estimate
|
8
|
+
estimate = convert_to_hours(raw_estimate)
|
9
|
+
Estimate.new(amount: estimate, date: date, tracking_notification_id: tracking_notification.id)
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_to(card)
|
13
|
+
card.estimates << estimate unless card.contains_estimate?(estimate)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def raw_estimate
|
19
|
+
extract_match_from_raw_tracking(/\[#{DURATION_REGEXP}\]/)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tracking
|
2
|
+
class InvalidTracking
|
3
|
+
include Base
|
4
|
+
|
5
|
+
def add_to(card)
|
6
|
+
# do nothing
|
7
|
+
Trello.logger.warn "Ignoring tracking notification: '#{raw_text}'"
|
8
|
+
end
|
9
|
+
|
10
|
+
def estimate
|
11
|
+
nil
|
12
|
+
end
|
13
|
+
|
14
|
+
def effort
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class TrackingFactory
|
2
|
+
|
3
|
+
DURATION_REGEXP = '(\d+\.?\d*[phdg])'
|
4
|
+
|
5
|
+
@match_pairs = {}
|
6
|
+
|
7
|
+
def self.match(match_pair)
|
8
|
+
@match_pairs.merge!(match_pair)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.build_from(tracking_notification)
|
12
|
+
matching_pair = @match_pairs.find { |regexp, tracking_class| tracking_notification.data['text'] =~ regexp }
|
13
|
+
|
14
|
+
tracking_class = matching_pair ? matching_pair.last : Tracking::InvalidTracking
|
15
|
+
tracking_class.new(tracking_notification)
|
16
|
+
end
|
17
|
+
|
18
|
+
match /\[#{DURATION_REGEXP}\]/ => Tracking::EstimateTracking
|
19
|
+
match /\+#{DURATION_REGEXP}/ => Tracking::EffortTracking
|
20
|
+
match /DONE/ => Tracking::CardDoneTracking
|
21
|
+
|
22
|
+
end
|
@@ -3,30 +3,14 @@ module TrelloAuthorize
|
|
3
3
|
include Trello::Authorization
|
4
4
|
|
5
5
|
def authorize_on_trello(auth_params={})
|
6
|
-
%w{developer_public_key access_token_key
|
6
|
+
%w{developer_public_key access_token_key}.each do |key|
|
7
7
|
auth_params[key] ||= ENV[key] || authorization_params_from_config_file[key]
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
private
|
14
|
-
|
15
|
-
def init_trello(auth_params)
|
16
|
-
ignoring_warnings do
|
17
|
-
Trello::Authorization.const_set(:AuthPolicy, OAuthPolicy)
|
10
|
+
Trello.configure do |config|
|
11
|
+
config.developer_public_key = auth_params["developer_public_key"]
|
12
|
+
config.member_token = auth_params["access_token_key"]
|
18
13
|
end
|
19
|
-
|
20
|
-
OAuthPolicy.consumer_credential = OAuthCredential.new(auth_params["developer_public_key"], auth_params["developer_secret"])
|
21
|
-
OAuthPolicy.token = OAuthCredential.new(auth_params["access_token_key"], nil)
|
22
14
|
end
|
23
15
|
|
24
|
-
def ignoring_warnings(&block)
|
25
|
-
begin
|
26
|
-
v, $VERBOSE = $VERBOSE, nil
|
27
|
-
block.call if block
|
28
|
-
ensure
|
29
|
-
$VERBOSE = v
|
30
|
-
end
|
31
|
-
end
|
32
16
|
end
|
@@ -15,19 +15,18 @@ class TrelloTracker
|
|
15
15
|
Trello.logger.info "Processing #{notifications.size} tracking notifications (from #{oldest} to #{latest}) starting from #{starting_date}..."
|
16
16
|
|
17
17
|
notifications.each do |notification|
|
18
|
-
tracking =
|
18
|
+
tracking = TrackingFactory.build_from(notification)
|
19
19
|
begin
|
20
|
-
|
21
|
-
|
20
|
+
tracked_card = TrackedCard.update_or_create_with(notification.card)
|
21
|
+
tracked_card.add!(tracking)
|
22
22
|
Trello.logger.info tracking
|
23
23
|
|
24
24
|
rescue StandardError => e
|
25
|
-
Trello.logger.
|
26
|
-
Trello.logger.
|
25
|
+
Trello.logger.warn "skipping tracking: #{e.message}".color(:magenta)
|
26
|
+
Trello.logger.debug "#{e.backtrace}"
|
27
27
|
end
|
28
28
|
end
|
29
29
|
Trello.logger.info "Done tracking cards!".color(:green)
|
30
|
-
print_all_cards
|
31
30
|
end
|
32
31
|
|
33
32
|
private
|
@@ -41,8 +40,4 @@ class TrelloTracker
|
|
41
40
|
[dates.min, dates.max]
|
42
41
|
end
|
43
42
|
|
44
|
-
def print_all_cards
|
45
|
-
TrackedCard.all.each { |tracked_card| Trello.logger.info(tracked_card.to_s.color(:yellow)) }
|
46
|
-
end
|
47
|
-
|
48
43
|
end
|
@@ -12,11 +12,17 @@ require 'trello_effort_tracker/tracked_card'
|
|
12
12
|
require 'trello_effort_tracker/member'
|
13
13
|
require 'trello_effort_tracker/estimate'
|
14
14
|
require 'trello_effort_tracker/effort'
|
15
|
-
require 'trello_effort_tracker/tracking'
|
15
|
+
require 'trello_effort_tracker/tracking/base'
|
16
|
+
require 'trello_effort_tracker/tracking/estimate_tracking'
|
17
|
+
require 'trello_effort_tracker/tracking/effort_tracking'
|
18
|
+
require 'trello_effort_tracker/tracking/card_done_tracking'
|
19
|
+
require 'trello_effort_tracker/tracking/invalid_tracking'
|
20
|
+
require 'trello_effort_tracker/tracking_factory'
|
16
21
|
require 'trello_effort_tracker/trello_tracker'
|
17
22
|
require 'trello_effort_tracker/google_docs_exporter'
|
18
23
|
|
19
24
|
require 'patches/trello/member'
|
25
|
+
require 'patches/trello/card'
|
20
26
|
|
21
27
|
TrelloConfiguration::Database.load_env(ENV['MONGOID_ENV'] || "development")
|
22
28
|
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe TrelloTracker do
|
5
|
+
# This integration test works on a real Trello board created just for this purpose
|
6
|
+
# (see https://trello.com/board/testingboard/50ff225c7162123e3600074f)
|
7
|
+
# The board has some cards in todo, one card in progress and one done
|
8
|
+
|
9
|
+
TODO_CARD_ID = "51062b71df2bfec47b0039fb"
|
10
|
+
IN_PROGRESS_CARD_ID = "51062b99d81a343121004046"
|
11
|
+
DONE_CARD_ID = "51062b936d2deed22100157e"
|
12
|
+
ANOTHER_DONE_CARD_ID = "510c46d7c7bc9ac6020007ab"
|
13
|
+
|
14
|
+
let(:config) {
|
15
|
+
# auth params for trackinguser_for_test/testinguser!
|
16
|
+
OpenStruct.new(tracker_username: "trackinguser_for_test",
|
17
|
+
developer_key: "ef7c400e711057d7ba5e00be20139a33",
|
18
|
+
access_token: "9047d8fdbfdc960d41910673e300516cc8630dd4967e9b418fc27e410516362e")
|
19
|
+
}
|
20
|
+
|
21
|
+
it "tracks some estimates and efforts", :needs_valid_configuration => true do
|
22
|
+
with_trackinguser(config.tracker_username) do
|
23
|
+
tracker = TrelloTracker.new("developer_public_key" => config.developer_key, "access_token_key" => config.access_token)
|
24
|
+
tracker.track(DateTime.parse("2013-01-28"))
|
25
|
+
end
|
26
|
+
|
27
|
+
# a card to do
|
28
|
+
todo_card = TrackedCard.find_by_trello_id(TODO_CARD_ID)
|
29
|
+
|
30
|
+
todo_card.estimates.should have(1).estimate
|
31
|
+
todo_card.estimates.first.amount.should == 4
|
32
|
+
todo_card.should_not be_done
|
33
|
+
|
34
|
+
# a card in progress
|
35
|
+
in_progress_card = TrackedCard.find_by_trello_id(IN_PROGRESS_CARD_ID)
|
36
|
+
|
37
|
+
in_progress_card.estimates.should have(1).estimate
|
38
|
+
in_progress_card.estimates.should have(1).effort
|
39
|
+
in_progress_card.estimates.first.amount.should == 5
|
40
|
+
in_progress_card.efforts.first.amount.should == 1
|
41
|
+
in_progress_card.should_not be_done
|
42
|
+
|
43
|
+
# a done card
|
44
|
+
done_card = TrackedCard.find_by_trello_id(DONE_CARD_ID)
|
45
|
+
done_card.total_effort.should == 2
|
46
|
+
done_card.should be_done
|
47
|
+
|
48
|
+
# another done card (this time for the DONE column)
|
49
|
+
another_done_card = TrackedCard.find_by_trello_id(ANOTHER_DONE_CARD_ID)
|
50
|
+
another_done_card.should be_done
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def with_trackinguser(tracking_user, &block)
|
57
|
+
original_tracker = ENV["tracker_username"]
|
58
|
+
original_error_level = Trello.logger.level
|
59
|
+
|
60
|
+
begin
|
61
|
+
ENV["tracker_username"] = tracking_user
|
62
|
+
Trello.logger.level = Logger::WARN
|
63
|
+
block.call unless block.nil?
|
64
|
+
ensure
|
65
|
+
ENV["tracker_username"] = original_tracker
|
66
|
+
Trello.logger.level = original_error_level
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Trello::Card do
|
4
|
+
|
5
|
+
describe "#in_done_column?" do
|
6
|
+
|
7
|
+
let(:trello_card) { Trello::Card.new("name" => "a name", "desc" => "any description") }
|
8
|
+
|
9
|
+
let(:todo_column) { Trello::List.new("name" => "ToDo") }
|
10
|
+
let(:done_column) { Trello::List.new("name" => "Done yesterday") }
|
11
|
+
|
12
|
+
it "is done when is in a DONE column" do
|
13
|
+
trello_card.stub(:list).and_return(done_column)
|
14
|
+
|
15
|
+
trello_card.in_done_column?.should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it "is still not done when is not in DONE column" do
|
19
|
+
trello_card.stub(:list).and_return(todo_column)
|
20
|
+
|
21
|
+
trello_card.in_done_column?.should be_false
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
|
3
|
+
require 'simplecov'
|
4
|
+
SimpleCov.start
|
5
|
+
|
3
6
|
# Set up gems listed in the Gemfile.
|
4
7
|
begin
|
5
8
|
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
|
@@ -11,7 +14,13 @@ rescue Bundler::GemNotFound => e
|
|
11
14
|
exit!
|
12
15
|
end
|
13
16
|
|
14
|
-
Bundler.require
|
17
|
+
Bundler.require(:spec)
|
18
|
+
|
19
|
+
require 'trello_effort_tracker'
|
20
|
+
|
21
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
22
|
+
# in spec/support/ and its subdirectories.
|
23
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
15
24
|
|
16
25
|
RSpec.configure do |configuration|
|
17
26
|
configuration.include Mongoid::Matchers
|
@@ -19,3 +28,39 @@ end
|
|
19
28
|
|
20
29
|
# force test env for the mongodb configuration
|
21
30
|
TrelloConfiguration::Database.load_env("test")
|
31
|
+
|
32
|
+
|
33
|
+
## Spec Helper Methods (TODO: should we move them in a separate file?)
|
34
|
+
|
35
|
+
def unrecognized_notification
|
36
|
+
create_notification(data: { 'text' => '@trackinguser hi there!' })
|
37
|
+
end
|
38
|
+
|
39
|
+
def notification_with_message(message)
|
40
|
+
create_notification(data: { 'text' => message })
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_estimate(time_measurement)
|
44
|
+
create_notification(data: { 'text' => "@trackinguser [1.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_effort(time_measurement)
|
48
|
+
create_notification(data: { 'text' => "@trackinguser +4.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
49
|
+
end
|
50
|
+
|
51
|
+
def with(notification)
|
52
|
+
tracking = TrackingFactory.build_from(notification)
|
53
|
+
yield(tracking)
|
54
|
+
end
|
55
|
+
|
56
|
+
def with_message(notification_message, &block)
|
57
|
+
with(notification_with_message(notification_message), &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_notification(custom_params)
|
61
|
+
params = { data: { 'text' => "@trackinguser +2h" }, date: "2012-10-28T21:06:14.801Z", member_creator: stub(username: "pietrodibello") }
|
62
|
+
params.merge!(custom_params)
|
63
|
+
|
64
|
+
stub(data: params[:data], date: params[:date], member_creator: params[:member_creator]).as_null_object
|
65
|
+
end
|
66
|
+
|
data/spec/tracked_card_spec.rb
CHANGED
@@ -4,11 +4,6 @@ describe TrackedCard do
|
|
4
4
|
|
5
5
|
before(:each) do
|
6
6
|
Date.stub(:today).and_return(Date.parse("2012-11-05"))
|
7
|
-
TrackedCard.delete_all
|
8
|
-
end
|
9
|
-
|
10
|
-
after(:each) do
|
11
|
-
TrackedCard.delete_all
|
12
7
|
end
|
13
8
|
|
14
9
|
subject(:card) { TrackedCard.new(name: "any", short_id: 1234, trello_id: "123123") }
|
@@ -48,6 +43,10 @@ describe TrackedCard do
|
|
48
43
|
describe ".update_or_create_with" do
|
49
44
|
let(:trello_card) { Trello::Card.new("id" => "ABC123", "name" => "a name", "idShort" => 1, "desc" => "any description") }
|
50
45
|
|
46
|
+
before(:each) do
|
47
|
+
Trello::Card.any_instance.stub(:in_done_column?)
|
48
|
+
end
|
49
|
+
|
51
50
|
it "creates a tracked card on a given trello card" do
|
52
51
|
tracked_card = TrackedCard.update_or_create_with(trello_card)
|
53
52
|
|
@@ -72,6 +71,22 @@ describe TrackedCard do
|
|
72
71
|
TrackedCard.all.should be_empty
|
73
72
|
end
|
74
73
|
|
74
|
+
it "tracks the card as done when the original trello card is moved in a DONE column" do
|
75
|
+
trello_card.stub(:in_done_column?).and_return(true)
|
76
|
+
|
77
|
+
tracked_card = TrackedCard.update_or_create_with(trello_card)
|
78
|
+
|
79
|
+
tracked_card.should be_done
|
80
|
+
end
|
81
|
+
|
82
|
+
it "tracks the card as NOT done when the original trello card is moved in a column different from DONE" do
|
83
|
+
trello_card.stub(:in_done_column?).and_return(false)
|
84
|
+
|
85
|
+
tracked_card = TrackedCard.update_or_create_with(trello_card)
|
86
|
+
|
87
|
+
tracked_card.should_not be_done
|
88
|
+
end
|
89
|
+
|
75
90
|
end
|
76
91
|
|
77
92
|
describe ".build_from" do
|
@@ -121,6 +136,42 @@ describe TrackedCard do
|
|
121
136
|
end
|
122
137
|
end
|
123
138
|
|
139
|
+
describe "#add" do
|
140
|
+
let(:card) { TrackedCard.new(name: "a name", trello_id: "123456789") }
|
141
|
+
let(:estimate_tracking) { Tracking::EstimateTracking.new(create_notification(data: { 'text' => "@trackinguser [1h]" })) }
|
142
|
+
|
143
|
+
it "adds an estimate from a tracking estimate notification" do
|
144
|
+
card.add(estimate_tracking)
|
145
|
+
card.estimates.should have(1).estimate
|
146
|
+
end
|
147
|
+
|
148
|
+
it "adds an estimate only once" do
|
149
|
+
card.add(estimate_tracking)
|
150
|
+
card.add(estimate_tracking)
|
151
|
+
|
152
|
+
card.estimates.should have(1).estimate
|
153
|
+
end
|
154
|
+
|
155
|
+
it "is done when has a DONE notification" do
|
156
|
+
card.should_not be_done
|
157
|
+
|
158
|
+
card.add(Tracking::CardDoneTracking.new(stub(:notification)))
|
159
|
+
card.should be_done
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "#add!" do
|
165
|
+
let(:card) { TrackedCard.new(name: "a name", trello_id: "123456789", short_id: "123") }
|
166
|
+
|
167
|
+
it "saves the tracked card after adding the tracking" do
|
168
|
+
any_tracking = Tracking::EstimateTracking.new(create_notification(data: { 'text' => "@trackinguser [1h]" }))
|
169
|
+
|
170
|
+
card.add!(any_tracking)
|
171
|
+
card.reload.should_not be_nil
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
124
175
|
describe "#total_effort" do
|
125
176
|
it "is zero when there's no effort" do
|
126
177
|
card.total_effort.should == 0
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Tracking
|
4
|
+
describe CardDoneTracking do
|
5
|
+
|
6
|
+
describe "#add_to" do
|
7
|
+
it "marks the card as done" do
|
8
|
+
card = TrackedCard.new
|
9
|
+
|
10
|
+
done_tracking = TrackingFactory.build_from(notification_with_message("DONE"))
|
11
|
+
done_tracking.add_to(card)
|
12
|
+
|
13
|
+
card.done?.should be_true
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Tracking
|
4
|
+
describe EffortTracking do
|
5
|
+
|
6
|
+
describe "#effort" do
|
7
|
+
|
8
|
+
%w{pietrodibello michelepangrazzi alessandrodescovi michelevincenzi}.each do |username|
|
9
|
+
let(username.to_sym) { Member.new(username: username) }
|
10
|
+
end
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
Trello::Member.stub(:find).and_return(Member.new(username: "any"))
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is nil when the notification does not contain an estimate" do
|
17
|
+
with(unrecognized_notification) { |tracking| tracking.effort.should be_nil }
|
18
|
+
end
|
19
|
+
|
20
|
+
it "does not parse effort in minutes (e.g. +30m)" do
|
21
|
+
with_message("@trackinguser +30m") { |tracking| tracking.effort.should be_nil }
|
22
|
+
end
|
23
|
+
|
24
|
+
it "is the hour-based effort when the notification contains an effort in hours" do
|
25
|
+
Trello::Member.should_receive(:find).with("michelepangrazzi").and_return(michelepangrazzi)
|
26
|
+
|
27
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser +2h" },
|
28
|
+
date: "2012-10-28T21:06:14.801Z",
|
29
|
+
member_creator: stub(username: "michelepangrazzi"))
|
30
|
+
|
31
|
+
TrackingFactory.build_from(raw_data).effort.should == Effort.new(amount: 2.0, date: Date.parse('2012-10-28'), members: [michelepangrazzi])
|
32
|
+
end
|
33
|
+
|
34
|
+
it "converts the effort in hours when the notification contains an effort in days" do
|
35
|
+
with_message("@trackinguser +1.5d") { |t| t.effort.amount.should == 8+4 }
|
36
|
+
with_message("@trackinguser +1.5g") { |t| t.effort.amount.should == 8+4 }
|
37
|
+
end
|
38
|
+
|
39
|
+
it "converts the effort in hours when the notification contains an effort in pomodori" do
|
40
|
+
with_message("@trackinguser +10p") { |t| t.effort.amount.should == 5}
|
41
|
+
end
|
42
|
+
|
43
|
+
it "fetch the effort from a complex effort message" do
|
44
|
+
with_message "@trackinguser ho speso +2h e spero che stavolta possiamo rilasciarla" do |tracking|
|
45
|
+
tracking.effort.amount.should == 2.0
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "fetch the effort even when beween square brackets" do
|
50
|
+
with_message "@trackinguser [+0.5h]" do |tracking|
|
51
|
+
tracking.effort.amount.should == 0.5
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "computes the effort considering all the mentioned team mates in the message" do
|
56
|
+
with_message "@trackinguser +2h assieme a @michelepangrazzi e @alessandrodescovi" do |tracking|
|
57
|
+
tracking.effort.amount.should == 2.0 * 3
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "tracks all the team mates which spent that effort on the card" do
|
62
|
+
%w{pietrodibello michelepangrazzi alessandrodescovi}.each do |username|
|
63
|
+
Trello::Member.should_receive(:find).with(username).and_return(self.send(username))
|
64
|
+
end
|
65
|
+
|
66
|
+
notification = create_notification(data: { 'text' => "@trackinguser +2h assieme a @michelepangrazzi e @alessandrodescovi" },
|
67
|
+
member_creator: stub(username: "pietrodibello"))
|
68
|
+
with notification do |tracking|
|
69
|
+
tracking.effort.members.should == [michelepangrazzi, alessandrodescovi, pietrodibello]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
it "tracks the effort only on the team members listed between round brackets" do
|
74
|
+
%w{michelevincenzi alessandrodescovi}.each do |username|
|
75
|
+
Trello::Member.should_receive(:find).with(username).and_return(self.send(username))
|
76
|
+
end
|
77
|
+
|
78
|
+
notification = create_notification(data: { 'text' => "@trackinguser +3p (@alessandrodescovi @michelevincenzi)" },
|
79
|
+
member_creator: stub(username: "pietrodibello"))
|
80
|
+
|
81
|
+
with notification do |tracking|
|
82
|
+
tracking.effort.members.should == [alessandrodescovi, michelevincenzi]
|
83
|
+
tracking.effort.amount.should == 1.5 * 2
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "tracks the effort with the date given in the notification text, not the actual notification date" do
|
88
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser 22.11.2012 +6p" }, date: "2012-09-19T12:46:13.713Z")
|
89
|
+
|
90
|
+
tracking = TrackingFactory.build_from(raw_data)
|
91
|
+
|
92
|
+
tracking.effort.date.should == Date.parse('2012-11-22')
|
93
|
+
end
|
94
|
+
|
95
|
+
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
96
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser yesterday +6p" }, date: "2012-09-19T12:46:13.713Z")
|
97
|
+
|
98
|
+
tracking = TrackingFactory.build_from(raw_data)
|
99
|
+
|
100
|
+
tracking.effort.date.should == Date.parse('2012-09-18')
|
101
|
+
end
|
102
|
+
|
103
|
+
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
104
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser +6p yesterday" }, date: "2012-09-19T12:46:13.713Z")
|
105
|
+
|
106
|
+
tracking = TrackingFactory.build_from(raw_data)
|
107
|
+
|
108
|
+
tracking.effort.date.should == Date.parse('2012-09-18')
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Tracking
|
4
|
+
describe EstimateTracking do
|
5
|
+
|
6
|
+
describe "#estimate" do
|
7
|
+
|
8
|
+
it "is nil when the notification does not contain an estimate" do
|
9
|
+
TrackingFactory.build_from(unrecognized_notification).estimate.should be_nil
|
10
|
+
end
|
11
|
+
|
12
|
+
it "is the hour-based estimate when the notification contains an estimate in hours" do
|
13
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser [2h]" }, date: "2012-10-28T21:06:14.801Z")
|
14
|
+
|
15
|
+
TrackingFactory.build_from(raw_data).estimate.should == Estimate.new(amount: 2.0, date: Date.parse('2012-10-28'))
|
16
|
+
end
|
17
|
+
|
18
|
+
it "converts the estimate in hours when the notification contains an estimate in days" do
|
19
|
+
TrackingFactory.build_from(create_notification(data: { 'text' => "@trackinguser [1.5d]" })).estimate.amount.should == 8+4
|
20
|
+
TrackingFactory.build_from(create_notification(data: { 'text' => "@trackinguser [1.5g]" })).estimate.amount.should == 8+4
|
21
|
+
end
|
22
|
+
|
23
|
+
it "converts the estimate in hours when the notification contains an estimate in pomodori" do
|
24
|
+
raw_data = create_notification(data: { 'text' => "@trackinguser [10p]" })
|
25
|
+
TrackingFactory.build_from(raw_data).estimate.amount.should == 5
|
26
|
+
end
|
27
|
+
|
28
|
+
it "fetch the estimate from a complex estimate message" do
|
29
|
+
raw_data = create_notification(data: { 'text' => "@maxmazza Dobbiamo ancora lavorarci.\n@trackinguser ristimo ancora [3h] per il fix" })
|
30
|
+
TrackingFactory.build_from(raw_data).estimate.amount.should == 3.0
|
31
|
+
end
|
32
|
+
|
33
|
+
it "tracks the effort with the date given in the notification text, not the actual notification date" do
|
34
|
+
raw_data = create_notification( data: { 'text' => "@trackinguser 22.11.2012 [6p]" }, date: "2012-09-19T12:46:13.713Z")
|
35
|
+
|
36
|
+
tracking = TrackingFactory.build_from(raw_data)
|
37
|
+
|
38
|
+
tracking.estimate.date.should == Date.parse('2012-11-22')
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TrackingFactory do
|
4
|
+
|
5
|
+
TIME_MEASUREMENTS = {
|
6
|
+
hours: 'h',
|
7
|
+
days: 'd',
|
8
|
+
giorni: 'g',
|
9
|
+
pomodori: 'p'
|
10
|
+
}
|
11
|
+
|
12
|
+
context "unknown tracking format" do
|
13
|
+
it "builds an invalid tracking instance" do
|
14
|
+
TrackingFactory.build_from(unrecognized_notification).class.should == Tracking::InvalidTracking
|
15
|
+
|
16
|
+
with_message("@trackinguser +30m") { |tracking| tracking.class.should == Tracking::InvalidTracking }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
TIME_MEASUREMENTS.each_key do |time_measurement|
|
21
|
+
|
22
|
+
context "estimate tracking notification in #{time_measurement}" do
|
23
|
+
it "builds an estimate tracking instance" do
|
24
|
+
TrackingFactory.build_from(create_estimate(time_measurement)).class.should == Tracking::EstimateTracking
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "effort tracking notification in #{time_measurement}" do
|
29
|
+
it "builds an effort tracking instance" do
|
30
|
+
TrackingFactory.build_from(create_effort(time_measurement)).class.should == Tracking::EffortTracking
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
context "card done tracking notification" do
|
37
|
+
it "builds a card done tracking instance" do
|
38
|
+
with_message("@trackinguser DONE") { |tracking| tracking.class.should == Tracking::CardDoneTracking }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|