trollolo 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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