trollolo 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.travis.yml +5 -1
- data/CHANGELOG.md +29 -0
- data/Gemfile +7 -2
- data/README.md +19 -0
- data/bin/trollolo +1 -1
- data/lib/array.rb +6 -0
- data/lib/backup.rb +67 -0
- data/lib/burndown_chart.rb +96 -67
- data/lib/burndown_data.rb +62 -123
- data/lib/card.rb +74 -30
- data/lib/cli.rb +131 -9
- data/lib/column.rb +61 -0
- data/lib/result.rb +0 -0
- data/lib/scrum_board.rb +104 -0
- data/lib/settings.rb +9 -4
- data/lib/trello_wrapper.rb +62 -0
- data/lib/trollolo.rb +10 -7
- data/lib/version.rb +1 -1
- data/scripts/.gitignore +1 -0
- data/scripts/burndowndata.py +113 -0
- data/scripts/create_burndown.py +111 -146
- data/scripts/graph.py +116 -0
- data/scripts/plot.py +131 -0
- data/spec/data/board.json +63 -0
- data/spec/data/burndown-data.yaml +3 -0
- data/spec/data/burndown_dir/burndown-data-01.yaml +1 -1
- data/spec/data/burndown_dir/burndown-data-02.yaml +1 -1
- data/spec/data/card.json +61 -0
- data/spec/data/full-board.json +1626 -0
- data/spec/data/lists.json +25 -25
- data/spec/data/trollolorc +5 -0
- data/spec/{command_line_spec.rb → integration/command_line_spec.rb} +1 -4
- data/spec/integration/create_burndown_spec.rb +57 -0
- data/spec/integration/integration_spec_helper.rb +10 -0
- data/spec/integration/support/aruba_hook.rb +11 -0
- data/spec/integration/support/custom_matchers.rb +13 -0
- data/spec/{wrapper → integration/wrapper}/credentials_input_wrapper +2 -2
- data/spec/{wrapper → integration/wrapper}/empty_config_trollolo_wrapper +2 -2
- data/spec/integration/wrapper/trollolo_wrapper +10 -0
- data/spec/unit/backup_spec.rb +107 -0
- data/spec/unit/burndown_chart_spec.rb +396 -0
- data/spec/unit/burndown_data_spec.rb +118 -0
- data/spec/unit/card_spec.rb +79 -0
- data/spec/unit/cli_spec.rb +38 -0
- data/spec/unit/retrieve_data_spec.rb +54 -0
- data/spec/unit/scrum_board_spec.rb +18 -0
- data/spec/{settings_spec.rb → unit/settings_spec.rb} +1 -1
- data/spec/{spec_helper.rb → unit/spec_helper.rb} +4 -12
- data/spec/unit/support/test_data_operations.rb +7 -0
- data/spec/unit/support/update_webmock_data +17 -0
- data/spec/unit/support/webmocks.rb +52 -0
- data/spec/unit/trello_wrapper_spec.rb +47 -0
- data/trollolo.gemspec +10 -11
- metadata +54 -37
- data/lib/trello.rb +0 -66
- data/spec/burndown_chart_spec.rb +0 -307
- data/spec/burndown_data_spec.rb +0 -125
- data/spec/card_spec.rb +0 -15
- data/spec/cli_spec.rb +0 -18
- data/spec/data/cards.json +0 -1002
- data/spec/trello_spec.rb +0 -32
- data/spec/wrapper/trollolo_wrapper +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5adc2629b2f526c70851abc5ba72765860d73e2f
|
4
|
+
data.tar.gz: d31159f96937237011765b1df87036d90a94fede
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7eb4de3cb4a144902d467e40471236ca54c8992228fc5b1b6531148887512609bb5e56f2b43abb646d4eca512008e9c6b7d3c228073c3f1bb2a94cd6a22532e9
|
7
|
+
data.tar.gz: 7df063a8b64b2e8eea6118115d1e0ab8b7653783c972abcd046b0c25b1a6951ac39147b2d4e01f4e1c1dfc7724f5554347cc85570695b5026310a6f746b9ab6f
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,34 @@
|
|
1
1
|
# Trollolo Changelog
|
2
2
|
|
3
|
+
## Version 0.0.4
|
4
|
+
|
5
|
+
* Allow to story points anywhere in the card name
|
6
|
+
* Read columns considered as not done from sprint yaml. This makes it possible
|
7
|
+
to configure additional work in progress columns.
|
8
|
+
* Add `burndowns` command to update multiple charts at once
|
9
|
+
* Add option `--no-tasks` to not show tasks part of the graph
|
10
|
+
* Add option `--with-fast-lane` to separately plot cards which have a
|
11
|
+
`Fast Lane` label.
|
12
|
+
* Store date and time when chart was updated
|
13
|
+
* Exclude checlists named "Feedback" from the tasks calculation
|
14
|
+
* Add commands to show organization data:
|
15
|
+
* The command `organization` shows basic info about the organization.
|
16
|
+
* The command `organization_members` lists all members.
|
17
|
+
* Add command to get raw JSON from Trello API
|
18
|
+
* Add handling of done tasks under the waterline at the beginning of a new
|
19
|
+
sprint
|
20
|
+
* Add `--plot` option to `burndown` command to immediately show chart
|
21
|
+
* Add `--output` option to `plot` command to specify the directory it uses
|
22
|
+
* Save date and time of fetching burndown data
|
23
|
+
* Optionally fetch general meta data for burndown chart from special card
|
24
|
+
* Include list named "Blocked" in burndown calculation
|
25
|
+
* Implement basic backup function:
|
26
|
+
* The command `backup` creates a backup of a board identified by its id
|
27
|
+
* The command `show_backup` shows the content of the backup
|
28
|
+
* The command `list_backups` shows the list of backups which have been made
|
29
|
+
* The backups are stored to the directory `~/.trollolo/backups` in JSON
|
30
|
+
format
|
31
|
+
|
3
32
|
## Version 0.0.3
|
4
33
|
|
5
34
|
* Document burndown generation work flow
|
data/Gemfile
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
source
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :test do
|
6
6
|
gem 'codeclimate-test-reporter'
|
7
|
-
gem 'rspec',
|
7
|
+
gem 'rspec', '~> 3'
|
8
8
|
gem 'aruba'
|
9
9
|
gem 'webmock'
|
10
10
|
gem 'given_filesystem'
|
11
|
+
gem 'byebug'
|
12
|
+
gem 'awesome_print'
|
13
|
+
gem 'pry'
|
14
|
+
gem 'ronn', '>=0.7.3'
|
15
|
+
gem 'rake'
|
11
16
|
end
|
data/README.md
CHANGED
@@ -19,6 +19,15 @@ functions work see the Trollolo man page. There is an
|
|
19
19
|
[example Trello board](https://trello.com/b/CRdddpdy/trollolo-testing-board)
|
20
20
|
which demonstrates the expected structure.
|
21
21
|
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
You can install Trollolo as gem with `gem install trollolo`.
|
25
|
+
|
26
|
+
For the chart generation you will need a working matplotlib installation and
|
27
|
+
the python module to read YAML. On openSUSE you can get that with
|
28
|
+
|
29
|
+
zypper install python-matplotlib python-matplotlib-tk python-PyYAML
|
30
|
+
|
22
31
|
## Configuration
|
23
32
|
|
24
33
|
Trollolo reads a configuration file `.trollolorc` in the home directory of the
|
@@ -85,8 +94,18 @@ To generate the actual burndown chart, go to the working directory and call:
|
|
85
94
|
|
86
95
|
trollolo plot SPRINT_NUMBER
|
87
96
|
|
97
|
+
or fetch and plot data in one step with:
|
98
|
+
|
99
|
+
trollolo burndown --plot
|
100
|
+
|
88
101
|
This will take the data from the file `burndown-data-SPRINT_NUMBER.yaml` and
|
89
102
|
create a nice chart from it. It will show the chart and also create a file
|
90
103
|
`burndown-SPRINT_NUMBER.png` you can upload as cover graphics to a card on your
|
91
104
|
Trello board.
|
92
105
|
|
106
|
+
Some more info can be found in the command line help with `trollolo help` and
|
107
|
+
`trollolo help burndown`.
|
108
|
+
|
109
|
+
### Example
|
110
|
+
|
111
|
+
![Burndown example](https://raw.githubusercontent.com/openSUSE/trollolo/master/examples/burndown-26.png)
|
data/bin/trollolo
CHANGED
data/lib/array.rb
ADDED
data/lib/backup.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class Backup
|
2
|
+
|
3
|
+
attr_accessor :directory
|
4
|
+
|
5
|
+
def initialize settings
|
6
|
+
@settings = settings
|
7
|
+
@directory = File.expand_path("~/.trollolo/backup")
|
8
|
+
end
|
9
|
+
|
10
|
+
def backup(board_id)
|
11
|
+
backup_path = File.join(@directory, board_id)
|
12
|
+
FileUtils.mkdir_p(backup_path)
|
13
|
+
|
14
|
+
trello = TrelloWrapper.new(@settings)
|
15
|
+
|
16
|
+
data = trello.backup(board_id)
|
17
|
+
|
18
|
+
File.open(File.join(backup_path, "board.json"), "w") do |f|
|
19
|
+
f.write(data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def list
|
24
|
+
Dir.entries(@directory).reject { |d| d =~ /^\./ }
|
25
|
+
end
|
26
|
+
|
27
|
+
def show(board_id, options = {})
|
28
|
+
out = options[:output] || STDOUT
|
29
|
+
|
30
|
+
backup_path = File.join(@directory, board_id)
|
31
|
+
|
32
|
+
board = JSON.parse(File.read(File.join(backup_path, "board.json")))
|
33
|
+
|
34
|
+
out.puts board["name"]
|
35
|
+
|
36
|
+
lists = {}
|
37
|
+
board["lists"].each do |list|
|
38
|
+
lists[list["id"]] = []
|
39
|
+
end
|
40
|
+
board["cards"].each do |card|
|
41
|
+
if lists[card["idList"]]
|
42
|
+
lists[card["idList"]].push(card)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
board["lists"].each do |list|
|
47
|
+
out.puts " #{list['name']}"
|
48
|
+
lists[list["id"]].each do |card|
|
49
|
+
out.puts " " + card["name"]
|
50
|
+
if options["show-descriptions"]
|
51
|
+
if !card["desc"].empty?
|
52
|
+
out.puts " Description"
|
53
|
+
out.puts " " + card["desc"]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
card["checklists"].each do |checklist|
|
57
|
+
out.puts " " + checklist["name"]
|
58
|
+
checklist["checkItems"].each do |checklist_item|
|
59
|
+
out.puts " " + checklist_item["name"] + " (" +
|
60
|
+
checklist_item["state"] + ")"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/burndown_chart.rb
CHANGED
@@ -14,11 +14,10 @@
|
|
14
14
|
#
|
15
15
|
# To contact SUSE about this file by physical or electronic mail,
|
16
16
|
# you may find current contact information at www.suse.com
|
17
|
-
|
18
17
|
class BurndownChart
|
19
18
|
|
20
19
|
attr_accessor :data
|
21
|
-
|
20
|
+
|
22
21
|
def initialize(settings)
|
23
22
|
@settings = settings
|
24
23
|
@burndown_data = BurndownData.new settings
|
@@ -33,65 +32,63 @@ class BurndownChart
|
|
33
32
|
"days" => []
|
34
33
|
}
|
35
34
|
end
|
36
|
-
|
35
|
+
|
37
36
|
def sprint
|
38
37
|
@data["meta"]["sprint"]
|
39
38
|
end
|
40
|
-
|
39
|
+
|
41
40
|
def sprint= s
|
42
41
|
@data["meta"]["sprint"] = s
|
43
42
|
end
|
44
|
-
|
43
|
+
|
45
44
|
def board_id
|
46
45
|
@data["meta"]["board_id"]
|
47
46
|
end
|
48
|
-
|
47
|
+
|
49
48
|
def board_id= id
|
50
49
|
@data["meta"]["board_id"] = id
|
51
50
|
end
|
52
|
-
|
51
|
+
|
53
52
|
def days
|
54
53
|
@data["days"]
|
55
54
|
end
|
56
|
-
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
"
|
61
|
-
"
|
62
|
-
"open" => burndown_data.story_points.open
|
63
|
-
},
|
64
|
-
"tasks" => {
|
65
|
-
"total" => burndown_data.tasks.total,
|
66
|
-
"open" => burndown_data.tasks.open
|
67
|
-
},
|
68
|
-
"story_points_extra" => {
|
69
|
-
"done" => burndown_data.extra_story_points.done
|
70
|
-
},
|
71
|
-
"tasks_extra" => {
|
72
|
-
"done" => burndown_data.extra_tasks.done
|
73
|
-
}
|
74
|
-
}
|
75
|
-
new_days = Array.new
|
76
|
-
replaced_entry = false
|
77
|
-
@data["days"].each do |entry|
|
78
|
-
if entry["date"] == date.to_s
|
79
|
-
new_days.push(new_entry)
|
80
|
-
replaced_entry = true
|
81
|
-
else
|
82
|
-
new_days.push(entry)
|
55
|
+
|
56
|
+
def merge_meta_data_from_board(burndown_data)
|
57
|
+
if burndown_data.meta
|
58
|
+
m = burndown_data.meta
|
59
|
+
if m["sprint"] == @data["meta"]["sprint"].to_i
|
60
|
+
@data["meta"] = @data["meta"].merge(m)
|
83
61
|
end
|
84
62
|
end
|
85
|
-
|
86
|
-
|
63
|
+
end
|
64
|
+
|
65
|
+
def replace_entry(date, new_entry)
|
66
|
+
days.each_with_index do |entry, idx|
|
67
|
+
days[idx] = new_entry if entry["date"] == date.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def entry_exists?(date)
|
72
|
+
days.any? { |entry| entry["date"] == date.to_s }
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_data(burndown_data)
|
76
|
+
new_entry = burndown_data.to_hash
|
77
|
+
if entry_exists?(burndown_data.date_time.to_date)
|
78
|
+
replace_entry(burndown_data.date_time.to_date, new_entry)
|
79
|
+
else
|
80
|
+
days.push(new_entry)
|
87
81
|
end
|
88
|
-
@data["days"] = new_days
|
89
82
|
end
|
90
|
-
|
83
|
+
|
91
84
|
def read_data filename
|
92
85
|
@data = YAML.load_file filename
|
86
|
+
not_done_columns = @data["meta"]["not_done_columns"]
|
87
|
+
if not_done_columns
|
88
|
+
@settings.not_done_columns = not_done_columns
|
89
|
+
end
|
93
90
|
end
|
94
|
-
|
91
|
+
|
95
92
|
def write_data filename
|
96
93
|
@data["days"].each do |day|
|
97
94
|
[ "story_points_extra", "tasks_extra" ].each do |key|
|
@@ -101,58 +98,90 @@ class BurndownChart
|
|
101
98
|
end
|
102
99
|
end
|
103
100
|
|
104
|
-
|
105
|
-
|
101
|
+
begin
|
102
|
+
File.open( filename, "w" ) do |file|
|
103
|
+
file.write @data.to_yaml
|
104
|
+
end
|
105
|
+
rescue Errno::ENOENT
|
106
|
+
raise TrolloloError.new( "'#{filename}' not found" )
|
106
107
|
end
|
107
108
|
end
|
108
|
-
|
109
|
+
|
109
110
|
def burndown_data_filename
|
110
111
|
"burndown-data-#{sprint.to_s.rjust(2,"0")}.yaml"
|
111
112
|
end
|
112
|
-
|
113
|
+
|
113
114
|
def setup(burndown_dir, board_id)
|
114
115
|
self.board_id = board_id
|
115
116
|
FileUtils.mkdir_p burndown_dir
|
116
117
|
write_data File.join(burndown_dir, burndown_data_filename)
|
117
118
|
end
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
if current_sprint > sprint
|
124
|
-
self.sprint = current_sprint
|
125
|
-
end
|
119
|
+
|
120
|
+
class << self
|
121
|
+
|
122
|
+
def plot_helper
|
123
|
+
File.expand_path('../../scripts/create_burndown.py', __FILE__ )
|
126
124
|
end
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
add_data(@burndown_data, Date.today)
|
133
|
-
write_data burndown_data_path
|
134
|
-
puts "Updated data for sprint #{self.sprint}"
|
135
|
-
rescue Errno::ENOENT
|
136
|
-
raise TrolloloError.new( "'#{burndown_data_path}' not found" )
|
125
|
+
|
126
|
+
def plot(sprint_number, options)
|
127
|
+
sprint_number = sprint_number.to_s.rjust(2, '0')
|
128
|
+
cli_switches = process_options(options)
|
129
|
+
system "python #{plot_helper} #{sprint_number} #{cli_switches.join(' ')}"
|
137
130
|
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def process_options(hash)
|
135
|
+
return [] unless hash
|
136
|
+
[].tap do |cli_switches|
|
137
|
+
cli_switches << '--no-tasks' if hash['no-tasks']
|
138
|
+
cli_switches << '--with-fast-lane' if hash['with-fast-lane']
|
139
|
+
cli_switches << "--output #{hash['output']}" if hash['output']
|
140
|
+
cli_switches << '--verbose' if hash['verbose']
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
138
144
|
end
|
139
145
|
|
140
|
-
def
|
146
|
+
def last_sprint(burndown_dir)
|
147
|
+
last_sprint = sprint
|
141
148
|
Dir.glob("#{burndown_dir}/burndown-data-*.yaml").each do |file|
|
142
149
|
file =~ /burndown-data-(.*).yaml/
|
143
150
|
current_sprint = $1.to_i
|
144
|
-
if current_sprint >
|
145
|
-
|
151
|
+
if current_sprint > last_sprint
|
152
|
+
last_sprint = current_sprint
|
146
153
|
end
|
147
154
|
end
|
155
|
+
last_sprint
|
156
|
+
end
|
157
|
+
|
158
|
+
def load_last_sprint(burndown_dir)
|
159
|
+
self.sprint = last_sprint(burndown_dir)
|
148
160
|
burndown_data_path = File.join(burndown_dir, burndown_data_filename)
|
149
161
|
begin
|
150
162
|
read_data burndown_data_path
|
151
|
-
self.sprint = self.sprint + 1
|
152
|
-
@data["days"] = []
|
153
|
-
write_data File.join(burndown_dir, burndown_data_filename)
|
154
163
|
rescue Errno::ENOENT
|
155
164
|
raise TrolloloError.new( "'#{burndown_data_path}' not found" )
|
156
165
|
end
|
166
|
+
return burndown_data_path
|
157
167
|
end
|
168
|
+
|
169
|
+
def update(options)
|
170
|
+
burndown_data_path = load_last_sprint(options['output'] || Dir.pwd)
|
171
|
+
@burndown_data.board_id = board_id
|
172
|
+
@burndown_data.fetch
|
173
|
+
add_data(@burndown_data)
|
174
|
+
write_data burndown_data_path
|
175
|
+
if options[:plot]
|
176
|
+
BurndownChart.plot(self.sprint, options)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def create_next_sprint(burndown_dir)
|
181
|
+
load_last_sprint(burndown_dir)
|
182
|
+
self.sprint = self.sprint + 1
|
183
|
+
@data["days"] = []
|
184
|
+
write_data File.join(burndown_dir, burndown_data_filename)
|
185
|
+
end
|
186
|
+
|
158
187
|
end
|
data/lib/burndown_data.rb
CHANGED
@@ -20,153 +20,92 @@
|
|
20
20
|
# or interaction with the files used to generate burndown charts.
|
21
21
|
class BurndownData
|
22
22
|
|
23
|
-
attr_accessor :story_points, :tasks, :extra_story_points, :extra_tasks
|
24
|
-
attr_accessor :board_id
|
25
|
-
|
26
23
|
class Result
|
27
24
|
attr_accessor :open, :done
|
28
|
-
|
25
|
+
|
29
26
|
def initialize
|
30
27
|
@open = 0
|
31
28
|
@done = 0
|
32
29
|
end
|
33
|
-
|
30
|
+
|
34
31
|
def total
|
35
32
|
@open + @done
|
36
33
|
end
|
37
34
|
end
|
38
35
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
@story_points = Result.new
|
43
|
-
@tasks = Result.new
|
36
|
+
attr_accessor :story_points, :tasks, :extra_story_points, :extra_tasks,
|
37
|
+
:board_id, :fast_lane_cards, :date_time
|
38
|
+
attr_reader :meta
|
44
39
|
|
40
|
+
def initialize(settings)
|
41
|
+
@settings = settings
|
42
|
+
@story_points = Result.new
|
43
|
+
@tasks = Result.new
|
45
44
|
@extra_story_points = Result.new
|
46
|
-
@extra_tasks
|
47
|
-
|
48
|
-
|
49
|
-
def trello
|
50
|
-
Trello.new(board_id: @board_id, developer_public_key: @settings.developer_public_key, member_token: @settings.member_token)
|
45
|
+
@extra_tasks = Result.new
|
46
|
+
@fast_lane_cards = Result.new
|
51
47
|
end
|
52
48
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
49
|
+
def to_hash
|
50
|
+
base = {
|
51
|
+
"date" => date_time.to_date.to_s,
|
52
|
+
"updated_at" => date_time.to_s,
|
53
|
+
"story_points" => {
|
54
|
+
"total" => story_points.total,
|
55
|
+
"open" => story_points.open
|
56
|
+
},
|
57
|
+
"tasks" => {
|
58
|
+
"total" => tasks.total,
|
59
|
+
"open" => tasks.open
|
60
|
+
},
|
61
|
+
"story_points_extra" => {
|
62
|
+
"done" => extra_story_points.done
|
63
|
+
},
|
64
|
+
"tasks_extra" => {
|
65
|
+
"done" => extra_tasks.done
|
66
|
+
}
|
67
|
+
}
|
68
|
+
if fast_lane_cards.total > 0
|
69
|
+
base.merge("fast_lane" => {
|
70
|
+
"total" => fast_lane_cards.total,
|
71
|
+
"open" => fast_lane_cards.open
|
72
|
+
})
|
73
|
+
else
|
74
|
+
base
|
59
75
|
end
|
60
|
-
|
61
|
-
raise "Unable to find sprint backlog column on sprint board"
|
62
76
|
end
|
63
77
|
|
64
|
-
def
|
65
|
-
|
66
|
-
lists.each do |l|
|
67
|
-
if l["name"] =~ /^Doing$/
|
68
|
-
return l["id"]
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
raise "Unable to find doing column on sprint board"
|
78
|
+
def trello
|
79
|
+
@trello ||= TrelloWrapper.new(@settings)
|
73
80
|
end
|
74
81
|
|
75
|
-
def
|
76
|
-
|
77
|
-
last_sprint = nil
|
78
|
-
lists.each do |l|
|
79
|
-
if l["name"] =~ /^Done Sprint (.*)$/
|
80
|
-
sprint = $1.to_i
|
81
|
-
if !last_sprint || sprint > last_sprint[:number]
|
82
|
-
last_sprint = { :number => sprint, :id => l["id"] }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
id = last_sprint[:id]
|
88
|
-
if !id
|
89
|
-
raise "Unable to find done column on sprint board"
|
90
|
-
end
|
91
|
-
id
|
82
|
+
def board
|
83
|
+
trello.board(@board_id)
|
92
84
|
end
|
93
|
-
|
94
|
-
def fetch
|
95
|
-
cards = trello.cards
|
96
|
-
|
97
|
-
todo_list_id = fetch_todo_list_id
|
98
|
-
doing_list_id = fetch_doing_list_id
|
99
|
-
done_list_id = fetch_done_list_id
|
100
|
-
|
101
|
-
if @settings.verbose
|
102
|
-
puts "Todo list: #{todo_list_id}"
|
103
|
-
puts "Doing list: #{doing_list_id}"
|
104
|
-
puts "Done list: #{done_list_id}"
|
105
|
-
end
|
106
|
-
|
107
|
-
sp_total = 0
|
108
|
-
sp_done = 0
|
109
|
-
|
110
|
-
extra_sp_total = 0
|
111
|
-
extra_sp_done = 0
|
112
85
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
86
|
+
def fetch
|
87
|
+
get_meta
|
88
|
+
@story_points.done = board.done_story_points
|
89
|
+
@story_points.open = board.open_story_points
|
90
|
+
@tasks.open = board.tasks - board.closed_tasks
|
91
|
+
@tasks.done = board.closed_tasks
|
92
|
+
@extra_story_points.done = board.extra_done_story_points
|
93
|
+
@extra_story_points.open = board.extra_open_story_points
|
94
|
+
@extra_tasks.done = board.extra_closed_tasks
|
95
|
+
@extra_tasks.open = board.extra_tasks - board.extra_closed_tasks
|
96
|
+
@fast_lane_cards.done = board.done_fast_lane_cards_count
|
97
|
+
@fast_lane_cards.open = board.open_fast_lane_cards_count
|
98
|
+
@date_time = DateTime.now
|
99
|
+
end
|
123
100
|
|
124
|
-
|
125
|
-
if card.has_sp?
|
126
|
-
if card.extra?
|
127
|
-
extra_sp_total += card.sp
|
128
|
-
else
|
129
|
-
sp_total += card.sp
|
130
|
-
end
|
131
|
-
end
|
132
|
-
if card.extra?
|
133
|
-
extra_tasks_total += card.tasks
|
134
|
-
extra_tasks_done += card.tasks_done
|
135
|
-
else
|
136
|
-
tasks_total += card.tasks
|
137
|
-
tasks_done += card.tasks_done
|
138
|
-
end
|
139
|
-
elsif list_id == done_list_id
|
140
|
-
if card.has_sp?
|
141
|
-
if card.extra?
|
142
|
-
extra_sp_total += card.sp
|
143
|
-
extra_sp_done += card.sp
|
144
|
-
else
|
145
|
-
sp_total += card.sp
|
146
|
-
sp_done += card.sp
|
147
|
-
end
|
148
|
-
end
|
149
|
-
if card.extra?
|
150
|
-
extra_tasks_total += card.tasks
|
151
|
-
extra_tasks_done += card.tasks_done
|
152
|
-
else
|
153
|
-
tasks_total += card.tasks
|
154
|
-
tasks_done += card.tasks_done
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
@story_points.done = sp_done
|
160
|
-
@story_points.open = sp_total - sp_done
|
161
|
-
|
162
|
-
@tasks.done = tasks_done
|
163
|
-
@tasks.open = tasks_total - tasks_done
|
101
|
+
private
|
164
102
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
@
|
103
|
+
def get_meta
|
104
|
+
meta_cards = board.meta_cards
|
105
|
+
return unless meta_cards.any?
|
106
|
+
current_sprint_meta_card = meta_cards.max_by(&:sprint_number)
|
107
|
+
@meta = Card.parse_yaml_from_description(current_sprint_meta_card.desc)
|
108
|
+
@meta['sprint'] = current_sprint_meta_card.sprint_number
|
170
109
|
end
|
171
110
|
|
172
111
|
end
|