tracco 0.0.15 → 0.0.16
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +4 -3
- data/CHANGELOG +11 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +17 -13
- data/README.md +31 -27
- data/bin/tracco +34 -0
- data/images/tracco.logo.png +0 -0
- data/images/tracking_example.png +0 -0
- data/lib/patches/trello/card.rb +1 -1
- data/lib/tasks/tasks.rake +32 -15
- data/lib/tracco.rb +5 -3
- data/lib/tracco/cli.rb +66 -0
- data/lib/tracco/configuration.rb +27 -0
- data/lib/tracco/exporters/google_docs.rb +71 -0
- data/lib/tracco/tracking/base.rb +7 -4
- data/lib/tracco/tracking/invalid_tracking.rb +1 -1
- data/lib/tracco/trello_configuration.rb +0 -12
- data/lib/tracco/trello_tracker.rb +1 -1
- data/lib/tracco/version.rb +1 -1
- data/script/ci/run_build.sh +2 -1
- data/spec/integration/trello_authorization_spec.rb +8 -3
- data/spec/integration/trello_tracker_spec.rb +1 -16
- data/spec/patches/trello/card_spec.rb +6 -1
- data/spec/spec_helper.rb +1 -3
- data/spec/support/spec_helper_methods.rb +22 -4
- data/spec/tracco_spec.rb +45 -0
- data/spec/tracking/effort_tracking_spec.rb +20 -15
- data/spec/tracking/invalid_tracking_spec.rb +17 -0
- data/spec/trello_configuration_spec.rb +9 -0
- data/tracco.gemspec +3 -6
- metadata +16 -72
- data/lib/tracco/google_docs_exporter.rb +0 -70
data/.travis.yml
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
language: ruby
|
2
|
+
bundler_args: --without development
|
2
3
|
rvm:
|
3
4
|
- 1.9.3
|
4
|
-
|
5
|
+
- 2.0.0
|
6
|
+
- ruby-head
|
5
7
|
env:
|
6
8
|
global:
|
7
9
|
- developer_public_key: e/zPNGKOwapoxFWZs/CBTAhaoqrDTkqqz+InOmCUvGBcZBpUxH398nPLv8Hi\nNQSvWuspzqanyNbbQrTA/2XhsWF1gIFX+gNexYM7S+MxtRwUD3cpVT8DzVOS\nMuckdMTEAADVsm92vIX/bUs5igxD4+zfXlhzXUNDrzRlZnsUF2M=
|
8
10
|
- access_token_key: GG1Q8oq7GkaXjP0lbMgvQLLEi+LXOZlwmELqjPk39Exfy8114QUs2ki8nr9n\ndGO+tgOSZsCd/bt9IHxS3WWWU0INSYOTgp/prfsDDgosg7/Elk/b6w1OW0At\nX3VAjMeI0yAGloT6XB58LCFyrj6S2b4vCQqyaHR3tlTHai/5bMQ=
|
9
11
|
- tracker_username=trackinguser
|
10
|
-
-
|
12
|
+
- TRACCO_ENV=test
|
11
13
|
|
12
14
|
services:
|
13
15
|
- mongodb
|
@@ -17,4 +19,3 @@ script: ./script/ci/run_build.sh
|
|
17
19
|
before_script:
|
18
20
|
- mongo tracco_test --eval 'db.addUser("travis", "test");'
|
19
21
|
- "./script/ci/before_script.sh"
|
20
|
-
|
data/CHANGELOG
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
0.0.16 / 2013-03-12
|
2
|
+
==================
|
3
|
+
slowly migrating from rake tasks to bin commands
|
4
|
+
improving readme
|
5
|
+
dropping ruby 1.9.2 support due to Mongoid issues (http://mongoid.org/en/mongoid/docs/tips.html#ruby)
|
6
|
+
updating depending gems
|
7
|
+
improving Tracco load env, avoiding double env loading when running the specs, renaming MONGOID_ENV to a more generic TRACCO_ENV
|
8
|
+
adding a logo for Tracco!
|
9
|
+
adding Ruby 2.0.0 compatibility
|
10
|
+
adding awesome_print gem to the console task
|
11
|
+
adding an helper task to copy the configuration template files
|
1
12
|
|
2
13
|
0.0.15 / 2013-03-01
|
3
14
|
==================
|
data/Gemfile
CHANGED
@@ -5,5 +5,11 @@ gemspec
|
|
5
5
|
# gem 'ruby-trello', :require => 'trello', :path => '../ruby-trello' # to hack on the ruby-trello gem itself
|
6
6
|
|
7
7
|
group :test do
|
8
|
+
gem 'rspec'
|
9
|
+
gem 'rspec-mocks'
|
10
|
+
gem 'mongoid-rspec'
|
11
|
+
gem 'database_cleaner'
|
12
|
+
gem 'factory_girl'
|
8
13
|
gem 'simplecov', :require => false, :platforms => [:mri, :mri_19]
|
14
|
+
gem 'rake' # see http://about.travis-ci.org/docs/user/languages/ruby/#Default-Test-Script
|
9
15
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
tracco (0.0.
|
4
|
+
tracco (0.0.16)
|
5
5
|
bson_ext
|
6
6
|
chronic
|
7
7
|
google_drive
|
@@ -9,6 +9,7 @@ PATH
|
|
9
9
|
mongoid
|
10
10
|
rainbow
|
11
11
|
ruby-trello
|
12
|
+
thor
|
12
13
|
|
13
14
|
GEM
|
14
15
|
remote: https://rubygems.org/
|
@@ -20,14 +21,15 @@ GEM
|
|
20
21
|
i18n (~> 0.6)
|
21
22
|
multi_json (~> 1.0)
|
22
23
|
addressable (2.3.3)
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
awesome_print (1.1.0)
|
25
|
+
bson (1.8.3)
|
26
|
+
bson_ext (1.8.3)
|
27
|
+
bson (~> 1.8.3)
|
26
28
|
builder (3.0.4)
|
27
29
|
chronic (0.9.1)
|
28
30
|
columnize (0.3.6)
|
29
31
|
database_cleaner (0.9.1)
|
30
|
-
debugger (1.
|
32
|
+
debugger (1.4.0)
|
31
33
|
columnize (>= 0.3.1)
|
32
34
|
debugger-linecache (~> 1.1.1)
|
33
35
|
debugger-ruby_core_source (~> 1.2.0)
|
@@ -39,27 +41,27 @@ GEM
|
|
39
41
|
activesupport (>= 3.0.0)
|
40
42
|
faraday (0.8.6)
|
41
43
|
multipart-post (~> 1.1)
|
42
|
-
google_drive (0.3.
|
44
|
+
google_drive (0.3.4)
|
43
45
|
nokogiri (>= 1.4.4, != 1.5.2, != 1.5.1)
|
44
46
|
oauth (>= 0.3.6)
|
45
47
|
oauth2 (>= 0.5.0)
|
46
48
|
highline (1.6.15)
|
47
49
|
httpauth (0.2.0)
|
48
|
-
i18n (0.6.
|
50
|
+
i18n (0.6.4)
|
49
51
|
json (1.7.7)
|
50
|
-
jwt (0.1.
|
51
|
-
multi_json (>= 1.
|
52
|
+
jwt (0.1.7)
|
53
|
+
multi_json (>= 1.5)
|
52
54
|
mime-types (1.21)
|
53
55
|
mongoid (3.1.2)
|
54
56
|
activemodel (~> 3.2)
|
55
57
|
moped (~> 1.4.2)
|
56
58
|
origin (~> 1.0)
|
57
59
|
tzinfo (~> 0.3.22)
|
58
|
-
mongoid-rspec (1.
|
60
|
+
mongoid-rspec (1.7.0)
|
59
61
|
mongoid (>= 3.0.1)
|
60
62
|
rake
|
61
63
|
rspec (>= 2.9)
|
62
|
-
moped (1.4.
|
64
|
+
moped (1.4.3)
|
63
65
|
multi_json (1.6.1)
|
64
66
|
multi_xml (0.5.3)
|
65
67
|
multipart-post (1.2.0)
|
@@ -86,7 +88,7 @@ GEM
|
|
86
88
|
rspec-expectations (2.13.0)
|
87
89
|
diff-lcs (>= 1.1.3, < 2.0)
|
88
90
|
rspec-mocks (2.13.0)
|
89
|
-
ruby-trello (0.
|
91
|
+
ruby-trello (0.6.0)
|
90
92
|
activemodel
|
91
93
|
addressable (~> 2.3)
|
92
94
|
json
|
@@ -96,12 +98,14 @@ GEM
|
|
96
98
|
multi_json (~> 1.0)
|
97
99
|
simplecov-html (~> 0.7.1)
|
98
100
|
simplecov-html (0.7.1)
|
99
|
-
|
101
|
+
thor (0.17.0)
|
102
|
+
tzinfo (0.3.36)
|
100
103
|
|
101
104
|
PLATFORMS
|
102
105
|
ruby
|
103
106
|
|
104
107
|
DEPENDENCIES
|
108
|
+
awesome_print
|
105
109
|
database_cleaner
|
106
110
|
debugger
|
107
111
|
factory_girl
|
data/README.md
CHANGED
@@ -1,30 +1,35 @@
|
|
1
|
-
|
2
|
-
[![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/xpepper/tracco)
|
1
|
+
![Tracco Logo](https://raw.github.com/xpepper/tracco/master/images/tracco.logo.png)
|
3
2
|
|
4
|
-
|
3
|
+
[![Gem Version](https://fury-badge.herokuapp.com/rb/tracco.png)](http://badge.fury.io/rb/tracco)
|
4
|
+
[![Build Status](https://secure.travis-ci.org/xpepper/tracco.png?branch=master)](http://travis-ci.org/xpepper/tracco)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/xpepper/tracco.png)](https://codeclimate.com/github/xpepper/tracco)
|
5
6
|
|
6
7
|
## What is Tracco?
|
7
8
|
Tracco is an effort tracker for Trello: the purpose of Tracco is to extract and track estimates and actual efforts out of the cards on your Trello boards.
|
8
|
-
All you have to do is
|
9
|
+
All you have to do is add estimates and efforts as comments added on your Trello cards, using a simple conventional format.
|
9
10
|
Tracco will extract and store these estimates and actual efforts to let you mine useful key metrics (e.g. estimate errors, remaining efforts, pair programming frequencies, and so on).
|
10
11
|
|
11
12
|
## Why Tracco?
|
12
|
-
Trello is a very good surrogate for a physical team board: it's simple and effective, and it can really help when you have a distributed team.
|
13
|
-
That said, Trello
|
13
|
+
[Trello](https://trello.com) is a very good surrogate for a physical team board: it's simple and effective, and it can really help when you have a distributed team.
|
14
|
+
That said, Trello (still) doesn't offer a way to track time estimated and actually spent on cards, though many people are [asking for that feature](https://trello.com/card/time-tracking/4d5ea62fd76aa1136000000c/1054) on Trello's development board.
|
15
|
+
|
16
|
+
Having that precise need, we defined a simple convention to track estimates and efforts on cards: we use a predefined board member (let's call him 'tracking user') which we sent comments to (we call them 'tracking notifications'), using the comment form available on the card panel.
|
17
|
+
|
18
|
+
![A tracking example](https://raw.github.com/xpepper/tracco/master/images/tracking_example.png)
|
14
19
|
|
15
|
-
Having that precise need, we defined a simple convention to track estimates and efforts on cards: we use a predefined board member (let's call him 'tracking user') which we sent special notifications to (we call them 'tracking notifications').
|
16
20
|
This 'tracking user' will then receives estimates and efforts notifications, and Tracco will collect and store them.
|
17
|
-
Moreover, a web app
|
21
|
+
Moreover, a web app is available to properly present card estimates and efforts: [Trello Effort App](https://github.com/xpepper/trello_effort_app).
|
18
22
|
|
19
23
|
## More details
|
20
|
-
|
24
|
+
To start using Tracco you should have a Trello account, a Trello board and a board member to use as 'tracking user'.
|
21
25
|
You'll also need to know your Trello developer key and generate a proper auth token to have access to the trackinguser's notifications.
|
22
26
|
To see how to have these two keys, see [the following section](#api_key).
|
23
27
|
|
24
28
|
The Trello API is used behind the scenes to read data from the team board. Tracco uses the awesome [Trello API Ruby wrapper](https://github.com/jeremytregunna/ruby-trello) for this purpose.
|
25
29
|
|
26
30
|
## Usage
|
27
|
-
|
31
|
+
Tracco is not provided with a built-in viewer for the collected data, so the recommended way to use Tracco is by using [Trello Effort App](https://github.com/xpepper/trello_effort_app) or including the gem in your own viewer app.
|
32
|
+
By the way, this tool can be used as a standalone gem or cloning this git repo.
|
28
33
|
|
29
34
|
### Installation as a ruby gem
|
30
35
|
|
@@ -38,16 +43,21 @@ gem install tracco
|
|
38
43
|
git clone git://github.com/xpepper/tracco.git
|
39
44
|
```
|
40
45
|
|
41
|
-
Then cd in the cloned repo and
|
46
|
+
Then cd in the cloned repo and install all the dependencies with Bundler
|
42
47
|
|
43
48
|
```shell
|
44
49
|
cd tracco
|
50
|
+
bundle install
|
51
|
+
```
|
52
|
+
|
53
|
+
Then copy the config template
|
54
|
+
```shell
|
45
55
|
cp config/config.template.yaml config/config.yml
|
46
56
|
```
|
47
57
|
|
48
|
-
and
|
58
|
+
and fill the correct values in the placeholders (see _"Where do I get an API key and API secret?"_ section).
|
49
59
|
|
50
|
-
|
60
|
+
And finally copy the mongoid config template
|
51
61
|
|
52
62
|
```shell
|
53
63
|
cp config/mongoid.template.yaml config/mongoid.yml
|
@@ -55,33 +65,27 @@ cp config/mongoid.template.yaml config/mongoid.yml
|
|
55
65
|
|
56
66
|
and fill the correct values for the mongodb environments ([see here](http://mongoid.org/en/mongoid/docs/installation.html#configuration) to have more details).
|
57
67
|
|
58
|
-
Then run bundle to get all the required gems:
|
59
|
-
|
60
|
-
```shell
|
61
|
-
bundle install
|
62
|
-
```
|
63
|
-
|
64
68
|
|
65
69
|
Full Disclosure: this library is still work-in-progress, so if you find anything missing or not functioning as you expect it to, please [open an issue on github](https://github.com/xpepper/tracco/issues).
|
66
70
|
|
67
71
|
## Requirements
|
72
|
+
* MRI version 1.9.3+
|
68
73
|
* [mongoDB](http://www.mongodb.org/) - macosx users with homebrew will just run 'brew install mongodb' to have mongoDB installed on their machine.
|
69
74
|
* (optional) [rvm](https://rvm.io/rvm/install/) is useful (but optional) for development
|
70
75
|
|
71
76
|
|
72
|
-
|
73
77
|
### <a id="api_key"></a>Where do I get an API key?
|
74
78
|
Log in to Trello with your account and visit [https://trello.com/1/appKey/generate](https://trello.com/1/appKey/generate) to get your developer\_public\_key.
|
75
79
|
|
76
80
|
### Where do I get an API Access Token Key?
|
77
81
|
To generate a proper access token key, log in to Trello with the 'tracking user' account. Then go to this URL:
|
78
82
|
|
79
|
-
https://trello.com/1/connect?key=<YOUR_DEVELOPER_PUBLIC_KEY>&name=
|
83
|
+
https://trello.com/1/connect?key=<YOUR_DEVELOPER_PUBLIC_KEY>&name=Tracco&response_type=token&scope=read&expiration=never
|
80
84
|
|
81
|
-
At the end of this process, you'll receive a valid access\_token\_key, which is needed by Tracco to fetch all the tracking notifications sent to the 'tracking user'.
|
85
|
+
At the end of this process, you'll receive a valid access\_token\_key, which is needed by Tracco to have the proper rights to fetch all the tracking notifications sent as comments to the 'tracking user'.
|
82
86
|
|
83
|
-
##
|
84
|
-
|
87
|
+
## Collecting data from Trello
|
88
|
+
To collect and store tracking data from your Trello board, you can use one of the provided rake tasks, e.g.
|
85
89
|
|
86
90
|
```ruby
|
87
91
|
rake 'run:today[test]' # will extract today's tracked data and store on the test db
|
@@ -106,7 +110,7 @@ Tracking data collected from Trello are stored in a MongoDB database.
|
|
106
110
|
|
107
111
|
There are two env variables you can set to configure mongodb
|
108
112
|
|
109
|
-
- `
|
113
|
+
- `TRACCO_ENV` defines which mongodb environment is actually used ("development", "test", "production"). Development is the default environment.
|
110
114
|
- `MONGOID_CONFIG_PATH` defines the path to the mongoid configuration file (default is `config/mongoid.yml`)
|
111
115
|
|
112
116
|
A standard mongoid.yml is the following:
|
@@ -171,7 +175,7 @@ The default env is development. To load a console in the (e.g.) production db en
|
|
171
175
|
rake "console[production]"
|
172
176
|
```
|
173
177
|
|
174
|
-
|
178
|
+
## Estimate format convention
|
175
179
|
To set an estimate on a card, a Trello user should send a notification from that card to the tracker username, e.g.
|
176
180
|
|
177
181
|
@trackinguser [15p]
|
@@ -184,7 +188,7 @@ estimates can be given in hours (h), days (d/g) or pomodori (p).
|
|
184
188
|
|
185
189
|
will add the estimate (4 hours) in date 22.11.2012.
|
186
190
|
|
187
|
-
|
191
|
+
## Effort format convention
|
188
192
|
To set an effort in the current day on a card, a Trello user should send a notification from that card to the tracker username, e.g.
|
189
193
|
|
190
194
|
@trackinguser +6p
|
data/bin/tracco
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib') unless $:.include?(File.dirname(__FILE__) + '/../lib')
|
3
|
+
|
4
|
+
require 'trello'
|
5
|
+
require 'rainbow'
|
6
|
+
require 'set'
|
7
|
+
require 'yaml'
|
8
|
+
require 'chronic'
|
9
|
+
require 'mongoid'
|
10
|
+
require 'forwardable'
|
11
|
+
|
12
|
+
require 'tracco/cli'
|
13
|
+
require 'tracco/version'
|
14
|
+
require 'tracco/mongoid_helper'
|
15
|
+
require 'tracco/trello_configuration'
|
16
|
+
require 'tracco/trello_authorize'
|
17
|
+
require 'tracco/models/tracked_card'
|
18
|
+
require 'tracco/models/member'
|
19
|
+
require 'tracco/models/estimate'
|
20
|
+
require 'tracco/models/effort'
|
21
|
+
require 'tracco/tracking/base'
|
22
|
+
require 'tracco/tracking/estimate_tracking'
|
23
|
+
require 'tracco/tracking/effort_tracking'
|
24
|
+
require 'tracco/tracking/card_done_tracking'
|
25
|
+
require 'tracco/tracking/invalid_tracking'
|
26
|
+
require 'tracco/tracking/factory'
|
27
|
+
require 'tracco/trello_tracker'
|
28
|
+
require 'tracco/configuration'
|
29
|
+
require 'tracco/exporters/google_docs'
|
30
|
+
|
31
|
+
require 'patches/trello/member'
|
32
|
+
require 'patches/trello/card'
|
33
|
+
|
34
|
+
Tracco::CLI.start(ARGV)
|
Binary file
|
Binary file
|
data/lib/patches/trello/card.rb
CHANGED
data/lib/tasks/tasks.rake
CHANGED
@@ -1,39 +1,56 @@
|
|
1
|
+
#TODO: deprecated (use 'tracco console')
|
1
2
|
desc "Open an irb session preloaded with this library, e.g. rake 'console[production]' will open a irb session with the production db env"
|
2
|
-
task :console, [:
|
3
|
-
args.with_defaults(
|
4
|
-
sh "export
|
3
|
+
task :console, [:tracco_env] do |t, args|
|
4
|
+
args.with_defaults(tracco_env: "development")
|
5
|
+
sh "export TRACCO_ENV=#{args.tracco_env}; irb -rubygems -I lib -r tracco -r startup_trello.rb -r awesome_print"
|
5
6
|
end
|
6
7
|
|
7
|
-
|
8
|
-
|
8
|
+
#TODO: deprecated (use 'tracco console')
|
9
|
+
task :c, [:tracco_env] do |t, args|
|
10
|
+
Rake::Task[:console].invoke(args.tracco_env)
|
9
11
|
end
|
10
12
|
|
13
|
+
desc "Copy template config files"
|
14
|
+
task :prepare do
|
15
|
+
Dir.glob("config/*.template.yml").each do |file|
|
16
|
+
template_file = File.basename(file)
|
17
|
+
target_file = template_file.sub('.template', '')
|
18
|
+
if File.exists?(File.join('config', target_file))
|
19
|
+
puts "skipping #{target_file.color(:yellow)}, already exists."
|
20
|
+
else
|
21
|
+
cp File.join('config', template_file), File.join('config', target_file)
|
22
|
+
puts "please edit the #{target_file} to have all the proper configurations"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
#TODO: deprecated (use 'tracco collect')
|
11
28
|
namespace :run do
|
12
29
|
include TrelloConfiguration
|
13
30
|
|
14
31
|
desc "Run on the cards tracked starting from a given day, e.g. rake 'run:from_day[2012-11-1]'"
|
15
|
-
task :from_day, [:starting_date, :
|
16
|
-
args.with_defaults(starting_date: Date.today.to_s,
|
17
|
-
|
32
|
+
task :from_day, [:starting_date, :tracco_env] => [:ensure_environment] do |t, args|
|
33
|
+
args.with_defaults(starting_date: Date.today.to_s, tracco_env: "development")
|
34
|
+
Tracco::Database.load_env(args.tracco_env)
|
18
35
|
|
19
36
|
tracker = Tracco::TrelloTracker.new
|
20
37
|
tracker.track(Date.parse(args.starting_date))
|
21
38
|
end
|
22
39
|
|
23
40
|
desc "Run on the cards tracked today, #{Date.today}"
|
24
|
-
task :today, [:
|
25
|
-
args.with_defaults(
|
26
|
-
Rake.application.invoke_task("run:from_day[#{Date.today.to_s}, #{args.
|
41
|
+
task :today, [:tracco_env] => [:ensure_environment] do |t, args|
|
42
|
+
args.with_defaults(tracco_env: "development")
|
43
|
+
Rake.application.invoke_task("run:from_day[#{Date.today.to_s}, #{args.tracco_env}]")
|
27
44
|
end
|
28
45
|
end
|
29
46
|
|
30
47
|
namespace :export do
|
31
48
|
desc "Export all cards to a google docs spreadsheet, e.g. rake \"export:google_docs[my_sheet,tracking,production]\""
|
32
|
-
task :google_docs, [:spreadsheet, :worksheet, :
|
33
|
-
args.with_defaults(
|
34
|
-
|
49
|
+
task :google_docs, [:spreadsheet, :worksheet, :tracco_env] => [:ensure_environment] do |t, args|
|
50
|
+
args.with_defaults(tracco_env: "development")
|
51
|
+
Tracco::Database.load_env(args.tracco_env)
|
35
52
|
|
36
|
-
exporter = Tracco::
|
53
|
+
exporter = Tracco::Exporters::GoogleDocs.new(args.spreadsheet, args.worksheet)
|
37
54
|
spreadsheet_url = exporter.export
|
38
55
|
|
39
56
|
puts "[DONE]".color(:green)
|
data/lib/tracco.rb
CHANGED
@@ -6,6 +6,8 @@ require 'chronic'
|
|
6
6
|
require 'mongoid'
|
7
7
|
require 'forwardable'
|
8
8
|
|
9
|
+
require 'tracco/cli'
|
10
|
+
require 'tracco/version'
|
9
11
|
require 'tracco/mongoid_helper'
|
10
12
|
require 'tracco/trello_configuration'
|
11
13
|
require 'tracco/trello_authorize'
|
@@ -20,11 +22,11 @@ require 'tracco/tracking/card_done_tracking'
|
|
20
22
|
require 'tracco/tracking/invalid_tracking'
|
21
23
|
require 'tracco/tracking/factory'
|
22
24
|
require 'tracco/trello_tracker'
|
23
|
-
require 'tracco/
|
25
|
+
require 'tracco/configuration'
|
26
|
+
require 'tracco/exporters/google_docs'
|
24
27
|
|
25
28
|
require 'patches/trello/member'
|
26
29
|
require 'patches/trello/card'
|
27
30
|
|
28
|
-
TrelloConfiguration::Database.load_env(ENV['MONGOID_ENV'] || "development", ENV['MONGOID_CONFIG_PATH'])
|
29
|
-
|
30
31
|
Trello.logger.level = Logger::DEBUG
|
32
|
+
Tracco.load_env!
|
data/lib/tracco/cli.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'thor/actions'
|
3
|
+
|
4
|
+
module Tracco
|
5
|
+
class CLI < Thor
|
6
|
+
include Thor::Actions
|
7
|
+
|
8
|
+
desc "console ENVIRONMENT", "Open an irb session preloaded with this library"
|
9
|
+
long_desc <<-LONGDESC
|
10
|
+
Open an irb session preloaded with this library.
|
11
|
+
e.g. 'tracco console production' will open a irb session with the production environment
|
12
|
+
LONGDESC
|
13
|
+
def console(environment="development")
|
14
|
+
error("invalid environment specified: #{environment}") unless is_valid_env?(environment)
|
15
|
+
|
16
|
+
run "export TRACCO_ENV=#{environment}; irb -rubygems -I lib -r tracco -r startup_trello.rb -r awesome_print"
|
17
|
+
end
|
18
|
+
map %w(c) => :console
|
19
|
+
|
20
|
+
|
21
|
+
desc "collect STARTING_FROM", "Run tracking data fetching on the cards tracked starting from a given date"
|
22
|
+
method_option :environment, :aliases => "-e", :desc => "the env to use", :default => "development"
|
23
|
+
method_option :mongoid_config_path, :aliases => "-m", :desc => "the mongoid config file to use"
|
24
|
+
def collect(starting_date=Date.today.to_s)
|
25
|
+
environment = options[:environment]
|
26
|
+
error("invalid environment specified: #{environment}") unless is_valid_env?(environment)
|
27
|
+
|
28
|
+
starting_date = Date.today.to_s if starting_date == "today"
|
29
|
+
error("invalid date: #{starting_date}") unless is_valid_date?(starting_date)
|
30
|
+
|
31
|
+
Tracco::Database.load_env(environment, options[:mongoid_config_path])
|
32
|
+
|
33
|
+
puts "collecting tracking data starting from #{starting_date} in the #{environment} env."
|
34
|
+
tracker = Tracco::TrelloTracker.new
|
35
|
+
tracker.track(Date.parse(starting_date))
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
desc "version", "Prints Tracco's version information"
|
40
|
+
def version
|
41
|
+
say "Tracco version #{Tracco::VERSION}"
|
42
|
+
end
|
43
|
+
map %w(-v --version) => :version
|
44
|
+
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def is_valid_env?(environment)
|
49
|
+
%w{production development test}.include? environment
|
50
|
+
end
|
51
|
+
|
52
|
+
def is_valid_date?(date)
|
53
|
+
begin
|
54
|
+
Date.parse(date)
|
55
|
+
true
|
56
|
+
rescue ArgumentError
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def error(message)
|
62
|
+
say "ERROR: #{message}"
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Tracco
|
2
|
+
def self.environment
|
3
|
+
ENV['TRACCO_ENV']
|
4
|
+
end
|
5
|
+
|
6
|
+
def self.environment=(env_name)
|
7
|
+
ENV['TRACCO_ENV'] = env_name.to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.load_env!
|
11
|
+
begin
|
12
|
+
Database.load_env(environment || "development", ENV['MONGOID_CONFIG_PATH'])
|
13
|
+
rescue Errno::ENOENT => e
|
14
|
+
puts e.message
|
15
|
+
puts "try running 'rake prepare'"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Database
|
20
|
+
def self.load_env(tracco_env, mongoid_configuration_path=nil)
|
21
|
+
Tracco.environment = tracco_env
|
22
|
+
Mongoid.load!(mongoid_configuration_path || "config/mongoid.yml", tracco_env)
|
23
|
+
Trello.logger.info "Mongo db env: #{tracco_env.color(:green)}."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require "google_drive"
|
2
|
+
require 'highline/import'
|
3
|
+
|
4
|
+
module Tracco
|
5
|
+
module Exporters
|
6
|
+
class GoogleDocs
|
7
|
+
include TrelloConfiguration
|
8
|
+
|
9
|
+
def initialize(spreadsheet_name, worksheet_name)
|
10
|
+
@spreadsheet_name = spreadsheet_name || "trello effort tracking"
|
11
|
+
@worksheet_name = worksheet_name || "tracking"
|
12
|
+
end
|
13
|
+
|
14
|
+
def export
|
15
|
+
Trello.logger.info "Running exporter from db env '#{Environment.name}' to google docs '#{@spreadsheet_name.color(:green)}##{@worksheet_name.color(:green)}'..."
|
16
|
+
|
17
|
+
spreadsheet = google_docs_session.spreadsheet_by_title(@spreadsheet_name) || google_docs_session.create_spreadsheet(@spreadsheet_name)
|
18
|
+
worksheet = spreadsheet.worksheet_by_title(@worksheet_name) || spreadsheet.add_worksheet(@worksheet_name)
|
19
|
+
|
20
|
+
create_header(worksheet)
|
21
|
+
index = 2 # skip the header
|
22
|
+
|
23
|
+
cards = TrackedCard.all_tracked_cards(:method => :first_activity_date, :order => :desc)
|
24
|
+
cards.each do |card|
|
25
|
+
print ".".color(:green)
|
26
|
+
worksheet[index, columns[:user_story_id]] = card.short_id
|
27
|
+
worksheet[index, columns[:user_story_name]] = card.name
|
28
|
+
worksheet[index, columns[:start_date]] = card.working_start_date
|
29
|
+
worksheet[index, columns[:total_effort]] = card.total_effort
|
30
|
+
worksheet[index, columns[:last_estimate_error]] = card.last_estimate_error
|
31
|
+
card.estimates.each_with_index do |estimate, i|
|
32
|
+
worksheet[index, columns[:estimate]+i] = estimate.amount
|
33
|
+
end
|
34
|
+
index += 1
|
35
|
+
end
|
36
|
+
|
37
|
+
saved = worksheet.save
|
38
|
+
spreadsheet.human_url if saved
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def google_docs_session(email=configuration["google_docs_username"])
|
44
|
+
@session ||= login(email)
|
45
|
+
end
|
46
|
+
|
47
|
+
def login(email)
|
48
|
+
username = ask("Enter your google docs username: ") { |q| q.default = email }
|
49
|
+
password = ask("Enter your google docs password: ") { |q| q.echo = false }
|
50
|
+
|
51
|
+
GoogleDrive.login(username, password)
|
52
|
+
end
|
53
|
+
|
54
|
+
def columns
|
55
|
+
@columns ||= {
|
56
|
+
user_story_id: 1,
|
57
|
+
user_story_name: 2,
|
58
|
+
start_date: 3,
|
59
|
+
total_effort: 4,
|
60
|
+
last_estimate_error: 5,
|
61
|
+
estimate: 6,
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def create_header(worksheet)
|
66
|
+
worksheet.update_cells(1,1, [["ID", "Story Name", "Start Date", "Total Effort (hours)", "Last estimate error (%)", "First Estimate", "2nd estimate", "3rd estimate"]])
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/tracco/tracking/base.rb
CHANGED
@@ -2,7 +2,6 @@ module Tracco
|
|
2
2
|
module Tracking
|
3
3
|
module Base
|
4
4
|
extend Forwardable
|
5
|
-
include TrelloConfiguration
|
6
5
|
|
7
6
|
TIME_CONVERTERS = {
|
8
7
|
'h' => lambda { |estimate| estimate },
|
@@ -26,7 +25,7 @@ module Tracco
|
|
26
25
|
end
|
27
26
|
|
28
27
|
def to_s
|
29
|
-
"[#{date}] From #{notifier.username.color(:green)}\t on card '#{trello_card.name.color(:yellow)}': #{
|
28
|
+
"[#{date}] From #{notifier.username.color(:green)}\t on card '#{trello_card.name.color(:yellow)}': #{tracking_message}"
|
30
29
|
end
|
31
30
|
|
32
31
|
private
|
@@ -44,10 +43,14 @@ module Tracco
|
|
44
43
|
end
|
45
44
|
|
46
45
|
def raw_tracking
|
47
|
-
|
46
|
+
@raw_tracking ||= remove_tracker_from(tracking_message)
|
48
47
|
end
|
49
48
|
|
50
|
-
def
|
49
|
+
def remove_tracker_from(tracking_message)
|
50
|
+
tracking_message.sub(/^\s*@\w+\s/, "")
|
51
|
+
end
|
52
|
+
|
53
|
+
def tracking_message
|
51
54
|
tracking_notification.data['text']
|
52
55
|
end
|
53
56
|
|
@@ -14,20 +14,8 @@ module TrelloConfiguration
|
|
14
14
|
|
15
15
|
end
|
16
16
|
|
17
|
-
class Database
|
18
|
-
def self.load_env(db_env, mongoid_configuration_path=nil)
|
19
|
-
ENV['MONGOID_ENV'] = db_env
|
20
|
-
Mongoid.load!(mongoid_configuration_path || "config/mongoid.yml", db_env)
|
21
|
-
Trello.logger.info "Mongo db env: #{db_env.color(:green)}."
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
17
|
private
|
26
18
|
|
27
|
-
def db_environment
|
28
|
-
ENV['MONGOID_ENV']
|
29
|
-
end
|
30
|
-
|
31
19
|
def configuration
|
32
20
|
@configuration ||= load_configuration
|
33
21
|
end
|
@@ -22,7 +22,7 @@ module Tracco
|
|
22
22
|
begin
|
23
23
|
tracked_card = TrackedCard.update_or_create_with(tracking_notification.card)
|
24
24
|
tracked_card.add!(tracking)
|
25
|
-
Trello.logger.info tracking
|
25
|
+
Trello.logger.info tracking.to_s
|
26
26
|
|
27
27
|
rescue StandardError => e
|
28
28
|
Trello.logger.warn "skipping tracking: #{e.message}".color(:magenta)
|
data/lib/tracco/version.rb
CHANGED
data/script/ci/run_build.sh
CHANGED
@@ -4,9 +4,14 @@ require 'trello'
|
|
4
4
|
describe "TrelloAuthorization" do
|
5
5
|
include TrelloAuthorize
|
6
6
|
|
7
|
+
let(:config) {
|
8
|
+
# auth params for trackinguser_for_test/testinguser!
|
9
|
+
trello_testing_board_auth_params
|
10
|
+
}
|
11
|
+
|
7
12
|
it "authorizes connection to Trello", :needs_valid_configuration => true do
|
8
|
-
authorize_on_trello
|
9
|
-
|
10
|
-
Trello::Member.find("me").
|
13
|
+
authorize_on_trello(developer_public_key: config.dev_key, access_token_key: config.token)
|
14
|
+
|
15
|
+
Trello::Member.find("me").username.should == "trackinguser_for_test"
|
11
16
|
end
|
12
17
|
end
|
@@ -14,9 +14,7 @@ module Tracco
|
|
14
14
|
|
15
15
|
let(:config) {
|
16
16
|
# auth params for trackinguser_for_test/testinguser!
|
17
|
-
|
18
|
-
dev_key: "ef7c400e711057d7ba5e00be20139a33",
|
19
|
-
token: "9047d8fdbfdc960d41910673e300516cc8630dd4967e9b418fc27e410516362e")
|
17
|
+
trello_testing_board_auth_params
|
20
18
|
}
|
21
19
|
|
22
20
|
it "tracks some estimates and efforts", :needs_valid_configuration => true do
|
@@ -51,18 +49,5 @@ module Tracco
|
|
51
49
|
another_done_card.should be_done
|
52
50
|
end
|
53
51
|
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def without_logging(&block)
|
58
|
-
original_error_level = Trello.logger.level
|
59
|
-
|
60
|
-
begin
|
61
|
-
Trello.logger.level = Logger::WARN
|
62
|
-
block.call unless block.nil?
|
63
|
-
ensure
|
64
|
-
Trello.logger.level = original_error_level
|
65
|
-
end
|
66
|
-
end
|
67
52
|
end
|
68
53
|
end
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe Trello::Card do
|
4
4
|
|
5
5
|
describe "#in_done_column?" do
|
6
|
-
|
6
|
+
|
7
7
|
let(:trello_card) { Trello::Card.new("name" => "a name", "desc" => "any description") }
|
8
8
|
|
9
9
|
let(:todo_column) { Trello::List.new("name" => "ToDo") }
|
@@ -21,5 +21,10 @@ describe Trello::Card do
|
|
21
21
|
trello_card.in_done_column?.should be_false
|
22
22
|
end
|
23
23
|
|
24
|
+
it "is false when the card cannot be found on Trello" do
|
25
|
+
trello_card.stub(:list).and_raise(Trello::Error)
|
26
|
+
trello_card.in_done_column?.should be_false
|
27
|
+
end
|
28
|
+
|
24
29
|
end
|
25
30
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -14,6 +14,7 @@ rescue Bundler::GemNotFound => e
|
|
14
14
|
exit!
|
15
15
|
end
|
16
16
|
|
17
|
+
ENV['TRACCO_ENV'] = "test"
|
17
18
|
require 'tracco'
|
18
19
|
|
19
20
|
require 'factory_girl'
|
@@ -27,6 +28,3 @@ RSpec.configure do |configuration|
|
|
27
28
|
configuration.include Mongoid::Matchers
|
28
29
|
configuration.include FactoryGirl::Syntax::Methods # Repeating "FactoryGirl" is too verbose for me...
|
29
30
|
end
|
30
|
-
|
31
|
-
# force test env for the mongodb configuration
|
32
|
-
TrelloConfiguration::Database.load_env("test")
|
@@ -5,8 +5,15 @@ TIME_MEASUREMENTS = {
|
|
5
5
|
pomodori: 'p'
|
6
6
|
}
|
7
7
|
|
8
|
+
def trello_testing_board_auth_params
|
9
|
+
# auth params for trackinguser_for_test/testinguser!
|
10
|
+
OpenStruct.new(tracker: "trackinguser_for_test",
|
11
|
+
dev_key: "ef7c400e711057d7ba5e00be20139a33",
|
12
|
+
token: "9047d8fdbfdc960d41910673e300516cc8630dd4967e9b418fc27e410516362e")
|
13
|
+
end
|
14
|
+
|
8
15
|
def unrecognized_notification
|
9
|
-
create_notification(data: { 'text' => '@
|
16
|
+
create_notification(data: { 'text' => '@any_tracker hi there!' })
|
10
17
|
end
|
11
18
|
|
12
19
|
def notification_with_message(message)
|
@@ -14,11 +21,11 @@ def notification_with_message(message)
|
|
14
21
|
end
|
15
22
|
|
16
23
|
def create_estimate(time_measurement)
|
17
|
-
create_notification(data: { 'text' => "@
|
24
|
+
create_notification(data: { 'text' => "@any_tracker [1.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
18
25
|
end
|
19
26
|
|
20
27
|
def create_effort(time_measurement)
|
21
|
-
create_notification(data: { 'text' => "@
|
28
|
+
create_notification(data: { 'text' => "@any_tracker +4.5#{TIME_MEASUREMENTS[time_measurement]}]" })
|
22
29
|
end
|
23
30
|
|
24
31
|
def with(notification)
|
@@ -31,8 +38,19 @@ def with_message(notification_message, &block)
|
|
31
38
|
end
|
32
39
|
|
33
40
|
def create_notification(custom_params)
|
34
|
-
params = { data: { 'text' => "@
|
41
|
+
params = { data: { 'text' => "@any_tracker +2h" }, date: "2012-10-28T21:06:14.801Z", member_creator: stub(username: "pietrodibello") }
|
35
42
|
params.merge!(custom_params)
|
36
43
|
|
37
44
|
stub(data: params[:data], date: params[:date], member_creator: params[:member_creator]).as_null_object
|
38
45
|
end
|
46
|
+
|
47
|
+
def without_logging(&block)
|
48
|
+
original_error_level = Trello.logger.level
|
49
|
+
|
50
|
+
begin
|
51
|
+
Trello.logger.level = Logger::WARN
|
52
|
+
block.call unless block.nil?
|
53
|
+
ensure
|
54
|
+
Trello.logger.level = original_error_level
|
55
|
+
end
|
56
|
+
end
|
data/spec/tracco_spec.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tracco do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@original = ENV["TRACCO_ENV"]
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
ENV["TRACCO_ENV"] = @original
|
11
|
+
end
|
12
|
+
|
13
|
+
describe ".environment" do
|
14
|
+
|
15
|
+
it "tells the current environment name" do
|
16
|
+
ENV['TRACCO_ENV'] = "any_env"
|
17
|
+
|
18
|
+
Tracco.environment.should == "any_env"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "sets an environment variable" do
|
22
|
+
Tracco.environment = "an_env"
|
23
|
+
|
24
|
+
Tracco.environment.should == "an_env"
|
25
|
+
ENV['TRACCO_ENV'].should == "an_env"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe ".environment=" do
|
30
|
+
|
31
|
+
it "tells the current environment name" do
|
32
|
+
ENV['TRACCO_ENV'] = "any_env"
|
33
|
+
|
34
|
+
Tracco.environment.should == "any_env"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "sets an environment variable" do
|
38
|
+
Tracco.environment = "an_env"
|
39
|
+
|
40
|
+
Tracco.environment.should == "an_env"
|
41
|
+
ENV['TRACCO_ENV'].should == "an_env"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -11,7 +11,7 @@ module Tracco
|
|
11
11
|
end
|
12
12
|
|
13
13
|
before(:each) do
|
14
|
-
Trello::Member.stub(:find).and_return(Member.new(username: "
|
14
|
+
Trello::Member.stub(:find).and_return(Member.new(username: "any_member"))
|
15
15
|
end
|
16
16
|
|
17
17
|
it "is nil when the notification does not contain an estimate" do
|
@@ -19,42 +19,47 @@ module Tracco
|
|
19
19
|
end
|
20
20
|
|
21
21
|
it "does not parse effort in minutes (e.g. +30m)" do
|
22
|
-
with_message("@
|
22
|
+
with_message("@test_tracker +30m") { |tracking| tracking.effort.should be_nil }
|
23
|
+
end
|
24
|
+
|
25
|
+
it "does not count the tracker as a member of the effort" do
|
26
|
+
with_message("@test_tracker +3p") { |tracking| tracking.effort.members.map(&:username).should == ["any_member"] }
|
23
27
|
end
|
24
28
|
|
25
29
|
it "is the hour-based effort when the notification contains an effort in hours" do
|
26
30
|
Trello::Member.should_receive(:find).with("michelepangrazzi").and_return(michelepangrazzi)
|
27
31
|
|
28
|
-
raw_data = create_notification(data: { 'text' => "@
|
32
|
+
raw_data = create_notification(data: { 'text' => "@test_tracker +2h" },
|
29
33
|
date: "2012-10-28T21:06:14.801Z",
|
30
34
|
member_creator: stub(username: "michelepangrazzi"))
|
31
35
|
|
32
|
-
|
36
|
+
expected_effort = Effort.new(amount: 2.0, date: Date.parse('2012-10-28'), members: [michelepangrazzi])
|
37
|
+
Tracking::Factory.build_from(raw_data).effort.should == expected_effort
|
33
38
|
end
|
34
39
|
|
35
40
|
it "converts the effort in hours when the notification contains an effort in days" do
|
36
|
-
with_message("@
|
37
|
-
with_message("@
|
41
|
+
with_message("@test_tracker +1.5d") { |t| t.effort.amount.should == 8+4 }
|
42
|
+
with_message("@test_tracker +1.5g") { |t| t.effort.amount.should == 8+4 }
|
38
43
|
end
|
39
44
|
|
40
45
|
it "converts the effort in hours when the notification contains an effort in pomodori" do
|
41
|
-
with_message("@
|
46
|
+
with_message("@test_tracker +10p") { |t| t.effort.amount.should == 5}
|
42
47
|
end
|
43
48
|
|
44
49
|
it "fetch the effort from a complex effort message" do
|
45
|
-
with_message "@
|
50
|
+
with_message "@test_tracker ho speso +2h e spero che stavolta possiamo rilasciarla" do |tracking|
|
46
51
|
tracking.effort.amount.should == 2.0
|
47
52
|
end
|
48
53
|
end
|
49
54
|
|
50
55
|
it "fetch the effort even when beween square brackets" do
|
51
|
-
with_message "@
|
56
|
+
with_message "@test_tracker [+0.5h]" do |tracking|
|
52
57
|
tracking.effort.amount.should == 0.5
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
56
61
|
it "computes the effort considering all the mentioned team mates in the message" do
|
57
|
-
with_message "@
|
62
|
+
with_message "@test_tracker +2h assieme a @michelepangrazzi e @alessandrodescovi" do |tracking|
|
58
63
|
tracking.effort.amount.should == 2.0 * 3
|
59
64
|
end
|
60
65
|
end
|
@@ -64,7 +69,7 @@ module Tracco
|
|
64
69
|
Trello::Member.should_receive(:find).with(username).and_return(self.send(username))
|
65
70
|
end
|
66
71
|
|
67
|
-
notification = create_notification(data: { 'text' => "@
|
72
|
+
notification = create_notification(data: { 'text' => "@test_tracker +2h assieme a @michelepangrazzi e @alessandrodescovi" },
|
68
73
|
member_creator: stub(username: "pietrodibello"))
|
69
74
|
with notification do |tracking|
|
70
75
|
tracking.effort.members.should == [michelepangrazzi, alessandrodescovi, pietrodibello]
|
@@ -76,7 +81,7 @@ module Tracco
|
|
76
81
|
Trello::Member.should_receive(:find).with(username).and_return(self.send(username))
|
77
82
|
end
|
78
83
|
|
79
|
-
notification = create_notification(data: { 'text' => "@
|
84
|
+
notification = create_notification(data: { 'text' => "@test_tracker +3p (@alessandrodescovi @michelevincenzi)" },
|
80
85
|
member_creator: stub(username: "pietrodibello"))
|
81
86
|
|
82
87
|
with notification do |tracking|
|
@@ -86,7 +91,7 @@ module Tracco
|
|
86
91
|
end
|
87
92
|
|
88
93
|
it "tracks the effort with the date given in the notification text, not the actual notification date" do
|
89
|
-
raw_data = create_notification(data: { 'text' => "@
|
94
|
+
raw_data = create_notification(data: { 'text' => "@test_tracker 22.11.2012 +6p" }, date: "2012-09-19T12:46:13.713Z")
|
90
95
|
|
91
96
|
tracking = Tracking::Factory.build_from(raw_data)
|
92
97
|
|
@@ -94,7 +99,7 @@ module Tracco
|
|
94
99
|
end
|
95
100
|
|
96
101
|
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
97
|
-
raw_data = create_notification(data: { 'text' => "@
|
102
|
+
raw_data = create_notification(data: { 'text' => "@test_tracker yesterday +6p" }, date: "2012-09-19T12:46:13.713Z")
|
98
103
|
|
99
104
|
tracking = Tracking::Factory.build_from(raw_data)
|
100
105
|
|
@@ -102,7 +107,7 @@ module Tracco
|
|
102
107
|
end
|
103
108
|
|
104
109
|
it "tracks the effort to yesterday when the keyword 'yesterday' is present before the effort amount" do
|
105
|
-
raw_data = create_notification(data: { 'text' => "@
|
110
|
+
raw_data = create_notification(data: { 'text' => "@test_tracker +6p yesterday" }, date: "2012-09-19T12:46:13.713Z")
|
106
111
|
|
107
112
|
tracking = Tracking::Factory.build_from(raw_data)
|
108
113
|
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Tracco
|
4
|
+
module Tracking
|
5
|
+
describe InvalidTracking do
|
6
|
+
|
7
|
+
describe "#add_to" do
|
8
|
+
it "just logs a warning message and does nothing" do
|
9
|
+
Trello.logger.should_receive(:warn).with(/^Ignoring tracking notification:/)
|
10
|
+
|
11
|
+
invalid_tracking = Tracking::Factory.build_from(unrecognized_notification)
|
12
|
+
invalid_tracking.add_to(TrackedCard.new)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -12,6 +12,15 @@ describe TrelloConfiguration do
|
|
12
12
|
authorization_params_from_config_file["developer_public_key"].should == "any_dpk"
|
13
13
|
authorization_params_from_config_file["access_token_key"].should == "any_atk"
|
14
14
|
end
|
15
|
+
|
16
|
+
it "returns an empty hash when the configuration file is invalid" do
|
17
|
+
YAML.should_receive(:load_file).with("config/config.yml").and_raise(NoMethodError)
|
18
|
+
|
19
|
+
without_logging do
|
20
|
+
authorization_params_from_config_file.should == {}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
end
|
16
25
|
|
17
26
|
describe "#tracker_username" do
|
data/tracco.gemspec
CHANGED
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
|
|
19
19
|
|
20
20
|
gem.require_paths = ["lib"]
|
21
21
|
gem.files = `git ls-files`.split("\n")
|
22
|
+
gem.executables = %w(tracco)
|
22
23
|
gem.test_files = `git ls-files -- {spec}/*`.split("\n")
|
23
24
|
gem.extra_rdoc_files = ["README.md"]
|
24
25
|
|
@@ -31,12 +32,8 @@ Gem::Specification.new do |gem|
|
|
31
32
|
gem.add_runtime_dependency 'rainbow'
|
32
33
|
gem.add_runtime_dependency 'chronic'
|
33
34
|
gem.add_runtime_dependency 'highline'
|
35
|
+
gem.add_runtime_dependency 'thor'
|
34
36
|
|
35
|
-
gem.add_development_dependency '
|
36
|
-
gem.add_development_dependency 'rspec'
|
37
|
-
gem.add_development_dependency 'rspec-mocks'
|
38
|
-
gem.add_development_dependency 'mongoid-rspec'
|
39
|
-
gem.add_development_dependency 'database_cleaner'
|
40
|
-
gem.add_development_dependency 'factory_girl'
|
37
|
+
gem.add_development_dependency 'awesome_print'
|
41
38
|
gem.add_development_dependency 'debugger'
|
42
39
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracco
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
12
|
+
date: 2013-03-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: ruby-trello
|
@@ -124,78 +124,14 @@ dependencies:
|
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
126
|
- !ruby/object:Gem::Dependency
|
127
|
-
name:
|
127
|
+
name: thor
|
128
128
|
requirement: !ruby/object:Gem::Requirement
|
129
129
|
none: false
|
130
130
|
requirements:
|
131
131
|
- - ! '>='
|
132
132
|
- !ruby/object:Gem::Version
|
133
133
|
version: '0'
|
134
|
-
type: :
|
135
|
-
prerelease: false
|
136
|
-
version_requirements: !ruby/object:Gem::Requirement
|
137
|
-
none: false
|
138
|
-
requirements:
|
139
|
-
- - ! '>='
|
140
|
-
- !ruby/object:Gem::Version
|
141
|
-
version: '0'
|
142
|
-
- !ruby/object:Gem::Dependency
|
143
|
-
name: rspec
|
144
|
-
requirement: !ruby/object:Gem::Requirement
|
145
|
-
none: false
|
146
|
-
requirements:
|
147
|
-
- - ! '>='
|
148
|
-
- !ruby/object:Gem::Version
|
149
|
-
version: '0'
|
150
|
-
type: :development
|
151
|
-
prerelease: false
|
152
|
-
version_requirements: !ruby/object:Gem::Requirement
|
153
|
-
none: false
|
154
|
-
requirements:
|
155
|
-
- - ! '>='
|
156
|
-
- !ruby/object:Gem::Version
|
157
|
-
version: '0'
|
158
|
-
- !ruby/object:Gem::Dependency
|
159
|
-
name: rspec-mocks
|
160
|
-
requirement: !ruby/object:Gem::Requirement
|
161
|
-
none: false
|
162
|
-
requirements:
|
163
|
-
- - ! '>='
|
164
|
-
- !ruby/object:Gem::Version
|
165
|
-
version: '0'
|
166
|
-
type: :development
|
167
|
-
prerelease: false
|
168
|
-
version_requirements: !ruby/object:Gem::Requirement
|
169
|
-
none: false
|
170
|
-
requirements:
|
171
|
-
- - ! '>='
|
172
|
-
- !ruby/object:Gem::Version
|
173
|
-
version: '0'
|
174
|
-
- !ruby/object:Gem::Dependency
|
175
|
-
name: mongoid-rspec
|
176
|
-
requirement: !ruby/object:Gem::Requirement
|
177
|
-
none: false
|
178
|
-
requirements:
|
179
|
-
- - ! '>='
|
180
|
-
- !ruby/object:Gem::Version
|
181
|
-
version: '0'
|
182
|
-
type: :development
|
183
|
-
prerelease: false
|
184
|
-
version_requirements: !ruby/object:Gem::Requirement
|
185
|
-
none: false
|
186
|
-
requirements:
|
187
|
-
- - ! '>='
|
188
|
-
- !ruby/object:Gem::Version
|
189
|
-
version: '0'
|
190
|
-
- !ruby/object:Gem::Dependency
|
191
|
-
name: database_cleaner
|
192
|
-
requirement: !ruby/object:Gem::Requirement
|
193
|
-
none: false
|
194
|
-
requirements:
|
195
|
-
- - ! '>='
|
196
|
-
- !ruby/object:Gem::Version
|
197
|
-
version: '0'
|
198
|
-
type: :development
|
134
|
+
type: :runtime
|
199
135
|
prerelease: false
|
200
136
|
version_requirements: !ruby/object:Gem::Requirement
|
201
137
|
none: false
|
@@ -204,7 +140,7 @@ dependencies:
|
|
204
140
|
- !ruby/object:Gem::Version
|
205
141
|
version: '0'
|
206
142
|
- !ruby/object:Gem::Dependency
|
207
|
-
name:
|
143
|
+
name: awesome_print
|
208
144
|
requirement: !ruby/object:Gem::Requirement
|
209
145
|
none: false
|
210
146
|
requirements:
|
@@ -238,7 +174,8 @@ dependencies:
|
|
238
174
|
description: ! 'Tracco is a Trello effort tracker: the purpose of Tracco is to extract
|
239
175
|
and track estimates and actual efforts out of the cards on your Trello boards.'
|
240
176
|
email: pierodibello@gmail.com
|
241
|
-
executables:
|
177
|
+
executables:
|
178
|
+
- tracco
|
242
179
|
extensions: []
|
243
180
|
extra_rdoc_files:
|
244
181
|
- README.md
|
@@ -253,16 +190,21 @@ files:
|
|
253
190
|
- LICENSE.txt
|
254
191
|
- README.md
|
255
192
|
- Rakefile
|
193
|
+
- bin/tracco
|
256
194
|
- config/config.template.yml
|
257
195
|
- config/config.yml.trackinguser_for_test
|
258
196
|
- config/mongoid.template.yml
|
197
|
+
- images/tracco.logo.png
|
198
|
+
- images/tracking_example.png
|
259
199
|
- lib/patches/trello/card.rb
|
260
200
|
- lib/patches/trello/member.rb
|
261
201
|
- lib/startup_trello.rb
|
262
202
|
- lib/tasks/rspec.rake
|
263
203
|
- lib/tasks/tasks.rake
|
264
204
|
- lib/tracco.rb
|
265
|
-
- lib/tracco/
|
205
|
+
- lib/tracco/cli.rb
|
206
|
+
- lib/tracco/configuration.rb
|
207
|
+
- lib/tracco/exporters/google_docs.rb
|
266
208
|
- lib/tracco/models/effort.rb
|
267
209
|
- lib/tracco/models/estimate.rb
|
268
210
|
- lib/tracco/models/member.rb
|
@@ -295,10 +237,12 @@ files:
|
|
295
237
|
- spec/spec_helper.rb
|
296
238
|
- spec/support/database_cleaner.rb
|
297
239
|
- spec/support/spec_helper_methods.rb
|
240
|
+
- spec/tracco_spec.rb
|
298
241
|
- spec/tracking/card_done_tracking_spec.rb
|
299
242
|
- spec/tracking/effort_tracking_spec.rb
|
300
243
|
- spec/tracking/estimate_tracking_spec.rb
|
301
244
|
- spec/tracking/factory_spec.rb
|
245
|
+
- spec/tracking/invalid_tracking_spec.rb
|
302
246
|
- spec/trello_authorize_spec.rb
|
303
247
|
- spec/trello_configuration_spec.rb
|
304
248
|
- spec/trello_tracker_spec.rb
|
@@ -318,7 +262,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
318
262
|
version: '0'
|
319
263
|
segments:
|
320
264
|
- 0
|
321
|
-
hash: -
|
265
|
+
hash: -2206961055360224389
|
322
266
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
323
267
|
none: false
|
324
268
|
requirements:
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require "google_drive"
|
2
|
-
require 'highline/import'
|
3
|
-
|
4
|
-
module Tracco
|
5
|
-
class GoogleDocsExporter
|
6
|
-
include TrelloConfiguration
|
7
|
-
|
8
|
-
def initialize(spreadsheet_name, worksheet_name)
|
9
|
-
@spreadsheet_name = spreadsheet_name || "trello effort tracking"
|
10
|
-
@worksheet_name = worksheet_name || "tracking"
|
11
|
-
end
|
12
|
-
|
13
|
-
def export
|
14
|
-
Trello.logger.info "Running exporter from db env '#{db_environment}' to google docs '#{@spreadsheet_name.color(:green)}##{@worksheet_name.color(:green)}'..."
|
15
|
-
|
16
|
-
spreadsheet = google_docs_session.spreadsheet_by_title(@spreadsheet_name) || google_docs_session.create_spreadsheet(@spreadsheet_name)
|
17
|
-
worksheet = spreadsheet.worksheet_by_title(@worksheet_name) || spreadsheet.add_worksheet(@worksheet_name)
|
18
|
-
|
19
|
-
create_header(worksheet)
|
20
|
-
index = 2 # skip the header
|
21
|
-
|
22
|
-
cards = TrackedCard.all_tracked_cards(:method => :first_activity_date, :order => :desc)
|
23
|
-
cards.each do |card|
|
24
|
-
print ".".color(:green)
|
25
|
-
worksheet[index, columns[:user_story_id]] = card.short_id
|
26
|
-
worksheet[index, columns[:user_story_name]] = card.name
|
27
|
-
worksheet[index, columns[:start_date]] = card.working_start_date
|
28
|
-
worksheet[index, columns[:total_effort]] = card.total_effort
|
29
|
-
worksheet[index, columns[:last_estimate_error]] = card.last_estimate_error
|
30
|
-
card.estimates.each_with_index do |estimate, i|
|
31
|
-
worksheet[index, columns[:estimate]+i] = estimate.amount
|
32
|
-
end
|
33
|
-
index += 1
|
34
|
-
end
|
35
|
-
|
36
|
-
saved = worksheet.save
|
37
|
-
spreadsheet.human_url if saved
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def google_docs_session(email=configuration["google_docs_username"])
|
43
|
-
@session ||= login(email)
|
44
|
-
end
|
45
|
-
|
46
|
-
def login(email)
|
47
|
-
username = ask("Enter your google docs username: ") { |q| q.default = email }
|
48
|
-
password = ask("Enter your google docs password: ") { |q| q.echo = false }
|
49
|
-
|
50
|
-
GoogleDrive.login(username, password)
|
51
|
-
end
|
52
|
-
|
53
|
-
def columns
|
54
|
-
@columns ||= {
|
55
|
-
user_story_id: 1,
|
56
|
-
user_story_name: 2,
|
57
|
-
start_date: 3,
|
58
|
-
total_effort: 4,
|
59
|
-
last_estimate_error: 5,
|
60
|
-
estimate: 6,
|
61
|
-
}
|
62
|
-
end
|
63
|
-
|
64
|
-
def create_header(worksheet)
|
65
|
-
worksheet.update_cells(1,1, [["ID", "Story Name", "Start Date", "Total Effort (hours)", "Last estimate error (%)", "First Estimate", "2nd estimate", "3rd estimate"]])
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|