trollolo 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/scrum/creator.rb CHANGED
@@ -9,7 +9,7 @@ module Scrum
9
9
  private
10
10
 
11
11
  def create_labels(board_id)
12
- @scrum.label_names.each { |_, name| Trello::Label.create(name: name, board_id: board_id) }
12
+ @scrum.label_names.each_value { |name| Trello::Label.create(name: name, board_id: board_id) }
13
13
  end
14
14
 
15
15
  def create_sprint_board
data/lib/scrum_board.rb CHANGED
@@ -12,6 +12,14 @@ class ScrumBoard
12
12
  @columns ||= @board_data['lists'].map{|x| Column.new(@board_data, x['id'], @settings)}
13
13
  end
14
14
 
15
+ def todo_columns
16
+ columns.select{|c| @settings.todo_columns.include?(c.name)}
17
+ end
18
+
19
+ def doing_columns
20
+ columns.select{|c| @settings.doing_columns.include?(c.name) }
21
+ end
22
+
15
23
  def done_column
16
24
  done_columns = columns.select{|c| c.name =~ @settings.done_column_name_regex }
17
25
  if done_columns.empty?
@@ -21,8 +29,11 @@ class ScrumBoard
21
29
  end
22
30
  end
23
31
 
32
+ def accepted_columns
33
+ columns.select{|c| c.name =~ @settings.accepted_column_name_regex }
34
+ end
35
+
24
36
  def accepted_column
25
- accepted_columns = columns.select{|c| c.name =~ @settings.accepted_column_name_regex }
26
37
  if accepted_columns.empty?
27
38
  EmptyColumn.new
28
39
  else
data/lib/settings.rb CHANGED
@@ -18,9 +18,9 @@
18
18
  class Settings
19
19
 
20
20
  attr_accessor :developer_public_key, :member_token, :board_aliases, :verbose,
21
- :raw, :not_done_columns, :todo_column, :accepted_column_name_regex,
21
+ :raw, :not_done_columns, :todo_columns, :doing_columns, :accepted_column_name_regex,
22
22
  :done_column_name_regex, :todo_column_name_regex, :scrum,
23
- :no_task_checklists
23
+ :no_task_checklists, :swimlanes
24
24
 
25
25
  def initialize(config_file_path)
26
26
  @config_file_path = config_file_path
@@ -34,10 +34,12 @@ class Settings
34
34
  @scrum = OpenStruct.new(@config['scrum'] || scrum_defaults)
35
35
  @not_done_columns = @config['not_done_columns'].freeze || ['Sprint Backlog', 'Doing']
36
36
  @no_task_checklists = @config['no_task_checklists'].freeze || ['Feedback']
37
- @todo_column = @config['todo_column'].freeze
37
+ @todo_columns = @config['todo_columns'].freeze || ['Sprint Backlog']
38
+ @doing_columns = @config['doing_columns'].freeze || ['Doing']
38
39
  @done_column_name_regex = @config['done_column_name_regex'].freeze || /\ADone/
39
40
  @accepted_column_name_regex = @config['accepted_column_name_regex'].freeze || /\AAccepted/
40
41
  @todo_column_name_regex = @config['todo_column_name_regex'].freeze || /\ATo Do\Z/
42
+ @swimlanes = @config['swimlanes'].freeze || []
41
43
  else
42
44
  raise "Couldn't read config data from '#{config_file_path}'"
43
45
  end
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Trollolo
2
2
 
3
- VERSION = '0.2.0'.freeze
3
+ VERSION = '0.3.0'.freeze
4
4
 
5
5
  end
@@ -0,0 +1,32 @@
1
+ ---
2
+ meta:
3
+ board_id: myboardid
4
+ doing_columns:
5
+ - Doing
6
+ - QA
7
+ sprint: 2
8
+ total_days: 9
9
+ weekend_lines:
10
+ - 3.5
11
+ - 7.5
12
+ days:
13
+ - date: '2014-04-23'
14
+ updated_at: '2014-04-23T10:00:00+01:00'
15
+ story_points:
16
+ total: 30
17
+ open: 23
18
+ tasks:
19
+ total: 25
20
+ open: 21
21
+ - date: '2014-04-24'
22
+ updated_at: '2014-04-24T19:00:00+01:00'
23
+ story_points:
24
+ total: 30
25
+ open: 21
26
+ tasks:
27
+ total: 26
28
+ open: 19
29
+ story_points_extra:
30
+ done: 3
31
+ tasks_extra:
32
+ done: 2
@@ -0,0 +1,32 @@
1
+ ---
2
+ meta:
3
+ board_id: myboardid
4
+ swimlanes:
5
+ - Swimlane One
6
+ - swimlanetwo
7
+ sprint: 2
8
+ total_days: 9
9
+ weekend_lines:
10
+ - 3.5
11
+ - 7.5
12
+ days:
13
+ - date: '2014-04-23'
14
+ updated_at: '2014-04-23T10:00:00+01:00'
15
+ story_points:
16
+ total: 30
17
+ open: 23
18
+ tasks:
19
+ total: 25
20
+ open: 21
21
+ - date: '2014-04-24'
22
+ updated_at: '2014-04-24T19:00:00+01:00'
23
+ story_points:
24
+ total: 30
25
+ open: 21
26
+ tasks:
27
+ total: 26
28
+ open: 19
29
+ story_points_extra:
30
+ done: 3
31
+ tasks_extra:
32
+ done: 2
@@ -0,0 +1,35 @@
1
+ ---
2
+ meta:
3
+ board_id: myboardid
4
+ todo_columns:
5
+ - Swimlane Backlog
6
+ - Sprint Backlog
7
+ swimlanes:
8
+ - Swimlane One
9
+ - swimlanetwo
10
+ sprint: 2
11
+ total_days: 9
12
+ weekend_lines:
13
+ - 3.5
14
+ - 7.5
15
+ days:
16
+ - date: '2014-04-23'
17
+ updated_at: '2014-04-23T10:00:00+01:00'
18
+ story_points:
19
+ total: 30
20
+ open: 23
21
+ tasks:
22
+ total: 25
23
+ open: 21
24
+ - date: '2014-04-24'
25
+ updated_at: '2014-04-24T19:00:00+01:00'
26
+ story_points:
27
+ total: 30
28
+ open: 21
29
+ tasks:
30
+ total: 26
31
+ open: 19
32
+ story_points_extra:
33
+ done: 3
34
+ tasks_extra:
35
+ done: 2
@@ -22,8 +22,8 @@ def compare_images_for_sprint(sprint_number, extra_args = [])
22
22
 
23
23
  result = run_helper(@working_dir, sprint_number, extra_args)
24
24
  expect(result).to exit_with_success('')
25
- expect(File.join(@working_dir, "burndown-#{sprint_number}.png")).
26
- to be_same_image_as("create_burndown_helper/burndown-#{sprint_number}.png")
25
+ expect(File.join(@working_dir, "burndown-#{sprint_number}.png"))
26
+ .to be_same_image_as("create_burndown_helper/burndown-#{sprint_number}.png")
27
27
  end
28
28
 
29
29
  describe 'create_burndown.py' do
@@ -0,0 +1,96 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe BoardMock do
4
+ context 'one column' do
5
+ let :subject do
6
+ BoardMock.new
7
+ .list('One')
8
+ end
9
+
10
+ it 'has one column' do
11
+ expect(subject.columns.count).to eq(1)
12
+ end
13
+
14
+ it 'has no cards' do
15
+ expect(subject.cards.count).to eq(0)
16
+ end
17
+ end
18
+
19
+ context 'two columns' do
20
+ let :subject do
21
+ board = BoardMock.new
22
+ board.list('One')
23
+ board.list('Two')
24
+ board
25
+ end
26
+
27
+ it 'has two columns' do
28
+ expect(subject.columns.count).to eq(2)
29
+ end
30
+
31
+ it 'has no cards' do
32
+ expect(subject.cards.count).to eq(0)
33
+ end
34
+ end
35
+
36
+ context 'one column and two cards' do
37
+ let :subject do
38
+ board = BoardMock.new
39
+ list = board.list('One')
40
+ list.card('Red')
41
+ list.card('Green')
42
+ board
43
+ end
44
+
45
+ it 'has one column' do
46
+ expect(subject.columns.count).to eq(1)
47
+ end
48
+
49
+ it 'has two cards' do
50
+ expect(subject.cards.count).to eq(2)
51
+ end
52
+ end
53
+
54
+ context 'two columns and two cards each' do
55
+ let :subject do
56
+ BoardMock.new
57
+ .list('One')
58
+ .card('Red')
59
+ .card('Green')
60
+ .list('Two')
61
+ .card('Blue')
62
+ .card('Yellow')
63
+ end
64
+
65
+ it 'has two columns' do
66
+ expect(subject.columns.count).to eq(2)
67
+ end
68
+
69
+ it 'has four cards' do
70
+ expect(subject.cards.count).to eq(4)
71
+ end
72
+
73
+ it 'has two cards in each list' do
74
+ subject.columns.each do |column|
75
+ expect(column.cards.count).to eq(2)
76
+ end
77
+ end
78
+ end
79
+
80
+ context 'one card with one label' do
81
+ let :subject do
82
+ BoardMock.new
83
+ .list('One')
84
+ .card('Red')
85
+ .label('Cold')
86
+ end
87
+
88
+ it 'has one card' do
89
+ expect(subject.cards.count).to eq(1)
90
+ end
91
+
92
+ it 'card has one label' do
93
+ expect(subject.cards.first.label?('Cold'))
94
+ end
95
+ end
96
+ end
@@ -234,10 +234,25 @@ describe BurndownChart do
234
234
  expect(@chart.data['days']).to eq @raw_data
235
235
  end
236
236
 
237
+ it 'reads todo columns' do
238
+ @chart.read_data given_file('burndown-data.yaml', from: 'burndown-data-with-todo-columns.yaml')
239
+ expect(@settings.todo_columns).to eq ['Swimlane Backlog', 'Sprint Backlog']
240
+ end
241
+
242
+ it 'reads doing columns' do
243
+ @chart.read_data given_file('burndown-data.yaml', from: 'burndown-data-with-doing-columns.yaml')
244
+ expect(@settings.doing_columns).to eq ['Doing', 'QA']
245
+ end
246
+
237
247
  it 'reads not done columns' do
238
248
  @chart.read_data given_file('burndown-data.yaml', from: 'burndown-data-with-config.yaml')
239
249
  expect(@settings.not_done_columns).to eq ['Sprint Backlog', 'Doing', 'QA']
240
250
  end
251
+
252
+ it 'reads swimlanes' do
253
+ @chart.read_data given_file('burndown-data.yaml', from: 'burndown-data-with-swimlanes.yaml')
254
+ expect(@settings.swimlanes).to eq ['Swimlane One', 'swimlanetwo']
255
+ end
241
256
  end
242
257
 
243
258
  describe '#write_data' do
@@ -3,146 +3,205 @@ require_relative 'spec_helper'
3
3
  include GivenFilesystemSpecHelpers
4
4
 
5
5
  describe BurndownData do
6
- before(:each) do
7
- @burndown = BurndownData.new(dummy_settings)
8
- @burndown.board_id = '53186e8391ef8671265eba9d'
9
- full_board_mock
10
- end
11
-
12
- describe BurndownData::Result do
13
- it 'calculates total' do
14
- r = described_class.new
15
- r.open = 7
16
- r.done = 4
17
-
18
- expect(r.total).to eq 11
19
- end
20
- end
21
-
22
- describe 'setters' do
23
- it 'sets open story points' do
24
- @burndown.story_points.open = 13
25
- expect(@burndown.story_points.open).to eq 13
6
+ context 'with full board mock' do
7
+ before(:each) do
8
+ @burndown = BurndownData.new(dummy_settings)
9
+ @burndown.board_id = '53186e8391ef8671265eba9d'
10
+ full_board_mock
26
11
  end
27
12
 
28
- it 'sets open tasks' do
29
- @burndown.tasks.open = 42
30
- expect(@burndown.tasks.open).to eq 42
31
- end
32
- end
13
+ describe BurndownData::Result do
14
+ it 'calculates total' do
15
+ r = described_class.new
16
+ r.open = 7
17
+ r.done = 4
33
18
 
34
- describe '#fetch' do
35
- context 'with meta data on sprint card' do
36
- before do
37
- @burndown.fetch
19
+ expect(r.total).to eq 11
38
20
  end
21
+ end
39
22
 
40
- it 'returns story points' do
41
- expect( @burndown.story_points.total ).to eq 16
42
- expect( @burndown.story_points.open ).to eq 13
43
- expect( @burndown.story_points.done ).to eq 3
23
+ describe 'setters' do
24
+ it 'sets open story points' do
25
+ @burndown.story_points.open = 13
26
+ expect(@burndown.story_points.open).to eq 13
44
27
  end
45
28
 
46
- it 'returns extra story points' do
47
- expect( @burndown.extra_story_points.total ).to eq 8
48
- expect( @burndown.extra_story_points.open ).to eq 8
49
- expect( @burndown.extra_story_points.done ).to eq 0
29
+ it 'sets open tasks' do
30
+ @burndown.tasks.open = 42
31
+ expect(@burndown.tasks.open).to eq 42
50
32
  end
33
+ end
51
34
 
52
- it 'returns unplanned story points' do
53
- expect( @burndown.unplanned_story_points.total ).to eq 3
54
- expect( @burndown.unplanned_story_points.open ).to eq 1
55
- expect( @burndown.unplanned_story_points.done ).to eq 2
35
+ describe '#fetch' do
36
+ context 'with meta data on sprint card' do
37
+ before do
38
+ @burndown.fetch
39
+ end
40
+
41
+ it 'returns story points' do
42
+ expect( @burndown.story_points.total ).to eq 16
43
+ expect( @burndown.story_points.open ).to eq 13
44
+ expect( @burndown.story_points.done ).to eq 3
45
+ end
46
+
47
+ it 'returns extra story points' do
48
+ expect( @burndown.extra_story_points.total ).to eq 8
49
+ expect( @burndown.extra_story_points.open ).to eq 8
50
+ expect( @burndown.extra_story_points.done ).to eq 0
51
+ end
52
+
53
+ it 'returns unplanned story points' do
54
+ expect( @burndown.unplanned_story_points.total ).to eq 3
55
+ expect( @burndown.unplanned_story_points.open ).to eq 1
56
+ expect( @burndown.unplanned_story_points.done ).to eq 2
57
+ end
58
+
59
+ it 'returns tasks' do
60
+ expect( @burndown.tasks.total ).to eq 13
61
+ expect( @burndown.tasks.open ).to eq 9
62
+ expect( @burndown.tasks.done ).to eq 4
63
+ end
64
+
65
+ it 'returns extra tasks' do
66
+ expect( @burndown.extra_tasks.total ).to eq 1
67
+ expect( @burndown.extra_tasks.open ).to eq 1
68
+ expect( @burndown.extra_tasks.done ).to eq 0
69
+ end
70
+
71
+ it 'returns unplanned tasks' do
72
+ expect( @burndown.unplanned_tasks.total ).to eq 2
73
+ expect( @burndown.unplanned_tasks.open ).to eq 1
74
+ expect( @burndown.unplanned_tasks.done ).to eq 1
75
+ end
76
+
77
+ it 'returns meta data' do
78
+ expect( @burndown.meta ).to eq( 'sprint' => 10,
79
+ 'total_days' => 18,
80
+ 'weekend_lines' => [1.5, 6.5, 11.5, 16.5])
81
+ end
82
+
83
+ it 'saves date and time' do
84
+ expected_date_time = DateTime.parse('2015-01-12T13:57:16+01:00')
85
+ allow(DateTime).to receive(:now).and_return(expected_date_time)
86
+ @burndown.fetch
87
+ expect(@burndown.date_time).to eq(expected_date_time)
88
+ end
56
89
  end
57
90
 
58
- it 'returns tasks' do
59
- expect( @burndown.tasks.total ).to eq 13
60
- expect( @burndown.tasks.open ).to eq 9
61
- expect( @burndown.tasks.done ).to eq 4
62
- end
91
+ context 'without meta data on sprint card' do
92
+ before do
93
+ allow(Card).to receive(:parse_yaml_from_description).and_return(nil)
94
+ @burndown.fetch
95
+ end
63
96
 
64
- it 'returns extra tasks' do
65
- expect( @burndown.extra_tasks.total ).to eq 1
66
- expect( @burndown.extra_tasks.open ).to eq 1
67
- expect( @burndown.extra_tasks.done ).to eq 0
68
- end
69
-
70
- it 'returns unplanned tasks' do
71
- expect( @burndown.unplanned_tasks.total ).to eq 2
72
- expect( @burndown.unplanned_tasks.open ).to eq 1
73
- expect( @burndown.unplanned_tasks.done ).to eq 1
97
+ it 'does not fail' do
98
+ expect(@burndown.meta).to be(nil)
99
+ end
74
100
  end
101
+ end
75
102
 
76
- it 'returns meta data' do
77
- expect( @burndown.meta ).to eq( 'sprint' => 10,
78
- 'total_days' => 18,
79
- 'weekend_lines' => [1.5, 6.5, 11.5, 16.5])
80
- end
103
+ describe '#to_hash' do
104
+ it 'converts to hash' do
105
+ @burndown.story_points.open = 1
106
+ @burndown.story_points.done = 2
107
+ @burndown.tasks.open = 3
108
+ @burndown.tasks.done = 4
109
+ @burndown.extra_story_points.open = 5
110
+ @burndown.extra_story_points.done = 6
111
+ @burndown.extra_tasks.open = 7
112
+ @burndown.extra_tasks.done = 8
113
+ @burndown.unplanned_story_points.open = 1
114
+ @burndown.unplanned_story_points.done = 2
115
+ @burndown.unplanned_tasks.open = 1
116
+ @burndown.unplanned_tasks.done = 1
117
+ @burndown.date_time = DateTime.parse('20150115')
118
+
119
+ expected_hash = {
120
+ 'date' => '2015-01-15',
121
+ 'updated_at' => '2015-01-15T00:00:00+00:00',
122
+ 'story_points' => {
123
+ 'total' => 3,
124
+ 'open' => 1
125
+ },
126
+ 'tasks' => {
127
+ 'total' => 7,
128
+ 'open' => 3
129
+ },
130
+ 'story_points_extra' => {
131
+ 'done' => 6
132
+ },
133
+ 'tasks_extra' => {
134
+ 'done' => 8
135
+ },
136
+ 'unplanned_story_points' => {
137
+ 'total' => 3,
138
+ 'open' => 1
139
+ },
140
+ 'unplanned_tasks' => {
141
+ 'total' => 2,
142
+ 'open' => 1
143
+ }
144
+ }
81
145
 
82
- it 'saves date and time' do
83
- expected_date_time = DateTime.parse('2015-01-12T13:57:16+01:00')
84
- allow(DateTime).to receive(:now).and_return(expected_date_time)
85
- @burndown.fetch
86
- expect(@burndown.date_time).to eq(expected_date_time)
146
+ expect(@burndown.to_hash).to eq(expected_hash)
87
147
  end
88
148
  end
149
+ end
89
150
 
90
- context 'without meta data on sprint card' do
91
- before do
92
- allow(Card).to receive(:parse_yaml_from_description).and_return(nil)
93
- @burndown.fetch
94
- end
151
+ context 'board with swimlanes' do
152
+ let :subject do
153
+ settings = dummy_settings
154
+ settings.todo_columns = ['Swimlane Backlog', 'Sprint Backlog']
155
+ settings.swimlanes = ['myswimlane']
156
+
157
+ mock_board = BoardMock.new(settings)
158
+ .list('Swimlane Backlog')
159
+ .card('(2) Three')
160
+ .label('myswimlane')
161
+ .list('Sprint Backlog')
162
+ .card('(3) One')
163
+ .card('(5) Two')
164
+ .list('Doing')
165
+ .card('(7) Two')
166
+ .label('myswimlane')
167
+ .list('Done')
168
+ .card('(11) Four')
169
+ .card('(13) Five')
170
+ .label('myswimlane')
171
+ .list('Accepted Sprint 2')
172
+ .card('(17) Six')
173
+ .label('myswimlane')
174
+ .list('Accepted Sprint 1')
175
+ .card('(21) Seven')
176
+ .label('myswimlane')
177
+
178
+ burndown = BurndownData.new(settings)
179
+ allow(burndown).to receive(:board).and_return mock_board
180
+ burndown.fetch
181
+ burndown
182
+ end
95
183
 
96
- it 'does not fail' do
97
- expect(@burndown.meta).to be(nil)
98
- end
184
+ it 'ignores swimlane story points' do
185
+ expect(subject.story_points.open).to eq(8)
186
+ expect(subject.story_points.done).to eq(11)
99
187
  end
100
- end
101
188
 
102
- describe '#to_hash' do
103
- it 'converts to hash' do
104
- @burndown.story_points.open = 1
105
- @burndown.story_points.done = 2
106
- @burndown.tasks.open = 3
107
- @burndown.tasks.done = 4
108
- @burndown.extra_story_points.open = 5
109
- @burndown.extra_story_points.done = 6
110
- @burndown.extra_tasks.open = 7
111
- @burndown.extra_tasks.done = 8
112
- @burndown.unplanned_story_points.open = 1
113
- @burndown.unplanned_story_points.done = 2
114
- @burndown.unplanned_tasks.open = 1
115
- @burndown.unplanned_tasks.done = 1
116
- @burndown.date_time = DateTime.parse('20150115')
189
+ it 'records swimlane story points' do
190
+ expect(subject.swimlanes['myswimlane'].todo).to eq(2)
191
+ expect(subject.swimlanes['myswimlane'].doing).to eq(7)
192
+ expect(subject.swimlanes['myswimlane'].done).to eq(51)
193
+ end
117
194
 
195
+ it 'includes swimlane story points in hash' do
118
196
  expected_hash = {
119
- 'date' => '2015-01-15',
120
- 'updated_at' => '2015-01-15T00:00:00+00:00',
121
- 'story_points' => {
122
- 'total' => 3,
123
- 'open' => 1
124
- },
125
- 'tasks' => {
126
- 'total' => 7,
127
- 'open' => 3
128
- },
129
- 'story_points_extra' => {
130
- 'done' => 6
131
- },
132
- 'tasks_extra' => {
133
- 'done' => 8
134
- },
135
- 'unplanned_story_points' => {
136
- 'total' => 3,
137
- 'open' => 1
138
- },
139
- 'unplanned_tasks' => {
140
- 'total' => 2,
141
- 'open' => 1
197
+ 'myswimlane' => {
198
+ 'todo' => 2,
199
+ 'doing' => 7,
200
+ 'done' => 51
142
201
  }
143
202
  }
144
-
145
- expect(@burndown.to_hash).to eq(expected_hash)
203
+ expect(subject.to_hash.key?('swimlanes')).to be true
204
+ expect(subject.to_hash['swimlanes']).to eq(expected_hash)
146
205
  end
147
206
  end
148
207
  end