trollolo 0.0.3 → 0.0.4

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.travis.yml +5 -1
  4. data/CHANGELOG.md +29 -0
  5. data/Gemfile +7 -2
  6. data/README.md +19 -0
  7. data/bin/trollolo +1 -1
  8. data/lib/array.rb +6 -0
  9. data/lib/backup.rb +67 -0
  10. data/lib/burndown_chart.rb +96 -67
  11. data/lib/burndown_data.rb +62 -123
  12. data/lib/card.rb +74 -30
  13. data/lib/cli.rb +131 -9
  14. data/lib/column.rb +61 -0
  15. data/lib/result.rb +0 -0
  16. data/lib/scrum_board.rb +104 -0
  17. data/lib/settings.rb +9 -4
  18. data/lib/trello_wrapper.rb +62 -0
  19. data/lib/trollolo.rb +10 -7
  20. data/lib/version.rb +1 -1
  21. data/scripts/.gitignore +1 -0
  22. data/scripts/burndowndata.py +113 -0
  23. data/scripts/create_burndown.py +111 -146
  24. data/scripts/graph.py +116 -0
  25. data/scripts/plot.py +131 -0
  26. data/spec/data/board.json +63 -0
  27. data/spec/data/burndown-data.yaml +3 -0
  28. data/spec/data/burndown_dir/burndown-data-01.yaml +1 -1
  29. data/spec/data/burndown_dir/burndown-data-02.yaml +1 -1
  30. data/spec/data/card.json +61 -0
  31. data/spec/data/full-board.json +1626 -0
  32. data/spec/data/lists.json +25 -25
  33. data/spec/data/trollolorc +5 -0
  34. data/spec/{command_line_spec.rb → integration/command_line_spec.rb} +1 -4
  35. data/spec/integration/create_burndown_spec.rb +57 -0
  36. data/spec/integration/integration_spec_helper.rb +10 -0
  37. data/spec/integration/support/aruba_hook.rb +11 -0
  38. data/spec/integration/support/custom_matchers.rb +13 -0
  39. data/spec/{wrapper → integration/wrapper}/credentials_input_wrapper +2 -2
  40. data/spec/{wrapper → integration/wrapper}/empty_config_trollolo_wrapper +2 -2
  41. data/spec/integration/wrapper/trollolo_wrapper +10 -0
  42. data/spec/unit/backup_spec.rb +107 -0
  43. data/spec/unit/burndown_chart_spec.rb +396 -0
  44. data/spec/unit/burndown_data_spec.rb +118 -0
  45. data/spec/unit/card_spec.rb +79 -0
  46. data/spec/unit/cli_spec.rb +38 -0
  47. data/spec/unit/retrieve_data_spec.rb +54 -0
  48. data/spec/unit/scrum_board_spec.rb +18 -0
  49. data/spec/{settings_spec.rb → unit/settings_spec.rb} +1 -1
  50. data/spec/{spec_helper.rb → unit/spec_helper.rb} +4 -12
  51. data/spec/unit/support/test_data_operations.rb +7 -0
  52. data/spec/unit/support/update_webmock_data +17 -0
  53. data/spec/unit/support/webmocks.rb +52 -0
  54. data/spec/unit/trello_wrapper_spec.rb +47 -0
  55. data/trollolo.gemspec +10 -11
  56. metadata +54 -37
  57. data/lib/trello.rb +0 -66
  58. data/spec/burndown_chart_spec.rb +0 -307
  59. data/spec/burndown_data_spec.rb +0 -125
  60. data/spec/card_spec.rb +0 -15
  61. data/spec/cli_spec.rb +0 -18
  62. data/spec/data/cards.json +0 -1002
  63. data/spec/trello_spec.rb +0 -32
  64. data/spec/wrapper/trollolo_wrapper +0 -11
@@ -0,0 +1,118 @@
1
+ require_relative 'spec_helper'
2
+
3
+ include GivenFilesystemSpecHelpers
4
+
5
+ describe BurndownData do
6
+
7
+ before(:each) do
8
+ @burndown = BurndownData.new(dummy_settings)
9
+ @burndown.board_id = "53186e8391ef8671265eba9d"
10
+ full_board_mock
11
+ end
12
+
13
+ describe BurndownData::Result do
14
+ it "calculates total" do
15
+ r = described_class.new
16
+ r.open = 7
17
+ r.done = 4
18
+
19
+ expect(r.total).to eq 11
20
+ end
21
+ end
22
+
23
+ describe "setters" do
24
+ it "sets open story points" do
25
+ @burndown.story_points.open = 13
26
+ expect(@burndown.story_points.open).to eq 13
27
+ end
28
+
29
+ it "sets open tasks" do
30
+ @burndown.tasks.open = 42
31
+ expect(@burndown.tasks.open).to eq 42
32
+ end
33
+ end
34
+
35
+ describe "#fetch" do
36
+
37
+ before do
38
+ @burndown.fetch
39
+ end
40
+
41
+ it "returns story points" do
42
+ expect( @burndown.story_points.total ).to eq 16
43
+ expect( @burndown.story_points.open ).to eq 13
44
+ expect( @burndown.story_points.done ).to eq 3
45
+ end
46
+
47
+ it "returns extra story points" do
48
+ expect( @burndown.extra_story_points.total ).to eq 8
49
+ expect( @burndown.extra_story_points.open ).to eq 8
50
+ expect( @burndown.extra_story_points.done ).to eq 0
51
+ end
52
+
53
+ it "returns tasks" do
54
+ expect( @burndown.tasks.total ).to eq 13
55
+ expect( @burndown.tasks.open ).to eq 9
56
+ expect( @burndown.tasks.done ).to eq 4
57
+ end
58
+
59
+ it "returns extra tasks" do
60
+ expect( @burndown.extra_tasks.total ).to eq 1
61
+ expect( @burndown.extra_tasks.open ).to eq 1
62
+ expect( @burndown.extra_tasks.done ).to eq 0
63
+ end
64
+
65
+ it "returns meta data" do
66
+ expect( @burndown.meta ).to eq({
67
+ "sprint" => 10,
68
+ "total_days" => 18,
69
+ "weekend_lines" => [1.5, 6.5, 11.5, 16.5]
70
+ })
71
+ end
72
+
73
+ it "saves date and time" do
74
+ expected_date_time = DateTime.parse("2015-01-12T13:57:16+01:00")
75
+ allow(DateTime).to receive(:now).and_return(expected_date_time)
76
+ @burndown.fetch
77
+ expect(@burndown.date_time).to eq(expected_date_time)
78
+ end
79
+ end
80
+
81
+ describe '#to_hash' do
82
+
83
+ it 'converts to hash' do
84
+ @burndown.story_points.open = 1
85
+ @burndown.story_points.done = 2
86
+ @burndown.tasks.open = 3
87
+ @burndown.tasks.done = 4
88
+ @burndown.extra_story_points.open = 5
89
+ @burndown.extra_story_points.done = 6
90
+ @burndown.extra_tasks.open = 7
91
+ @burndown.extra_tasks.done = 8
92
+ @burndown.date_time = DateTime.parse('20150115')
93
+
94
+ expected_hash = {
95
+ 'date' => '2015-01-15',
96
+ 'updated_at' => '2015-01-15T00:00:00+00:00',
97
+ 'story_points' => {
98
+ 'total' => 3,
99
+ 'open' => 1
100
+ },
101
+ 'tasks' => {
102
+ 'total' => 7,
103
+ 'open' => 3
104
+ },
105
+ 'story_points_extra' => {
106
+ 'done' => 6
107
+ },
108
+ 'tasks_extra' => {
109
+ 'done' => 8
110
+ }
111
+ }
112
+
113
+ expect(@burndown.to_hash).to eq(expected_hash)
114
+ end
115
+
116
+ end
117
+
118
+ end
@@ -0,0 +1,79 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe Card do
4
+
5
+ describe "parses name" do
6
+ before(:each) do
7
+ allow_any_instance_of(Card).to receive(:init_data)
8
+ @card = Card.new(double, double)
9
+ end
10
+
11
+ it "extracts single digit story point value from card name" do
12
+ allow(@card).to receive(:name).and_return("(3) P1: Refactor cards")
13
+ expect(@card.story_points).to eq(3)
14
+ end
15
+
16
+ it "extracts double digit story point value from card name" do
17
+ allow(@card).to receive(:name).and_return "(13) P1: Refactor cards"
18
+ expect(@card.story_points).to eq(13)
19
+ end
20
+
21
+ it "extracts fractional story point value from card name" do
22
+ allow(@card).to receive(:name).and_return "(0.5) P1: Refactor cards"
23
+ expect(@card.story_points).to eq(0.5)
24
+ end
25
+
26
+ it "extracts story points when value is not at beginning of card name" do
27
+ allow(@card).to receive(:name).and_return "P01: (3) Refactor cards"
28
+ expect(@card.story_points).to eq(3)
29
+ end
30
+ end
31
+
32
+ describe "#parse_yaml_from_description" do
33
+ it "parses description only having YAML" do
34
+ description = <<EOT
35
+ ```yaml
36
+ total_days: 18
37
+ weekend_lines:
38
+ - 1.5
39
+ - 6.5
40
+ ```
41
+ EOT
42
+ meta = Card.parse_yaml_from_description(description)
43
+ expect(meta["total_days"]).to eq(18)
44
+ expect(meta["weekend_lines"]).to eq([1.5, 6.5])
45
+ end
46
+
47
+ it "parses description only having unmarked YAML" do
48
+ description = <<EOT
49
+ ```
50
+ total_days: 18
51
+ weekend_lines:
52
+ - 1.5
53
+ - 6.5
54
+ ```
55
+ EOT
56
+ meta = Card.parse_yaml_from_description(description)
57
+ expect(meta["total_days"]).to eq(18)
58
+ expect(meta["weekend_lines"]).to eq([1.5, 6.5])
59
+ end
60
+
61
+ it "parses description having YAML and text" do
62
+ description = <<EOT
63
+ This is some text
64
+
65
+ ```yaml
66
+ total_days: 18
67
+ weekend_lines:
68
+ - 1.5
69
+ - 6.5
70
+ ```
71
+
72
+ And more text.
73
+ EOT
74
+ meta = Card.parse_yaml_from_description(description)
75
+ expect(meta["total_days"]).to eq(18)
76
+ expect(meta["weekend_lines"]).to eq([1.5, 6.5])
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,38 @@
1
+ require_relative 'spec_helper'
2
+
3
+ include GivenFilesystemSpecHelpers
4
+
5
+ describe Cli do
6
+
7
+ use_given_filesystem
8
+
9
+ before(:each) do
10
+ Cli.settings = dummy_settings
11
+ @cli = Cli.new
12
+
13
+ allow(STDOUT).to receive(:puts)
14
+ end
15
+
16
+ it "fetches burndown data" do
17
+ expect_any_instance_of(BurndownData).to receive(:fetch)
18
+
19
+ @cli.fetch_burndown_data
20
+ end
21
+
22
+ it "fetches burndown data from board-list" do
23
+ full_board_mock
24
+ dir = given_directory
25
+ @cli.options = {"board-list" => "spec/data/board-list.yaml",
26
+ "output" => dir}
27
+ @cli.burndowns
28
+ expect(File.exist?(File.join(dir,"orange/burndown-data-01.yaml")))
29
+ expect(File.exist?(File.join(dir,"blue/burndown-data-01.yaml")))
30
+ end
31
+
32
+ it "backups board" do
33
+ expect_any_instance_of(Backup).to receive(:backup)
34
+ @cli.options = {"board-id" => "1234"}
35
+ @cli.backup
36
+ end
37
+
38
+ end
@@ -0,0 +1,54 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe "retrieve data through Trello API" do
4
+ before(:each) do
5
+ full_board_mock
6
+ trello_wrapper = TrelloWrapper.new(dummy_settings)
7
+ @board = trello_wrapper.board("53186e8391ef8671265eba9d")
8
+ end
9
+
10
+ describe "board" do
11
+ it "gets id" do
12
+ expect(@board.id).to eq("53186e8391ef8671265eba9d")
13
+ end
14
+
15
+ it "gets columns" do
16
+ columns = @board.columns
17
+ expect(columns.count).to eq(6)
18
+ expect(columns[0].name).to eq("Sprint Backlog")
19
+ end
20
+
21
+ it "gets cards" do
22
+ cards = @board.columns[0].cards
23
+ expect(cards.count).to eq(6)
24
+ expect(cards[0].name).to eq("Sprint 3")
25
+ end
26
+
27
+ it "gets checklist item counts" do
28
+ card = @board.columns[1].cards[0]
29
+ expect(card.tasks).to eq(2)
30
+ expect(card.done_tasks).to eq(1)
31
+ end
32
+
33
+ it "gets card labels" do
34
+ card = @board.columns[0].cards[5]
35
+ expect(card.card_labels.count).to eq(1)
36
+ expect(card.card_labels[0]["name"]).to eq("Under waterline")
37
+ end
38
+
39
+ it "gets card description" do
40
+ card = @board.columns[2].cards[1]
41
+ expected_desc = <<EOT
42
+ ```yaml
43
+ total_days: 18
44
+ weekend_lines:
45
+ - 1.5
46
+ - 6.5
47
+ - 11.5
48
+ - 16.5
49
+ ```
50
+ EOT
51
+ expect(card.desc).to eq(expected_desc.chomp)
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,18 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe ScrumBoard do
4
+ describe '#done_column' do
5
+ before(:each) do
6
+ @settings = dummy_settings
7
+
8
+ board_data = JSON.parse(load_test_file("full-board.json"))
9
+ @scrum_board = ScrumBoard.new(board_data, @settings)
10
+ end
11
+
12
+ it 'raises error when done column cannot be found' do
13
+ @settings.done_column_name_regex = /thiscolumndoesntexist/
14
+
15
+ expect{@scrum_board.done_column}.to raise_error ScrumBoard::DoneColumnNotFoundError
16
+ end
17
+ end
18
+ end
@@ -6,7 +6,7 @@ describe Settings do
6
6
 
7
7
  context "given config file" do
8
8
  before(:each) do
9
- @settings = Settings.new( File.expand_path('../data/trollolorc',__FILE__) )
9
+ @settings = Settings.new( File.expand_path('../../data/trollolorc',__FILE__) )
10
10
  end
11
11
 
12
12
  it "is not verbose by default" do
@@ -1,23 +1,15 @@
1
1
  require "codeclimate-test-reporter"
2
2
  CodeClimate::TestReporter.start
3
-
4
- require_relative '../lib/trollolo'
5
-
3
+ require_relative '../../lib/trollolo'
6
4
  require 'given_filesystem/spec_helpers'
7
5
  require 'webmock/rspec'
8
-
6
+ require 'byebug'
9
7
  WebMock.disable_net_connect!(:allow => "codeclimate.com")
10
8
 
11
- bin_path = File.expand_path( "../../bin/", __FILE__ )
9
+ bin_path = File.expand_path( "../../../bin/", __FILE__ )
12
10
 
13
11
  if ENV['PATH'] !~ /#{bin_path}/
14
12
  ENV['PATH'] = bin_path + File::PATH_SEPARATOR + ENV['PATH']
15
13
  end
16
14
 
17
- def load_test_file filename
18
- File.read(File.expand_path('../data/' + filename,__FILE__))
19
- end
20
-
21
- def dummy_settings
22
- Settings.new( File.expand_path('../data/trollolorc',__FILE__) )
23
- end
15
+ Dir.glob(::File.expand_path('../support/*.rb', __FILE__)).each { |f| require_relative f }
@@ -0,0 +1,7 @@
1
+ def load_test_file(filename)
2
+ File.read(File.expand_path('../../../data/' + filename, __FILE__))
3
+ end
4
+
5
+ def dummy_settings
6
+ Settings.new(File.expand_path('../../../data/trollolorc', __FILE__))
7
+ end
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative "webmocks"
4
+
5
+ trollolo_bin = File.expand_path("../../../bin/trollolo", __FILE__)
6
+ spec_data_dir = File.expand_path("../../data", __FILE__)
7
+
8
+ STDERR.puts "Updating web mock data"
9
+
10
+ webmock_mapping.each do |mapping|
11
+ url = mapping[:path] + parameters_as_string(mapping)
12
+ file = mapping[:file]
13
+
14
+ cmd = "#{trollolo_bin} get-raw '#{url}' >#{spec_data_dir}/#{file}"
15
+ puts cmd
16
+ system cmd
17
+ end
@@ -0,0 +1,52 @@
1
+ def webmock_mapping
2
+ [
3
+ {
4
+ path: 'boards/53186e8391ef8671265eba9d',
5
+ file: 'board.json'
6
+ },
7
+ {
8
+ path: 'boards/53186e8391ef8671265eba9d/lists',
9
+ parameters: {
10
+ "filter" => "open"
11
+ },
12
+ file: 'lists.json'
13
+ },
14
+ {
15
+ path: 'boards/53186e8391ef8671265eba9d',
16
+ parameters: {
17
+ "cards" => "open",
18
+ "lists" => "open",
19
+ "card_checklists" => "all"
20
+ },
21
+ file: 'full-board.json'
22
+ }
23
+ ]
24
+ end
25
+
26
+ def parameters_as_string(mapping, parameters = nil)
27
+ parameters ||= []
28
+ if mapping[:parameters]
29
+ mapping[:parameters].each do |key, value|
30
+ parameters.push("#{key}=#{value}")
31
+ end
32
+ end
33
+ if !parameters.empty?
34
+ parameters_string = "?" + parameters.join("&")
35
+ else
36
+ parameters_string = ""
37
+ end
38
+ parameters_string
39
+ end
40
+
41
+ def mapping_url(mapping, parameters = nil)
42
+ url = "https://api.trello.com/1/" + mapping[:path]
43
+ url += parameters_as_string(mapping, parameters)
44
+ end
45
+
46
+ def full_board_mock
47
+ webmock_mapping.each do |mapping|
48
+ url = mapping_url(mapping, [ "key=mykey", "token=mytoken" ])
49
+ stub_request(:get, url)
50
+ .to_return(:status => 200, :body => load_test_file(mapping[:file]))
51
+ end
52
+ end
@@ -0,0 +1,47 @@
1
+ require_relative 'spec_helper'
2
+
3
+ describe TrelloWrapper do
4
+
5
+ let!(:settings){ double('settings', developer_public_key: "mykey", member_token: "mytoken") }
6
+ subject { described_class.new(settings) }
7
+
8
+ before do
9
+ stub_request(:get, "https://api.trello.com/1/boards/myboard?cards=open&key=mykey&lists=open&token=mytoken").
10
+ to_return(:status => 200, :body => load_test_file("board.json"), :headers => {})
11
+ full_board_mock
12
+ end
13
+
14
+ describe '.new' do
15
+ it 'populates settings' do
16
+ expect(subject.instance_variable_get(:@settings)).to be settings
17
+ end
18
+
19
+ it 'init trello configuration' do
20
+ expect_any_instance_of(described_class).to receive(:init_trello)
21
+ described_class.new(settings)
22
+ end
23
+ end
24
+
25
+ describe '#board' do
26
+ before(:each) do
27
+ expect(subject).to receive(:retrieve_board_data).with('myboard').and_return(:board)
28
+ end
29
+
30
+ it 'finds board via Trello' do
31
+ subject.board("myboard")
32
+ end
33
+
34
+ it 'instantiate ScrumBoard with trello board and settings' do
35
+ expect(ScrumBoard).to receive(:new).with(:board, subject.instance_variable_get(:@settings))
36
+ subject.board("myboard")
37
+ end
38
+
39
+ it 'returns instance of a ScrumBoard' do
40
+ expect(subject.board("myboard")).to be_instance_of(ScrumBoard)
41
+ end
42
+
43
+ it 'memoize board object' do
44
+ expect(subject.board("myboard")).to be subject.board("myboard")
45
+ end
46
+ end
47
+ end