trello_effort_tracker 0.0.3
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 +25 -0
- data/.rspec +3 -0
- data/.rvmrc.template +2 -0
- data/.travis.yml +21 -0
- data/Gemfile +22 -0
- data/Gemfile.lock +101 -0
- data/LICENSE.txt +15 -0
- data/README.md +159 -0
- data/Rakefile +72 -0
- data/config/config.template.yml +7 -0
- data/config/mongoid.template.yml +24 -0
- data/lib/patches/trello/member.rb +20 -0
- data/lib/startup_trello.rb +2 -0
- data/lib/trello_effort_tracker/effort.rb +27 -0
- data/lib/trello_effort_tracker/estimate.rb +25 -0
- data/lib/trello_effort_tracker/google_docs_exporter.rb +67 -0
- data/lib/trello_effort_tracker/member.rb +46 -0
- data/lib/trello_effort_tracker/mongoid_helper.rb +13 -0
- data/lib/trello_effort_tracker/tracked_card.rb +103 -0
- data/lib/trello_effort_tracker/tracking.rb +130 -0
- data/lib/trello_effort_tracker/trello_authorize.rb +32 -0
- data/lib/trello_effort_tracker/trello_configuration.rb +33 -0
- data/lib/trello_effort_tracker/trello_tracker.rb +48 -0
- data/lib/trello_effort_tracker/version.rb +3 -0
- data/lib/trello_effort_tracker.rb +23 -0
- data/script/ci/before_script.sh +1 -0
- data/script/ci/run_build.sh +2 -0
- data/script/crontab.template +8 -0
- data/script/mate.sh +1 -0
- data/spec/effort_spec.rb +52 -0
- data/spec/estimate_spec.rb +38 -0
- data/spec/integration/trello_authorization_spec.rb +12 -0
- data/spec/member_spec.rb +45 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/tracked_card_spec.rb +267 -0
- data/spec/tracking_spec.rb +236 -0
- data/spec/trello_authorize_spec.rb +71 -0
- data/spec/trello_configuration_spec.rb +43 -0
- data/trello_effort_tracker.gemspec +19 -0
- metadata +86 -0
@@ -0,0 +1,103 @@
|
|
1
|
+
class TrackedCard
|
2
|
+
include Mongoid::Document
|
3
|
+
include Mongoid::Timestamps
|
4
|
+
extend MongoidHelper
|
5
|
+
|
6
|
+
field :name
|
7
|
+
field :description
|
8
|
+
field :short_id, type: Integer
|
9
|
+
field :trello_id
|
10
|
+
field :due, type: Date
|
11
|
+
field :closed, type: Boolean
|
12
|
+
field :url
|
13
|
+
field :pos
|
14
|
+
|
15
|
+
embeds_many :estimates
|
16
|
+
embeds_many :efforts
|
17
|
+
|
18
|
+
validates_presence_of :name, :short_id, :trello_id
|
19
|
+
validates_numericality_of :short_id
|
20
|
+
|
21
|
+
def self.find_by_trello_id(trello_id)
|
22
|
+
without_mongo_raising_errors do
|
23
|
+
find_by(trello_id: trello_id)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.update_or_create_with(trello_card)
|
28
|
+
card = TrackedCard.find_or_create_by(trello_id: trello_card.id)
|
29
|
+
trello_card.attributes.delete(:id)
|
30
|
+
success = card.update_attributes(trello_card.attributes)
|
31
|
+
return card if success
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.build_from(trello_card)
|
35
|
+
trello_card_id = trello_card.id
|
36
|
+
trello_card.attributes.delete(:id)
|
37
|
+
new(trello_card.attributes.merge(trello_id: trello_card_id))
|
38
|
+
end
|
39
|
+
|
40
|
+
def add(tracking)
|
41
|
+
if tracking.estimate? && estimates.none? {|e| e.tracking_notification_id == tracking.estimate.tracking_notification_id}
|
42
|
+
estimates << tracking.estimate
|
43
|
+
elsif tracking.effort? && efforts.none? {|e| e.tracking_notification_id == tracking.effort.tracking_notification_id}
|
44
|
+
efforts << tracking.effort
|
45
|
+
else
|
46
|
+
Trello.logger.warn "Ignoring tracking notification: #{tracking}" if tracking.unknown_format?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def no_tracking?
|
51
|
+
first_activity_date.nil?
|
52
|
+
end
|
53
|
+
|
54
|
+
def first_activity_date
|
55
|
+
[working_start_date, first_estimate_date].compact.min
|
56
|
+
end
|
57
|
+
|
58
|
+
def working_start_date
|
59
|
+
efforts.sort_by(&:date).first.date if efforts.present?
|
60
|
+
end
|
61
|
+
|
62
|
+
def first_estimate_date
|
63
|
+
estimates.sort_by(&:date).first.date if estimates.present?
|
64
|
+
end
|
65
|
+
|
66
|
+
def last_estimate_date
|
67
|
+
estimates.sort_by(&:date).last.date if estimates.present?
|
68
|
+
end
|
69
|
+
|
70
|
+
def total_effort
|
71
|
+
efforts.map(&:amount).inject(0, &:+)
|
72
|
+
end
|
73
|
+
|
74
|
+
def members
|
75
|
+
efforts.map(&:members).flatten.uniq
|
76
|
+
end
|
77
|
+
|
78
|
+
def last_estimate_error
|
79
|
+
estimate_errors.last
|
80
|
+
end
|
81
|
+
|
82
|
+
def estimate_errors
|
83
|
+
return [] if estimates.empty? || efforts.empty?
|
84
|
+
|
85
|
+
estimate_errors = []
|
86
|
+
estimates.each do |each|
|
87
|
+
estimate_errors << (100 * ((total_effort - each.amount) / each.amount * 1.0)).round(2)
|
88
|
+
end
|
89
|
+
|
90
|
+
estimate_errors
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_s
|
94
|
+
"[#{name}]. Total effort: #{total_effort}h. Estimates #{estimates.map(&:to_s)}. Efforts: #{efforts.map(&:to_s)}"
|
95
|
+
end
|
96
|
+
|
97
|
+
def ==(other)
|
98
|
+
return true if other.equal?(self)
|
99
|
+
return false unless other.kind_of?(self.class)
|
100
|
+
trello_id == other.trello_id
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
class Tracking
|
2
|
+
extend Forwardable
|
3
|
+
include TrelloConfiguration
|
4
|
+
|
5
|
+
TIME_CONVERTERS = {
|
6
|
+
'h' => lambda { |estimate| estimate },
|
7
|
+
'd' => lambda { |estimate| estimate * 8 },
|
8
|
+
'g' => lambda { |estimate| estimate * 8 },
|
9
|
+
'p' => lambda { |estimate| estimate / 2 }
|
10
|
+
}
|
11
|
+
|
12
|
+
DURATION_REGEXP = '(\d+\.?\d*[phdg])'
|
13
|
+
DATE_REGEXP = /(\d{2})\.(\d{2})\.(\d{4})/
|
14
|
+
|
15
|
+
# delegate to the trello notification the member_creator method aliased as 'notifier'
|
16
|
+
def_delegator :@tracking_notification, :member_creator, :notifier
|
17
|
+
|
18
|
+
def initialize(tracking_notification)
|
19
|
+
@tracking_notification = tracking_notification
|
20
|
+
end
|
21
|
+
|
22
|
+
def date
|
23
|
+
Chronic.parse(date_as_string).to_date
|
24
|
+
end
|
25
|
+
|
26
|
+
def estimate?
|
27
|
+
!raw_estimate.nil?
|
28
|
+
end
|
29
|
+
|
30
|
+
def estimate
|
31
|
+
estimate = convert_to_hours(raw_estimate)
|
32
|
+
Estimate.new(amount: estimate, date: date, tracking_notification_id: @tracking_notification.id) if estimate
|
33
|
+
end
|
34
|
+
|
35
|
+
def effort?
|
36
|
+
!raw_effort.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def effort
|
40
|
+
effort_amount = convert_to_hours(raw_effort)
|
41
|
+
if effort_amount
|
42
|
+
total_effort = effort_amount * effort_members.size
|
43
|
+
Effort.new(amount: total_effort, date: date, members: effort_members, tracking_notification_id: @tracking_notification.id)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def unknown_format?
|
48
|
+
!estimate? && !effort?
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_s
|
52
|
+
"[#{date}] From #{notifier.username.color(:green)}\t on card '#{trello_card.name.color(:yellow)}': #{raw_text}"
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def effort_members
|
58
|
+
@effort_members ||= users_involved_in_the_effort.map do |username|
|
59
|
+
Member.build_from(Trello::Member.find(username))
|
60
|
+
end
|
61
|
+
|
62
|
+
@effort_members
|
63
|
+
end
|
64
|
+
|
65
|
+
def users_involved_in_the_effort
|
66
|
+
users_involved_in_the_effort = raw_tracking.scan(/@(\w+)/).flatten
|
67
|
+
users_involved_in_the_effort << notifier.username unless should_count_only_listed_members?
|
68
|
+
|
69
|
+
users_involved_in_the_effort
|
70
|
+
end
|
71
|
+
|
72
|
+
def should_count_only_listed_members?
|
73
|
+
raw_tracking =~ /\((@\w+\W*\s*)+\)/
|
74
|
+
end
|
75
|
+
|
76
|
+
def raw_tracking
|
77
|
+
raw_text.gsub("@#{tracker_username}", "")
|
78
|
+
end
|
79
|
+
|
80
|
+
def raw_text
|
81
|
+
@tracking_notification.data['text']
|
82
|
+
end
|
83
|
+
|
84
|
+
def raw_estimate
|
85
|
+
extract_match_from_raw_tracking(/\[#{DURATION_REGEXP}\]/)
|
86
|
+
end
|
87
|
+
|
88
|
+
def raw_effort
|
89
|
+
extract_match_from_raw_tracking(/\+#{DURATION_REGEXP}/)
|
90
|
+
end
|
91
|
+
|
92
|
+
def convert_to_hours(duration_as_string)
|
93
|
+
return if duration_as_string.nil?
|
94
|
+
|
95
|
+
time_scale = duration_as_string.slice!(-1)
|
96
|
+
converter = TIME_CONVERTERS[time_scale]
|
97
|
+
converter.call(Float(duration_as_string))
|
98
|
+
end
|
99
|
+
|
100
|
+
def date_as_string
|
101
|
+
case raw_tracking
|
102
|
+
when DATE_REGEXP
|
103
|
+
day, month, year = raw_tracking.scan(DATE_REGEXP).flatten
|
104
|
+
"#{year}-#{month}-#{day}"
|
105
|
+
when /yesterday\s+\+#{DURATION_REGEXP}/, /\+#{DURATION_REGEXP}\s+yesterday/
|
106
|
+
(notification_date - 1).to_s
|
107
|
+
else
|
108
|
+
@tracking_notification.date
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def extract_match_from_raw_tracking(regexp)
|
113
|
+
extracted = nil
|
114
|
+
raw_tracking.scan(regexp) do |match|
|
115
|
+
extracted = match.first
|
116
|
+
end
|
117
|
+
|
118
|
+
extracted
|
119
|
+
end
|
120
|
+
|
121
|
+
def trello_card
|
122
|
+
@trello_card ||= @tracking_notification.card
|
123
|
+
end
|
124
|
+
|
125
|
+
def notification_date
|
126
|
+
Chronic.parse(@tracking_notification.date).to_date
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module TrelloAuthorize
|
2
|
+
include TrelloConfiguration
|
3
|
+
include Trello::Authorization
|
4
|
+
|
5
|
+
def authorize_on_trello(auth_params={})
|
6
|
+
%w{developer_public_key access_token_key developer_secret}.each do |key|
|
7
|
+
auth_params[key] ||= ENV[key] || authorization_params_from_config_file[key]
|
8
|
+
end
|
9
|
+
|
10
|
+
init_trello(auth_params)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def init_trello(auth_params)
|
16
|
+
ignoring_warnings do
|
17
|
+
Trello::Authorization.const_set(:AuthPolicy, OAuthPolicy)
|
18
|
+
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
|
+
end
|
23
|
+
|
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
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module TrelloConfiguration
|
2
|
+
|
3
|
+
def tracker_username
|
4
|
+
@tracker_username ||= ENV["tracker_username"] || configuration["tracker_username"]
|
5
|
+
end
|
6
|
+
|
7
|
+
def authorization_params_from_config_file
|
8
|
+
configuration["trello"]
|
9
|
+
end
|
10
|
+
|
11
|
+
class Database
|
12
|
+
def self.load_env(db_env)
|
13
|
+
ENV['MONGOID_ENV'] = db_env
|
14
|
+
Mongoid.load!("config/mongoid.yml", db_env)
|
15
|
+
Trello.logger.info "Mongo db env: #{db_env.color(:green)}."
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def db_environment
|
22
|
+
ENV['MONGOID_ENV']
|
23
|
+
end
|
24
|
+
|
25
|
+
def configuration
|
26
|
+
@configuration ||= load_configuration
|
27
|
+
end
|
28
|
+
|
29
|
+
def load_configuration
|
30
|
+
YAML.load_file("config/config.yml")
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
class TrelloTracker
|
2
|
+
include TrelloAuthorize
|
3
|
+
include Trello
|
4
|
+
|
5
|
+
trap("SIGINT") { exit! }
|
6
|
+
|
7
|
+
def initialize(custom_auth_params = {})
|
8
|
+
authorize_on_trello(custom_auth_params)
|
9
|
+
end
|
10
|
+
|
11
|
+
def track(starting_date=Date.today)
|
12
|
+
notifications = tracker.notifications_from(starting_date)
|
13
|
+
|
14
|
+
oldest, latest = boundary_dates_in(notifications)
|
15
|
+
Trello.logger.info "Processing #{notifications.size} tracking notifications (from #{oldest} to #{latest}) starting from #{starting_date}..."
|
16
|
+
|
17
|
+
notifications.each do |notification|
|
18
|
+
tracking = Tracking.new(notification)
|
19
|
+
begin
|
20
|
+
card = TrackedCard.update_or_create_with(notification.card)
|
21
|
+
card.add(tracking)
|
22
|
+
Trello.logger.info tracking
|
23
|
+
|
24
|
+
rescue StandardError => e
|
25
|
+
Trello.logger.error "skipping tracking: #{e.message}".color(:magenta)
|
26
|
+
Trello.logger.error "#{e.backtrace}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
Trello.logger.info "Done tracking cards!".color(:green)
|
30
|
+
print_all_cards
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def tracker
|
36
|
+
@tracker ||= Member.find(tracker_username)
|
37
|
+
end
|
38
|
+
|
39
|
+
def boundary_dates_in(notifications)
|
40
|
+
dates = notifications.map { |each_notification| Chronic.parse(each_notification.date) }
|
41
|
+
[dates.min, dates.max]
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_all_cards
|
45
|
+
TrackedCard.all.each { |tracked_card| Trello.logger.info(tracked_card.to_s.color(:yellow)) }
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'trello'
|
2
|
+
require 'rainbow'
|
3
|
+
require 'set'
|
4
|
+
require 'yaml'
|
5
|
+
require 'chronic'
|
6
|
+
require 'mongoid'
|
7
|
+
|
8
|
+
require 'trello_effort_tracker/mongoid_helper'
|
9
|
+
require 'trello_effort_tracker/trello_configuration'
|
10
|
+
require 'trello_effort_tracker/trello_authorize'
|
11
|
+
require 'trello_effort_tracker/tracked_card'
|
12
|
+
require 'trello_effort_tracker/member'
|
13
|
+
require 'trello_effort_tracker/estimate'
|
14
|
+
require 'trello_effort_tracker/effort'
|
15
|
+
require 'trello_effort_tracker/tracking'
|
16
|
+
require 'trello_effort_tracker/trello_tracker'
|
17
|
+
require 'trello_effort_tracker/google_docs_exporter'
|
18
|
+
|
19
|
+
require 'patches/trello/member'
|
20
|
+
|
21
|
+
TrelloConfiguration::Database.load_env(ENV['MONGOID_ENV'] || "development")
|
22
|
+
|
23
|
+
Trello.logger.level = Logger::DEBUG
|
@@ -0,0 +1 @@
|
|
1
|
+
cp -f config/mongoid.template.yml config/mongoid.yml
|
@@ -0,0 +1,8 @@
|
|
1
|
+
SHELL=/Users/pierodibello/.rvm/bin/rvm-shell
|
2
|
+
|
3
|
+
GEMSET="ruby-1.9.3-p194@spikes"
|
4
|
+
PROJECT_PATH="/Users/$USER/Documents/workspace/trello_effort_tracker"
|
5
|
+
LC_ALL=en_US.UTF-8
|
6
|
+
|
7
|
+
# m h dom mon dow command
|
8
|
+
*/10 * * * * rvm-shell $GEMSET -c "cd $PROJECT_PATH; bundle exec rake run:today[production]" >> /tmp/crontab.out 2>&1
|
data/script/mate.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mate $(ls -a | grep -v '\.\.$' | grep -v '\.$' | grep -v '\.git$'| grep -v '\.DS_Store'| grep -v '\.tmtags' | grep -v '\tags')
|
data/spec/effort_spec.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mongoid-rspec'
|
3
|
+
|
4
|
+
describe Effort do
|
5
|
+
|
6
|
+
it { should have_fields(:amount, :date) }
|
7
|
+
it { should be_embedded_in(:tracked_card) }
|
8
|
+
it { should embed_many(:members) }
|
9
|
+
|
10
|
+
describe "validation" do
|
11
|
+
it { should validate_presence_of(:amount) }
|
12
|
+
it { should validate_presence_of(:date) }
|
13
|
+
it { should validate_presence_of(:members) }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "equality" do
|
17
|
+
%w{piero tommaso tom ugo}.each do |username|
|
18
|
+
let(username.to_sym) { Member.new(username: username) }
|
19
|
+
end
|
20
|
+
|
21
|
+
it "is equal to another effort with same amount, date and members" do
|
22
|
+
effort = Effort.new(amount: 3, date: Date.parse("2012-11-09"), members: [piero, tommaso])
|
23
|
+
same_effort = Effort.new(amount: 3, date: Date.parse("2012-11-09"), members: [piero, tommaso])
|
24
|
+
yet_same_effort = Effort.new(amount: 3, date: Date.parse("2012-11-09"), members: [tommaso, piero])
|
25
|
+
|
26
|
+
effort.should == same_effort
|
27
|
+
effort.should == yet_same_effort
|
28
|
+
end
|
29
|
+
|
30
|
+
it "is not equal when amount differs" do
|
31
|
+
effort = Effort.new(amount: 3, date: Date.today, members: [tom, ugo])
|
32
|
+
another_effort = Effort.new(amount: 1, date: Date.today, members: [tom, ugo])
|
33
|
+
|
34
|
+
effort.should_not == another_effort
|
35
|
+
end
|
36
|
+
|
37
|
+
it "is not equal when date differs" do
|
38
|
+
effort = Effort.new(amount: 3, date: Date.parse("2012-11-09"), members: [tom, ugo])
|
39
|
+
another_effort = Effort.new(amount: 3, date: Date.parse("2011-10-08"), members: [tom, ugo])
|
40
|
+
|
41
|
+
effort.should_not == another_effort
|
42
|
+
end
|
43
|
+
|
44
|
+
it "is not equal when members differ" do
|
45
|
+
effort = Effort.new(amount: 3, date: Date.today, members: [tom, ugo])
|
46
|
+
another_effort = Effort.new(amount: 3, date: Date.today, members: [piero, ugo])
|
47
|
+
|
48
|
+
effort.should_not == another_effort
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mongoid-rspec'
|
3
|
+
|
4
|
+
describe Estimate do
|
5
|
+
|
6
|
+
it { should have_fields(:amount, :date) }
|
7
|
+
it { should be_embedded_in(:tracked_card) }
|
8
|
+
|
9
|
+
describe "validation" do
|
10
|
+
it { should validate_presence_of(:amount) }
|
11
|
+
it { should validate_presence_of(:date) }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "equality" do
|
15
|
+
|
16
|
+
it "is equal to another estimate with same amount and date" do
|
17
|
+
estimate = Estimate.new(amount: 3, date: Date.parse("2012-11-09"))
|
18
|
+
same_estimate = Estimate.new(amount: 3, date: Date.parse("2012-11-09"))
|
19
|
+
|
20
|
+
estimate.should == same_estimate
|
21
|
+
end
|
22
|
+
|
23
|
+
it "is not equal when amount differs" do
|
24
|
+
estimate = Estimate.new(amount: 3, date: Date.today)
|
25
|
+
another_estimate = Estimate.new(amount: 1, date: Date.today)
|
26
|
+
|
27
|
+
estimate.should_not == another_estimate
|
28
|
+
end
|
29
|
+
|
30
|
+
it "is not equal when date differs" do
|
31
|
+
estimate = Estimate.new(amount: 3, date: Date.parse("2012-11-09"))
|
32
|
+
another_estimate = Estimate.new(amount: 3, date: Date.parse("2011-10-08"))
|
33
|
+
|
34
|
+
estimate.should_not == another_estimate
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'trello'
|
3
|
+
|
4
|
+
describe "TrelloAuthorization" do
|
5
|
+
include TrelloAuthorize
|
6
|
+
|
7
|
+
it "authorizes connection to Trello", :needs_valid_configuration => true do
|
8
|
+
authorize_on_trello
|
9
|
+
|
10
|
+
Trello::Member.find("me").should_not be_nil
|
11
|
+
end
|
12
|
+
end
|
data/spec/member_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mongoid-rspec'
|
3
|
+
|
4
|
+
describe Member do
|
5
|
+
|
6
|
+
it { should have_fields(:trello_id, :username, :full_name, :avatar_id, :bio, :url) }
|
7
|
+
it { should be_embedded_in(:effort) }
|
8
|
+
|
9
|
+
describe "validation" do
|
10
|
+
it { should validate_presence_of(:username) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "equality" do
|
14
|
+
it "is equal to another member with the same username" do
|
15
|
+
member = Member.new(username: "piero")
|
16
|
+
same_member = Member.new(username: "piero")
|
17
|
+
different_member = Member.new(username: "tommaso")
|
18
|
+
|
19
|
+
member.should == same_member
|
20
|
+
member.should_not == different_member
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".build_from" do
|
25
|
+
it "builds a Member from a Trello Member" do
|
26
|
+
member = Member.build_from(Trello::Member.new("username" => "piero"))
|
27
|
+
|
28
|
+
member.username.should == "piero"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "takes the Trello Member id and set it as trello_id" do
|
32
|
+
member = Member.build_from(Trello::Member.new("username" => "piero", "id" => "1234567abc"))
|
33
|
+
|
34
|
+
member.id.should_not == "1234567abc"
|
35
|
+
member.trello_id.should == "1234567abc"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#avatar_url" do
|
40
|
+
it "points to the avatar thumbnail image" do
|
41
|
+
member = Member.new(avatar_id: "123xyz")
|
42
|
+
member.avatar_url.should == "https://trello-avatars.s3.amazonaws.com/123xyz/30.png"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
# Set up gems listed in the Gemfile.
|
4
|
+
begin
|
5
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../Gemfile', File.dirname(__FILE__))
|
6
|
+
require 'bundler'
|
7
|
+
Bundler.setup
|
8
|
+
rescue Bundler::GemNotFound => e
|
9
|
+
STDERR.puts e.message
|
10
|
+
STDERR.puts "Try running `bundle install`."
|
11
|
+
exit!
|
12
|
+
end
|
13
|
+
|
14
|
+
Bundler.require
|
15
|
+
|
16
|
+
RSpec.configure do |configuration|
|
17
|
+
configuration.include Mongoid::Matchers
|
18
|
+
end
|
19
|
+
|
20
|
+
# force test env for the mongodb configuration
|
21
|
+
TrelloConfiguration::Database.load_env("test")
|