story_branch 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 0f515e7349d6e9e3c97deb9036626e0b609a4961
4
+ data.tar.gz: 7cf773b74675fd4060b5c7f664b0dd4dcad6d87d
5
+ SHA512:
6
+ metadata.gz: 1146269635ae3f44f03aae8da7556fb566a65648997ae107aa59531958a800589eccf0129bc2c0661d80ddd7150b6a9910808890f8a780fbb770b9b889022e00
7
+ data.tar.gz: e39bee90b82d67fd713e9a8155c756b9b9b548f2552c9aaef89a694a9f305ad7561a4f97daa33483c31e5332f46a9d81d95c396b80c3f24b618663fc6428c093
data/LICENCE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Jason Milkins, Gabe Hollombe, Rui Baltazar, Dominic Wong
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,114 @@
1
+ [![Gem Version](https://badge.fury.io/rb/story_branch.png)](http://badge.fury.io/rb/story_branch)
2
+
3
+ # Story Branch
4
+
5
+ Create a git feature branch with automatic reference to a Pivotal Tracker Story
6
+
7
+ By default `story_branch` will present a list of started stories from
8
+ your Pivotal Tracker project, you select one and then provide
9
+ a feature branch name for that story. The branch will be created and
10
+ the name will include the selected `story_id` as a suffix.
11
+
12
+ When picking a story, enter the selection number on the left, using the up
13
+ arrow (or C-p) will scroll through the selection numbers.
14
+
15
+ Once a story is selected, a feature branch name can be entered, a
16
+ suggestion is provided (press the up arrow (or C-p) to see it)
17
+
18
+ The feature branch name input has full
19
+ [Readline](http://tiswww.case.edu/php/chet/readline/rluserman.html#SEC5)
20
+ capability, to make it easy and pleasant to edit.
21
+
22
+ ## Setup
23
+
24
+ Install the gem:
25
+
26
+ gem install story_branch
27
+
28
+ Config the Pivotal API key and Project ID, either in the environment
29
+ or using a config YAML file. (`.story_branch` in the git root, or
30
+ `~/.story_branch`)
31
+
32
+ The environment variables to set are `PIVOTAL_API_KEY` and `PIVOTAL_PROJECT_ID`
33
+
34
+ The **Pivotal API** key is visble at the bottom of your Pivotal Tracker
35
+ Profile page when you're logged in. the **Project ID** is in the URL for
36
+ your pivotal project.
37
+
38
+ If you decide to use the `.story_branch` config file, it should look
39
+ something like:
40
+
41
+ project: 123456
42
+ api: REHTKHMYKEYISM328974Y32487AND_SO_ON
43
+
44
+ Or just:
45
+
46
+ project: 123456
47
+
48
+ Replace the values with your own. Any value not found in the config
49
+ will attempt to be set from the environment. An error is thrown for a
50
+ value that cannot be found anywhere.
51
+
52
+ Note, that only one config file will be used at the moment, values
53
+ **CANNOT** currently be split over `.story_branch` in the git root and
54
+ `~/.story_branch`
55
+
56
+ ## Usage
57
+
58
+ While checked out at your master branch, and located in the git root.
59
+
60
+ story_branch
61
+
62
+ Follow the directions on screen. When the process is finished, you'll
63
+ be switched automatically to the newly created branch.
64
+
65
+ ## Aliases
66
+
67
+ You can also run story branch using the following aliases.
68
+
69
+ git story
70
+
71
+ git story-branch
72
+
73
+ story-branch
74
+
75
+
76
+ ## Roadmap
77
+
78
+ Prepare a v1.0 release
79
+
80
+ ## Changelog
81
+
82
+ * Banish constraint of master as parent branch
83
+ * Verify API key / Project ID
84
+ * Update config method to use YAML .story_branch files (in git root or $HOME) see above.
85
+ * Build/Publish as Ruby gem
86
+ * Simple sanitization
87
+ * Begin test coverage
88
+ * Refactor to class
89
+ * Provide readline editing for inputs
90
+ * Present safe version of story name (dash-cased) for editing
91
+ * Readline history injection for story selection & branch name suggestion
92
+ * Validate that branchname is 'legal'
93
+ * Validate that branchname doesn't already exist (strip pivotal
94
+ tracker ids suffix from existing names when present)
95
+ * Use Levenshtein Distance to determine if name is (very) similar to
96
+ existing branch names
97
+ * Use Git gem
98
+ * Use ActiveSupport gem
99
+ * Use Levenschtein-ffi gem
100
+ * ~~Look for pivotal project id (.pivotal-id) in repo root (we assume
101
+ we're in project root.) fallback to `PIVOTAL_PROJECT_ID` environment
102
+ var~~ **PLEASE NOTE:** Now uses `.story_branch` or `~/.story_branch`
103
+ as config file, containing YAML. Only one is used, the local root
104
+ `.story_branch` is favoured.
105
+
106
+ ## Contributing
107
+
108
+ If you'd like to contribute to `story_branch` please follow the steps below.
109
+
110
+ * Fork, start a feature branch and check it out
111
+ * Write tests / Pass them
112
+ * Send a pull request
113
+
114
+ **Note:** Pull requests require full test coverage to be accepted.
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'story_branch'
3
+ # require_relative '../lib/story_branch'
4
+
5
+ sb = StoryBranch.new()
6
+ sb.connect
data/bin/git-story ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'story_branch'
3
+ # require_relative '../lib/story_branch'
4
+
5
+ sb = StoryBranch.new()
6
+ sb.connect
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'story_branch'
3
+ # require_relative '../lib/story_branch'
4
+
5
+ sb = StoryBranch.new()
6
+ sb.connect
data/bin/story-branch ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'story_branch'
3
+ # require_relative '../lib/story_branch'
4
+
5
+ sb = StoryBranch.new()
6
+ sb.connect
data/bin/story_branch ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'story_branch'
3
+ # require_relative '../lib/story_branch'
4
+
5
+ sb = StoryBranch.new()
6
+ sb.connect
@@ -0,0 +1,214 @@
1
+ # Name: story_branch (recommend: setting a git alias as "git story")
2
+ #
3
+ # Authors: Jason Milkins <jason@opsmanager.com>
4
+ # Rui Baltazar <rui.p.baltazar@gmail.com>
5
+ # Gabe Hollombe <gabe@neo.com>
6
+ # Dominic Wong <dominic.wong.617@gmail.com>
7
+ #
8
+ # Version: 0.1.8
9
+ #
10
+ # Description:
11
+ #
12
+ # Create a git branch with automatic reference to a Pivotal Tracker
13
+ # Story ID
14
+ #
15
+ # Commentary:
16
+ #
17
+ # By default story_branch will present a list of started stories from
18
+ # your active PivotalTracker project, you select one and then provide
19
+ # a feature branch name for that story. The branch will be created and
20
+ # the name will include the story_id as a suffix.
21
+ #
22
+ # When picking a story, enter the selection number on the left (up
23
+ # arrow / C-p will scroll through the numbers)
24
+ #
25
+ # Once a story is selected, a feature branch name must be entered, a
26
+ # suggestion is shown if you press up arrow / C-p
27
+ #
28
+ # Usage:
29
+ #
30
+ # Note: Run story_branch from the project root folder, with the
31
+ # master branch checked out, or an error will be thrown.
32
+ #
33
+ # You must have a PIVOTAL_API_KEY environment variable set to your
34
+ # Pivotal api key, and either a .pivotal-id file or PIVOTAL_PROJECT_ID
35
+ # environment variable set, (the file will supersede the environment
36
+ # variable)
37
+ #
38
+
39
+ require 'yaml'
40
+ require 'pivotal-tracker'
41
+ require 'readline'
42
+ require 'git'
43
+ require 'levenshtein'
44
+
45
+ class StoryBranch
46
+
47
+ # Config file = .pivotal or ~/.pivotal
48
+ # contains YAML
49
+ # project: pivotal-id
50
+ # api: pivotal api key
51
+
52
+ # NOTE: Is this Windows friendly? Await freak-outs from those users... *crickets*
53
+ PIVOTAL_CONFIG_FILES = ['.story_branch',"#{ENV['HOME']}/.story_branch"]
54
+
55
+ def initialize
56
+ if config_file
57
+ @pivotal_info = YAML.load_file config_file
58
+ end
59
+
60
+ @api_key = config_value "api", 'PIVOTAL_API_KEY'
61
+ @project_id = config_value "project", 'PIVOTAL_PROJECT_ID'
62
+ end
63
+
64
+ def config_file
65
+ PIVOTAL_CONFIG_FILES.select{|conf| File.exists? conf}.first
66
+ end
67
+
68
+ def config_value key, env
69
+ value = @pivotal_info[key] if @pivotal_info and @pivotal_info[key]
70
+ value ||= env_required env
71
+ value
72
+ end
73
+
74
+ def connect
75
+ begin
76
+ pivotal_story_branch @api_key, @project_id
77
+ rescue RestClient::Unauthorized
78
+ puts "Pivotal API key or Project ID invalid"
79
+ exit
80
+ end
81
+ end
82
+
83
+ def valid?
84
+ return (not @api_key.strip.empty? and not @project_id.strip.empty?)
85
+ end
86
+
87
+ private
88
+ def env_required var_name
89
+ if ENV[var_name].nil?
90
+ puts "$#{var_name} must be set or in .story_branch file"
91
+ exit
92
+ end
93
+ ENV[var_name]
94
+ end
95
+
96
+ def readline prompt, history=[]
97
+ if history.length > 0
98
+ history.each {|i| Readline::HISTORY.push i}
99
+ end
100
+ begin
101
+ Readline.readline(prompt, false)
102
+ rescue Interrupt
103
+ exit
104
+ end
105
+ end
106
+
107
+ def dashed s
108
+ s.tr(' _,./:;', '-')
109
+ end
110
+
111
+ def simple_sanitize s
112
+ s.tr '\'"%!@#$(){}[]*\\?', ''
113
+ end
114
+
115
+ # Branch name validation
116
+ def validate_branch_name name
117
+ unless valid_branch_name? name
118
+ puts "Error: #{name}\nis an invalid name."
119
+ return false
120
+ end
121
+ existing_name_score = is_existing_branch?(name)
122
+ unless existing_name_score == -1
123
+ puts <<-END.strip_heredoc
124
+ Name Collision Error:
125
+
126
+ #{name}
127
+
128
+ This is too similar to the name of an existing
129
+ branch, a more unique name is required
130
+ END
131
+ end
132
+ end
133
+
134
+ def valid_branch_name? name
135
+ # Valid names begin with a letter and are followed by alphanumeric
136
+ # with _ . - as allowed punctuation
137
+ valid = /[a-zA-Z][-._0-9a-zA-Z]*/
138
+ name.match valid
139
+ end
140
+
141
+ # Git operations
142
+
143
+ def is_existing_branch? name
144
+ # we don't use the Git gem's is_local_branch? because we want to
145
+ # ignore the id suffix while still avoiding name collisions
146
+ git_branch_names.each do |n|
147
+ normalised_branch_name = simple_sanitize(dashed(n.match(/(^.*)(-[1-9][0-9]+$)?/)[1]))
148
+ levenshtein_distance = Levenshtein.distance normalised_branch_name, name
149
+ if levenshtein_distance < 2
150
+ return levenshtein_distance
151
+ end
152
+ end
153
+ return -1
154
+ end
155
+
156
+ def git_branch_names
157
+ g = Git.open "."
158
+ g.branches.map(&:name)
159
+ end
160
+
161
+ def git_current_branch
162
+ g = Git.open "."
163
+ g.current_branch
164
+ end
165
+
166
+ def git_create_branch name
167
+ g = Git.open "."
168
+ g.branch(name).create
169
+ g.branch(name).checkout
170
+ end
171
+
172
+ # Use Pivotal tracker API to get Stories
173
+
174
+ def list_pivotal_stories api_key, project_id
175
+ PivotalTracker::Client.token = api_key
176
+ project = PivotalTracker::Project.find(project_id.to_i)
177
+ stories = project.stories.all({current_state: :started})
178
+ stories.each_with_index{|s,i| puts "[#{i+1}] ##{s.id} : #{s.name}"}
179
+ stories
180
+ end
181
+
182
+ def select_story stories
183
+ story_selection = nil
184
+ while story_selection == nil or story_selection == 0 or story_selection > stories.length + 1
185
+ puts "invalid selection" if story_selection != nil
186
+ story_selection = readline("Select a story: ", Range.new(1,stories.length).to_a.map(&:to_s)).to_i
187
+ end
188
+ story = stories[story_selection - 1]
189
+ puts "Selected : ##{story.id} : #{story.name}"
190
+ return story
191
+ end
192
+
193
+ def create_feature_branch story
194
+ current_branch = git_current_branch
195
+ dashed_story_name = simple_sanitize((dashed story.name).downcase).squeeze("-")
196
+ feature_branch_name = nil
197
+ puts "You are checked out at: #{current_branch}"
198
+ while feature_branch_name == nil or feature_branch_name == ""
199
+ puts "Provide a new branch name..." if [nil, ""].include? feature_branch_name
200
+ feature_branch_name = readline("Name of feature branch: ", [dashed_story_name])
201
+ end
202
+ feature_branch_name.chomp!
203
+ validate_branch_name feature_branch_name
204
+ feature_branch_name_with_story_id = "#{feature_branch_name}-#{story.id}"
205
+ puts "Creating: #{feature_branch_name_with_story_id} with #{current_branch} as parent"
206
+ git_create_branch feature_branch_name_with_story_id
207
+ end
208
+
209
+ def pivotal_story_branch api_key, project_id
210
+ stories = list_pivotal_stories api_key, project_id
211
+ story = select_story stories
212
+ create_feature_branch story
213
+ end
214
+ end
metadata ADDED
@@ -0,0 +1,121 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: story_branch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.8
5
+ platform: ruby
6
+ authors:
7
+ - Jason Milkins
8
+ - Gabe Hollombe
9
+ - Rui Baltazar
10
+ - Dominic Wong
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2014-06-24 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: pivotal-tracker
18
+ requirement: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - "~>"
21
+ - !ruby/object:Gem::Version
22
+ version: '0.5'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.5'
30
+ - !ruby/object:Gem::Dependency
31
+ name: git
32
+ requirement: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - "~>"
35
+ - !ruby/object:Gem::Version
36
+ version: '1.2'
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.2'
44
+ - !ruby/object:Gem::Dependency
45
+ name: levenshtein-ffi
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.0'
51
+ type: :runtime
52
+ prerelease: false
53
+ version_requirements: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec
60
+ requirement: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ type: :development
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ description: Simple gem that fetches the available stories in your pivotaltracker
73
+ project and allows you to create a git branch with the name based on the selected
74
+ story
75
+ email:
76
+ - jasonm23@gmail.com
77
+ - gabe@neo.com
78
+ - rui.p.baltazar@gmail.com
79
+ - dominic.wong.617@gmail.com
80
+ executables:
81
+ - story_branch
82
+ - story-branch
83
+ - git-story
84
+ - git-story-branch
85
+ - git-pivotal-story
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - LICENCE
90
+ - README.md
91
+ - bin/git-pivotal-story
92
+ - bin/git-story
93
+ - bin/git-story-branch
94
+ - bin/story-branch
95
+ - bin/story_branch
96
+ - lib/story_branch.rb
97
+ homepage: https://github.com/jasonm23/pivotal-story-branch
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 1.9.3
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.2.2
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: Story Branch - create git branches based on pivotal tracker stories
121
+ test_files: []