pivo_flow 0.3.8 → 0.3.9
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +17 -5
- data/lib/pivo_flow/cli.rb +38 -19
- data/lib/pivo_flow/pivotal.rb +27 -4
- data/lib/pivo_flow/version.rb +1 -1
- data/spec/pivo_flow/cli_spec.rb +58 -1
- data/spec/pivo_flow/pivotal_spec.rb +88 -3
- metadata +2 -2
data/README.md
CHANGED
@@ -17,7 +17,15 @@ All the required information is gathered on demand, but it's a good idea to prep
|
|
17
17
|
* project's Pivotal Tracker ID
|
18
18
|
* your Pivotal Tracker API token
|
19
19
|
|
20
|
-
|
20
|
+
Show help
|
21
|
+
|
22
|
+
pf help
|
23
|
+
|
24
|
+
or
|
25
|
+
|
26
|
+
pf --help
|
27
|
+
|
28
|
+
Get list of current stories with an interactive choice menu
|
21
29
|
|
22
30
|
pf stories
|
23
31
|
|
@@ -33,6 +41,10 @@ Clear current story without notifying Pivotal
|
|
33
41
|
|
34
42
|
pf clear
|
35
43
|
|
44
|
+
Show finished stories and select the one you would like to deliver
|
45
|
+
|
46
|
+
pf deliver
|
47
|
+
|
36
48
|
Display current gem version
|
37
49
|
|
38
50
|
pf version
|
@@ -50,18 +62,18 @@ This gem installs a `pepare-commit-msg` hook by adding a reference to `pf-prepar
|
|
50
62
|
|
51
63
|
### 0.3 Current release
|
52
64
|
|
53
|
-
* single-story view
|
65
|
+
* single-story view with comments and tasks
|
54
66
|
* flow:
|
55
67
|
* select story
|
56
68
|
* read the story description
|
57
69
|
* accept or back to story selection
|
58
70
|
* `pf info` displaying info about current task
|
59
|
-
* `pf
|
60
|
-
*
|
71
|
+
* `pf deliver` ability to deliver finished stories [#6]
|
72
|
+
* options via `OptionParser`
|
61
73
|
|
62
74
|
### 0.2
|
63
75
|
|
64
|
-
* git
|
76
|
+
* git hook
|
65
77
|
* formatted output
|
66
78
|
* bugfixes
|
67
79
|
|
data/lib/pivo_flow/cli.rb
CHANGED
@@ -36,17 +36,29 @@ module PivoFlow
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def finish story_id=nil
|
39
|
-
|
40
|
-
|
39
|
+
unless current_story_id
|
40
|
+
puts no_story_found_message
|
41
|
+
return 1
|
41
42
|
end
|
42
|
-
pivotal_object.finish_story(
|
43
|
+
pivotal_object.finish_story(current_story_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def deliver
|
47
|
+
pivotal_object.deliver
|
43
48
|
end
|
44
49
|
|
45
50
|
def clear
|
46
|
-
|
51
|
+
unless current_story_id.nil?
|
47
52
|
FileUtils.remove_file(@file_story_path)
|
53
|
+
puts "Current pivotal story id cleared."
|
54
|
+
else
|
55
|
+
puts no_story_found_message
|
56
|
+
return 1
|
48
57
|
end
|
49
|
-
|
58
|
+
end
|
59
|
+
|
60
|
+
def current
|
61
|
+
puts current_story_id || no_story_found_message
|
50
62
|
end
|
51
63
|
|
52
64
|
def reconfig
|
@@ -67,6 +79,10 @@ module PivoFlow
|
|
67
79
|
@pivotal_object ||= PivoFlow::Pivotal.new(@options)
|
68
80
|
end
|
69
81
|
|
82
|
+
def no_story_found_message
|
83
|
+
"No story found in #{@file_story_path}"
|
84
|
+
end
|
85
|
+
|
70
86
|
def no_method_error
|
71
87
|
puts "You forgot a method name"
|
72
88
|
end
|
@@ -75,6 +91,11 @@ module PivoFlow
|
|
75
91
|
puts "Ups, no such method..."
|
76
92
|
end
|
77
93
|
|
94
|
+
def current_story_id
|
95
|
+
return nil unless File.exists?(@file_story_path)
|
96
|
+
File.open(@file_story_path).read.strip
|
97
|
+
end
|
98
|
+
|
78
99
|
def parse_argv(args)
|
79
100
|
@options = {}
|
80
101
|
|
@@ -82,11 +103,14 @@ module PivoFlow
|
|
82
103
|
opts.banner = "Usage: pf <COMMAND> [OPTIONS]\n"
|
83
104
|
opts.separator "Commands"
|
84
105
|
opts.separator " clear: clears STORY_ID from temp file"
|
85
|
-
opts.separator "
|
106
|
+
opts.separator " deliver: shows finished stories and mark selected as delivered in Pivotal Tracker"
|
107
|
+
opts.separator " help shows this message"
|
86
108
|
opts.separator " finish [STORY_ID]: finish story on Pivotal"
|
109
|
+
opts.separator " info: shows info about current story"
|
87
110
|
opts.separator " reconfig: clears API_TOKEN and PROJECT_ID from git config"
|
88
111
|
opts.separator " start <STORY_ID>: start a story of given ID"
|
89
112
|
opts.separator " stories: list stories for current project"
|
113
|
+
opts.separator " version: show gem version"
|
90
114
|
opts.separator ""
|
91
115
|
opts.separator "Options"
|
92
116
|
|
@@ -113,21 +137,15 @@ module PivoFlow
|
|
113
137
|
opt_parser.parse!(args)
|
114
138
|
|
115
139
|
case args[0]
|
116
|
-
when "
|
117
|
-
|
118
|
-
when "
|
119
|
-
|
120
|
-
when "
|
121
|
-
|
122
|
-
when "stories"
|
123
|
-
stories
|
124
|
-
when "finish"
|
125
|
-
finish args[1]
|
126
|
-
when "info"
|
127
|
-
info
|
140
|
+
when "start", "finish"
|
141
|
+
self.send(args[0].to_sym, args[1])
|
142
|
+
when "help"
|
143
|
+
puts opt_parser
|
144
|
+
when "clear", "current", "deliver", "info", "reconfig", "stories"
|
145
|
+
self.send(args[0].to_sym)
|
128
146
|
when nil
|
129
147
|
no_method_error
|
130
|
-
puts opt_parser
|
148
|
+
puts opt_parser
|
131
149
|
return 1
|
132
150
|
else
|
133
151
|
invalid_method_error
|
@@ -138,4 +156,5 @@ module PivoFlow
|
|
138
156
|
end
|
139
157
|
|
140
158
|
end
|
159
|
+
|
141
160
|
end
|
data/lib/pivo_flow/pivotal.rb
CHANGED
@@ -35,6 +35,10 @@ module PivoFlow
|
|
35
35
|
project_stories.select{ |story| story.owned_by == nil }
|
36
36
|
end
|
37
37
|
|
38
|
+
def finished_stories
|
39
|
+
fetch_stories(10, "finished")
|
40
|
+
end
|
41
|
+
|
38
42
|
def current_story force = false
|
39
43
|
if (@options[:current_story] && !force)
|
40
44
|
@options[:current_story]
|
@@ -44,6 +48,11 @@ module PivoFlow
|
|
44
48
|
end
|
45
49
|
|
46
50
|
def list_stories_to_output stories
|
51
|
+
if (stories.nil? || stories.empty?)
|
52
|
+
puts "No stories to show"
|
53
|
+
return 1
|
54
|
+
end
|
55
|
+
|
47
56
|
HighLine.new.choose do |menu|
|
48
57
|
menu.header = "\n--- STORIES FROM PIVOTAL TRACKER ---\nWhich one would you like to start? "
|
49
58
|
menu.prompt = "story no.? "
|
@@ -54,13 +63,18 @@ module PivoFlow
|
|
54
63
|
end
|
55
64
|
end
|
56
65
|
|
66
|
+
def deliver
|
67
|
+
list_stories_to_output finished_stories
|
68
|
+
end
|
69
|
+
|
57
70
|
def show_story story_id
|
58
71
|
story = find_story(story_id)
|
59
72
|
show_info story
|
60
|
-
|
73
|
+
ask_for = story.current_state == "finished" ? "deliver" : "start"
|
74
|
+
proceed = ask_question "Do you want to #{ask_for} this story?"
|
61
75
|
accepted_answers = %w[yes y sure ofc jup yep yup ja tak]
|
62
76
|
if accepted_answers.include?(proceed.downcase)
|
63
|
-
pick_up_story(story_id)
|
77
|
+
story.current_state == "finished" ? deliver_story(story_id) : pick_up_story(story_id)
|
64
78
|
else
|
65
79
|
show_stories
|
66
80
|
end
|
@@ -94,7 +108,7 @@ module PivoFlow
|
|
94
108
|
owner: story_owner(story),
|
95
109
|
description: story.description,
|
96
110
|
labels: story_labels(story),
|
97
|
-
started: story
|
111
|
+
started: story_state_sign(story)
|
98
112
|
}
|
99
113
|
if long
|
100
114
|
"STORY %{started} %{story_type} [#%{story_id}]
|
@@ -148,6 +162,11 @@ module PivoFlow
|
|
148
162
|
story.labels.nil? ? "" : story.labels.split(",").map{ |l| "##{l}" }.join(", ")
|
149
163
|
end
|
150
164
|
|
165
|
+
def story_state_sign story
|
166
|
+
return "*" if story.current_state == "unstarted"
|
167
|
+
story.current_state[0].capitalize
|
168
|
+
end
|
169
|
+
|
151
170
|
def initials name
|
152
171
|
name.split.map{ |n| n[0] }.join
|
153
172
|
end
|
@@ -189,6 +208,10 @@ module PivoFlow
|
|
189
208
|
remove_story_id_file if story_id.nil? or update_story(story_id, :finished)
|
190
209
|
end
|
191
210
|
|
211
|
+
def deliver_story story_id
|
212
|
+
update_story(story_id, :delivered)
|
213
|
+
end
|
214
|
+
|
192
215
|
def remove_story_id_file
|
193
216
|
FileUtils.remove_file(@story_id_file_path)
|
194
217
|
end
|
@@ -203,7 +226,7 @@ module PivoFlow
|
|
203
226
|
list_stories_to_output stories.first(9)
|
204
227
|
end
|
205
228
|
|
206
|
-
def fetch_stories(count = 100, state = "unstarted,started,unscheduled")
|
229
|
+
def fetch_stories(count = 100, state = "unstarted,started,unscheduled,rejected")
|
207
230
|
conditions = { current_state: state, limit: count }
|
208
231
|
@options[:stories] = @options[:project].stories.all(conditions)
|
209
232
|
end
|
data/lib/pivo_flow/version.rb
CHANGED
data/spec/pivo_flow/cli_spec.rb
CHANGED
@@ -60,8 +60,65 @@ describe PivoFlow::Cli do
|
|
60
60
|
end
|
61
61
|
|
62
62
|
end
|
63
|
+
|
64
|
+
describe "reads story id from file" do
|
65
|
+
|
66
|
+
it "and returns nil if there is no such file" do
|
67
|
+
File.stub(:exists?).and_return(false)
|
68
|
+
PivoFlow::Cli.new.send(:current_story_id).should be_nil
|
69
|
+
end
|
70
|
+
|
71
|
+
it "and returns story id if file exists" do
|
72
|
+
File.stub(:exists?).and_return(true)
|
73
|
+
f = mock('File', :read => "123")
|
74
|
+
File.stub(:open).and_return(f)
|
75
|
+
PivoFlow::Cli.new.send(:current_story_id).should eq "123"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "finish method" do
|
80
|
+
|
81
|
+
it "calls finish_story on pivotal object on finish method" do
|
82
|
+
pivo = mock("PivoFlow::Pivotal")
|
83
|
+
PivoFlow::Cli.any_instance.should_receive(:pivotal_object).and_return(pivo)
|
84
|
+
pivo.should_receive(:finish_story).with("123")
|
85
|
+
PivoFlow::Cli.any_instance.should_receive(:current_story_id).twice.and_return("123")
|
86
|
+
PivoFlow::Cli.new("finish").go!
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns 1 if there is no current_story_id" do
|
90
|
+
PivoFlow::Cli.any_instance.should_receive(:current_story_id).and_return(nil)
|
91
|
+
PivoFlow::Cli.new.send(:finish).should eq 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "start method" do
|
96
|
+
|
97
|
+
it "returns 1 if no story given" do
|
98
|
+
PivoFlow::Cli.new.send(:start).should eq 1
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "clear method" do
|
104
|
+
|
105
|
+
it "returns 1 if current story is nil" do
|
106
|
+
PivoFlow::Cli.any_instance.should_receive(:current_story_id).and_return(nil)
|
107
|
+
PivoFlow::Cli.new.send(:clear).should eq 1
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
it "removes file if current story is present" do
|
112
|
+
PivoFlow::Cli.any_instance.should_receive(:current_story_id).and_return(1)
|
113
|
+
FileUtils.should_receive(:remove_file).and_return(true)
|
114
|
+
PivoFlow::Cli.new.send(:clear)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
|
63
120
|
describe "should allow to run command named" do
|
64
|
-
methods = [:stories, :start, :info, :finish, :clear, :reconfig]
|
121
|
+
methods = [:stories, :start, :info, :finish, :clear, :help, :reconfig, :current, :deliver]
|
65
122
|
methods.each do |method|
|
66
123
|
it "#{method.to_s}" do
|
67
124
|
PivoFlow::Cli.any_instance.stub(method)
|
@@ -44,9 +44,91 @@ describe PivoFlow::Pivotal do
|
|
44
44
|
pivotal.unasigned_stories.should eq [@story_unassigned]
|
45
45
|
end
|
46
46
|
|
47
|
+
it "show_stories should display stories on output" do
|
48
|
+
pivotal.should_receive(:list_stories_to_output)
|
49
|
+
pivotal.show_stories
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "story_string" do
|
53
|
+
|
54
|
+
it "includes story id" do
|
55
|
+
pivotal.story_string(@story_feature).should match(/[##{@story_feature.id}]/) end
|
56
|
+
|
57
|
+
it "includes story name" do
|
58
|
+
pivotal.story_string(@story_feature).should match(/#{@story_feature.name}/)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "deliver" do
|
64
|
+
|
65
|
+
it "list only the stories with 'finished' status" do
|
66
|
+
@project.stub_chain(:stories, :all).and_return([@story_finished])
|
67
|
+
pivotal.should_receive(:list_stories_to_output).with([@story_finished])
|
68
|
+
pivotal.deliver
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "list_stories_to_output" do
|
74
|
+
|
75
|
+
it "returns 1 if stories are nil" do
|
76
|
+
pivotal.list_stories_to_output(nil).should eq 1
|
77
|
+
end
|
78
|
+
|
79
|
+
it "returns 1 if stories are []" do
|
80
|
+
pivotal.list_stories_to_output([]).should eq 1
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "show_story" do
|
86
|
+
|
87
|
+
after(:each) do
|
88
|
+
pivotal.stub(:show_stories)
|
89
|
+
# pivotal.stub(:update_story)
|
90
|
+
pivotal.stub(:show_info)
|
91
|
+
|
92
|
+
pivotal.show_story 1
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "if story's state is 'finished'" do
|
96
|
+
|
97
|
+
before(:each) do
|
98
|
+
@story_feature.stub(:current_state).and_return("finished")
|
99
|
+
pivotal.stub(:ask_question).and_return("y")
|
100
|
+
end
|
101
|
+
|
102
|
+
it "ask for deliver the story" do
|
103
|
+
pivotal.should_receive(:ask_question).with(/deliver/)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "updates story on pivotal with 'delivered' status" do
|
107
|
+
@story_feature.should_receive(:update).with({ owned_by: @story_feature.owned_by, current_state: :delivered })
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
it "shows info about the story" do
|
114
|
+
pivotal.stub(:ask_question).and_return("no")
|
115
|
+
pivotal.should_receive(:show_info)
|
116
|
+
end
|
117
|
+
|
118
|
+
it "updates the story if user response is 'yes'" do
|
119
|
+
pivotal.stub(:ask_question).and_return("yes")
|
120
|
+
pivotal.should_receive(:update_story)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "show stories if user response is 'no'" do
|
124
|
+
pivotal.stub(:ask_question).and_return("no")
|
125
|
+
pivotal.should_receive(:show_stories)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
47
129
|
describe "start_story" do
|
130
|
+
|
48
131
|
before(:each) do
|
49
|
-
@story_feature.stub_chain(:update, :errors, :count).and_return(0)
|
50
132
|
@story_feature.should_receive(:update).with({ current_state: :started, owned_by: pivotal.user_name })
|
51
133
|
end
|
52
134
|
|
@@ -112,7 +194,10 @@ def stub_pivotal_project
|
|
112
194
|
requested_by: "Paul Newman",
|
113
195
|
owned_by: "Adam Newman",
|
114
196
|
labels: "first,second")
|
115
|
-
@
|
116
|
-
@
|
197
|
+
@story_feature.stub_chain(:update).and_return(mock(errors: []))
|
198
|
+
@story_unassigned = PivotalTracker::Story.new(owned_by: nil, name: "test", current_state: "started")
|
199
|
+
@story_rejected = PivotalTracker::Story.new(current_state: "rejected", owned_by: "Mark Marco", name: "test_rejected")
|
200
|
+
@story_finished = PivotalTracker::Story.new(current_state: "finished", owned_by: "Mark Marco", name: "finished")
|
201
|
+
@project.stub_chain(:stories, :all).and_return([@story_feature, @story_unassigned, @story_rejected, @story_finished])
|
117
202
|
PivotalTracker::Project.stub(:find).and_return(@project)
|
118
203
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pivo_flow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-08-
|
12
|
+
date: 2012-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: pivotal-tracker
|