git-scripts 0.4.0 → 0.5.0

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -0
  3. data/bin/feature +81 -32
  4. data/bin/hotfix +40 -4
  5. data/completion/_feature +2 -1
  6. data/completion/bash_completion.sh +2 -2
  7. data/lib/github.rb +32 -6
  8. data/lib/helpers.rb +17 -6
  9. data/lib/plugins.rb +25 -0
  10. data/man/feature-finish-issue.1 +2 -2
  11. data/man/feature-finish-issue.1.ronn +1 -1
  12. data/man/feature-finish.1 +1 -1
  13. data/man/feature-switch.1 +12 -2
  14. data/man/feature-switch.1.ronn +5 -2
  15. data/man/feature-url.1 +22 -0
  16. data/man/feature-url.1.ronn +23 -0
  17. data/man/feature.1 +9 -1
  18. data/man/feature.1.ronn +4 -0
  19. data/man/hotfix-finish-issue.1 +2 -2
  20. data/man/hotfix-finish-issue.1.ronn +1 -1
  21. data/man/hotfix-finish.1 +1 -1
  22. data/man/hotfix-switch.1 +17 -1
  23. data/man/hotfix-switch.1.ronn +10 -2
  24. data/man/hotfix-url.1 +22 -0
  25. data/man/hotfix-url.1.ronn +23 -0
  26. data/man/hotfix.1 +9 -1
  27. data/man/hotfix.1.ronn +4 -0
  28. metadata +45 -78
  29. data/man/feature-clean.1.html +0 -120
  30. data/man/feature-clean.1.markdown +0 -61
  31. data/man/feature-finish-issue.1.html +0 -113
  32. data/man/feature-finish-issue.1.markdown +0 -56
  33. data/man/feature-finish.1.html +0 -113
  34. data/man/feature-finish.1.markdown +0 -56
  35. data/man/feature-github-test.1.html +0 -110
  36. data/man/feature-github-test.1.markdown +0 -53
  37. data/man/feature-list.1.html +0 -119
  38. data/man/feature-list.1.markdown +0 -60
  39. data/man/feature-merge.1.html +0 -116
  40. data/man/feature-merge.1.markdown +0 -59
  41. data/man/feature-prune.1.html +0 -116
  42. data/man/feature-prune.1.markdown +0 -60
  43. data/man/feature-start.1.html +0 -110
  44. data/man/feature-start.1.markdown +0 -53
  45. data/man/feature-stashes.1.html +0 -122
  46. data/man/feature-stashes.1.markdown +0 -63
  47. data/man/feature-status.1.html +0 -113
  48. data/man/feature-status.1.markdown +0 -56
  49. data/man/feature-switch.1.html +0 -120
  50. data/man/feature-switch.1.markdown +0 -61
  51. data/man/feature.1.html +0 -129
  52. data/man/feature.1.markdown +0 -80
  53. data/man/hotfix-finish-issue.1.html +0 -113
  54. data/man/hotfix-finish-issue.1.markdown +0 -56
  55. data/man/hotfix-finish.1.html +0 -112
  56. data/man/hotfix-finish.1.markdown +0 -55
  57. data/man/hotfix-list.1.html +0 -119
  58. data/man/hotfix-list.1.markdown +0 -60
  59. data/man/hotfix-merge.1.html +0 -116
  60. data/man/hotfix-merge.1.markdown +0 -59
  61. data/man/hotfix-start.1.html +0 -110
  62. data/man/hotfix-start.1.markdown +0 -53
  63. data/man/hotfix-switch.1.html +0 -112
  64. data/man/hotfix-switch.1.markdown +0 -55
  65. data/man/hotfix.1.html +0 -123
  66. data/man/hotfix.1.markdown +0 -68
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a2d6d6518dbc7ecc8f65e1d05f2d726198bbd74
4
- data.tar.gz: 676e53c8cc96c98d13745280205c74108d7aa281
3
+ metadata.gz: af70a37bea46ed2bb2c96555972ca8a4be70a0a2
4
+ data.tar.gz: c9398a71ddcfb1b623c12fbf08db5ffabb465fa1
5
5
  SHA512:
6
- metadata.gz: 4d8177e27268f8eb876a17936a196364c7bb633c2ded649e4a715fa22fd6a8d8f6895e7dbe8d57122f03bab8d1ff75291bb46744b0ede02568fa1766c80efeab
7
- data.tar.gz: 05cb8fd81e03130a108f45be0d1802cbc5d1bf2ef5faf2250958f2714a87c69a8f3f8c05838cbef976fc727c6cd2b5d9615394cd99f6ad4ace0bc6b9ade6c5d9
6
+ metadata.gz: b3a9bc18372e11269d784c3f60ddced3853e286ee4bf13ae4586f08ce17831098f5f00b6039f8b94294871c89fcab912991f462cd76126bd4da1e2532f59feb8
7
+ data.tar.gz: fb056a372806a58a188d6e6418486d71903f3c3d9372dbcf30109c9741f32ee8ce08b9e45c085b38f8c94c88fff0ce374360c3c302197d67c5d11a6289830c19
data/README.md CHANGED
@@ -124,3 +124,11 @@ Merges the hotfix branch back into `stable` with `--no-ff`. Also does a
124
124
  merge back into `master`.
125
125
 
126
126
  [gitflow]: http://nvie.com/posts/a-successful-git-branching-model/
127
+
128
+ ## Plugins
129
+
130
+ Any files matching `plugins/*.rb` will be loaded as plugins. The plugin
131
+ architecture is *very* simple. There are a few hooks scattered over the
132
+ code-base of the form: `Plugins.invoke :before_start, :feature`. If a plugin
133
+ has a method of the same name `before_start` it will be called, passing along
134
+ any arguments passed to `Plugins.invoke`.
@@ -3,6 +3,7 @@ require_relative '../lib/signal_handlers.rb'
3
3
  require_relative '../lib/github.rb'
4
4
  require_relative '../lib/git.rb'
5
5
  require_relative '../lib/helpers.rb'
6
+ require_relative '../lib/plugins.rb'
6
7
 
7
8
  command=ARGV.first
8
9
 
@@ -16,21 +17,22 @@ end
16
17
 
17
18
  case command
18
19
  when 'github-test'
19
- octokit = Github::api
20
20
  # Should succeed if authentication is setup.
21
- octokit.pulls(Github::get_github_repo)
21
+ Github.pulls
22
22
  puts "[Successfully Authenticated]"
23
23
 
24
24
  when 'start'
25
25
  require_argument(:feature, :start)
26
26
  feature = ARGV[1]
27
27
 
28
- exit unless confirm("Create feature branch named: '#{feature}' ?")
29
28
  development_branch = Git::get_branch('development')
30
29
 
30
+ Plugins.invoke :before_start, :feature, feature
31
+
31
32
  Git::run_safe([
32
33
  "git checkout #{development_branch}",
33
- "git pull --rebase",
34
+ "git fetch",
35
+ "git rebase --preserve-merges origin/#{development_branch}",
34
36
  "git branch \"#{feature}\" #{development_branch}",
35
37
  "git checkout \"#{feature}\"",
36
38
  ])
@@ -83,12 +85,19 @@ when 'status'
83
85
 
84
86
  when 'finish'
85
87
  feature = ARGV[1] || Git::current_branch
88
+
89
+ if is_hotfix_branch feature
90
+ abort "This is a hotfix branch. Please use hotfix-finish."
91
+ end
92
+
86
93
  # Push commits to origin
87
94
  Git::run_safe(["git push origin #{feature}:#{feature}"])
88
95
 
89
96
  exit 1 unless confirm("Create a pull-request for feature branch named: '#{feature}' ?")
90
97
  octokit = Github::api
91
98
 
99
+ Plugins.invoke :before_finish, :feature, feature
100
+
92
101
  description = Github::get_pull_request_description(feature)
93
102
  puts "Pull-request description:"
94
103
  puts description[:title]
@@ -103,6 +112,7 @@ when 'finish'
103
112
  description[:body]
104
113
  )
105
114
 
115
+ Plugins.invoke :after_finish, :feature, feature, response
106
116
  puts "Successfully created pull-request ##{response[:number]}"
107
117
  puts " " + response[:html_url]
108
118
 
@@ -110,6 +120,11 @@ when 'finish-issue'
110
120
  require_argument(:feature, :'finish-issue')
111
121
  issue = ARGV[1]
112
122
  feature = Git::current_branch
123
+
124
+ if is_hotfix_branch feature
125
+ abort "This is a hotfix branch. Please use hotfix-finish-issue."
126
+ end
127
+
113
128
  # Push commits to origin
114
129
  Git::run_safe(["git push origin #{feature}:#{feature}"])
115
130
 
@@ -166,6 +181,9 @@ when 'merge'
166
181
  feature = ARGV[1] || Git::current_branch
167
182
  end
168
183
 
184
+ if is_hotfix_branch feature
185
+ exit 1 unless confirm("It looks like this is a hotfix branch. Are you sure you want to merge it into only #{dev_branch}?")
186
+ end
169
187
 
170
188
  pull_info = Github::get_pull_request_info_from_api(feature, dev_branch)
171
189
 
@@ -174,6 +192,8 @@ when 'merge'
174
192
  puts highlight(warning)
175
193
  end
176
194
 
195
+ Plugins.invoke :before_merge, :feature, feature
196
+
177
197
  exit 1 unless confirm("Merge feature branch named: '#{feature}' ?")
178
198
 
179
199
  update = Git::submodules_update("get")
@@ -195,6 +215,8 @@ when 'merge'
195
215
  "git branch -d \"#{feature}\""
196
216
  ])
197
217
 
218
+ Plugins.invoke :after_merge, :feature, feature
219
+
198
220
  puts
199
221
  puts "Successfully merged feature-branch: #{feature} into #{dev_branch}"
200
222
  puts "If you are satisfied with the result, do this:\n" + <<CMDS
@@ -203,7 +225,7 @@ CMDS
203
225
 
204
226
  when 'switch'
205
227
 
206
- require_argument(:feature, :switch, min=2, max=4)
228
+ require_argument(:feature, :switch, min=2, max=5)
207
229
 
208
230
  feature = ARGV[1]
209
231
 
@@ -213,6 +235,20 @@ when 'switch'
213
235
 
214
236
  Git::switch_branch(feature)
215
237
 
238
+ optional_pull
239
+
240
+ when 'url'
241
+ require_argument(:feature, :url, min=1, max=2)
242
+ feature = ARGV[1] || Git::current_branch
243
+
244
+ url = Github::get_url(feature)
245
+ if url
246
+ puts url
247
+ else
248
+ abort "There is no pull request available for #{feature}.\n" +
249
+ 'You can make one by using `feature finish`.'
250
+ end
251
+
216
252
  when 'prune'
217
253
  require_argument(:feature, :prune, min=3, max=3)
218
254
  location = ARGV[1]
@@ -227,52 +263,65 @@ when 'prune'
227
263
  abort("Valid options: preview, clean.")
228
264
  end
229
265
 
230
- currentBranch = Git::current_branch()
266
+ current_branch = Git::current_branch()
231
267
  development_branch = Git::get_branch('development')
232
268
  stable_branch = Git::get_branch('stable')
233
269
 
234
- def branches_cmd(location, currentBranch)
235
- branch = location == 'origin' ? "origin/#{development_branch}" : development_branch
236
- return "git branch --merged #{branch} |
237
- grep -v #{development_branch} |
238
- grep -v #{stable_branch} |
239
- grep -v #{currentBranch}"
270
+ # Returns a shell command that will output a list of branches that can be
271
+ # safely pruned (are merged into the development_branch).
272
+ # Note: if location != 'local' this will return remote branches
273
+ branches_cmd = lambda do
274
+ if location == 'local'
275
+ branch = development_branch
276
+ options = ''
277
+ prefix=''
278
+ else
279
+ branch = "#{location}/#{development_branch}"
280
+ options = '--remotes'
281
+ prefix='origin/'
282
+ end
283
+ return "git branch #{options} --merged #{esc branch} |
284
+ sed 's/^* //g' | sed 's/^\s*//' |
285
+ grep --invert-match --line-regexp \
286
+ --regexp=#{esc (prefix + development_branch)} \
287
+ --regexp=#{esc (prefix + stable_branch)} \
288
+ --regexp=#{esc (prefix + current_branch)}"
240
289
  end
241
290
 
242
- def preview(location, currentBranch)
291
+ preview = lambda do
243
292
  puts "Would delete the following..."
244
- commands = branches_cmd(location, currentBranch)
245
293
 
246
- if location == "local"
247
- system(commands)
248
- elsif location == "origin"
249
- message = `git remote prune -n origin && #{commands}`
250
- puts message.gsub(" * [would prune] origin/",'')
294
+ system(branches_cmd.call)
295
+
296
+ if location != "local"
297
+ system("git remote prune --dry-run #{esc location}")
251
298
  end
252
299
  end
253
300
 
254
- def delete(location, currentBranch)
301
+ delete = lambda do |preview = true|
255
302
  puts "Deleting..."
256
- commands = branches_cmd(location, currentBranch)
257
303
 
258
304
  if location == "local"
259
- system("#{commands} | xargs git branch -d")
260
- elsif location == "origin"
261
- system("git remote prune origin &&
262
- git branch -r --merged origin/#{development_branch} |
263
- grep -v #{development_branch} |
264
- grep -v #{stable_branch} |
265
- grep -v #{currentBranch} |
266
- sed -n 's| origin/|:|p' |
267
- xargs git push origin")
305
+ action_command = "xargs git branch -d"
306
+ else
307
+ sed_str = "s|^#{location}/|:|p"
308
+ action_command = "sed -n #{esc sed_str} | xargs git push origin &&
309
+ git remote prune #{esc location}"
268
310
  end
311
+
312
+ if `#{branches_cmd.call}`.empty?
313
+ puts "No branches need to be pruned"
314
+ return
315
+ end
316
+
317
+ system("#{branches_cmd.call} | #{action_command}")
269
318
  end
270
319
 
271
320
  if option == 'preview'
272
- preview(location, currentBranch)
321
+ preview.call
273
322
  elsif option == 'clean'
274
323
  exit unless confirm("Are you sure you want to prune branches?")
275
- delete(location, currentBranch)
324
+ delete.call
276
325
  end
277
326
 
278
327
  when 'clean'
data/bin/hotfix CHANGED
@@ -3,6 +3,7 @@ require_relative '../lib/signal_handlers.rb'
3
3
  require_relative '../lib/github.rb'
4
4
  require_relative '../lib/git.rb'
5
5
  require_relative '../lib/helpers.rb'
6
+ require_relative '../lib/plugins.rb'
6
7
 
7
8
  command=ARGV.first
8
9
 
@@ -20,11 +21,12 @@ when 'start'
20
21
  hotfix = hotfix_branch(ARGV[1])
21
22
  stable_branch = Git::get_branch('stable')
22
23
 
23
- exit unless confirm("Create hotfix branch named: '#{hotfix}' ?")
24
+ Plugins.invoke :before_start, :hotfix, hotfix
24
25
 
25
26
  Git::run_safe([
26
27
  "git checkout #{stable_branch}",
27
- "git pull --rebase",
28
+ "git fetch",
29
+ "git rebase --preserve-merges origin/#{stable_branch}",
28
30
  "git branch \"#{hotfix}\" #{stable_branch}",
29
31
  "git checkout \"#{hotfix}\""
30
32
  ])
@@ -38,21 +40,42 @@ when 'start'
38
40
  "git config branch.#{hotfix}.rebase true"
39
41
  ])
40
42
 
43
+ when 'url'
44
+ require_argument(:hotfix, :url, min=1, max=2)
45
+ hotfix = ARGV[1] || Git::current_branch
46
+
47
+ url = Github::get_url(hotfix)
48
+ if url
49
+ puts url
50
+ else
51
+ abort "There is no pull request available for #{hotfix}.\n" +
52
+ 'You can make one by using `hotfix finish`.'
53
+ end
54
+
55
+
41
56
  when 'switch'
42
- require_argument(:hotfix, :switch, min=2, max=3)
57
+ require_argument(:hotfix, :switch, min=2, max=5)
43
58
  hotfix = current_hotfix_branch
44
59
 
45
60
  Git::switch_branch(hotfix)
46
61
 
62
+ optional_pull
63
+
47
64
  when 'finish'
48
65
  hotfix = current_hotfix_branch
49
66
 
67
+ if !is_hotfix_branch hotfix
68
+ abort "This is a feature branch. Please use feature-finish."
69
+ end
70
+
50
71
  # Push commits to origin
51
72
  Git::run_safe(["git push origin #{hotfix}:#{hotfix}"])
52
73
 
53
74
  exit 1 unless confirm("Create a pull-request for hotfix branch named: '#{hotfix}' ?")
54
75
  octokit = Github::api
55
76
 
77
+ Plugins.invoke :before_finish, :hotfix, hotfix
78
+
56
79
  description = Github::get_pull_request_description(hotfix)
57
80
  puts "Pull-request description:"
58
81
  puts description[:title]
@@ -67,6 +90,7 @@ when 'finish'
67
90
  description[:body]
68
91
  )
69
92
 
93
+ Plugins.invoke :after_finish, :hotfix, hotfix, response
70
94
  puts "Successfully created pull-request ##{response[:number]}"
71
95
  puts " " + response[:html_url]
72
96
 
@@ -75,6 +99,10 @@ when 'finish-issue'
75
99
  issue = ARGV[1]
76
100
  hotfix = Git::current_branch
77
101
 
102
+ if !is_hotfix_branch hotfix
103
+ abort "This is a feature branch. Please use feature-finish-issue."
104
+ end
105
+
78
106
  # Push commits to origin
79
107
  Git::run_safe(["git push origin #{hotfix}:#{hotfix}"])
80
108
 
@@ -127,6 +155,10 @@ when 'merge'
127
155
  stable_branch = Git::get_branch('stable')
128
156
  hotfix = current_hotfix_branch
129
157
 
158
+ if !is_hotfix_branch hotfix
159
+ exit 1 unless confirm("It looks like this is a feature branch. Are you sure you want to merge it into #{stable_branch}?")
160
+ end
161
+
130
162
  Git::run_safe(["git fetch"])
131
163
 
132
164
  pull_info = Github::get_pull_request_info_from_api(hotfix, stable_branch)
@@ -136,6 +168,8 @@ when 'merge'
136
168
  puts highlight(warning)
137
169
  end
138
170
 
171
+ Plugins.invoke :before_merge, :hotfix, hotfix
172
+
139
173
  exit 1 unless confirm("Merge hotfix named: '#{hotfix}' ?")
140
174
 
141
175
  commit_message = Git::get_description_from_user(pull_info[:description])
@@ -157,7 +191,7 @@ when 'merge'
157
191
  # Merge into master.
158
192
  "git checkout #{dev_branch}",
159
193
  # Pull the latest changes and rebase the unpushed master commits if any.
160
- "git rebase origin/#{dev_branch}",
194
+ "git rebase --preserve-merges origin/#{dev_branch}",
161
195
  # Merge the hotfix branch into master.
162
196
  "git merge --no-ff --no-edit -m #{commit_message_dev.shellescape} \"#{hotfix}\"",
163
197
  # Init any submodules in the master branch. Note: no need to change.
@@ -170,6 +204,8 @@ when 'merge'
170
204
  "git checkout #{stable_branch}"
171
205
  ])
172
206
 
207
+ Plugins.invoke :after_merge, :hotfix, hotfix
208
+
173
209
  puts "Successfully merged hotfix branch: #{hotfix} into #{stable_branch} and #{dev_branch}"
174
210
  puts "If you are satisfied with the result, do this:\n" + <<CMDS
175
211
  git push
@@ -11,7 +11,7 @@ _feature() {
11
11
 
12
12
  case $state in
13
13
  commands)
14
- _arguments '1:Commands:(list start switch finish finish-issue merge pull prune status stashes clean github-test)'
14
+ _arguments '1:Commands:(list start switch finish finish-issue merge pull prune status stashes clean github-test url)'
15
15
  ;;
16
16
  params)
17
17
  if [[ "$words[2]" == "prune" ]]; then
@@ -19,6 +19,7 @@ _feature() {
19
19
  fi
20
20
  if [[ "$words[2]" == "switch" ||
21
21
  "$words[2]" == "merge" ||
22
+ "$words[2]" == "url" ||
22
23
  "$words[2]" == "finish" ]]; then
23
24
  local -a featureBranches args
24
25
  featureBranches="$(git branch -a | tr -d ' *' | grep -v 'hotfix-' | sed 's|remotes/origin/||')"
@@ -10,7 +10,7 @@ _git-scripts()
10
10
  case "$cmd" in
11
11
  feature)
12
12
  if [ "$line" = "$cmd $cur" ]; then
13
- words="switch start finish finish-issue stashes list merge pull status clean prune"
13
+ words="switch start finish finish-issue stashes list merge pull status clean prune url"
14
14
  else
15
15
  # get branch names minus hotfixes
16
16
  words="$(git branch -a | tr -d ' *' | grep -v 'hotfix-' | sed 's|remotes/origin/||')"
@@ -18,7 +18,7 @@ _git-scripts()
18
18
  ;;
19
19
  hotfix)
20
20
  if [ "$line" = "$cmd $cur" ]; then
21
- words="switch start finish finish-issue merge list clean"
21
+ words="switch start finish finish-issue merge list clean url"
22
22
  else
23
23
  # get hotfix branch names
24
24
  words="$(git branch -a | tr -d ' *' | grep 'hotfix-' | sed -e 's|remotes/origin/||' -e 's|hotfix-||')"
@@ -34,6 +34,8 @@ module Github
34
34
  # }
35
35
  ##
36
36
  def self.api(authorization_info = {})
37
+ # Let Octokit handle pagination automagically for us.
38
+ Octokit.auto_traversal = true
37
39
  # Defaults
38
40
  authorization_info = {
39
41
  :scopes => ['repo'],
@@ -120,6 +122,13 @@ Body of pull-request
120
122
  return self::open_title_body_editor(initial_message)
121
123
  end
122
124
 
125
+ ##
126
+ # Returns the most recent github commit status for a given commit
127
+ ##
128
+ def self.get_most_recent_commit_status(repo, sha)
129
+ api.statuses(repo, sha).sort_by {|status| status['id'] }.last
130
+ end
131
+
123
132
  ##
124
133
  # Prompts the user (using $EDITOR) to confirm the title and body
125
134
  # in the provided message.
@@ -133,6 +142,8 @@ Body of pull-request
133
142
  msg.write(message)
134
143
  msg.close
135
144
 
145
+ Plugins.invoke :pre_message_edit, msg.path
146
+
136
147
  editor = Git::editor
137
148
  if (editor == 'vim')
138
149
  opts = "'+set ft=gitcommit' '+set textwidth=72'" +
@@ -162,17 +173,19 @@ Body of pull-request
162
173
  }
163
174
  end
164
175
 
176
+ # Returns a URL based off the branch name.
177
+ def self.get_url(branch_name)
178
+ pull = self.pull_for_branch(branch_name)
179
+ return pull && pull[:html_url]
180
+ end
181
+
165
182
  def self.get_pull_request_info_from_api(branch_name, into_branch)
166
- octokit = Github::api
167
- # Should succeed if authentication is set up.
168
- repo = Github::get_github_repo
169
- pulls = octokit.pulls(repo)
170
- pull = pulls.find {|pull| branch_name == pull[:head][:ref] }
183
+ pull = self.pull_for_branch(branch_name)
171
184
 
172
185
  if pull
173
186
  # This will grab the latest commit and retrieve the state from it.
174
187
  sha = pull[:head][:sha]
175
- state = octokit.statuses(repo, sha).shift
188
+ state = self.get_most_recent_commit_status(get_github_repo, sha)
176
189
  state = state ? state[:state] : 'none'
177
190
 
178
191
  desc = <<-MSG
@@ -189,6 +202,19 @@ Merge #{branch_name} (##{pull[:number]}) into #{into_branch}
189
202
  end
190
203
  end
191
204
 
205
+ @@pulls = nil
206
+ def self.pulls
207
+ if !@@pulls
208
+ repo = get_github_repo
209
+ @@pulls = api.pulls(repo)
210
+ end
211
+ return @@pulls
212
+ end
213
+
214
+ def self.pull_for_branch(branch_name)
215
+ pull = self.pulls.find {|pull| branch_name == pull[:head][:ref] }
216
+ end
217
+
192
218
  def self.get_commit_status_warning(status)
193
219
  warning = 'Merge with caution.'
194
220
  case status