pivo_flow 0.3.8 → 0.3.9

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.
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
- Get list of current stories
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 --help` and other options via OptionParser
60
- * comments and tasks in a single-story view
71
+ * `pf deliver` ability to deliver finished stories [#6]
72
+ * options via `OptionParser`
61
73
 
62
74
  ### 0.2
63
75
 
64
- * git hoook
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
- if File.exists? @file_story_path
40
- story_id = File.open(@file_story_path).read.strip
39
+ unless current_story_id
40
+ puts no_story_found_message
41
+ return 1
41
42
  end
42
- pivotal_object.finish_story(story_id)
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
- if File.exists? @file_story_path
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
- puts "Current pivotal story id cleared."
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 " info: shows info about current story"
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 "clear"
117
- clear
118
- when "reconfig"
119
- reconfig
120
- when "start"
121
- start args[1]
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.to_s
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
@@ -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
- proceed = ask_question "Do you want to start this story?"
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.current_state == "started" ? "S" : "N"
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
@@ -1,3 +1,3 @@
1
1
  module PivoFlow
2
- VERSION = "0.3.8"
2
+ VERSION = "0.3.9"
3
3
  end
@@ -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
- @story_unassigned = PivotalTracker::Story.new(owned_by: nil)
116
- @project.stub_chain(:stories, :all).and_return([@story_feature, @story_unassigned])
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.8
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-13 00:00:00.000000000 Z
12
+ date: 2012-08-15 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pivotal-tracker