trollolo 0.0.3 → 0.0.4

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