trollolo 0.1.1 → 0.2.0

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -2
  3. data/.rubocop_todo.yml +105 -270
  4. data/CHANGELOG.md +10 -0
  5. data/CONTRIBUTING.md +6 -4
  6. data/Gemfile +1 -1
  7. data/README.md +10 -1
  8. data/Rakefile +4 -4
  9. data/bin/trollolo +2 -2
  10. data/lib/backup.rb +21 -23
  11. data/lib/burndown_chart.rb +46 -49
  12. data/lib/burndown_data.rb +21 -21
  13. data/lib/card.rb +23 -32
  14. data/lib/checklist.rb +13 -1
  15. data/lib/cli.rb +105 -110
  16. data/lib/column.rb +11 -10
  17. data/lib/empty_column.rb +2 -2
  18. data/lib/scrum/backlog_mover.rb +3 -3
  19. data/lib/scrum/card_type_detection.rb +1 -1
  20. data/lib/scrum/creator.rb +7 -7
  21. data/lib/scrum/prioritizer.rb +1 -1
  22. data/lib/scrum/sprint_board.rb +4 -4
  23. data/lib/scrum/sprint_cleaner.rb +3 -3
  24. data/lib/scrum/sprint_planning_board.rb +2 -4
  25. data/lib/scrum_board.rb +3 -3
  26. data/lib/settings.rb +29 -27
  27. data/lib/trello_service.rb +1 -1
  28. data/lib/trello_wrapper.rb +9 -9
  29. data/lib/version.rb +1 -1
  30. data/spec/data/card.json +19 -0
  31. data/spec/data/trollolorc +3 -0
  32. data/spec/integration/command_line_spec.rb +14 -14
  33. data/spec/integration/create_burndown_spec.rb +25 -25
  34. data/spec/integration/integration_spec_helper.rb +1 -1
  35. data/spec/integration/wrapper/credentials_input_wrapper +7 -11
  36. data/spec/integration/wrapper/empty_config_trollolo_wrapper +2 -2
  37. data/spec/integration/wrapper/trollolo_wrapper +2 -2
  38. data/spec/unit/backup_spec.rb +14 -14
  39. data/spec/unit/burndown_chart_spec.rb +176 -184
  40. data/spec/unit/burndown_data_spec.rb +21 -23
  41. data/spec/unit/card_spec.rb +38 -24
  42. data/spec/unit/cli_spec.rb +57 -57
  43. data/spec/unit/empty_column_spec.rb +1 -1
  44. data/spec/unit/retrieve_data_spec.rb +13 -13
  45. data/spec/unit/scrum/backlog_mover_spec.rb +8 -8
  46. data/spec/unit/scrum/card_type_detection_spec.rb +12 -12
  47. data/spec/unit/scrum/creator_spec.rb +8 -8
  48. data/spec/unit/scrum/prioritizer_spec.rb +19 -19
  49. data/spec/unit/scrum/priority_name_spec.rb +16 -16
  50. data/spec/unit/scrum/sprint_board_spec.rb +3 -3
  51. data/spec/unit/scrum/sprint_cleaner_spec.rb +15 -15
  52. data/spec/unit/scrum/sprint_planning_board_spec.rb +2 -2
  53. data/spec/unit/scrum_board_spec.rb +56 -56
  54. data/spec/unit/settings_spec.rb +23 -23
  55. data/spec/unit/spec_helper.rb +3 -3
  56. data/spec/unit/support/test_data_operations.rb +4 -0
  57. data/spec/unit/support/update_webmock_data +9 -11
  58. data/spec/unit/support/vcr.rb +3 -3
  59. data/spec/unit/support/webmocks.rb +21 -12
  60. data/spec/unit/trello_wrapper_spec.rb +40 -29
  61. data/trollolo.gemspec +3 -3
  62. metadata +8 -5
@@ -15,21 +15,22 @@
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
17
  class Column
18
- def initialize(board_data, list_id)
18
+ def initialize(board_data, list_id, settings = nil)
19
19
  @board_data = board_data
20
- @list_data = @board_data["lists"].find{|l| l["id"] == list_id}
20
+ @settings = settings
21
+ @list_data = @board_data['lists'].find{|l| l['id'] == list_id}
21
22
  end
22
23
 
23
24
  def name
24
- @list_data["name"]
25
+ @list_data['name']
25
26
  end
26
27
 
27
28
  def estimated_cards
28
- cards.select{|x| x.estimated? }
29
+ cards.select(&:estimated?)
29
30
  end
30
31
 
31
32
  def sum
32
- estimated_cards.map{|x| x.story_points}.sum
33
+ estimated_cards.map(&:story_points).sum
33
34
  end
34
35
 
35
36
  def tasks
@@ -41,11 +42,11 @@ class Column
41
42
  end
42
43
 
43
44
  def extra_cards
44
- cards.select{|c| c.extra?}
45
+ cards.select(&:extra?)
45
46
  end
46
47
 
47
48
  def unplanned_cards
48
- cards.select{|c| c.unplanned?}
49
+ cards.select(&:unplanned?)
49
50
  end
50
51
 
51
52
  def committed_cards
@@ -53,13 +54,13 @@ class Column
53
54
  end
54
55
 
55
56
  def fast_lane_cards
56
- cards.select{|c| c.fast_lane?}
57
+ cards.select(&:fast_lane?)
57
58
  end
58
59
 
59
60
  def cards
60
61
  return @cards if @cards
61
62
 
62
- cards = @board_data["cards"].select{|c| c["idList"] == @list_data["id"]}
63
- @cards = cards.map{|c| Card.new(@board_data, c["id"])}
63
+ cards = @board_data['cards'].select{|c| c['idList'] == @list_data['id']}
64
+ @cards = cards.map{|c| Card.new(@board_data, c['id'], @settings)}
64
65
  end
65
66
  end
@@ -1,5 +1,5 @@
1
1
  class EmptyColumn < Column
2
- def initialize
3
- super({"lists" => [], "cards" => []}, nil)
2
+ def initialize(settings = nil)
3
+ super({'lists' => [], 'cards' => []}, nil, settings)
4
4
  end
5
5
  end
@@ -12,10 +12,10 @@ module Scrum
12
12
 
13
13
  def setup(planning_board_id, sprint_board_id)
14
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
15
+ raise "sprint board is missing #{@sprint_board.backlog_list_name} list" unless @sprint_board.backlog_list
16
16
 
17
17
  @planning_board = planning_board(planning_board_id)
18
- fail "backlog list not found on planning board" unless @planning_board.backlog_list
18
+ raise 'backlog list not found on planning board' unless @planning_board.backlog_list
19
19
 
20
20
  @waterline_card = @planning_board.waterline_card
21
21
  @seabed_card = @planning_board.seabed_card
@@ -27,7 +27,7 @@ module Scrum
27
27
  break
28
28
  elsif @waterline_card && card == @waterline_card
29
29
  @sprint_board.place_waterline(@waterline_card)
30
- puts "under the waterline"
30
+ puts 'under the waterline'
31
31
  else
32
32
  move_sprint_card(card) unless @planning_board.sticky?(card)
33
33
  end
@@ -1,7 +1,7 @@
1
1
  module Scrum
2
2
  module CardTypeDetection
3
3
  def sticky?(card)
4
- card.labels.any? { |l| l.name == @settings.label_names["sticky"] }
4
+ card.labels.any? { |l| l.name == @settings.label_names['sticky'] }
5
5
  end
6
6
 
7
7
  def waterline?(card)
@@ -13,17 +13,17 @@ module Scrum
13
13
  end
14
14
 
15
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"])
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
20
  create_labels(board.id)
21
21
  end
22
22
 
23
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"])
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
27
  create_labels(board.id)
28
28
  end
29
29
  end
@@ -4,7 +4,7 @@ module Scrum
4
4
 
5
5
  def prioritize(board_id, list_name = nil)
6
6
  @board = planning_board(board_id, list_name)
7
- fail "list named '#{@board.backlog_list_name}' not found on board" unless @board.backlog_list
7
+ raise "list named '#{@board.backlog_list_name}' not found on board" unless @board.backlog_list
8
8
  update_priorities
9
9
  end
10
10
 
@@ -14,7 +14,7 @@ module Scrum
14
14
  end
15
15
 
16
16
  def backlog_list_name
17
- @settings.list_names["sprint_backlog"]
17
+ @settings.list_names['sprint_backlog']
18
18
  end
19
19
 
20
20
  def doing_list
@@ -74,15 +74,15 @@ module Scrum
74
74
  end
75
75
 
76
76
  def waterline_label_name
77
- @settings.label_names["waterline"]
77
+ @settings.label_names['waterline']
78
78
  end
79
79
 
80
80
  def qa_list_name
81
- @settings.list_names["sprint_qa"]
81
+ @settings.list_names['sprint_qa']
82
82
  end
83
83
 
84
84
  def doing_list_name
85
- @settings.list_names["sprint_doing"]
85
+ @settings.list_names['sprint_doing']
86
86
  end
87
87
  end
88
88
  end
@@ -4,9 +4,9 @@ module Scrum
4
4
 
5
5
  def cleanup(board_id, target_board_id)
6
6
  @board = sprint_board(board_id)
7
- fail "backlog list '#{@board.backlog_list_name}' not found on sprint board" unless @board.backlog_list
7
+ raise "backlog list '#{@board.backlog_list_name}' not found on sprint board" unless @board.backlog_list
8
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
9
+ raise "ready list '#{@settings.scrum.list_names['planning_ready']}' not found on planning board" unless target_list
10
10
 
11
11
  gen_burndown
12
12
 
@@ -18,7 +18,7 @@ module Scrum
18
18
  private
19
19
 
20
20
  def target_list
21
- @target_list ||= @target_board.lists.find { |l| l.name == @settings.scrum.list_names["planning_ready"] }
21
+ @target_list ||= @target_board.lists.find { |l| l.name == @settings.scrum.list_names['planning_ready'] }
22
22
  end
23
23
 
24
24
  def waterline_label(card)
@@ -6,15 +6,13 @@ module Scrum
6
6
 
7
7
  def initialize(settings)
8
8
  @settings = settings
9
- @backlog_list_name = settings.list_names["planning_backlog"]
9
+ @backlog_list_name = settings.list_names['planning_backlog']
10
10
  end
11
11
 
12
12
  attr_accessor :backlog_list
13
13
 
14
14
  def setup(id, list_name = nil)
15
- if list_name
16
- @backlog_list_name = list_name
17
- end
15
+ @backlog_list_name = list_name if list_name
18
16
  @board, @backlog_list = TrelloService.find_list(id, @backlog_list_name)
19
17
  self
20
18
  end
@@ -3,13 +3,13 @@ class ScrumBoard
3
3
  class DoneColumnNotFoundError < StandardError; end
4
4
  class AcceptedColumnNotFoundError < StandardError; end
5
5
 
6
- def initialize(board_data, settings)
6
+ def initialize(board_data, settings = nil)
7
7
  @settings = settings
8
8
  @board_data = board_data
9
9
  end
10
10
 
11
11
  def columns
12
- @columns ||= @board_data["lists"].map{|x| Column.new(@board_data, x["id"])}
12
+ @columns ||= @board_data['lists'].map{|x| Column.new(@board_data, x['id'], @settings)}
13
13
  end
14
14
 
15
15
  def done_column
@@ -138,7 +138,7 @@ class ScrumBoard
138
138
  end
139
139
 
140
140
  def id
141
- @board_data["id"]
141
+ @board_data['id']
142
142
  end
143
143
 
144
144
  def cards
@@ -19,23 +19,25 @@ class Settings
19
19
 
20
20
  attr_accessor :developer_public_key, :member_token, :board_aliases, :verbose,
21
21
  :raw, :not_done_columns, :todo_column, :accepted_column_name_regex,
22
- :done_column_name_regex, :todo_column_name_regex, :scrum
22
+ :done_column_name_regex, :todo_column_name_regex, :scrum,
23
+ :no_task_checklists
23
24
 
24
- def initialize config_file_path
25
+ def initialize(config_file_path)
25
26
  @config_file_path = config_file_path
26
27
  if File.exists? config_file_path
27
28
  @config = YAML.load_file(config_file_path)
28
29
 
29
30
  if @config
30
- @developer_public_key = @config["developer_public_key"]
31
- @member_token = @config["member_token"]
32
- @board_aliases = @config["board_aliases"] || {}
33
- @scrum = OpenStruct.new(@config["scrum"] || scrum_defaults)
34
- @not_done_columns = @config["not_done_columns"].freeze || ["Sprint Backlog", "Doing"]
35
- @todo_column = @config["todo_column"].freeze
36
- @done_column_name_regex = @config["done_column_name_regex"].freeze || /\ADone/
37
- @accepted_column_name_regex = @config["accepted_column_name_regex"].freeze || /\AAccepted/
38
- @todo_column_name_regex = @config["todo_column_name_regex"].freeze || /\ATo Do\Z/
31
+ @developer_public_key = @config['developer_public_key']
32
+ @member_token = @config['member_token']
33
+ @board_aliases = @config['board_aliases'] || {}
34
+ @scrum = OpenStruct.new(@config['scrum'] || scrum_defaults)
35
+ @not_done_columns = @config['not_done_columns'].freeze || ['Sprint Backlog', 'Doing']
36
+ @no_task_checklists = @config['no_task_checklists'].freeze || ['Feedback']
37
+ @todo_column = @config['todo_column'].freeze
38
+ @done_column_name_regex = @config['done_column_name_regex'].freeze || /\ADone/
39
+ @accepted_column_name_regex = @config['accepted_column_name_regex'].freeze || /\AAccepted/
40
+ @todo_column_name_regex = @config['todo_column_name_regex'].freeze || /\ATo Do\Z/
39
41
  else
40
42
  raise "Couldn't read config data from '#{config_file_path}'"
41
43
  end
@@ -47,10 +49,10 @@ class Settings
47
49
 
48
50
  def save_config
49
51
  @config = {}
50
- @config["developer_public_key"] = @developer_public_key
51
- @config["member_token"] = @member_token
52
+ @config['developer_public_key'] = @developer_public_key
53
+ @config['member_token'] = @member_token
52
54
 
53
- File.open(@config_file_path, "w") do |f|
55
+ File.open(@config_file_path, 'w') do |f|
54
56
  f.write(@config.to_yaml)
55
57
  end
56
58
  end
@@ -63,21 +65,21 @@ class Settings
63
65
 
64
66
  def scrum_defaults
65
67
  {
66
- "board_names" => {
67
- "planning" => "Planning Board",
68
- "sprint" => "Sprint Board"
68
+ 'board_names' => {
69
+ 'planning' => 'Planning Board',
70
+ 'sprint' => 'Sprint Board'
69
71
  },
70
- "label_names" => {
71
- "sticky" => "Sticky",
72
- "waterline" => "Under waterline"
73
- },
74
- "list_names" => {
75
- "sprint_backlog" => "Sprint Backlog",
76
- "sprint_qa" => "QA",
77
- "sprint_doing" => "Doing",
78
- "planning_backlog" => "Backlog",
79
- "planning_ready" => "Ready for Estimation"
72
+ 'label_names' => {
73
+ 'sticky' => 'Sticky',
74
+ 'waterline' => 'Under waterline'
80
75
  },
76
+ 'list_names' => {
77
+ 'sprint_backlog' => 'Sprint Backlog',
78
+ 'sprint_qa' => 'QA',
79
+ 'sprint_doing' => 'Doing',
80
+ 'planning_backlog' => 'Backlog',
81
+ 'planning_ready' => 'Ready for Estimation'
82
+ }
81
83
  }.freeze
82
84
  end
83
85
  end
@@ -8,7 +8,7 @@ class TrelloService
8
8
 
9
9
  def self.find_list(board_id, name)
10
10
  board = Trello::Board.find(board_id)
11
- return board, board.lists.find { |l| l.name == name }
11
+ [board, board.lists.find { |l| l.name == name }]
12
12
  end
13
13
 
14
14
  protected
@@ -42,23 +42,23 @@ class TrelloWrapper < TrelloService
42
42
 
43
43
  def add_attachment(card_id, filename)
44
44
  card = Trello::Card.find(card_id)
45
- card.add_attachment(File.open(filename, "rb"))
45
+ card.add_attachment(File.open(filename, 'rb'))
46
46
  end
47
47
 
48
48
  def make_cover(card_id, image_name)
49
49
  attachment_id = attachment_id_by_name(card_id, image_name)
50
- raise("Error: The attachment with the name '#{image_name}' was not found") if !attachment_id
50
+ raise("Error: The attachment with the name '#{image_name}' was not found") unless attachment_id
51
+ make_cover_with_id(card_id, attachment_id)
52
+ end
53
+
54
+ def make_cover_with_id(card_id, attachment_id)
51
55
  client.put("/cards/#{card_id}/idAttachmentCover?value=#{attachment_id}")
52
56
  end
53
57
 
54
58
  def attachment_id_by_name(card_id, image_name)
55
59
  json = JSON.parse(client.get("/cards/#{card_id}/attachments?fields=name"))
56
- attachment = json.find{ |e| e["name"] == image_name }
57
- if attachment
58
- attachment["id"]
59
- else
60
- nil
61
- end
60
+ attachment = json.find{ |e| e['name'] == image_name }
61
+ attachment['id'] if attachment
62
62
  end
63
63
 
64
64
  def get_description(card_id)
@@ -79,7 +79,7 @@ class TrelloWrapper < TrelloService
79
79
  end
80
80
 
81
81
  def get_board(board_id)
82
- raise TrolloloError.new("Board id cannot be blank") if board_id.blank?
82
+ raise TrolloloError, 'Board id cannot be blank' if board_id.blank?
83
83
 
84
84
  client.get("/boards/#{board_id}?lists=open&cards=open&card_checklists=all")
85
85
  end
@@ -1,5 +1,5 @@
1
1
  module Trollolo
2
2
 
3
- VERSION = "0.1.1"
3
+ VERSION = '0.2.0'.freeze
4
4
 
5
5
  end
@@ -49,6 +49,25 @@
49
49
  "idChecklists": [
50
50
  "5319c04d592a9182153db831"
51
51
  ],
52
+ "checklists": [
53
+ { "id": "5319c052d86da6cb6fa2a9e0",
54
+ "name": "Tasks",
55
+ "checkItems": [
56
+ { "name": "Task 1", "state": "complete"},
57
+ { "name": "Task 2", "state": "incomplete"},
58
+ { "name": "Task 3", "state": "incomplete"}
59
+ ]
60
+ },
61
+ {
62
+ "id": "5319c0562fef3bc511c79279",
63
+ "name": "Definition of done",
64
+ "checkItems": [
65
+ { "name": "DoD 1", "state": "complete"},
66
+ { "name": "DoD 2", "state": "complete"},
67
+ { "name": "DoD 3", "state": "inmplete"}
68
+ ]
69
+ }
70
+ ],
52
71
  "idMembers": [
53
72
 
54
73
  ],
@@ -5,6 +5,9 @@ not_done_columns:
5
5
  - Doing
6
6
  - In review
7
7
  - Sprint Backlog
8
+ no_task_checklists:
9
+ - Definition of done
10
+ - Feedback
8
11
  scrum:
9
12
  board_names:
10
13
  planning: Planning Board
@@ -15,36 +15,36 @@ def credentials_input_wrapper
15
15
  File.expand_path('../wrapper/credentials_input_wrapper', __FILE__)
16
16
  end
17
17
 
18
- describe "command line" do
18
+ describe 'command line' do
19
19
 
20
- it "processes help option" do
21
- result = run_command(args: ["-h"])
20
+ it 'processes help option' do
21
+ result = run_command(args: ['-h'])
22
22
  expect(result).to exit_with_success(/Commands:/)
23
- expect(result.stdout).to match("trollolo help")
24
- expect(result.stdout).to match("Options:")
23
+ expect(result.stdout).to match('trollolo help')
24
+ expect(result.stdout).to match('Options:')
25
25
  end
26
26
 
27
- it "throws error on invalid command" do
28
- result = run_command(cmd: trollolo_cmd, args: ["invalid_command"])
27
+ it 'throws error on invalid command' do
28
+ result = run_command(cmd: trollolo_cmd, args: ['invalid_command'])
29
29
  expect(result).to exit_with_error(1, "Could not find command \"invalid_command\".\n")
30
30
  end
31
31
 
32
- it "asks for authorization data" do
33
- expect(run_command(cmd: credentials_input_wrapper, args: ["get-cards", "--board-id=myboardid"])).to exit_with_success("")
32
+ it 'asks for authorization data' do
33
+ expect(run_command(cmd: credentials_input_wrapper, args: ['get-cards', '--board-id=myboardid'])).to exit_with_success('')
34
34
  end
35
35
 
36
- describe "burndown chart" do
36
+ describe 'burndown chart' do
37
37
  use_given_filesystem
38
38
 
39
- it "inits burndown directory" do
39
+ it 'inits burndown directory' do
40
40
  path = given_directory
41
- result = run_command(cmd: trollolo_cmd, args: ["burndown-init", "-o", "#{path}", "--board-id=myboardid"])
41
+ result = run_command(cmd: trollolo_cmd, args: ['burndown-init', '-o', path.to_s, '--board-id=myboardid'])
42
42
  expect(result).to exit_with_success(/Preparing/)
43
43
  end
44
44
 
45
- it "fails, if burndown data is not found" do
45
+ it 'fails, if burndown data is not found' do
46
46
  path = given_directory
47
- result = run_command(cmd: trollolo_cmd, args: ["burndown", "-o", "#{path}"])
47
+ result = run_command(cmd: trollolo_cmd, args: ['burndown', '-o', path.to_s])
48
48
  expect(result).to exit_with_error(1, /burndown-data-01.yaml' not found/)
49
49
  end
50
50
  end