story_branch 0.2.7 → 0.2.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/story_branch.rb +85 -76
  4. metadata +19 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9c0e160a81842521457a2ef968e48f3960b2681d
4
- data.tar.gz: a1a816524e43ce91699ca78b0f772c6e89a2795a
3
+ metadata.gz: dfb03c2e2971ef4d7821325027d126506ec4d02c
4
+ data.tar.gz: de96f85c513ad4ec77f7bd058e7954edd0658446
5
5
  SHA512:
6
- metadata.gz: 8328b3529fb52fd129fe8a936b1c07e940c094c6aa3d03d297ff1a9da0b0471e5d228f180ee1accfa2f0a8ff1c858136179cf111f9384e0b655bb6f1c917745d
7
- data.tar.gz: 99e3f567048af4d348d0b510d09f3aca8e1147cb9afd00708614d4f079b5295517ff9c47a62dc594cbb0735edf345a76105087dd69db671660ee5cf9800d1bc6
6
+ metadata.gz: 9a326ba3d7ff1913aa8ba33af7519548b512d111a74c64899170190d533b5608726ee4800343210a22076cb908974e57cb7377cb9c3e82be88507bbebba58281
7
+ data.tar.gz: 2d8d4811aa52d7eb47bed0fa185f7424a54137f905b9d0e70b602586dc82856f489895acf7d3b5839e213e2bf587fb924f38d961d8af13f6f9cdebce58f93a52
data/README.md CHANGED
@@ -19,10 +19,10 @@ e.g. `my-story-name-1234567`
19
19
 
20
20
  `git finish`: Creates a git commit message for the staged changes.
21
21
 
22
- e.g: `[Finishes #1234567] My Story Title`
22
+ e.g: `[Finishes #1234567] My story name`
23
23
 
24
24
  You must stage all changes (or stash them) first. Note the commit will not
25
- be pushed. Note: You'll be able to bail out before.
25
+ be pushed. Note: You'll be able to bail out of the commit.
26
26
 
27
27
  `git start`: Start a story in Pivotal Tracker from the terminal.
28
28
  It'll get all unstarted stories in your current project. You can
data/lib/story_branch.rb CHANGED
@@ -6,7 +6,7 @@
6
6
  # Ranhiru Cooray <ranhiru@gmail.com>
7
7
  # Gabe Hollombe <gabe@neo.com>
8
8
  #
9
- # Version: 0.2.7
9
+ # Version: 0.2.8
10
10
  #
11
11
  # ## Description
12
12
  # A small collection of tools for working with git branches and Pivotal
@@ -26,10 +26,10 @@
26
26
  #
27
27
  # `git finish`: Creates a git commit message for the staged changes.
28
28
  #
29
- # e.g: `[Finishes #1234567] My Story Title`
29
+ # e.g: `[Finishes #1234567] My story name`
30
30
  #
31
31
  # You must stage all changes (or stash them) first. Note the commit will not
32
- # be pushed. Note: You'll be able to bail out before.
32
+ # be pushed. Note: You'll be able to bail out of the commit.
33
33
  #
34
34
  # `git start`: Start a story in Pivotal Tracker from the terminal.
35
35
  # It'll get all unstarted stories in your current project. You can
@@ -81,85 +81,83 @@
81
81
  #
82
82
  # Code:
83
83
 
84
+ require 'byebug'
84
85
  require 'yaml'
85
- require 'pivotal-tracker'
86
+ require 'blanket'
86
87
  require 'rb-readline'
87
88
  require 'readline'
88
89
  require 'git'
89
90
  require 'levenshtein'
90
91
 
91
- trap('INT') {exit}
92
+ trap('INT') { exit }
92
93
 
93
94
  module StoryBranch
94
-
95
95
  class Main
96
-
97
96
  ERRORS = {
98
- "Stories in the started state must be estimated." =>
97
+ 'Stories in the started state must be estimated.' =>
99
98
  "Error: Pivotal won't allow you to start an unestimated story"
100
99
  }
101
100
 
102
- PIVOTAL_CONFIG_FILES = ['.story_branch',"#{ENV['HOME']}/.story_branch"]
101
+ PIVOTAL_CONFIG_FILES = ['.story_branch', "#{ENV['HOME']}/.story_branch"]
103
102
 
104
103
  attr_accessor :p
105
104
 
106
105
  def initialize
107
- if config_file
108
- @pivotal_info = YAML.load_file config_file
109
- end
110
- @p = PivotalUtils.new
111
- @p.api_key = config_value "api", 'PIVOTAL_API_KEY'
112
- @p.project_id = config_value "project", 'PIVOTAL_PROJECT_ID'
106
+ @pivotal_info = YAML.load_file config_file if config_file
107
+ @p = PivotalUtils.new
108
+ @p.api_key = config_value 'api', 'PIVOTAL_API_KEY'
109
+ @p.project_id = config_value 'project', 'PIVOTAL_PROJECT_ID'
113
110
  exit unless @p.valid?
114
111
  end
115
112
 
113
+ def unauthorised_message
114
+ $stderr.puts 'Pivotal API key or Project ID invalid'
115
+ end
116
+
116
117
  def create_story_branch
117
118
  begin
118
- puts "Connecting with Pivotal Tracker"
119
+ puts 'Connecting with Pivotal Tracker'
119
120
  @p.get_project
120
- puts "Getting stories..."
121
+ puts 'Getting stories...'
121
122
  stories = @p.display_stories :started, false
122
123
  if stories.length < 1
123
- puts "No stories started, exiting"
124
+ puts 'No stories started, exiting'
124
125
  exit
125
126
  end
126
127
  story = @p.select_story stories
127
128
  if story
128
129
  @p.create_feature_branch story
129
130
  end
130
- rescue RestClient::Unauthorized
131
- $stderr.puts "Pivotal API key or Project ID invalid"
131
+ rescue Blanket::Unauthorized
132
+ unauthorised_message
132
133
  return nil
133
134
  end
134
135
  end
135
136
 
136
137
  def pick_and_update filter, hash, msg, is_estimated
137
138
  begin
138
- puts "Connecting with Pivotal Tracker"
139
+ puts 'Connecting with Pivotal Tracker'
139
140
  @p.get_project
140
- puts "Getting stories..."
141
+ puts 'Getting stories...'
141
142
  stories = @p.filtered_stories_list filter, is_estimated
142
143
  story = @p.select_story stories
143
144
  if story
144
- result = story.update hash
145
- if result.errors.count > 0
146
- puts result.errors.to_a.uniq.map{|e| ERRORS[e] }
147
- return nil
148
- end
145
+ result = @p.story_update story, hash
146
+ fail result.error if result.error
149
147
  puts "#{story.id} #{msg}"
150
148
  end
151
- rescue RestClient::Unauthorized
152
- $stderr.puts "Pivotal API key or Project ID invalid"
149
+ rescue Blanket::Unauthorized
150
+ unauthorised_message
153
151
  return nil
154
152
  end
155
153
  end
156
154
 
157
155
  def story_start
158
- pick_and_update(:unstarted, {:current_state => "started"}, "started", true)
156
+ pick_and_update(:unstarted, { current_state: 'started' }, 'started', true)
159
157
  end
160
158
 
161
159
  def story_unstart
162
- pick_and_update(:started, {:current_state => "unstarted"}, "unstarted", false)
160
+ pick_and_update(:started, { current_state: 'unstarted' }, 'unstarted', false)
163
161
  end
164
162
 
165
163
  def story_estimate
@@ -168,7 +166,7 @@ module StoryBranch
168
166
 
169
167
  def story_finish
170
168
  begin
171
- puts "Connecting with Pivotal Tracker"
169
+ puts 'Connecting with Pivotal Tracker'
172
170
  @p.get_project
173
171
 
174
172
  unless @p.is_current_branch_a_story?
@@ -177,29 +175,29 @@ module StoryBranch
177
175
  end
178
176
 
179
177
  if GitUtils.has_status? :untracked or GitUtils.has_status? :modified
180
- puts "There are unstaged changes"
181
- puts "Use git add to stage changes before running git finish"
182
- puts "Use git stash if you want to hide changes for this commit"
178
+ puts 'There are unstaged changes'
179
+ puts 'Use git add to stage changes before running git finish'
180
+ puts 'Use git stash if you want to hide changes for this commit'
183
181
  return nil
184
182
  end
185
183
 
186
184
  unless GitUtils.has_status? :added or GitUtils.has_status? :staged
187
- puts "There are no staged changes."
188
- puts "Nothing to do"
185
+ puts 'There are no staged changes.'
186
+ puts 'Nothing to do'
189
187
  return nil
190
188
  end
191
189
 
192
- puts "Use standard finishing commit message: [y/N]?"
190
+ puts 'Use standard finishing commit message: [y/N]?'
193
191
  commit_message = "[Finishes ##{GitUtils.current_branch_story_parts[:id]}] #{StringUtils.undashed GitUtils.current_branch_story_parts[:title]}"
194
192
  puts commit_message
195
193
 
196
- if gets.chomp!.downcase == "y"
194
+ if gets.chomp!.downcase == 'y'
197
195
  GitUtils.commit commit_message
198
196
  else
199
- puts "Aborted"
197
+ puts 'Aborted'
200
198
  end
201
- rescue RestClient::Unauthorized
202
- $stderr.puts "Pivotal API key or Project ID invalid"
199
+ rescue Blanket::Unauthorized
200
+ unauthorised_message
203
201
  return nil
204
202
  end
205
203
  end
@@ -235,23 +233,22 @@ module StoryBranch
235
233
  end
236
234
 
237
235
  def self.normalised_branch_name s
238
- simple_sanitize((dashed s).downcase).squeeze("-")
236
+ simple_sanitize((dashed s).downcase).squeeze('-')
239
237
  end
240
238
 
241
239
  def self.strip_newlines s
242
- s.tr "\n", "-"
240
+ s.tr '\n', '-'
243
241
  end
244
242
 
245
243
  def self.undashed s
246
- s.gsub(/-/, " ").capitalize
244
+ s.gsub(/-/, ' ').capitalize
247
245
  end
248
246
 
249
247
  end
250
248
 
251
249
  class GitUtils
252
-
253
250
  def self.g
254
- Git.open "."
251
+ Git.open '.'
255
252
  end
256
253
 
257
254
  def self.is_existing_branch? name
@@ -321,7 +318,7 @@ module StoryBranch
321
318
  untracked_rx = /^\?\? (.*)/
322
319
  staged_rx = /^M (.*)/
323
320
  added_rx = /^A (.*)/
324
- status = g.lib.send(:command, "status", "-s").lines
321
+ status = g.lib.send(:command, 'status', '-s').lines
325
322
  return nil if status.length == 0
326
323
  {
327
324
  modified: status_collect(status, modified_rx),
@@ -343,16 +340,25 @@ module StoryBranch
343
340
  end
344
341
 
345
342
  class PivotalUtils
346
-
347
- attr_accessor :api_key, :project_id, :project
343
+ API_URL = 'https://www.pivotaltracker.com/services/v5/'
344
+ attr_accessor :api_key, :project_id
348
345
 
349
346
  def valid?
350
- return (not @api_key.nil? and not @project_id.nil?)
347
+ !@api_key.nil? && !@project_id.nil?
348
+ end
349
+
350
+ def api
351
+ fail 'API key must be specified' unless @api_key
352
+ Blanket.wrap API_URL, headers: { 'X-TrackerToken' => @api_key }
351
353
  end
352
354
 
353
355
  def get_project
354
- PivotalTracker::Client.token = @api_key
355
- @project = PivotalTracker::Project.find @project_id.to_i
356
+ fail 'Project ID must be set' unless @project_id
357
+ api.projects(@project_id.to_i)
358
+ end
359
+
360
+ def story_accessor
361
+ get_project.stories
356
362
  end
357
363
 
358
364
  def is_current_branch_a_story?
@@ -364,21 +370,22 @@ module StoryBranch
364
370
  end
365
371
 
366
372
  def story_from_current_branch
367
- get_project.stories.find(GitUtils.current_story[2].to_i) if GitUtils.current_story.length == 3
373
+ story_accessor.get(GitUtils.current_story[2].to_i) if GitUtils.current_story.length == 3
368
374
  end
369
375
 
370
- # TODO: Add some other predicates as we need them...
371
- # Filtering on where a story lives (Backlog, IceBox)
372
- # Filtering on tags/labels
373
-
376
+ # TODO: Maybe add some other predicates
377
+ # - Filtering on where a story lives (Backlog, IceBox)
378
+ # - Filtering on labels
379
+ # as the need arises...
380
+ #
374
381
  def filtered_stories_list state, estimated
375
- project = get_project
376
- stories = project.stories.all({current_state: state})
382
+ options = { with_state: state.to_s }
383
+ stories = [* story_accessor.get(params: options).payload]
377
384
  if estimated
378
- stories.select{|s|
379
- s.story_type == "bug" or
380
- s.story_type == "chore" or
381
- (s.story_type == "feature" and s.estimate and s.estimate >= 0)}
385
+ stories.select do |s|
386
+ s.story_type == 'bug' || s.story_type == 'chore' ||
387
+ (s.story_type == 'feature' && s.estimate && s.estimate >= 0)
388
+ end
382
389
  else
383
390
  stories
384
391
  end
@@ -394,11 +401,9 @@ module StoryBranch
394
401
 
395
402
  def select_story stories
396
403
  story_texts = stories.map{|s| one_line_story s }
397
- puts "Leave blank to exit, use <up>/<down> to scroll through stories, TAB to list all and auto-complete"
398
- story_selection = readline("Select a story: ", story_texts)
399
- if story_selection == "" or story_selection.nil?
400
- return nil
401
- end
404
+ puts 'Leave blank to exit, use <up>/<down> to scroll through stories, TAB to list all and auto-complete'
405
+ story_selection = readline('Select a story: ', story_texts)
406
+ return nil if story_selection == '' or story_selection.nil?
402
407
  story = stories.select{|s| story_matcher s, story_selection }.first
403
408
  if story.nil?
404
409
  puts "Not found: #{story_selection}"
@@ -409,6 +414,10 @@ module StoryBranch
409
414
  end
410
415
  end
411
416
 
417
+ def story_update story, hash
418
+ get_project.stories(story.id).put(body: hash).payload
419
+ end
420
+
412
421
  def story_matcher story, selection
413
422
  m = selection.match(/^(\d*) /)
414
423
  return false unless m
@@ -420,9 +429,9 @@ module StoryBranch
420
429
  dashed_story_name = StringUtils.normalised_branch_name story.name
421
430
  feature_branch_name = nil
422
431
  puts "You are checked out at: #{GitUtils.current_branch}"
423
- while feature_branch_name == nil or feature_branch_name == ""
424
- puts "Provide a new branch name... (TAB for suggested name)" if [nil, ""].include? feature_branch_name
425
- feature_branch_name = readline("Name of feature branch: ", [dashed_story_name])
432
+ while feature_branch_name == nil or feature_branch_name == ''
433
+ puts 'Provide a new branch name... (TAB for suggested name)' if [nil, ''].include? feature_branch_name
434
+ feature_branch_name = readline('Name of feature branch: ', [dashed_story_name])
426
435
  end
427
436
  feature_branch_name.chomp!
428
437
  if validate_branch_name feature_branch_name, story.id
@@ -439,7 +448,7 @@ module StoryBranch
439
448
  return false
440
449
  end
441
450
  if GitUtils.is_existing_branch? name
442
- puts "Error: This name is very similar to an existing branch. Avoid confusion and use a more unique name."
451
+ puts 'Error: This name is very similar to an existing branch. Avoid confusion and use a more unique name.'
443
452
  return false
444
453
  end
445
454
  unless valid_branch_name? name
@@ -461,9 +470,9 @@ module StoryBranch
461
470
  RbReadline.clear_history
462
471
  if completions.length > 0
463
472
  completions.each {|i| Readline::HISTORY.push i}
464
- RbReadline.rl_completer_word_break_characters = ""
465
- Readline.completion_proc = proc {|s| completions.grep(/#{Regexp.escape(s)}/) }
466
- Readline.completion_append_character = ""
473
+ RbReadline.rl_completer_word_break_characters = ''
474
+ Readline.completion_proc = proc { |s| completions.grep(/#{Regexp.escape(s)}/) }
475
+ Readline.completion_append_character = ''
467
476
  end
468
477
  Readline.readline(prompt, false)
469
478
  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.7
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Milkins
@@ -12,22 +12,22 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-04-14 00:00:00.000000000 Z
15
+ date: 2015-05-12 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
- name: pivotal-tracker
18
+ name: blanket_wrapper
19
19
  requirement: !ruby/object:Gem::Requirement
20
20
  requirements:
21
21
  - - "~>"
22
22
  - !ruby/object:Gem::Version
23
- version: '0.5'
23
+ version: '3.0'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
28
  - - "~>"
29
29
  - !ruby/object:Gem::Version
30
- version: '0.5'
30
+ version: '3.0'
31
31
  - !ruby/object:Gem::Dependency
32
32
  name: git
33
33
  requirement: !ruby/object:Gem::Requirement
@@ -84,6 +84,20 @@ dependencies:
84
84
  - - "~>"
85
85
  - !ruby/object:Gem::Version
86
86
  version: '3.0'
87
+ - !ruby/object:Gem::Dependency
88
+ name: byebug
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - "~>"
92
+ - !ruby/object:Gem::Version
93
+ version: '4.0'
94
+ type: :development
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - "~>"
99
+ - !ruby/object:Gem::Version
100
+ version: '4.0'
87
101
  description: Simple gem that fetches the available stories in your pivotaltracker
88
102
  project and allows you to create a git branch with the name based on the selected
89
103
  story