pivotal-to-trello 0.1.2 → 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.
- checksums.yaml +4 -4
- data/.rubocop.yml +102 -0
- data/Dockerfile +24 -0
- data/Gemfile +5 -4
- data/README.markdown +11 -2
- data/Rakefile +10 -10
- data/VERSION +1 -1
- data/lib/pivotal-to-trello.rb +1 -1
- data/lib/pivotal_to_trello/core.rb +91 -83
- data/lib/pivotal_to_trello/pivotal_wrapper.rb +10 -11
- data/lib/pivotal_to_trello/trello_wrapper.rb +44 -25
- data/pivotal-to-trello.gemspec +22 -17
- data/spec/pivotal_to_trello/core_spec.rb +44 -44
- data/spec/pivotal_to_trello/pivotal_wrapper_spec.rb +12 -10
- data/spec/pivotal_to_trello/trello_wrapper_spec.rb +75 -53
- data/spec/spec_helper.rb +35 -34
- metadata +35 -17
@@ -3,32 +3,31 @@ require 'pivotal-tracker'
|
|
3
3
|
module PivotalToTrello
|
4
4
|
# Interface to the Pivotal Tracker API.
|
5
5
|
class PivotalWrapper
|
6
|
-
|
7
6
|
# Constructor
|
8
7
|
def initialize(token)
|
9
8
|
::PivotalTracker::Client.token = token
|
9
|
+
::PivotalTracker::Client.use_ssl = true
|
10
10
|
end
|
11
11
|
|
12
12
|
# Returns a hash of available projects keyed on project ID.
|
13
13
|
def project_choices
|
14
|
-
::PivotalTracker::Project.all.
|
14
|
+
::PivotalTracker::Project.all.each_with_object({}) do |project, hash|
|
15
15
|
hash[project.id] = project.name
|
16
|
-
|
16
|
+
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
20
|
# Returns all stories for the given project.
|
21
21
|
def stories(project_id)
|
22
|
-
project(project_id).stories.all
|
22
|
+
project(project_id).stories.all.sort_by(&:created_at)
|
23
23
|
end
|
24
24
|
|
25
25
|
private
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
# Returns the Pivotal project that we're exporting.
|
28
|
+
def project(project_id)
|
29
|
+
@projects ||= {}
|
30
|
+
@projects[project_id] ||= ::PivotalTracker::Project.find(project_id)
|
31
|
+
end
|
33
32
|
end
|
34
|
-
end
|
33
|
+
end
|
@@ -3,7 +3,6 @@ require 'trello'
|
|
3
3
|
module PivotalToTrello
|
4
4
|
# Interface to the Trello API.
|
5
5
|
class TrelloWrapper
|
6
|
-
|
7
6
|
# Constructor
|
8
7
|
def initialize(key, token)
|
9
8
|
Trello.configure do |config|
|
@@ -18,15 +17,13 @@ module PivotalToTrello
|
|
18
17
|
card ||= begin
|
19
18
|
puts "Creating a card for #{pivotal_story.story_type} '#{pivotal_story.name}'."
|
20
19
|
card = Trello::Card.create(
|
21
|
-
:
|
22
|
-
:
|
23
|
-
:
|
20
|
+
name: pivotal_story.name,
|
21
|
+
desc: pivotal_story.description,
|
22
|
+
list_id: list_id,
|
24
23
|
)
|
25
24
|
|
26
|
-
pivotal_story
|
27
|
-
|
28
|
-
end
|
29
|
-
|
25
|
+
create_notes(card, pivotal_story)
|
26
|
+
create_tasks(card, pivotal_story)
|
30
27
|
card
|
31
28
|
end
|
32
29
|
|
@@ -38,9 +35,8 @@ module PivotalToTrello
|
|
38
35
|
|
39
36
|
# Returns a hash of available boards, keyed on board ID.
|
40
37
|
def board_choices
|
41
|
-
Trello::Board.all.
|
38
|
+
Trello::Board.all.each_with_object({}) do |board, hash|
|
42
39
|
hash[board.id] = board.name
|
43
|
-
hash
|
44
40
|
end
|
45
41
|
end
|
46
42
|
|
@@ -49,9 +45,8 @@ module PivotalToTrello
|
|
49
45
|
# Cache the list to improve performance.
|
50
46
|
@lists ||= {}
|
51
47
|
@lists[board_id] ||= begin
|
52
|
-
choices = Trello::Board.find(board_id).lists.
|
48
|
+
choices = Trello::Board.find(board_id).lists.each_with_object({}) do |list, hash|
|
53
49
|
hash[list.id] = list.name
|
54
|
-
hash
|
55
50
|
end
|
56
51
|
choices = Hash[choices.sort_by { |_, v| v }]
|
57
52
|
choices[false] = "[don't import these stories]"
|
@@ -64,17 +59,21 @@ module PivotalToTrello
|
|
64
59
|
# Returns a list of all cards in the given list, keyed on name.
|
65
60
|
def cards_for_list(list_id)
|
66
61
|
@cards ||= {}
|
67
|
-
@cards[list_id] ||= Trello::List.find(list_id).cards.
|
62
|
+
@cards[list_id] ||= Trello::List.find(list_id).cards.each_with_object({}) do |card, hash|
|
68
63
|
hash[card_hash(card.name, card.desc)] = card
|
69
|
-
hash
|
70
64
|
end
|
71
65
|
|
72
66
|
@cards[list_id]
|
73
67
|
end
|
74
68
|
|
75
69
|
# Adds the given label to the card.
|
76
|
-
def add_label(card,
|
77
|
-
|
70
|
+
def add_label(card, label_name, label_color)
|
71
|
+
@labels ||= {}
|
72
|
+
@labels[card.board_id] ||= Trello::Board.find(card.board_id).labels
|
73
|
+
label = @labels[card.board_id].find { |l| l.name == label_name && l.color == label_color }
|
74
|
+
label ||= Trello::Label.create(name: label_name, board_id: card.board_id, color: label_color)
|
75
|
+
|
76
|
+
card.add_label(label) unless card.labels.detect { |l| l.id == label.id }
|
78
77
|
end
|
79
78
|
|
80
79
|
# Returns a list of colors that can be used to label cards.
|
@@ -86,22 +85,42 @@ module PivotalToTrello
|
|
86
85
|
'purple' => 'Purple',
|
87
86
|
'red' => 'Red',
|
88
87
|
'yellow' => 'Yellow',
|
89
|
-
false => '[none]'
|
88
|
+
false => '[none]',
|
90
89
|
}
|
91
90
|
end
|
92
91
|
|
93
92
|
private
|
94
93
|
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
# Copies notes from the pivotal story to the card.
|
95
|
+
def create_notes(card, pivotal_story)
|
96
|
+
pivotal_story.notes.all.each do |note|
|
97
|
+
card.add_comment("[#{note.author}] #{note.text.to_s.strip}") unless note.text.to_s.strip.empty?
|
98
98
|
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Copies notes from the pivotal story to the card.
|
102
|
+
def create_tasks(card, pivotal_story)
|
103
|
+
tasks = pivotal_story.tasks.all
|
104
|
+
return if tasks.empty?
|
99
105
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
106
|
+
checklist = Trello::Checklist.create(name: 'Tasks', card_id: card.id)
|
107
|
+
card.add_checklist(checklist)
|
108
|
+
|
109
|
+
tasks.each do |task|
|
110
|
+
puts " - Creating task '#{task.description}'"
|
111
|
+
checklist.add_item(task.description, task.complete)
|
104
112
|
end
|
113
|
+
end
|
105
114
|
|
115
|
+
# Returns a unique identifier for this list/name/description combination.
|
116
|
+
def card_hash(name, description)
|
117
|
+
Digest::SHA1.hexdigest("#{name}_#{description}")
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns a card with the given name and description if it exists in the given list, nil otherwise.
|
121
|
+
def get_card(list_id, name, description)
|
122
|
+
key = card_hash(name, description)
|
123
|
+
cards_for_list(list_id)[key] unless cards_for_list(list_id)[key].nil?
|
124
|
+
end
|
106
125
|
end
|
107
|
-
end
|
126
|
+
end
|
data/pivotal-to-trello.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: pivotal-to-trello 0.
|
5
|
+
# stub: pivotal-to-trello 0.2.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "pivotal-to-trello"
|
9
|
-
s.version = "0.
|
9
|
+
s.version = "0.2.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
|
-
s.authors = ["Dave Perrett"]
|
14
|
-
s.date = "
|
13
|
+
s.authors = ["Dave Perrett", "Erik Frederiksen", "Kenneth Kalmer"]
|
14
|
+
s.date = "2017-08-10"
|
15
15
|
s.description = "Pulls stories from Pivotal Tracker and imports them into Trello"
|
16
16
|
s.email = "hello@daveperrett.com"
|
17
17
|
s.executables = ["pivotal-to-trello"]
|
@@ -21,6 +21,8 @@ Gem::Specification.new do |s|
|
|
21
21
|
]
|
22
22
|
s.files = [
|
23
23
|
".document",
|
24
|
+
".rubocop.yml",
|
25
|
+
"Dockerfile",
|
24
26
|
"Gemfile",
|
25
27
|
"LICENSE.txt",
|
26
28
|
"README.markdown",
|
@@ -40,34 +42,37 @@ Gem::Specification.new do |s|
|
|
40
42
|
]
|
41
43
|
s.homepage = "http://github.com/recurser/pivotal-to-trello"
|
42
44
|
s.licenses = ["MIT"]
|
43
|
-
s.rubygems_version = "2.
|
45
|
+
s.rubygems_version = "2.4.5"
|
44
46
|
s.summary = "Pivotal Tracker to Trello exporter"
|
45
47
|
|
46
48
|
if s.respond_to? :specification_version then
|
47
49
|
s.specification_version = 4
|
48
50
|
|
49
51
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
-
s.add_runtime_dependency(%q<highline>, ["
|
51
|
-
s.add_runtime_dependency(%q<ruby-trello>, ["
|
52
|
-
s.add_runtime_dependency(%q<pivotal-tracker>, ["
|
52
|
+
s.add_runtime_dependency(%q<highline>, ["~> 1.7.8"])
|
53
|
+
s.add_runtime_dependency(%q<ruby-trello>, ["~> 2.0.0"])
|
54
|
+
s.add_runtime_dependency(%q<pivotal-tracker>, ["~> 0.5.13"])
|
53
55
|
s.add_development_dependency(%q<rspec>, [">= 2.14.1"])
|
54
56
|
s.add_development_dependency(%q<rdoc>, [">= 4.1.1"])
|
55
|
-
s.add_development_dependency(%q<jeweler>, [">= 2.
|
57
|
+
s.add_development_dependency(%q<jeweler>, [">= 2.3.7"])
|
58
|
+
s.add_development_dependency(%q<rubocop>, [">= 0.49.1"])
|
56
59
|
else
|
57
|
-
s.add_dependency(%q<highline>, ["
|
58
|
-
s.add_dependency(%q<ruby-trello>, ["
|
59
|
-
s.add_dependency(%q<pivotal-tracker>, ["
|
60
|
+
s.add_dependency(%q<highline>, ["~> 1.7.8"])
|
61
|
+
s.add_dependency(%q<ruby-trello>, ["~> 2.0.0"])
|
62
|
+
s.add_dependency(%q<pivotal-tracker>, ["~> 0.5.13"])
|
60
63
|
s.add_dependency(%q<rspec>, [">= 2.14.1"])
|
61
64
|
s.add_dependency(%q<rdoc>, [">= 4.1.1"])
|
62
|
-
s.add_dependency(%q<jeweler>, [">= 2.
|
65
|
+
s.add_dependency(%q<jeweler>, [">= 2.3.7"])
|
66
|
+
s.add_dependency(%q<rubocop>, [">= 0.49.1"])
|
63
67
|
end
|
64
68
|
else
|
65
|
-
s.add_dependency(%q<highline>, ["
|
66
|
-
s.add_dependency(%q<ruby-trello>, ["
|
67
|
-
s.add_dependency(%q<pivotal-tracker>, ["
|
69
|
+
s.add_dependency(%q<highline>, ["~> 1.7.8"])
|
70
|
+
s.add_dependency(%q<ruby-trello>, ["~> 2.0.0"])
|
71
|
+
s.add_dependency(%q<pivotal-tracker>, ["~> 0.5.13"])
|
68
72
|
s.add_dependency(%q<rspec>, [">= 2.14.1"])
|
69
73
|
s.add_dependency(%q<rdoc>, [">= 4.1.1"])
|
70
|
-
s.add_dependency(%q<jeweler>, [">= 2.
|
74
|
+
s.add_dependency(%q<jeweler>, [">= 2.3.7"])
|
75
|
+
s.add_dependency(%q<rubocop>, [">= 0.49.1"])
|
71
76
|
end
|
72
77
|
end
|
73
78
|
|
@@ -6,32 +6,32 @@ describe 'Core' do
|
|
6
6
|
let(:trello) { mock_trello_wrapper }
|
7
7
|
|
8
8
|
before(:each) do
|
9
|
-
IO.
|
10
|
-
core.
|
11
|
-
core.
|
12
|
-
|
13
|
-
core.
|
14
|
-
core.
|
15
|
-
core.
|
16
|
-
core.
|
17
|
-
core.
|
18
|
-
core.
|
19
|
-
core.
|
20
|
-
core.
|
21
|
-
core.
|
22
|
-
core.
|
23
|
-
core.
|
24
|
-
core.
|
25
|
-
core.
|
26
|
-
core.
|
27
|
-
core.
|
28
|
-
core.
|
9
|
+
allow_any_instance_of(IO).to receive(:puts)
|
10
|
+
allow(core).to receive_messages(pivotal: pivotal)
|
11
|
+
allow(core).to receive_messages(trello: trello)
|
12
|
+
|
13
|
+
allow(core).to receive(:prompt_selection).with('Which Pivotal project would you like to export?', pivotal.project_choices).and_return('pivotal_project_id')
|
14
|
+
allow(core).to receive(:prompt_selection).with('Which Trello board would you like to import into?', trello.board_choices).and_return('trello_board_id')
|
15
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'icebox' stories into?", trello.list_choices).and_return('icebox_list_id')
|
16
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'current' stories into?", trello.list_choices).and_return('current_list_id')
|
17
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'finished' stories into?", trello.list_choices).and_return('finished_list_id')
|
18
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'delivered' stories into?", trello.list_choices).and_return('delivered_list_id')
|
19
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'accepted' stories into?", trello.list_choices).and_return('accepted_list_id')
|
20
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'rejected' stories into?", trello.list_choices).and_return('rejected_list_id')
|
21
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'backlog' bugs into?", trello.list_choices).and_return('bug_list_id')
|
22
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'backlog' chores into?", trello.list_choices).and_return('chore_list_id')
|
23
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'backlog' features into?", trello.list_choices).and_return('feature_list_id')
|
24
|
+
allow(core).to receive(:prompt_selection).with("Which Trello list would you like to put 'backlog' releases into?", trello.list_choices).and_return('release_list_id')
|
25
|
+
allow(core).to receive(:prompt_selection).with('What color would you like to label bugs with?', trello.label_choices).and_return('bug_label')
|
26
|
+
allow(core).to receive(:prompt_selection).with('What color would you like to label features with?', trello.label_choices).and_return('feature_label')
|
27
|
+
allow(core).to receive(:prompt_selection).with('What color would you like to label chores with?', trello.label_choices).and_return('chore_label')
|
28
|
+
allow(core).to receive(:prompt_selection).with('What color would you like to label releases with?', trello.label_choices).and_return('release_label')
|
29
29
|
end
|
30
30
|
|
31
31
|
context '#import!' do
|
32
32
|
it 'prompts the user for details' do
|
33
33
|
core.import!
|
34
|
-
core.options.
|
34
|
+
expect(core.options).to eq(mock_options)
|
35
35
|
end
|
36
36
|
|
37
37
|
describe 'story handling' do
|
@@ -39,68 +39,68 @@ describe 'Core' do
|
|
39
39
|
let(:story) { mock_pivotal_story }
|
40
40
|
|
41
41
|
before(:each) do
|
42
|
-
pivotal.
|
43
|
-
trello.
|
42
|
+
expect(pivotal).to receive(:stories).and_return([story])
|
43
|
+
allow(trello).to receive_messages(add_label: true, create_card: card)
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'handles accepted stories' do
|
47
|
-
story.
|
48
|
-
trello.
|
47
|
+
allow(story).to receive_messages(current_state: 'accepted')
|
48
|
+
expect(trello).to receive(:create_card).with(core.options.accepted_list_id, story).and_return(card)
|
49
49
|
core.import!
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'handles rejected stories' do
|
53
|
-
story.
|
54
|
-
trello.
|
53
|
+
allow(story).to receive_messages(current_state: 'rejected')
|
54
|
+
expect(trello).to receive(:create_card).with(core.options.rejected_list_id, story).and_return(card)
|
55
55
|
core.import!
|
56
56
|
end
|
57
57
|
|
58
58
|
it 'handles finished stories' do
|
59
|
-
story.
|
60
|
-
trello.
|
59
|
+
allow(story).to receive_messages(current_state: 'finished')
|
60
|
+
expect(trello).to receive(:create_card).with(core.options.finished_list_id, story).and_return(card)
|
61
61
|
core.import!
|
62
62
|
end
|
63
63
|
|
64
64
|
it 'handles delivered stories' do
|
65
|
-
story.
|
66
|
-
trello.
|
65
|
+
allow(story).to receive_messages(current_state: 'delivered')
|
66
|
+
expect(trello).to receive(:create_card).with(core.options.delivered_list_id, story).and_return(card)
|
67
67
|
core.import!
|
68
68
|
end
|
69
69
|
|
70
70
|
it 'handles unstarted features' do
|
71
|
-
story.
|
72
|
-
trello.
|
71
|
+
allow(story).to receive_messages(current_state: 'unstarted', story_type: 'feature')
|
72
|
+
expect(trello).to receive(:create_card).with(core.options.feature_list_id, story).and_return(card)
|
73
73
|
core.import!
|
74
74
|
end
|
75
75
|
|
76
76
|
it 'handles unstarted chores' do
|
77
|
-
story.
|
78
|
-
trello.
|
77
|
+
allow(story).to receive_messages(current_state: 'unstarted', story_type: 'chore')
|
78
|
+
expect(trello).to receive(:create_card).with(core.options.chore_list_id, story).and_return(card)
|
79
79
|
core.import!
|
80
80
|
end
|
81
81
|
|
82
82
|
it 'handles unstarted bugs' do
|
83
|
-
story.
|
84
|
-
trello.
|
83
|
+
allow(story).to receive_messages(current_state: 'unstarted', story_type: 'bug')
|
84
|
+
expect(trello).to receive(:create_card).with(core.options.bug_list_id, story).and_return(card)
|
85
85
|
core.import!
|
86
86
|
end
|
87
87
|
|
88
88
|
it 'handles unstarted releases' do
|
89
|
-
story.
|
90
|
-
trello.
|
89
|
+
allow(story).to receive_messages(current_state: 'unstarted', story_type: 'release')
|
90
|
+
expect(trello).to receive(:create_card).with(core.options.release_list_id, story).and_return(card)
|
91
91
|
core.import!
|
92
92
|
end
|
93
93
|
|
94
94
|
it 'labels stories' do
|
95
|
-
story.
|
96
|
-
trello.
|
95
|
+
allow(story).to receive_messages(story_type: 'bug')
|
96
|
+
expect(trello).to receive(:add_label).with(card, 'bug', core.options.bug_label)
|
97
97
|
core.import!
|
98
98
|
end
|
99
99
|
|
100
100
|
it 'ignores nil labels' do
|
101
|
-
core.options.
|
102
|
-
story.
|
103
|
-
trello.
|
101
|
+
allow(core.options).to receive_messages(bug_label: nil)
|
102
|
+
allow(story).to receive_messages(story_type: 'bug')
|
103
|
+
expect(trello).not_to receive(:add_label)
|
104
104
|
core.import!
|
105
105
|
end
|
106
106
|
end
|
@@ -5,26 +5,28 @@ describe 'PivotalWrapper' do
|
|
5
5
|
|
6
6
|
context '#initialize' do
|
7
7
|
it 'sets the pivotal token' do
|
8
|
-
::PivotalTracker::Client.
|
8
|
+
expect(::PivotalTracker::Client).to receive(:token=).with('token')
|
9
9
|
PivotalToTrello::PivotalWrapper.new('token')
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
13
|
context '#project_choices' do
|
14
14
|
it 'returns a hash of pivotal projects' do
|
15
|
-
project = OpenStruct.new(:
|
16
|
-
::PivotalTracker::Project.
|
17
|
-
wrapper.project_choices.
|
15
|
+
project = OpenStruct.new(id: 'id', name: 'My Project')
|
16
|
+
expect(::PivotalTracker::Project).to receive(:all).and_return([project])
|
17
|
+
expect(wrapper.project_choices).to eq('id' => 'My Project')
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
context '#stories' do
|
22
|
-
it 'returns
|
23
|
-
|
22
|
+
it 'returns a sorted array of pivotal stories' do
|
23
|
+
first_story = mock_pivotal_story(created_at: Time.now - 10_000)
|
24
|
+
last_story = mock_pivotal_story(created_at: Time.now + 10_000)
|
24
25
|
project = double(PivotalTracker::Project)
|
25
|
-
::PivotalTracker::Project.
|
26
|
-
project.
|
27
|
-
wrapper.stories('project_id').
|
26
|
+
expect(::PivotalTracker::Project).to receive(:find).with('project_id').and_return(project)
|
27
|
+
allow(project).to receive_message_chain(:stories, :all).and_return([last_story, first_story])
|
28
|
+
expect(wrapper.stories('project_id').first).to eq(first_story)
|
29
|
+
expect(wrapper.stories('project_id').last).to eq(last_story)
|
28
30
|
end
|
29
31
|
end
|
30
|
-
end
|
32
|
+
end
|
@@ -4,15 +4,15 @@ describe 'TrelloWrapper' do
|
|
4
4
|
let(:wrapper) { PivotalToTrello::TrelloWrapper.new('key', 'token') }
|
5
5
|
|
6
6
|
before(:each) do
|
7
|
-
IO.
|
7
|
+
allow_any_instance_of(IO).to receive(:puts)
|
8
8
|
end
|
9
9
|
|
10
10
|
context '#initialize' do
|
11
11
|
it 'sets the auth credentials' do
|
12
12
|
config = double
|
13
|
-
Trello.
|
14
|
-
config.
|
15
|
-
config.
|
13
|
+
expect(Trello).to receive(:configure).and_yield(config)
|
14
|
+
expect(config).to receive(:developer_public_key=).with('key')
|
15
|
+
expect(config).to receive(:member_token=).with('token')
|
16
16
|
PivotalToTrello::TrelloWrapper.new('key', 'token')
|
17
17
|
end
|
18
18
|
end
|
@@ -22,93 +22,115 @@ describe 'TrelloWrapper' do
|
|
22
22
|
|
23
23
|
it 'creates a new card if none exists' do
|
24
24
|
story = mock_pivotal_story
|
25
|
-
wrapper.
|
26
|
-
Trello::Card.
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
25
|
+
expect(wrapper).to receive(:get_card).and_return(nil)
|
26
|
+
expect(Trello::Card).to receive(:create).with(
|
27
|
+
name: story.name,
|
28
|
+
desc: story.description,
|
29
|
+
list_id: 'list_id',
|
30
30
|
).and_return(card)
|
31
|
-
wrapper.create_card('list_id', story).
|
31
|
+
expect(wrapper.create_card('list_id', story)).to eq(card)
|
32
32
|
end
|
33
33
|
|
34
34
|
it 'does not create a new card if one exists with the same name' do
|
35
|
-
story = mock_pivotal_story(:
|
36
|
-
Trello::List.
|
37
|
-
Trello::Card.
|
38
|
-
wrapper.create_card('list_id', story).
|
35
|
+
story = mock_pivotal_story(name: 'My Card')
|
36
|
+
allow(Trello::List).to receive_message_chain(:find, :cards).and_return([card])
|
37
|
+
expect(Trello::Card).not_to receive(:create)
|
38
|
+
expect(wrapper.create_card('list_id', story)).to eq(card)
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'creates a new card if one exists with a different name' do
|
42
|
-
story = mock_pivotal_story(:
|
43
|
-
Trello::List.
|
44
|
-
Trello::Card.
|
45
|
-
:
|
46
|
-
:
|
47
|
-
:
|
42
|
+
story = mock_pivotal_story(name: 'My Foo')
|
43
|
+
allow(Trello::List).to receive_message_chain(:find, :cards).and_return([card])
|
44
|
+
expect(Trello::Card).to receive(:create).with(
|
45
|
+
name: story.name,
|
46
|
+
desc: story.description,
|
47
|
+
list_id: 'list_id',
|
48
48
|
).and_return(card)
|
49
|
-
wrapper.create_card('list_id', story).
|
49
|
+
expect(wrapper.create_card('list_id', story)).to eq(card)
|
50
50
|
end
|
51
51
|
|
52
52
|
it 'adds comments' do
|
53
|
-
note = OpenStruct.new(:
|
53
|
+
note = OpenStruct.new(text: 'My Note', author: 'John Smith')
|
54
54
|
story = mock_pivotal_story
|
55
|
-
story.
|
56
|
-
wrapper.
|
57
|
-
Trello::Card.
|
58
|
-
card.
|
59
|
-
wrapper.create_card('list_id', story).
|
55
|
+
allow(story).to receive_message_chain(:notes, :all).and_return([note])
|
56
|
+
expect(wrapper).to receive(:get_card).and_return(nil)
|
57
|
+
expect(Trello::Card).to receive(:create).and_return(card)
|
58
|
+
expect(card).to receive(:add_comment).with('[John Smith] My Note')
|
59
|
+
expect(wrapper.create_card('list_id', story)).to eq(card)
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'adds tasks' do
|
63
|
+
task = OpenStruct.new(description: 'My Task', complete: false)
|
64
|
+
story = mock_pivotal_story
|
65
|
+
checklist = double(Trello::Checklist)
|
66
|
+
allow(story).to receive_message_chain(:tasks, :all).and_return([task])
|
67
|
+
expect(wrapper).to receive(:get_card).and_return(nil)
|
68
|
+
expect(Trello::Card).to receive(:create).and_return(card)
|
69
|
+
expect(Trello::Checklist).to receive(:create).with(name: 'Tasks', card_id: card.id).and_return(checklist)
|
70
|
+
expect(card).to receive(:add_checklist).with(checklist)
|
71
|
+
expect(checklist).to receive(:add_item).with(task.description, task.complete)
|
72
|
+
expect(wrapper.create_card('list_id', story)).to eq(card)
|
60
73
|
end
|
61
74
|
end
|
62
75
|
|
63
76
|
context '#board_choices' do
|
64
77
|
it 'returns a hash of Trello boards' do
|
65
|
-
board = OpenStruct.new(:
|
66
|
-
Trello::Board.
|
67
|
-
wrapper.board_choices.
|
78
|
+
board = OpenStruct.new(id: 'id', name: 'My Board')
|
79
|
+
expect(Trello::Board).to receive(:all).and_return([board])
|
80
|
+
expect(wrapper.board_choices).to eq('id' => 'My Board')
|
68
81
|
end
|
69
82
|
end
|
70
83
|
|
71
84
|
context '#list_choices' do
|
72
85
|
it 'returns a hash of Trello lists' do
|
73
86
|
board = double(Trello::Board)
|
74
|
-
list = OpenStruct.new(:
|
75
|
-
Trello::Board.
|
76
|
-
board.
|
77
|
-
wrapper.list_choices('board_id').
|
78
|
-
|
79
|
-
false => "[don't import these stories]",
|
80
|
-
}
|
87
|
+
list = OpenStruct.new(id: 'id', name: 'My List')
|
88
|
+
expect(Trello::Board).to receive(:find).with('board_id').and_return(board)
|
89
|
+
expect(board).to receive(:lists).and_return([list])
|
90
|
+
expect(wrapper.list_choices('board_id')).to eq( 'id' => 'My List',
|
91
|
+
false => "[don't import these stories]")
|
81
92
|
end
|
82
93
|
end
|
83
94
|
|
84
95
|
context '#cards_for_list' do
|
85
96
|
it 'returns a hash of Trello lists' do
|
86
97
|
list = double(Trello::List)
|
87
|
-
card
|
88
|
-
Trello::List.
|
89
|
-
list.
|
90
|
-
expected = {'193060beddd00d64259bdc1271d6c5a330e92e7d' => card}
|
91
|
-
wrapper.cards_for_list('list_id').
|
98
|
+
card = OpenStruct.new(name: 'My Card', desc: 'My Description')
|
99
|
+
expect(Trello::List).to receive(:find).with('list_id').and_return(list)
|
100
|
+
expect(list).to receive(:cards).and_return([card])
|
101
|
+
expected = { '193060beddd00d64259bdc1271d6c5a330e92e7d' => card }
|
102
|
+
expect(wrapper.cards_for_list('list_id')).to eq(expected)
|
92
103
|
# Test caching.
|
93
|
-
Trello::List.
|
94
|
-
wrapper.cards_for_list('list_id').
|
104
|
+
expect(Trello::List).not_to receive(:find)
|
105
|
+
expect(wrapper.cards_for_list('list_id')).to eq(expected)
|
95
106
|
end
|
96
107
|
end
|
97
108
|
|
98
109
|
context '#add_label' do
|
110
|
+
let(:board) { double(Trello::Board) }
|
111
|
+
|
112
|
+
before do
|
113
|
+
expect(Trello::Board).to receive(:find).with('board_id').and_return(board)
|
114
|
+
allow(board).to receive(:labels).and_return([])
|
115
|
+
end
|
116
|
+
|
99
117
|
it 'adds a label if it does not already exist' do
|
100
|
-
|
101
|
-
card
|
102
|
-
card.
|
103
|
-
|
118
|
+
label = double(Trello::Label)
|
119
|
+
card = mock_trello_card(board_id: 'board_id')
|
120
|
+
allow(card).to receive_messages(labels: [])
|
121
|
+
expect(Trello::Label).to receive(:create).with(name: 'bug', board_id: 'board_id', color: 'red').and_return(label)
|
122
|
+
expect(card).to receive(:add_label).with(label)
|
123
|
+
wrapper.add_label(card, 'bug', 'red')
|
104
124
|
end
|
105
125
|
|
106
126
|
it 'does not add a label if it already exists' do
|
107
|
-
|
108
|
-
card
|
109
|
-
|
110
|
-
|
127
|
+
label = double(Trello::Label, id: '1234', name: 'bug', color: 'red')
|
128
|
+
card = mock_trello_card(board_id: 'board_id')
|
129
|
+
allow(board).to receive(:labels).and_return([label])
|
130
|
+
allow(card).to receive_messages(labels: [label])
|
131
|
+
expect(card).not_to receive(:add_label)
|
132
|
+
wrapper.add_label(card, 'bug', 'red')
|
111
133
|
end
|
112
134
|
end
|
113
135
|
|
114
|
-
end
|
136
|
+
end
|