story_branch 0.2.7 → 0.2.8

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.
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