story_branch 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/story_branch.rb +81 -41
- metadata +11 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9cc200c930d34b90699a03c634f1de29e2c599b
|
4
|
+
data.tar.gz: 7abb7d7e9c1001d9e4d1c2236925995de29ff39b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd86ebf0d42dcbc66a70ab1e4e2d9403996ddce94a422b8ae2ccd46921cd5ddb1eec096f127678f7f506604f219083be4717c2760e21b2f9390b8363c637236b
|
7
|
+
data.tar.gz: 4e7e215be23201bd48cc94fec811f76dcb87eaae3bd3214994bae5c1e3b4d25761b4638d7c36b899dd1e3bad64f378dc35e43f59adc53fdadf6da2b7ed9d850e
|
data/README.md
CHANGED
@@ -17,8 +17,8 @@ accept. The branch will be created (the story_id will automatically
|
|
17
17
|
be used as a suffix in the branch name)
|
18
18
|
|
19
19
|
**git start**: Start a story in Pivotal Tracker from the terminal.
|
20
|
-
|
21
|
-
|
20
|
+
Lists all unstarted stories in your current project. Select a story
|
21
|
+
from the displayed list, and it will tell Pivotal Tracker to start it.
|
22
22
|
|
23
23
|
**git finish**: Create a finishing commit + message, for example:
|
24
24
|
"[Finishes #1234567] My Story Title" - optionally Finishes the story
|
data/lib/story_branch.rb
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# Dominic Wong <dominic.wong.617@gmail.com>
|
6
6
|
# Gabe Hollombe <gabe@neo.com>
|
7
7
|
#
|
8
|
-
# Version: 0.2.
|
8
|
+
# Version: 0.2.1
|
9
9
|
#
|
10
10
|
# ## Description
|
11
11
|
#
|
@@ -77,10 +77,17 @@ require 'git'
|
|
77
77
|
require 'active_support/core_ext/string/inflections'
|
78
78
|
require 'levenshtein'
|
79
79
|
|
80
|
+
trap('INT') {exit}
|
81
|
+
|
80
82
|
module StoryBranch
|
81
83
|
|
82
84
|
class Main
|
83
85
|
|
86
|
+
ERRORS = {
|
87
|
+
"Stories in the started state must be estimated." =>
|
88
|
+
"Error: Pivotal won't allow you to start an unestimated story"
|
89
|
+
}
|
90
|
+
|
84
91
|
PIVOTAL_CONFIG_FILES = ['.story_branch',"#{ENV['HOME']}/.story_branch"]
|
85
92
|
|
86
93
|
attr_accessor :p
|
@@ -97,13 +104,14 @@ module StoryBranch
|
|
97
104
|
|
98
105
|
def create_story_branch
|
99
106
|
begin
|
107
|
+
puts "Connecting with Pivotal Tracker"
|
100
108
|
@p.get_project
|
101
|
-
|
109
|
+
puts "Getting stories..."
|
110
|
+
stories = @p.display_stories :started, false
|
102
111
|
if stories.length < 1
|
103
|
-
puts "No stories started
|
112
|
+
puts "No stories started, exiting"
|
104
113
|
exit
|
105
114
|
end
|
106
|
-
puts "[0] Exit"
|
107
115
|
story = @p.select_story stories
|
108
116
|
if story
|
109
117
|
@p.create_feature_branch story
|
@@ -114,16 +122,20 @@ module StoryBranch
|
|
114
122
|
end
|
115
123
|
end
|
116
124
|
|
117
|
-
def
|
125
|
+
def pick_and_update filter, hash, msg, is_estimated
|
118
126
|
begin
|
127
|
+
puts "Connecting with Pivotal Tracker"
|
119
128
|
@p.get_project
|
120
|
-
|
121
|
-
stories = @p.
|
122
|
-
puts "[0] Exit"
|
129
|
+
puts "Getting stories..."
|
130
|
+
stories = @p.filtered_stories_list filter, is_estimated
|
123
131
|
story = @p.select_story stories
|
124
132
|
if story
|
125
|
-
story.update
|
126
|
-
|
133
|
+
result = story.update hash
|
134
|
+
if result.errors.count > 0
|
135
|
+
puts result.errors.to_a.uniq.map{|e| ERRORS[e] }
|
136
|
+
return nil
|
137
|
+
end
|
138
|
+
puts "#{story.id} #{msg}"
|
127
139
|
end
|
128
140
|
rescue RestClient::Unauthorized
|
129
141
|
puts "Pivotal API key or Project ID invalid"
|
@@ -131,16 +143,24 @@ module StoryBranch
|
|
131
143
|
end
|
132
144
|
end
|
133
145
|
|
146
|
+
def story_start
|
147
|
+
pick_and_update(:unstarted, {:current_state => "started"}, "started", true)
|
148
|
+
end
|
149
|
+
|
134
150
|
def story_unstart
|
135
|
-
|
151
|
+
pick_and_update(:started, {:current_state => "unstarted"}, "unstarted", false)
|
152
|
+
end
|
153
|
+
|
154
|
+
def story_estimate
|
155
|
+
# TODO: estimate a story
|
136
156
|
end
|
137
157
|
|
138
158
|
def story_finish
|
139
159
|
begin
|
160
|
+
puts "Connecting with Pivotal Tracker"
|
140
161
|
@p.get_project
|
141
162
|
unless @p.is_current_branch_a_story?
|
142
|
-
puts "Your current branch: #{GitUtils.current_branch}"
|
143
|
-
puts "is not linked to a started story."
|
163
|
+
puts "Your current branch: '#{GitUtils.current_branch}' is not linked to a Pivotal Tracker story."
|
144
164
|
return
|
145
165
|
end
|
146
166
|
|
@@ -158,7 +178,7 @@ module StoryBranch
|
|
158
178
|
end
|
159
179
|
|
160
180
|
puts "Use standard finishing commit message: [y/N]?"
|
161
|
-
commit_message = "[Finishes ##{GitUtils.current_branch_story_parts[:id]}] #{GitUtils.current_branch_story_parts[:description]}"
|
181
|
+
commit_message = "[Finishes ##{GitUtils.current_branch_story_parts[:id]}] #{GitUtils.current_branch_story_parts[:description].StringUtils.undashed}"
|
162
182
|
puts commit_message
|
163
183
|
|
164
184
|
if gets.chomp!.downcase == "y"
|
@@ -202,6 +222,10 @@ module StoryBranch
|
|
202
222
|
s.tr '\'"%!@#$(){}[]*\\?', ''
|
203
223
|
end
|
204
224
|
|
225
|
+
def self.undashed s
|
226
|
+
s.underscore.humanize
|
227
|
+
end
|
228
|
+
|
205
229
|
end
|
206
230
|
|
207
231
|
class GitUtils
|
@@ -297,8 +321,9 @@ module StoryBranch
|
|
297
321
|
end
|
298
322
|
|
299
323
|
def is_current_branch_a_story?
|
324
|
+
GitUtils.current_story and
|
300
325
|
GitUtils.current_story.length == 3 and
|
301
|
-
filtered_stories_list(:started).map(&:id).include? GitUtils.current_story[2].to_i
|
326
|
+
filtered_stories_list(:started, true).map(&:id).include? GitUtils.current_story[2].to_i
|
302
327
|
end
|
303
328
|
|
304
329
|
def story_from_current_branch
|
@@ -310,32 +335,46 @@ module StoryBranch
|
|
310
335
|
# Filtering on tags/labels
|
311
336
|
# Filtering on estimation (estimated?, 0 point, 1 point etc.)
|
312
337
|
|
313
|
-
def filtered_stories_list state
|
338
|
+
def filtered_stories_list state, estimated
|
314
339
|
project = get_project
|
315
|
-
project.stories.all({current_state: state})
|
340
|
+
stories = project.stories.all({current_state: state})
|
341
|
+
if estimated
|
342
|
+
stories.select{|s| s.estimate and s.estimate > 1 }
|
343
|
+
else
|
344
|
+
stories
|
345
|
+
end
|
316
346
|
end
|
317
347
|
|
318
|
-
def display_stories state
|
319
|
-
filtered_stories_list(state).
|
348
|
+
def display_stories state, estimated
|
349
|
+
filtered_stories_list(state, estimated).each {|s| puts one_line_story s }
|
320
350
|
end
|
321
351
|
|
322
|
-
def one_line_story s
|
323
|
-
"
|
352
|
+
def one_line_story s
|
353
|
+
"#{s.id} - #{s.name}"
|
324
354
|
end
|
325
355
|
|
326
356
|
def select_story stories
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
357
|
+
story_texts = stories.map{|s| one_line_story s }
|
358
|
+
puts "Leave blank to exit, use <up>/<down> to scroll through stories, TAB to list all and auto-complete"
|
359
|
+
story_selection = readline("Select a story: ", story_texts)
|
360
|
+
if story_selection == "" or story_selection.nil?
|
361
|
+
return nil
|
332
362
|
end
|
333
|
-
|
363
|
+
story = stories.select{|s| story_matcher s, story_selection }.first
|
364
|
+
if story.nil?
|
365
|
+
puts "Not found: #{story_selection}"
|
334
366
|
return nil
|
367
|
+
else
|
368
|
+
puts "Selected : #{one_line_story story}"
|
369
|
+
return story
|
335
370
|
end
|
336
|
-
|
337
|
-
|
338
|
-
|
371
|
+
end
|
372
|
+
|
373
|
+
def story_matcher story, selection
|
374
|
+
m = selection.match(/^(\d*) /)
|
375
|
+
return false unless m
|
376
|
+
id = m.captures.first
|
377
|
+
return story.id.to_s == id
|
339
378
|
end
|
340
379
|
|
341
380
|
def create_feature_branch story
|
@@ -343,7 +382,7 @@ module StoryBranch
|
|
343
382
|
feature_branch_name = nil
|
344
383
|
puts "You are checked out at: #{GitUtils.current_branch}"
|
345
384
|
while feature_branch_name == nil or feature_branch_name == ""
|
346
|
-
puts "Provide a new branch name... (
|
385
|
+
puts "Provide a new branch name... (TAB for suggested name)" if [nil, ""].include? feature_branch_name
|
347
386
|
feature_branch_name = readline("Name of feature branch: ", [dashed_story_name])
|
348
387
|
end
|
349
388
|
feature_branch_name.chomp!
|
@@ -361,14 +400,14 @@ module StoryBranch
|
|
361
400
|
end
|
362
401
|
existing_name_score = GitUtils.is_existing_branch?(name)
|
363
402
|
unless existing_name_score == -1
|
364
|
-
puts <<-
|
403
|
+
puts <<-EOD.strip_heredoc
|
365
404
|
Name Collision Error:
|
366
405
|
|
367
406
|
#{name}
|
368
407
|
|
369
408
|
This is too similar to the name of an existing
|
370
409
|
branch, a more unique name is required
|
371
|
-
|
410
|
+
EOD
|
372
411
|
end
|
373
412
|
end
|
374
413
|
|
@@ -379,15 +418,16 @@ module StoryBranch
|
|
379
418
|
name.match valid
|
380
419
|
end
|
381
420
|
|
382
|
-
def readline prompt,
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
Readline.
|
388
|
-
|
421
|
+
def readline prompt, completions=[]
|
422
|
+
# Store the state of the terminal
|
423
|
+
Readline::HISTORY.clear
|
424
|
+
if completions.length > 0
|
425
|
+
completions.each {|i| Readline::HISTORY.push i}
|
426
|
+
Readline.special_prefixes = " .{}()[]!?\"'_-#@$%^&*"
|
427
|
+
Readline.completion_proc = proc {|s| completions.grep(/#{Regexp.escape(s)}/) }
|
428
|
+
Readline.completion_append_character = ""
|
389
429
|
end
|
430
|
+
Readline.readline(prompt, false)
|
390
431
|
end
|
391
|
-
|
392
432
|
end
|
393
433
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: story_branch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Milkins
|
@@ -17,56 +17,56 @@ dependencies:
|
|
17
17
|
name: pivotal-tracker
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
|
-
- -
|
20
|
+
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: '0.5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0.5'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: git
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
|
-
- -
|
34
|
+
- - ~>
|
35
35
|
- !ruby/object:Gem::Version
|
36
36
|
version: '1.2'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
|
-
- -
|
41
|
+
- - ~>
|
42
42
|
- !ruby/object:Gem::Version
|
43
43
|
version: '1.2'
|
44
44
|
- !ruby/object:Gem::Dependency
|
45
45
|
name: levenshtein-ffi
|
46
46
|
requirement: !ruby/object:Gem::Requirement
|
47
47
|
requirements:
|
48
|
-
- -
|
48
|
+
- - ~>
|
49
49
|
- !ruby/object:Gem::Version
|
50
50
|
version: '1.0'
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
|
-
- -
|
55
|
+
- - ~>
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '1.0'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: rspec
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
|
-
- -
|
62
|
+
- - ~>
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: '3.0'
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
68
68
|
requirements:
|
69
|
-
- -
|
69
|
+
- - ~>
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '3.0'
|
72
72
|
description: Simple gem that fetches the available stories in your pivotaltracker
|
@@ -120,12 +120,12 @@ require_paths:
|
|
120
120
|
- lib
|
121
121
|
required_ruby_version: !ruby/object:Gem::Requirement
|
122
122
|
requirements:
|
123
|
-
- -
|
123
|
+
- - '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 1.9.3
|
126
126
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
|
-
- -
|
128
|
+
- - '>='
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
131
|
requirements: []
|