trollolo 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -0
- data/.rubocop_todo.yml +3 -28
- data/.travis.yml +2 -1
- data/CHANGELOG.md +4 -1
- data/CONTRIBUTING.md +17 -3
- data/Gemfile +8 -8
- data/README.md +40 -2
- data/lib/burndown_chart.rb +9 -0
- data/lib/burndown_data.rb +80 -7
- data/lib/card.rb +17 -1
- data/lib/cli.rb +1 -1
- data/lib/column.rb +1 -1
- data/lib/scrum/creator.rb +1 -1
- data/lib/scrum_board.rb +12 -1
- data/lib/settings.rb +5 -3
- data/lib/version.rb +1 -1
- data/spec/data/burndown-data-with-doing-columns.yaml +32 -0
- data/spec/data/burndown-data-with-swimlanes.yaml +32 -0
- data/spec/data/burndown-data-with-todo-columns.yaml +35 -0
- data/spec/integration/create_burndown_spec.rb +2 -2
- data/spec/unit/board_mock_spec.rb +96 -0
- data/spec/unit/burndown_chart_spec.rb +15 -0
- data/spec/unit/burndown_data_spec.rb +174 -115
- data/spec/unit/card_spec.rb +111 -0
- data/spec/unit/cli_spec.rb +2 -0
- data/spec/unit/scrum_board_spec.rb +31 -0
- data/spec/unit/settings_spec.rb +0 -1
- data/spec/unit/support/board_mock.rb +63 -0
- data/spec/unit/trello_wrapper_spec.rb +15 -12
- data/trollolo.gemspec +3 -3
- metadata +11 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 39645441651332bd9aa763b5eea9827f46681b85569482dd8a5f69aae5a54f6f
|
4
|
+
data.tar.gz: 638a3a09670e1515faf53a02a8e8fc849ef46156c27509d4f8799a21c19cc25b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19fe728b12ab77109ad83310ab46e781be3bdf24c6388a5bf403b783043e327d7cbe6119b836c503995c4fe66db37cb5e2229c20969b95446e29d9fc6a9f6e97
|
7
|
+
data.tar.gz: 9983169a36878297fdbd4fc10bb46f4c97b030b24308a95abd96cd9ca6f013bbe5f73a55ededfa0a0fb7cb8a9b9deec5b1fdb6e7199e0d0ec87896d1c5f7a205
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
@@ -6,14 +6,6 @@
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
|
-
# Offense count: 7
|
10
|
-
# Cop supports --auto-correct.
|
11
|
-
# Configuration parameters: Include, TreatCommentsAsGroupSeparators.
|
12
|
-
# Include: **/*.gemfile, **/Gemfile, **/gems.rb
|
13
|
-
Bundler/OrderedGems:
|
14
|
-
Exclude:
|
15
|
-
- 'Gemfile'
|
16
|
-
|
17
9
|
# Offense count: 1
|
18
10
|
# Cop supports --auto-correct.
|
19
11
|
# Configuration parameters: Include, TreatCommentsAsGroupSeparators.
|
@@ -29,15 +21,6 @@ Gemspec/RequiredRubyVersion:
|
|
29
21
|
Exclude:
|
30
22
|
- 'trollolo.gemspec'
|
31
23
|
|
32
|
-
# Offense count: 8
|
33
|
-
# Cop supports --auto-correct.
|
34
|
-
# Configuration parameters: EnforcedStyle.
|
35
|
-
# SupportedStyles: leading, trailing
|
36
|
-
Layout/DotPosition:
|
37
|
-
Exclude:
|
38
|
-
- 'spec/integration/create_burndown_spec.rb'
|
39
|
-
- 'spec/unit/trello_wrapper_spec.rb'
|
40
|
-
|
41
24
|
# Offense count: 1
|
42
25
|
# Cop supports --auto-correct.
|
43
26
|
Layout/EmptyLineAfterMagicComment:
|
@@ -158,6 +141,9 @@ Layout/MultilineMethodCallIndentation:
|
|
158
141
|
Exclude:
|
159
142
|
- 'lib/burndown_chart.rb'
|
160
143
|
- 'spec/unit/trello_wrapper_spec.rb'
|
144
|
+
- 'spec/unit/board_mock_spec.rb' # Indendation is used to express structure of board
|
145
|
+
- 'spec/unit/burndown_data_spec.rb' # Indendation is used to express structure of board
|
146
|
+
- 'spec/unit/scrum_board_spec.rb' # Indendation is used to express structure of board
|
161
147
|
|
162
148
|
# Offense count: 2
|
163
149
|
# Cop supports --auto-correct.
|
@@ -308,14 +294,6 @@ Naming/UncommunicativeMethodArgName:
|
|
308
294
|
- 'lib/scrum/sprint_board.rb'
|
309
295
|
- 'lib/scrum/sprint_planning_board.rb'
|
310
296
|
|
311
|
-
# Offense count: 2
|
312
|
-
# Cop supports --auto-correct.
|
313
|
-
# Configuration parameters: AutoCorrect.
|
314
|
-
Performance/HashEachMethods:
|
315
|
-
Exclude:
|
316
|
-
- 'lib/cli.rb'
|
317
|
-
- 'lib/scrum/creator.rb'
|
318
|
-
|
319
297
|
# Offense count: 1
|
320
298
|
# Cop supports --auto-correct.
|
321
299
|
Security/YAMLLoad:
|
@@ -416,6 +394,3 @@ Style/PercentLiteralDelimiters:
|
|
416
394
|
# Cop supports --auto-correct.
|
417
395
|
# Configuration parameters: EnforcedStyle, AllowInnerSlashes.
|
418
396
|
# SupportedStyles: slashes, percent_r, mixed
|
419
|
-
Style/RegexpLiteral:
|
420
|
-
Exclude:
|
421
|
-
- 'trollolo.gemspec'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -10,7 +10,7 @@ To discuss anything please [contact Cornelius](mailto:cschum@suse.de).
|
|
10
10
|
|
11
11
|
## Contribute code
|
12
12
|
|
13
|
-
To contribute code
|
13
|
+
To contribute code fork the repository and open pull requests with your changes.
|
14
14
|
|
15
15
|
Ensure that rspec and rubocop pass locally before sending your PR and always that you add new changes.
|
16
16
|
|
@@ -18,9 +18,9 @@ If your changes include important new features or bug fixes please add them to t
|
|
18
18
|
|
19
19
|
### To run rspec test
|
20
20
|
|
21
|
-
To run all the
|
21
|
+
To run all the unit tests:
|
22
22
|
|
23
|
-
`bundle exec rspec`
|
23
|
+
`bundle exec rspec spec/unit`
|
24
24
|
|
25
25
|
To run all the test in one spec file, for example `spec/unit/burndown_chart_spec.rb`:
|
26
26
|
|
@@ -30,8 +30,22 @@ To only run the test in the line 415 of the file:
|
|
30
30
|
|
31
31
|
`bundle exec rspec spec/unit/burndown_chart_spec.rb:415`
|
32
32
|
|
33
|
+
### To try your changes
|
34
|
+
|
35
|
+
Build the gem:
|
36
|
+
|
37
|
+
`bundle exec rake gem:build`
|
38
|
+
|
39
|
+
Install the gem:
|
40
|
+
|
41
|
+
`gem install trollolo-<version>.gem`
|
42
|
+
|
33
43
|
### To run rubocop
|
34
44
|
|
35
45
|
To run Rubocop displaying cop names in offense messages:
|
36
46
|
|
37
47
|
`bundle exec rubocop -D`
|
48
|
+
|
49
|
+
## Code of Conduct
|
50
|
+
|
51
|
+
Trollolo is part of the openSUSE project. We follow all the [openSUSE Guiding Principles](https://en.opensuse.org/openSUSE:Guiding_principles)!
|
data/Gemfile
CHANGED
@@ -3,17 +3,17 @@ source 'https://rubygems.org'
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :test do
|
6
|
-
gem '
|
7
|
-
gem '
|
6
|
+
gem 'awesome_print'
|
7
|
+
gem 'byebug'
|
8
8
|
gem 'cli_tester'
|
9
|
-
gem '
|
10
|
-
gem 'vcr'
|
9
|
+
gem 'codeclimate-test-reporter', '>= 1.0.0'
|
11
10
|
gem 'given_filesystem'
|
12
|
-
gem 'byebug'
|
13
|
-
gem 'awesome_print'
|
14
11
|
gem 'pry'
|
15
|
-
gem 'ronn', '>=0.7.3'
|
16
12
|
gem 'rake'
|
17
|
-
gem '
|
13
|
+
gem 'ronn', '>=0.7.3'
|
14
|
+
gem 'rspec', '~> 3.5'
|
18
15
|
gem 'rspec-mocks'
|
16
|
+
gem 'rubocop', '0.52.1'
|
17
|
+
gem 'vcr'
|
18
|
+
gem 'webmock'
|
19
19
|
end
|
data/README.md
CHANGED
@@ -21,7 +21,7 @@ which demonstrates the expected structure.
|
|
21
21
|
|
22
22
|
## Installation
|
23
23
|
|
24
|
-
You need to have Ruby install. Trollolo works with Ruby
|
24
|
+
You need to have Ruby install. Trollolo works with Ruby >= 2.2.
|
25
25
|
|
26
26
|
You can install Trollolo as gem with `gem install trollolo`.
|
27
27
|
|
@@ -139,7 +139,6 @@ The specified `URL` can contain placeholders which will be replaced:
|
|
139
139
|
:board => Board ID
|
140
140
|
|
141
141
|
|
142
|
-
|
143
142
|
To generate the actual burndown chart, go to the working directory and call:
|
144
143
|
|
145
144
|
trollolo plot SPRINT_NUMBER
|
@@ -156,6 +155,45 @@ Trello board.
|
|
156
155
|
Some more info can be found in the command line help with `trollolo help` and
|
157
156
|
`trollolo help burndown`.
|
158
157
|
|
158
|
+
### Swimlanes
|
159
|
+
|
160
|
+
You can define swimlanes to exclude certain cards from the normal burndown
|
161
|
+
data. This can be useful when you track work of multiple projects on the same
|
162
|
+
board and you don't want to apply the full Scrum framework to all of them. An
|
163
|
+
example would be a side project which you limit to one card in process.
|
164
|
+
|
165
|
+
Swimlanes are defined by putting a label with the name of the swimlane on all
|
166
|
+
cards which belong to this swimlane. It does not matter in which column they
|
167
|
+
are. To make Trollolo aware of the swimlane, you need to add an entry in the
|
168
|
+
meta section of the burndown YAML such as:
|
169
|
+
|
170
|
+
meta:
|
171
|
+
swimlanes:
|
172
|
+
- My Side Project
|
173
|
+
|
174
|
+
This lets Trollolo exclude all cards which have the label with the name
|
175
|
+
`My Side Project` from the burndown chart.
|
176
|
+
|
177
|
+
The data for swimlane cards is collected separately in the burndown YAML
|
178
|
+
separated in `todo`, `doing`, and `done` values. This can be used to generate
|
179
|
+
statistics for the swimlanes. Trollolo currently only writes the raw data
|
180
|
+
but doesn't support any statistics such as generating graphs.
|
181
|
+
|
182
|
+
### Column names
|
183
|
+
|
184
|
+
Trollolo by default looks for columns named such as `Sprint Backlog`, `Doing`,
|
185
|
+
or `Done`. If you need more or other names you can configure that in the burndown
|
186
|
+
YAML. Here is an example:
|
187
|
+
|
188
|
+
meta:
|
189
|
+
todo_columns:
|
190
|
+
- Main Backlog
|
191
|
+
- Swimlane Backlog
|
192
|
+
doing_columns:
|
193
|
+
- Doing
|
194
|
+
- Review
|
195
|
+
- QA
|
196
|
+
|
159
197
|
### Example
|
160
198
|
|
161
199
|
![Burndown example](https://raw.githubusercontent.com/openSUSE/trollolo/master/examples/burndown-26.png)
|
data/lib/burndown_chart.rb
CHANGED
@@ -84,8 +84,17 @@ class BurndownChart
|
|
84
84
|
|
85
85
|
def read_data(filename)
|
86
86
|
@data = YAML.load_file filename
|
87
|
+
|
88
|
+
todo_columns = @data['meta']['todo_columns']
|
89
|
+
@settings.todo_columns = todo_columns if todo_columns
|
90
|
+
|
91
|
+
doing_columns = @data['meta']['doing_columns']
|
92
|
+
@settings.doing_columns = doing_columns if doing_columns
|
93
|
+
|
87
94
|
not_done_columns = @data['meta']['not_done_columns']
|
88
95
|
@settings.not_done_columns = not_done_columns if not_done_columns
|
96
|
+
|
97
|
+
@settings.swimlanes = @data['meta']['swimlanes'] || []
|
89
98
|
end
|
90
99
|
|
91
100
|
def write_data(filename)
|
data/lib/burndown_data.rb
CHANGED
@@ -33,9 +33,31 @@ class BurndownData
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
class SwimlaneResult
|
37
|
+
attr_accessor :todo, :doing, :done
|
38
|
+
|
39
|
+
def add_todo(story_points)
|
40
|
+
@todo += story_points
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_doing(story_points)
|
44
|
+
@doing += story_points
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_done(story_points)
|
48
|
+
@done += story_points
|
49
|
+
end
|
50
|
+
|
51
|
+
def initialize
|
52
|
+
@todo = 0
|
53
|
+
@doing = 0
|
54
|
+
@done = 0
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
36
58
|
attr_accessor :story_points, :tasks, :extra_story_points, :extra_tasks,
|
37
59
|
:unplanned_story_points, :unplanned_tasks,
|
38
|
-
:board_id, :fast_lane_cards, :date_time
|
60
|
+
:board_id, :fast_lane_cards, :date_time, :swimlanes
|
39
61
|
attr_reader :meta
|
40
62
|
|
41
63
|
def initialize(settings)
|
@@ -48,6 +70,11 @@ class BurndownData
|
|
48
70
|
@unplanned_tasks = Result.new
|
49
71
|
@fast_lane_cards = Result.new
|
50
72
|
@date_time = Time.now
|
73
|
+
|
74
|
+
@swimlanes = {}
|
75
|
+
settings.swimlanes.each do |swimlane|
|
76
|
+
@swimlanes[swimlane] = SwimlaneResult.new
|
77
|
+
end
|
51
78
|
end
|
52
79
|
|
53
80
|
def to_hash
|
@@ -69,12 +96,9 @@ class BurndownData
|
|
69
96
|
'done' => extra_tasks.done
|
70
97
|
}
|
71
98
|
}
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
'open' => fast_lane_cards.open
|
76
|
-
}
|
77
|
-
end
|
99
|
+
|
100
|
+
base['fast_lane'] = fast_lane_to_hash if fast_lane_cards.total > 0
|
101
|
+
|
78
102
|
if unplanned_story_points.total > 0
|
79
103
|
base['unplanned_story_points'] = {
|
80
104
|
'total' => unplanned_story_points.total,
|
@@ -85,9 +109,31 @@ class BurndownData
|
|
85
109
|
'open' => unplanned_tasks.open
|
86
110
|
}
|
87
111
|
end
|
112
|
+
|
113
|
+
base['swimlanes'] = swimlanes_to_hash unless swimlanes.empty?
|
114
|
+
|
88
115
|
base
|
89
116
|
end
|
90
117
|
|
118
|
+
def fast_lane_to_hash
|
119
|
+
{
|
120
|
+
'total' => fast_lane_cards.total,
|
121
|
+
'open' => fast_lane_cards.open
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def swimlanes_to_hash
|
126
|
+
swimlanes_element = {}
|
127
|
+
swimlanes.each do |name, swimlane_result|
|
128
|
+
swimlanes_element[name] = {
|
129
|
+
'todo' => swimlane_result.todo,
|
130
|
+
'doing' => swimlane_result.doing,
|
131
|
+
'done' => swimlane_result.done
|
132
|
+
}
|
133
|
+
end
|
134
|
+
swimlanes_element
|
135
|
+
end
|
136
|
+
|
91
137
|
def trello
|
92
138
|
@trello ||= TrelloWrapper.new(@settings)
|
93
139
|
end
|
@@ -113,6 +159,33 @@ class BurndownData
|
|
113
159
|
@fast_lane_cards.done = board.done_fast_lane_cards_count
|
114
160
|
@fast_lane_cards.open = board.open_fast_lane_cards_count
|
115
161
|
@date_time = DateTime.now
|
162
|
+
|
163
|
+
fetch_swimlanes
|
164
|
+
end
|
165
|
+
|
166
|
+
def fetch_swimlanes
|
167
|
+
@settings.swimlanes.each do |swimlane|
|
168
|
+
board.todo_columns.each do |column|
|
169
|
+
column.cards.each do |card|
|
170
|
+
@swimlanes[swimlane].add_todo(card.story_points) if card.label?(swimlane)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
board.doing_columns.each do |column|
|
175
|
+
column.cards.each do |card|
|
176
|
+
@swimlanes[swimlane].add_doing(card.story_points) if card.label?(swimlane)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
board.done_column.cards.each do |card|
|
181
|
+
@swimlanes[swimlane].add_done(card.story_points) if card.label?(swimlane)
|
182
|
+
end
|
183
|
+
board.accepted_columns.each do |column|
|
184
|
+
column.cards.each do |card|
|
185
|
+
@swimlanes[swimlane].add_done(card.story_points) if card.label?(swimlane)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
116
189
|
end
|
117
190
|
|
118
191
|
private
|
data/lib/card.rb
CHANGED
@@ -52,10 +52,17 @@ class Card
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def card_labels
|
55
|
-
@card_data['labels']
|
55
|
+
@card_data['labels'] || []
|
56
|
+
end
|
57
|
+
|
58
|
+
def label?(label_name)
|
59
|
+
card_labels.any? do |label|
|
60
|
+
label['name'].include?(label_name)
|
61
|
+
end
|
56
62
|
end
|
57
63
|
|
58
64
|
def checklists
|
65
|
+
return [] unless @card_data['checklists']
|
59
66
|
@card_data['checklists'].map do |checklist|
|
60
67
|
Checklist.new(checklist)
|
61
68
|
end
|
@@ -84,6 +91,15 @@ class Card
|
|
84
91
|
end
|
85
92
|
end
|
86
93
|
|
94
|
+
def swimlane?
|
95
|
+
card_labels.each do |label|
|
96
|
+
@settings.swimlanes.each do |swimlane|
|
97
|
+
return true if label['name'].include?(swimlane)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
87
103
|
def meta_card?
|
88
104
|
name =~ SPRINT_NUMBER_REGEX
|
89
105
|
end
|
data/lib/cli.rb
CHANGED
@@ -134,7 +134,7 @@ EOT
|
|
134
134
|
def burndowns
|
135
135
|
process_global_options options
|
136
136
|
board_list = YAML.load_file(options['board-list'])
|
137
|
-
board_list.
|
137
|
+
board_list.each_key do |name|
|
138
138
|
raise 'invalid character in team name' if name =~ /[^[:alnum:]. _]/ # sanitize
|
139
139
|
board = board_list[name]
|
140
140
|
if options['output']
|