trollolo 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.
- 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
|
+

|
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
|