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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +5 -1
  4. data/CHANGELOG.md +29 -0
  5. data/Gemfile +7 -2
  6. data/README.md +19 -0
  7. data/bin/trollolo +1 -1
  8. data/lib/array.rb +6 -0
  9. data/lib/backup.rb +67 -0
  10. data/lib/burndown_chart.rb +96 -67
  11. data/lib/burndown_data.rb +62 -123
  12. data/lib/card.rb +74 -30
  13. data/lib/cli.rb +131 -9
  14. data/lib/column.rb +61 -0
  15. data/lib/result.rb +0 -0
  16. data/lib/scrum_board.rb +104 -0
  17. data/lib/settings.rb +9 -4
  18. data/lib/trello_wrapper.rb +62 -0
  19. data/lib/trollolo.rb +10 -7
  20. data/lib/version.rb +1 -1
  21. data/scripts/.gitignore +1 -0
  22. data/scripts/burndowndata.py +113 -0
  23. data/scripts/create_burndown.py +111 -146
  24. data/scripts/graph.py +116 -0
  25. data/scripts/plot.py +131 -0
  26. data/spec/data/board.json +63 -0
  27. data/spec/data/burndown-data.yaml +3 -0
  28. data/spec/data/burndown_dir/burndown-data-01.yaml +1 -1
  29. data/spec/data/burndown_dir/burndown-data-02.yaml +1 -1
  30. data/spec/data/card.json +61 -0
  31. data/spec/data/full-board.json +1626 -0
  32. data/spec/data/lists.json +25 -25
  33. data/spec/data/trollolorc +5 -0
  34. data/spec/{command_line_spec.rb → integration/command_line_spec.rb} +1 -4
  35. data/spec/integration/create_burndown_spec.rb +57 -0
  36. data/spec/integration/integration_spec_helper.rb +10 -0
  37. data/spec/integration/support/aruba_hook.rb +11 -0
  38. data/spec/integration/support/custom_matchers.rb +13 -0
  39. data/spec/{wrapper → integration/wrapper}/credentials_input_wrapper +2 -2
  40. data/spec/{wrapper → integration/wrapper}/empty_config_trollolo_wrapper +2 -2
  41. data/spec/integration/wrapper/trollolo_wrapper +10 -0
  42. data/spec/unit/backup_spec.rb +107 -0
  43. data/spec/unit/burndown_chart_spec.rb +396 -0
  44. data/spec/unit/burndown_data_spec.rb +118 -0
  45. data/spec/unit/card_spec.rb +79 -0
  46. data/spec/unit/cli_spec.rb +38 -0
  47. data/spec/unit/retrieve_data_spec.rb +54 -0
  48. data/spec/unit/scrum_board_spec.rb +18 -0
  49. data/spec/{settings_spec.rb → unit/settings_spec.rb} +1 -1
  50. data/spec/{spec_helper.rb → unit/spec_helper.rb} +4 -12
  51. data/spec/unit/support/test_data_operations.rb +7 -0
  52. data/spec/unit/support/update_webmock_data +17 -0
  53. data/spec/unit/support/webmocks.rb +52 -0
  54. data/spec/unit/trello_wrapper_spec.rb +47 -0
  55. data/trollolo.gemspec +10 -11
  56. metadata +54 -37
  57. data/lib/trello.rb +0 -66
  58. data/spec/burndown_chart_spec.rb +0 -307
  59. data/spec/burndown_data_spec.rb +0 -125
  60. data/spec/card_spec.rb +0 -15
  61. data/spec/cli_spec.rb +0 -18
  62. data/spec/data/cards.json +0 -1002
  63. data/spec/trello_spec.rb +0 -32
  64. data/spec/wrapper/trollolo_wrapper +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c781701661ccd9a1f161f56cd7c07c6b4b0cf7e0
4
- data.tar.gz: a4615b48df363c710ff45788c9fb72c963690ed3
3
+ metadata.gz: 5adc2629b2f526c70851abc5ba72765860d73e2f
4
+ data.tar.gz: d31159f96937237011765b1df87036d90a94fede
5
5
  SHA512:
6
- metadata.gz: 0772e65840bbc21aff6cd757adace1938fbca7b4094c78a550d1d7c2bb4069ff66e3af37e17b55618b259a62ee0ce7c0726415d6f2f593f813f22ece587fc528
7
- data.tar.gz: 321418dcee6afb7c3283ffb13370c287367270887fd8b8a316ff2d00fc384805762b68a1cb1c4b8d3bb43bb8407a8f3df3794d84b03f5f4e42cdf5cc88d1fb16
6
+ metadata.gz: 7eb4de3cb4a144902d467e40471236ca54c8992228fc5b1b6531148887512609bb5e56f2b43abb646d4eca512008e9c6b7d3c228073c3f1bb2a94cd6a22532e9
7
+ data.tar.gz: 7df063a8b64b2e8eea6118115d1e0ab8b7653783c972abcd046b0c25b1a6951ac39147b2d4e01f4e1c1dfc7724f5554347cc85570695b5026310a6f746b9ab6f
data/.gitignore CHANGED
@@ -2,3 +2,5 @@
2
2
  Gemfile.lock
3
3
  tmp
4
4
  coverage
5
+ *.png
6
+ *.yaml
@@ -1,8 +1,12 @@
1
1
  language: ruby
2
+ cache: bundler
3
+ before_install:
4
+ - gem update --system
5
+ - gem --version
2
6
  rvm:
3
7
  - "2.0.0"
4
8
  - "2.1.1"
5
- script: bundle exec rspec spec
9
+ script: bundle exec rspec spec/unit
6
10
 
7
11
  addons:
8
12
  code_climate:
@@ -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 "https://rubygems.org"
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', "~>3"
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)
@@ -26,7 +26,7 @@ Cli.settings = Settings.new(config_path)
26
26
  ENV["THOR_DEBUG"] = "1"
27
27
  begin
28
28
  Cli.check_unknown_options!
29
- result = Cli.start ARGV
29
+ Cli.start
30
30
  rescue Thor::Error => e
31
31
  STDERR.puts e
32
32
  exit 1
@@ -0,0 +1,6 @@
1
+ class Array
2
+ def sum
3
+ return 0 if empty?
4
+ inject(:+)
5
+ end
6
+ end
@@ -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
@@ -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 add_data(burndown_data, date)
58
- new_entry = {
59
- "date" => date.to_s,
60
- "story_points" => {
61
- "total" => burndown_data.story_points.total,
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
- if !replaced_entry
86
- new_days.push(new_entry)
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
- File.open( filename, "w" ) do |file|
105
- file.write @data.to_yaml
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
- def update(burndown_dir)
120
- Dir.glob("#{burndown_dir}/burndown-data-*.yaml").each do |file|
121
- file =~ /burndown-data-(.*).yaml/
122
- current_sprint = $1.to_i
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
- burndown_data_path = File.join(burndown_dir, burndown_data_filename)
128
- begin
129
- read_data burndown_data_path
130
- @burndown_data.board_id = board_id
131
- @burndown_data.fetch
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 create_next_sprint(burndown_dir)
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 > sprint
145
- self.sprint = current_sprint
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
@@ -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
- def initialize settings
40
- @settings = settings
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 = Result.new
47
- end
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 fetch_todo_list_id
54
- lists = trello.lists
55
- lists.each do |l|
56
- if l["name"] =~ /^Sprint Backlog$/
57
- return l["id"]
58
- end
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 fetch_doing_list_id
65
- lists = trello.lists
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 fetch_done_list_id
76
- lists = trello.lists
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
- tasks_total = 0
114
- tasks_done = 0
115
-
116
- extra_tasks_total = 0
117
- extra_tasks_done = 0
118
-
119
- cards.each do |c|
120
- card = Card.parse c
121
-
122
- list_id = c["idList"]
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
- if list_id == todo_list_id || list_id == doing_list_id
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
- @extra_story_points.done = extra_sp_done
166
- @extra_story_points.open = extra_sp_total - extra_sp_done
167
-
168
- @extra_tasks.done = extra_tasks_done
169
- @extra_tasks.open = extra_tasks_total - extra_tasks_done
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