trollolo 0.0.9 → 0.0.10

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