trollolo 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/Gemfile +1 -1
  4. data/README.md +97 -0
  5. data/lib/card.rb +0 -14
  6. data/lib/cli.rb +66 -27
  7. data/lib/empty_column.rb +5 -0
  8. data/lib/scrum/backlog_mover.rb +47 -0
  9. data/lib/scrum/card_type_detection.rb +23 -0
  10. data/lib/scrum/creator.rb +30 -0
  11. data/lib/scrum/prioritizer.rb +24 -0
  12. data/lib/scrum/priority_name.rb +15 -0
  13. data/lib/scrum/scrum_boards.rb +11 -0
  14. data/lib/scrum/sprint_board.rb +82 -0
  15. data/lib/scrum/sprint_cleaner.rb +41 -0
  16. data/lib/scrum/sprint_planning_board.rb +26 -0
  17. data/lib/scrum.rb +13 -0
  18. data/lib/scrum_board.rb +17 -7
  19. data/lib/settings.rb +36 -12
  20. data/lib/trello_service.rb +22 -0
  21. data/lib/trello_wrapper.rb +9 -23
  22. data/lib/trollolo.rb +3 -2
  23. data/lib/version.rb +1 -1
  24. data/man/trollolo.1.md +22 -1
  25. data/spec/data/board.json +3 -4
  26. data/spec/data/full-board-with-accepted.json +1817 -0
  27. data/spec/data/full-board.json +3 -27
  28. data/spec/data/trollolorc +13 -0
  29. data/spec/data/trollolorc_with_board_aliases +9 -0
  30. data/spec/data/vcr/creator_custom_config.yml +824 -0
  31. data/spec/data/vcr/creator_default_config.yml +824 -0
  32. data/spec/data/vcr/move_backlog.yml +2375 -0
  33. data/spec/data/vcr/move_backlog_missing_backlog.yml +155 -0
  34. data/spec/data/vcr/move_backlog_missing_waterbed.yml +364 -0
  35. data/spec/data/vcr/prioritize_backlog_list.yml +2335 -0
  36. data/spec/data/vcr/prioritize_no_backlog_list.yml +190 -0
  37. data/spec/data/vcr/sprint_board.yml +624 -0
  38. data/spec/data/vcr/sprint_board_no_waterline.yml +556 -0
  39. data/spec/data/vcr/sprint_cleanup.yml +1239 -7500
  40. data/spec/data/vcr/sprint_planning_board.yml +239 -0
  41. data/spec/integration/create_burndown_spec.rb +1 -1
  42. data/spec/unit/card_spec.rb +0 -41
  43. data/spec/unit/cli_spec.rb +74 -1
  44. data/spec/unit/empty_column_spec.rb +9 -0
  45. data/spec/unit/scrum/backlog_mover_spec.rb +26 -0
  46. data/spec/unit/scrum/card_type_detection_spec.rb +35 -0
  47. data/spec/unit/scrum/creator_spec.rb +23 -0
  48. data/spec/unit/scrum/prioritizer_spec.rb +45 -0
  49. data/spec/unit/scrum/priority_name_spec.rb +35 -0
  50. data/spec/unit/scrum/sprint_board_spec.rb +22 -0
  51. data/spec/unit/scrum/sprint_cleaner_spec.rb +26 -0
  52. data/spec/unit/scrum/sprint_planning_board_spec.rb +14 -0
  53. data/spec/unit/scrum_board_spec.rb +90 -0
  54. data/spec/unit/settings_spec.rb +42 -6
  55. data/spec/unit/spec_helper.rb +3 -2
  56. data/spec/unit/support/update_webmock_data +3 -1
  57. data/spec/unit/support/vcr.rb +8 -8
  58. data/spec/unit/support/webmocks.rb +9 -0
  59. data/spec/unit/trello_wrapper_spec.rb +20 -0
  60. data/trollolo.gemspec +2 -1
  61. metadata +52 -9
  62. data/lib/prioritizer.rb +0 -34
  63. data/lib/sprint_cleanup.rb +0 -54
  64. data/spec/unit/prioritizer_spec.rb +0 -47
  65. data/spec/unit/sprint_cleanup_spec.rb +0 -18
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1b0bc626175dfcdffe5dffa8942ec7469797ec4
4
- data.tar.gz: a8feeb3163223a858044f9d2c9be8bb66e350699
3
+ metadata.gz: edecf120a728ec76d245cb2e64669fd8c075e34c
4
+ data.tar.gz: ada5a9fc6e5691786b28297662fdf8f7f5d42f83
5
5
  SHA512:
6
- metadata.gz: cf9922a6a5d5ec348be19bde09f391115f6022e1fb0e2a2fc5b5f0c83cae7ee1b3de95037d3964b0fcbb54db1fb16c106a0f85df118f0928aed9f8f1424b7286
7
- data.tar.gz: f5345fe994f6db7343aece171c5e57782264f493c454e742aba148f6e58c8d111eb714986ec3f2b2aa99d8bfd3c968b4644f2b16adb67a060b1ece658effa1f7
6
+ metadata.gz: e9365f00bb685300806a0663cc84d075fcb92cea09eba9e04acfd328aa21a82e8ebe694db6c3d0ef731b3f6971a3d0698af7bc70cdf538116a9adad841716eba
7
+ data.tar.gz: 170c8a25882e6ee7f70fdfa634a7e7b75ac7e4f2d573b830556f8d3428afbe88b5dcb1d468302489fadb0cdda4478070d3021ab73517a29c476eed55214f0a5c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Trollolo Changelog
2
2
 
3
+ ## Version 0.0.10
4
+
5
+ * Rename `sprint-cleanup` to `cleanup-sprint`.
6
+ * Configure board, list and label names to trollolorc. The commands
7
+ `cleanup-sprint`, `move-backlog`, `set-priorities` and `setup-scrum` will use
8
+ these names. You will still need to provide board IDs, or their aliases, as
9
+ several boards can share the same name.
10
+ * Add `setup-scrum` command to create all necessary elements of our scrumb board
11
+ as configured in trollolorc or using the defaults. A sample configuration can
12
+ be found in `spec/data/trollolorc`. Fixes #57
13
+ * Add option for backlog list name in `set-priorities`.
14
+ * Add `move-backlog` command for moving a backlog from a planning to a sprint board
15
+ * Handle boards which have an "Accepted" column in addition to a "Done" column
16
+
3
17
  ## Version 0.0.9
4
18
 
5
19
  * Add `sprint-cleanup` command to move cards back from the sprint board to the
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :test do
6
- gem 'codeclimate-test-reporter'
6
+ gem 'codeclimate-test-reporter', '>= 1.0.0'
7
7
  gem 'rspec', '~> 3.5'
8
8
  gem 'cli_tester'
9
9
  gem 'webmock'
data/README.md CHANGED
@@ -57,6 +57,24 @@ To create a member token for the `set-priority` command use this URL instead:
57
57
 
58
58
  The board id is the cryptic string in the URL of your board.
59
59
 
60
+ The `.trollolorc` file can also be used to set aliases for board ids. When set,
61
+ you will be able to use the alias instead of the board-id in the various
62
+ commands. E.g.
63
+
64
+ With the following configuration
65
+
66
+ ```
67
+ board_aliases:
68
+ MyTrelloBoard: 53186e8391ef8671265ebf9e
69
+
70
+ ```
71
+
72
+ You can issue the command:
73
+
74
+ ```
75
+ trollolo get-cards --board-id=MyTrelloBoard
76
+ ```
77
+
60
78
  ## Creating burndown charts
61
79
 
62
80
  Trollolo implements a simple work flow for creating burndown charts from the
@@ -129,3 +147,82 @@ Some more info can be found in the command line help with `trollolo help` and
129
147
  ### Example
130
148
 
131
149
  ![Burndown example](https://raw.githubusercontent.com/openSUSE/trollolo/master/examples/burndown-26.png)
150
+
151
+ ## Other SCRUM commands
152
+
153
+ Trollolo supports SCRUM on Trello by using one board for the sprint and another one for planning.
154
+ On these boards several lists are used to organize stories.
155
+
156
+ The `setup-scrum` command creates the necessary elements. The names are taken from the configuration.
157
+ If you change the names in Trello, you need to update theconfiguration in `trollolorc`.
158
+
159
+ At the end of a sprint, after the review meeting, remaining cards can be moved back to the planning
160
+ board with `cleanup-sprint`.
161
+ Once the sprint backlog is ready, priorities can be added to the card titles with `prioritize`.
162
+ Move the planning backlog to the sprint board with `move-backlog`.
163
+
164
+ ### Labels
165
+
166
+ * `sticky`: used to mark cards which are not moved, like the goal card
167
+ * `waterline`: for cards which are under the waterline
168
+
169
+ ### Lists
170
+
171
+ * `sprint_backlog`: this list contains the stories of the current sprint
172
+ * `sprint_qa`: any cards in the current sprint which need QA
173
+ * `sprint_doing`: cards currently being worked on
174
+ * `planning_backlog`: used to plan the next sprint, these cards will be prioritized
175
+ * `planning_ready`: contains cards which are not yet estimated and therefore not in the backlog
176
+
177
+ ### Default Configuration
178
+
179
+ These are the default names, add this to `trollolorc` and change as necessary.
180
+
181
+ scrum:
182
+ board_names:
183
+ planning: Planning Board
184
+ sprint: Sprint Board
185
+ label_names:
186
+ sticky: Sticky
187
+ waterline: Waterline
188
+ list_names:
189
+ sprint_backlog: Sprint Backlog
190
+ sprint_qa: QA
191
+ sprint_doing: Doing
192
+ planning_backlog: Backlog
193
+ planning_ready: Ready for Estimation
194
+
195
+ The board names are not used to find the boards on trello.
196
+ Since several boards can share the same name, they are only used when creating the SCRUM setup.
197
+
198
+ ### Examples
199
+
200
+ Create the boards and lists:
201
+
202
+ trollolo setup-scrum
203
+
204
+ Lookup the ID of the created boards and use them as arguments:
205
+
206
+ # https://trello.com/b/123abC/sprint-board
207
+ # https://trello.com/b/GHi456/planning-board
208
+
209
+ trollolo cleanup-sprint --board-id=123abC --target-board-id=GHi456
210
+ trollolo set-priorities --board-id=GHi456
211
+ trollolo move-backlog --planning-board-id=GHi456 --sprint-board-id=123abC
212
+
213
+ You can use aliases, as described in the configuration section, instead of IDs.
214
+
215
+ ## Updating VCR specs
216
+
217
+ Some specs use VCR to reply with stored Trello API replies. The specs are annotated with `vcr:` and `vcr_record:`. To
218
+ re-record the stored replies, set `vcr_record:` to true and replace `dummy_settings` with `real_settings`.
219
+
220
+ describe Scrum::BacklogMover do
221
+ subject { described_class.new(real_settings) }
222
+
223
+ it "fails without moving if backlog list is missing waterline or seabed", vcr: "move_backlog_missing_waterbed", vcr_record: true do
224
+ expect { subject.move("neUHHzDo", "NzGCbEeN") }.to raise_error
225
+ end
226
+ end
227
+
228
+ The VCR support methods will replace your Trello token and key with dummy values, before saving the replies.
data/lib/card.rb CHANGED
@@ -18,7 +18,6 @@
18
18
  class Card
19
19
  # Assuming we have card titles as follows '(8) This is the card name'
20
20
  ESTIMATED_REGEX = /\(([\d.]+)\)/
21
- PRIORITY_REGEX = /^(?:\([\d.]+\) )?P(\d+): /
22
21
  SPRINT_NUMBER_REGEX = /\ASprint (\d+)/
23
22
 
24
23
  def initialize(board_data, card_id)
@@ -43,19 +42,6 @@ class Card
43
42
  name.match(ESTIMATED_REGEX).captures.first.to_f
44
43
  end
45
44
 
46
- def priority
47
- return unless m = name.match(PRIORITY_REGEX)
48
- m.captures.first.to_i
49
- end
50
-
51
- def priority=(n)
52
- if priority
53
- @card_data["name"].sub!(/P\d+: /, "P#{n}: ")
54
- else
55
- @card_data["name"] = "P#{n}: #{name}"
56
- end
57
- end
58
-
59
45
  def done_tasks
60
46
  count = 0
61
47
  @card_data["checklists"].each do |checklist|
data/lib/cli.rb CHANGED
@@ -74,7 +74,7 @@ EOT
74
74
  require_trello_credentials
75
75
 
76
76
  trello = TrelloWrapper.new(@@settings)
77
- board = trello.board(options["board-id"])
77
+ board = trello.board(board_id(options["board-id"]))
78
78
  lists = board.columns
79
79
 
80
80
  if @@settings.raw
@@ -93,7 +93,7 @@ EOT
93
93
  require_trello_credentials
94
94
 
95
95
  trello = TrelloWrapper.new(@@settings)
96
- board = trello.board(options["board-id"])
96
+ board = trello.board(board_id(options["board-id"]))
97
97
  cards = board.cards
98
98
 
99
99
  if @@settings.raw
@@ -118,7 +118,7 @@ EOT
118
118
  require_trello_credentials
119
119
 
120
120
  trello = TrelloWrapper.new(@@settings)
121
- board = trello.board(options["board-id"])
121
+ board = trello.board(board_id(options["board-id"]))
122
122
  board.cards.each do |card|
123
123
  card.checklists.each do |checklist|
124
124
  puts checklist.name
@@ -160,7 +160,7 @@ EOT
160
160
 
161
161
  chart = BurndownChart.new @@settings
162
162
  puts "Preparing directory..."
163
- chart.setup(options[:output],options["board-id"])
163
+ chart.setup(options[:output],board_id(options["board-id"]))
164
164
  end
165
165
 
166
166
  desc "burndown", "Update burndown chart"
@@ -203,7 +203,7 @@ EOT
203
203
  require_trello_credentials
204
204
 
205
205
  b = Backup.new @@settings
206
- b.backup(options["board-id"])
206
+ b.backup(board_id(options["board-id"]))
207
207
  end
208
208
 
209
209
  desc "list-backups", "List all backups"
@@ -219,7 +219,7 @@ EOT
219
219
  option "show-descriptions", :desc => "Show descriptions of cards", :required => false, :type => :boolean
220
220
  def show_backup
221
221
  b = Backup.new @@settings
222
- b.show(options["board-id"], options)
222
+ b.show(board_id(options["board-id"]), options)
223
223
  end
224
224
 
225
225
  desc "organization", "Show organization info"
@@ -293,21 +293,6 @@ EOT
293
293
  trello.make_cover(options["card-id"], filename)
294
294
  end
295
295
 
296
- desc "set-priorities", "Set priority text into card titles"
297
- long_desc <<EOT
298
- Add 'P<n>: ' to the beginning of every cards title, replace where
299
- already present. n is the current position of the list on the card.
300
- EOT
301
- option "board-id", :desc => "Id of the board", :required => true
302
- option "list-name", :desc => "Name of the list", :required => true
303
- def set_priorities
304
- process_global_options options
305
- require_trello_credentials
306
-
307
- p = Prioritizer.new(@@settings)
308
- p.prioritize(options["board-id"], options["list-name"])
309
- end
310
-
311
296
  desc "list-member-boards", "List name and id of all boards"
312
297
  option "member-id", :desc => "Id of the member", :required => true
313
298
  def list_member_boards
@@ -322,19 +307,66 @@ EOT
322
307
  }
323
308
  end
324
309
 
325
- desc "sprint-cleanup", "Move remaining cards to backlog"
310
+ desc "setup-scrum", "Create necessary elements of our SCRUM setup"
311
+ long_desc <<-EOT
312
+ Will create board, lists and labels with names as configured in trollolorc,
313
+ or use the defaults.
314
+ EOT
315
+ def setup_scrum
316
+ process_global_options options
317
+ require_trello_credentials
318
+
319
+ c = Scrum::Creator.new(@@settings)
320
+ c.create
321
+ end
322
+
323
+ desc "set-priorities", "Set priority text into card titles"
324
+ long_desc <<EOT
325
+ Add 'P<n>: ' to the beginning of every cards title in the 'Backlog' list,
326
+ replace where already present. n is the current position of the list on
327
+ the card.
328
+ EOT
329
+ option "board-id", :desc => "Id of the board", :required => true
330
+ option "backlog-list-name", :desc => "Name of backlog list", :required => false
331
+ def set_priorities
332
+ process_global_options options
333
+ require_trello_credentials
334
+
335
+ p = Scrum::Prioritizer.new(@@settings)
336
+ p.prioritize(board_id(options["board-id"]), options["backlog-list-name"])
337
+ end
338
+
339
+ desc "cleanup-sprint", "Move remaining cards to the planning board"
326
340
  long_desc <<EOT
327
- After the sprint, move remaining cards from 'Sprint Backlog' and 'Doing'
328
- back to the planning board into the 'Ready' list.
341
+ After the sprint, move remaining cards from 'Sprint Backlog', 'Doing'
342
+ and 'QA' lists back to the planning board into the 'Ready' list.
329
343
  EOT
330
344
  option "board-id", :desc => "Id of the board", :required => true
331
345
  option "target-board-id", :desc => "Id of the target board", :required => true
332
- def sprint_cleanup
346
+ def cleanup_sprint
347
+ process_global_options options
348
+ require_trello_credentials
349
+
350
+ s = Scrum::SprintCleaner.new(@@settings)
351
+ s.cleanup(board_id(options["board-id"]),
352
+ board_id(options["target-board-id"]))
353
+ end
354
+
355
+ desc "move-backlog", "Move the planning backlog to the sprint board"
356
+ long_desc <<-EOT
357
+ Two separate boards are used, a planning board and a sprint board for the
358
+ current sprint.
359
+ After each planning meeting the cards are moved from the planning boards
360
+ 'Backlog' list to the sprint boards 'Sprint Backlog' list.
361
+ EOT
362
+ option "planning-board-id", desc: "Id of the planning board", required: true
363
+ option "sprint-board-id", desc: "Id of the sprint board", required: true
364
+ def move_backlog
333
365
  process_global_options options
334
366
  require_trello_credentials
335
367
 
336
- s = SprintCleanup.new(@@settings)
337
- s.cleanup(options["board-id"], options["target-board-id"])
368
+ m = Scrum::BacklogMover.new(@@settings)
369
+ m.move(board_id(options["planning-board-id"]), board_id(options["sprint-board-id"]))
338
370
  end
339
371
 
340
372
  private
@@ -368,4 +400,11 @@ EOT
368
400
  exit 1
369
401
  end
370
402
  end
403
+
404
+ # Returns the board_id using id_or_alias. If id_or_alias matches a mapping
405
+ # from trollolorc then the mapped id is returned or else the id_or_alias
406
+ # is returned.
407
+ def board_id(id_or_alias)
408
+ @@settings.board_aliases[id_or_alias] || id_or_alias
409
+ end
371
410
  end
@@ -0,0 +1,5 @@
1
+ class EmptyColumn < Column
2
+ def initialize
3
+ super({"lists" => [], "cards" => []}, nil)
4
+ end
5
+ end
@@ -0,0 +1,47 @@
1
+ module Scrum
2
+ class BacklogMover < TrelloService
3
+ include ScrumBoards
4
+
5
+ def move(planning_board_id, sprint_board_id)
6
+ setup(planning_board_id, sprint_board_id)
7
+ inspect_backlog
8
+ @sprint_board.place_seabed(@seabed_card)
9
+ end
10
+
11
+ private
12
+
13
+ def setup(planning_board_id, sprint_board_id)
14
+ @sprint_board = sprint_board(sprint_board_id)
15
+ fail "sprint board is missing #{@sprint_board.backlog_list_name} list" unless @sprint_board.backlog_list
16
+
17
+ @planning_board = planning_board(planning_board_id)
18
+ fail "backlog list not found on planning board" unless @planning_board.backlog_list
19
+
20
+ @waterline_card = @planning_board.waterline_card
21
+ fail "backlog list on planning board is missing waterline or seabed card" unless @waterline_card
22
+
23
+ @seabed_card = @planning_board.seabed_card
24
+ fail "backlog list on planning board is missing waterline or seabed card" unless @seabed_card
25
+ end
26
+
27
+ def inspect_backlog
28
+ @planning_board.backlog_cards.each do |card|
29
+ if card == @seabed_card
30
+ break
31
+
32
+ elsif card == @waterline_card
33
+ @sprint_board.place_waterline(@waterline_card)
34
+ puts "under the waterline"
35
+
36
+ else
37
+ move_sprint_card(card) unless @planning_board.sticky?(card)
38
+ end
39
+ end
40
+ end
41
+
42
+ def move_sprint_card(card)
43
+ puts %(moving card "#{card.name}")
44
+ @sprint_board.receive(card)
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ module Scrum
2
+ module CardTypeDetection
3
+ def sticky?(card)
4
+ card.labels.any? { |l| l.name == @settings.label_names["sticky"] }
5
+ end
6
+
7
+ def waterline?(card)
8
+ card.name =~ /w.?a.?t.?e.?r.?l.?i.?n.?e/i
9
+ end
10
+
11
+ def seabed?(card)
12
+ card.name =~ /s.?e.?a.?b.?e.?d/i
13
+ end
14
+
15
+ def waterline_card
16
+ @backlog_list.cards.find { |card| waterline?(card) }
17
+ end
18
+
19
+ def seabed_card
20
+ @backlog_list.cards.find { |card| seabed?(card) }
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ module Scrum
2
+ class Creator < TrelloService
3
+ def create
4
+ @scrum = @settings.scrum
5
+ create_sprint_board
6
+ create_planning_board
7
+ end
8
+
9
+ private
10
+
11
+ def create_labels(board_id)
12
+ @scrum.label_names.each { |_, name| Trello::Label.create(name: name, board_id: board_id) }
13
+ end
14
+
15
+ def create_sprint_board
16
+ board = Trello::Board.create(name: @scrum.board_names["sprint"])
17
+ Trello::List.create(board_id: board.id, name: @scrum.list_names["sprint_backlog"])
18
+ Trello::List.create(board_id: board.id, name: @scrum.list_names["sprint_qa"])
19
+ Trello::List.create(board_id: board.id, name: @scrum.list_names["sprint_doing"])
20
+ create_labels(board.id)
21
+ end
22
+
23
+ def create_planning_board
24
+ board = Trello::Board.create(name: @scrum.board_names["planning"])
25
+ Trello::List.create(board_id: board.id, name: @scrum.list_names["planning_backlog"])
26
+ Trello::List.create(board_id: board.id, name: @scrum.list_names["planning_ready"])
27
+ create_labels(board.id)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ module Scrum
2
+ class Prioritizer < TrelloService
3
+ include ScrumBoards
4
+
5
+ def prioritize(board_id, list_name = nil)
6
+ @board = planning_board(board_id, list_name)
7
+ fail "list named '#{@board.backlog_list_name}' not found on board" unless @board.backlog_list
8
+ update_priorities
9
+ end
10
+
11
+ private
12
+
13
+ def update_priorities
14
+ n = 1
15
+ @board.backlog_cards.each do |card|
16
+ next if @board.sticky?(card) || @board.waterline?(card)
17
+ puts %(set priority to #{n} for "#{card.name}")
18
+ card.name = PriorityName.build(card.name, n)
19
+ card.save
20
+ n += 1
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module Scrum
2
+ class PriorityName
3
+ PRIORITY_REGEX = /^(?:\([\d.]+\) )?P(\d+): /
4
+
5
+ def self.priority(name)
6
+ return unless m = name.match(PRIORITY_REGEX)
7
+ m.captures.first.to_i
8
+ end
9
+
10
+ def self.build(name, n)
11
+ return name.sub(/P\d+: /, "P#{n}: ") if priority(name)
12
+ "P#{n}: #{name}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,11 @@
1
+ module Scrum
2
+ module ScrumBoards
3
+ def sprint_board(board_id)
4
+ Scrum::SprintBoard.new(@settings.scrum).setup(board_id)
5
+ end
6
+
7
+ def planning_board(board_id, list_name = nil)
8
+ Scrum::SprintPlanningBoard.new(@settings.scrum).setup(board_id, list_name)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,82 @@
1
+ module Scrum
2
+ class SprintBoard
3
+ include CardTypeDetection
4
+
5
+ def initialize(settings)
6
+ @under_waterline = false
7
+ @settings = settings
8
+ end
9
+ attr_reader :backlog_list
10
+
11
+ def setup(id)
12
+ @board, @backlog_list = TrelloService.find_list(id, backlog_list_name)
13
+ self
14
+ end
15
+
16
+ def backlog_list_name
17
+ @settings.list_names["sprint_backlog"]
18
+ end
19
+
20
+ def doing_list
21
+ @doing_list ||= @board.lists.find { |l| l.name == doing_list_name }
22
+ end
23
+
24
+ def qa_list
25
+ @qa_list ||= @board.lists.find { |l| l.name == qa_list_name }
26
+ end
27
+
28
+ def receive(card)
29
+ card.move_to_board(@board, @backlog_list)
30
+ add_waterline_label(card) if @under_waterline
31
+ end
32
+
33
+ def place_waterline(planning_waterline_card)
34
+ place_card_at_bottom(waterline_card, planning_waterline_card)
35
+ @under_waterline = true
36
+ end
37
+
38
+ def place_seabed(planning_seabed_card)
39
+ place_card_at_bottom(seabed_card, planning_seabed_card)
40
+ end
41
+
42
+ def find_waterline_label(labels)
43
+ labels.find do |label|
44
+ label.name == waterline_label_name ||
45
+ label.name =~ /waterline/i
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def under_waterline_label
52
+ @label ||= find_waterline_label(@board.labels)
53
+ @label ||= Trello::Label.create(name: waterline_label_name)
54
+ end
55
+
56
+ def add_waterline_label(original_card)
57
+ new_card = @backlog_list.cards.find { |card| card.name == original_card.name }
58
+ new_card.card_labels << under_waterline_label
59
+ end
60
+
61
+ def place_card_at_bottom(existing_card, planning_card)
62
+ if existing_card
63
+ existing_card.pos = 'bottom'
64
+ existing_card.save
65
+ else
66
+ planning_card.move_to_board(@board, @backlog_list)
67
+ end
68
+ end
69
+
70
+ def waterline_label_name
71
+ @settings.label_names["waterline"]
72
+ end
73
+
74
+ def qa_list_name
75
+ @settings.list_names["sprint_qa"]
76
+ end
77
+
78
+ def doing_list_name
79
+ @settings.list_names["sprint_doing"]
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,41 @@
1
+ module Scrum
2
+ class SprintCleaner < TrelloService
3
+ include ScrumBoards
4
+
5
+ def cleanup(board_id, target_board_id)
6
+ @board = sprint_board(board_id)
7
+ fail "backlog list '#{@board.backlog_list_name}' not found on sprint board" unless @board.backlog_list
8
+ @target_board = Trello::Board.find(target_board_id)
9
+ fail "ready list '#{@settings.scrum.list_names["planning_ready"]}' not found on planning board" unless target_list
10
+
11
+ move_cards(@board.backlog_list)
12
+ move_cards(@board.doing_list) if @board.doing_list
13
+ move_cards(@board.qa_list) if @board.qa_list
14
+ end
15
+
16
+ private
17
+
18
+ def target_list
19
+ @target_list ||= @target_board.lists.find { |l| l.name == @settings.scrum.list_names["planning_ready"] }
20
+ end
21
+
22
+ def waterline_label(card)
23
+ @board.find_waterline_label(card.labels)
24
+ end
25
+
26
+ def remove_waterline_label(card)
27
+ label = waterline_label(card)
28
+ card.remove_label(label) if label
29
+ end
30
+
31
+ def move_cards(source_list)
32
+ source_list.cards.each do |card|
33
+ next if @board.sticky?(card)
34
+ puts %(moving card "#{card.name}" to list "#{target_list.name}")
35
+ card.members.each { |member| card.remove_member(member) }
36
+ remove_waterline_label(card)
37
+ card.move_to_board(@target_board, target_list)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,26 @@
1
+ module Scrum
2
+ class SprintPlanningBoard
3
+ include CardTypeDetection
4
+
5
+ attr_reader :backlog_list_name
6
+
7
+ def initialize(settings)
8
+ @settings = settings
9
+ @backlog_list_name = settings.list_names["planning_backlog"]
10
+ end
11
+
12
+ attr_accessor :backlog_list
13
+
14
+ def setup(id, list_name = nil)
15
+ if list_name
16
+ @backlog_list_name = list_name
17
+ end
18
+ @board, @backlog_list = TrelloService.find_list(id, @backlog_list_name)
19
+ self
20
+ end
21
+
22
+ def backlog_cards
23
+ @backlog_list.cards
24
+ end
25
+ end
26
+ end
data/lib/scrum.rb ADDED
@@ -0,0 +1,13 @@
1
+ module Scrum
2
+ end
3
+
4
+ require_relative 'scrum/card_type_detection'
5
+ require_relative 'scrum/sprint_board'
6
+ require_relative 'scrum/sprint_planning_board'
7
+ require_relative 'scrum/scrum_boards'
8
+
9
+ require_relative 'scrum/priority_name'
10
+ require_relative 'scrum/prioritizer'
11
+ require_relative 'scrum/sprint_cleaner'
12
+ require_relative 'scrum/backlog_mover'
13
+ require_relative 'scrum/creator'