git_pr 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c87ac91486e6a5273bc76ffdd29e36669010d56f
4
+ data.tar.gz: 7503626a0aa947362e5f12c15c40818e3320244f
5
+ SHA512:
6
+ metadata.gz: 2f2710728e24a9ce6c7d5aaedfbc39cd2d948a21ed1e58f37adfc9c9b37b3024ef11d2341dc8404ea848f1f02524fe84f8ff091e675283f873cf3d26b431d6ad
7
+ data.tar.gz: c5026497f74f7a8979dccf51e54375c1d00b817f7521466ad5d49b63f4f1a535aa42adbcacbad7b27f0b7c75e8e67db95c141a9aa6ede2b1e3b0e22a9562c3c9
data/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in git_pr.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Brian Sharon
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # GitPr
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'git_pr'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install git_pr
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( https://github.com/[my-github-username]/git_pr/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
data/bin/git-pr ADDED
@@ -0,0 +1,380 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # Future improvements:
4
+ # 1) Use more git shell integration
5
+ # https://www.kernel.org/pub/software/scm/git/docs/git-sh-setup.html
6
+ # https://coderwall.com/p/bt93ia
7
+ # 2) Take a branch name instead of a PR number and Do The Right Thing
8
+
9
+
10
+ require 'colorize'
11
+ require 'git'
12
+ require 'highline/import'
13
+ require 'io/console'
14
+ require 'netrc'
15
+ require 'octokit'
16
+ require 'optparse'
17
+ require 'pp'
18
+ require 'git_pr'
19
+ require 'ostruct'
20
+
21
+ options = OpenStruct.new(:help => false,
22
+ :verbose => false,
23
+ :auth => OpenStruct.new(),
24
+ :list => OpenStruct.new(),
25
+ :merge => OpenStruct.new(:remote => "origin"),
26
+ :open => OpenStruct.new())
27
+
28
+ global_options = OptionParser.new do |opts|
29
+ opts.banner = "Usage: git pr [options] subcommand [options]"
30
+
31
+ opts.separator "\nGlobal options"
32
+
33
+ opts.on("-h", "--help", "Show help") do
34
+ options.help = true
35
+ end
36
+ opts.on("-v", "--verbose", "Verbose output") do
37
+ options.verbose = true
38
+ end
39
+ opts.on("-V", "--version", "Print version") do
40
+ puts GitPr::VERSION
41
+ exit
42
+ end
43
+
44
+ # auth: Check GitHub auth credentials, and prompt to update them if necessary
45
+ # list: List open pull requests
46
+ # open: Open the webpage for a pull request
47
+ opts.separator <<eos
48
+
49
+ Valid subcommands:
50
+ merge: Merge and close a pull request
51
+
52
+ eos
53
+ end
54
+
55
+ subcommands = {
56
+ # 'auth' => OptionParser.new do |opts|
57
+ # opts.banner = "Usage: git pr auth [options]"
58
+
59
+ # opts.separator "\nAuth command options"
60
+
61
+ # opts.on("-r", "--readonly", "Check without prompting") do |v|
62
+ # options.auth.readonly = true
63
+ # end
64
+
65
+ # opts.separator ""
66
+ # end,
67
+ # 'list' => OptionParser.new do |opts|
68
+ # opts.banner = "Usage: git pr list [options]"
69
+
70
+ # opts.separator "\nList command options"
71
+
72
+ # opts.on("-r", "--readonly", "Check without prompting") do |v|
73
+ # options.list.readonly = true
74
+ # end
75
+
76
+ # opts.separator ""
77
+ # end,
78
+ 'merge' => OptionParser.new do |opts|
79
+ opts.banner = "Usage: git pr merge [options] [PR number]"
80
+
81
+ opts.separator "\nMerge command options"
82
+
83
+ opts.on("-r", "--remote REMOTE", "Remote that PR will be merged into. Default: origin") do |remote|
84
+ puts remote
85
+ options.merge.remote = remote
86
+ end
87
+
88
+ opts.separator ""
89
+ end,
90
+ # 'open' => OptionParser.new do |opts|
91
+ # opts.banner = "Usage: git pr open [options]"
92
+
93
+ # opts.separator "\nOpen command options"
94
+
95
+ # opts.on("-r", "--readonly", "Check without prompting") do |v|
96
+ # options.open.readonly = true
97
+ # end
98
+
99
+ # opts.separator ""
100
+ # end
101
+ }
102
+
103
+ begin
104
+ global_options.order!
105
+ rescue OptionParser::InvalidOption => e
106
+ puts e
107
+ puts global_options
108
+ exit
109
+ end
110
+
111
+ command = ARGV.shift
112
+ if !subcommands[command]
113
+ puts global_options
114
+ exit
115
+ end
116
+
117
+ begin
118
+ options[command].additional_arguments = subcommands[command].permute!
119
+ rescue OptionParser::InvalidOption => e
120
+ puts e
121
+ puts subcommands[command]
122
+ exit
123
+ end
124
+
125
+ # TODO: clean up subcommand parsing
126
+ if command == "merge" and !options.merge.additional_arguments.empty?
127
+ options.merge.pr = options.merge.additional_arguments.shift.to_i
128
+ end
129
+
130
+ AUTH_KEY_NAME = "git-merge-pull"
131
+ NETRC_KEY = "#{AUTH_KEY_NAME}.api.github.com"
132
+
133
+ def run(cmd, args = { :failure => lambda {} })
134
+ puts cmd.green
135
+ puts `#{cmd}`
136
+ puts ''
137
+ if $?.exitstatus != 0
138
+ args[:failure].call()
139
+ exit -1
140
+ end
141
+ end
142
+
143
+ def run_test_output_empty(cmd)
144
+ "" == `#{cmd}`
145
+ end
146
+
147
+ def test_github_credentials
148
+ n = Netrc.read
149
+ user, oauth_token = n[NETRC_KEY]
150
+ client = Octokit::Client.new :access_token => oauth_token
151
+ begin
152
+ client.user
153
+ rescue
154
+ n.delete NETRC_KEY
155
+ n.save
156
+ return false
157
+ end
158
+ return true
159
+ end
160
+
161
+ def prompt_for_github_credentials(args = {})
162
+ user = args[:user]
163
+ pass = args[:pass]
164
+ needs_otp = args[:needs_otp]
165
+ headers = {}
166
+
167
+ unless user
168
+ print "Enter your github username: "
169
+ user = STDIN.gets.chomp!
170
+ print "Password: "
171
+ pass = STDIN.noecho(&:gets).chomp!
172
+ puts "\n"
173
+ end
174
+
175
+ if needs_otp
176
+ print "Enter an OTP code: "
177
+ otp = STDIN.gets.chomp!
178
+ headers = { "X-GitHub-OTP" => "#{otp}" }
179
+ end
180
+
181
+ client = Octokit::Client.new :login => user, :password => pass
182
+ begin
183
+ authorizations = client.authorizations :headers => headers
184
+ auth = authorizations.find { |x| x[:app][:name].match "^#{AUTH_KEY_NAME}" }
185
+ unless auth
186
+ auth = client.create_authorization(:scopes => ["user", "repo"], :note => AUTH_KEY_NAME, :headers => headers)
187
+ end
188
+ rescue Octokit::Unauthorized
189
+ puts "Invalid username or password."
190
+ return false
191
+ rescue Octokit::OneTimePasswordRequired
192
+ # Come back through this method, prompting for an OTP
193
+ return prompt_for_github_credentials :user => user, :pass => pass, :needs_otp => true
194
+ end
195
+
196
+ n = Netrc.read
197
+ n[NETRC_KEY] = user, auth[:token]
198
+ n.save
199
+
200
+ return true
201
+ end
202
+
203
+ def pull_summary(pull)
204
+ return "##{pull[:number]} from #{pull[:user][:login]}: \"#{pull[:title]}\""
205
+ end
206
+
207
+ def query_for_pull_to_merge(pulls)
208
+ puts
209
+ pull_to_merge = nil
210
+ choose do |menu|
211
+ menu.prompt = "Select PR to merge: "
212
+ pulls.each do |pull|
213
+ menu.choice(pull_summary(pull)) { pull_to_merge = pull }
214
+ end
215
+ menu.choice(:Quit, "Exit program.") { exit }
216
+ end
217
+ return pull_to_merge
218
+ end
219
+
220
+ if not test_github_credentials and not prompt_for_github_credentials
221
+ exit -1
222
+ end
223
+
224
+ # Get local Git object pointed at our repo root
225
+ git = Git.open `git rev-parse --show-toplevel`.chomp!
226
+
227
+ # Find the target repository that we'll merge the pull request into
228
+ # TODO: could read off command line instead
229
+ target_remote = git.remotes.find { |x| x.name == options.merge.remote }
230
+ url_match = target_remote.url.match "^git@github.com:(.*)/(.*).git"
231
+ organization = url_match[1]
232
+ repository = url_match[2]
233
+
234
+ n = Netrc.read
235
+ user, oauth_token = n[NETRC_KEY]
236
+ Octokit.configure do |c|
237
+ c.access_token = oauth_token
238
+ end
239
+
240
+ github_repo = Octokit.repo "#{organization}/#{repository}"
241
+ # pp github_repo
242
+
243
+ pulls = Octokit.pulls "#{organization}/#{repository}/pulls"
244
+ if options.merge.pr
245
+ pull = pulls.find { |p| p[:number] == options.merge.pr }
246
+ unless pull
247
+ puts "Pull request #{options.merge.pr} not found!".red
248
+ exit
249
+ end
250
+ else
251
+ pull = query_for_pull_to_merge pulls
252
+ end
253
+
254
+ pull_number = pull[:number]
255
+ source_branch = pull[:head][:ref]
256
+ source_repo_ssh_url = pull[:head][:repo][:git_url]
257
+ source_repo_clone_url = pull[:head][:repo][:clone_url]
258
+
259
+ target_branch = pull[:base][:ref]
260
+ target_repo_ssh_url = pull[:base][:repo][:git_url]
261
+ target_repo_clone_url = pull[:base][:repo][:clone_url]
262
+
263
+ puts
264
+ puts "Merging #{pull_summary(pull)}".cyan
265
+ puts "#{target_repo_ssh_url}/#{target_branch} <= #{source_repo_ssh_url}/#{source_branch}".cyan
266
+
267
+ # find or add a remote for the PR
268
+ # pp git.remotes.last
269
+ source_remote = git.remotes.find { |x| [pull[:head][:repo][:git_url],
270
+ pull[:head][:repo][:ssh_url]].include? x.url }
271
+ unless source_remote
272
+ puts "Adding remote: #{pull[:user][:login]} from #{pull[:head][:repo][:ssh_url]}"
273
+ source_remote = git.add_remote pull[:user][:login], pull[:head][:repo][:ssh_url]
274
+ end
275
+
276
+ # Fetch latest changes from source & target remotes. Useful in case one of source or target
277
+ # branches doesn't exist locally yet, or if we've never pulled from one of the remotes.
278
+ puts "Fetching latest changes from #{source_remote}"
279
+ source_remote.fetch
280
+ puts "Fetching latest changes from #{target_remote}"
281
+ target_remote.fetch
282
+
283
+ # Get the target branch up to date
284
+ run "git checkout #{target_branch}"
285
+ run "git pull --no-rebase --ff-only", :failure => lambda {
286
+ "Unable to update local target branch (#{target_branch}). Please repair manually before continuing.".red
287
+ }
288
+
289
+ # If the local target branch differs from the remote target branch, they
290
+ # must be reconciled manually.
291
+ remote_target_branch = "#{target_remote}/#{target_branch}"
292
+ if (not run_test_output_empty "git diff #{target_branch} #{remote_target_branch}")
293
+ puts "Local branch (#{target_branch}) differs from remote branch (#{remote_target_branch}). Please reconcile before continuing.".red
294
+ exit -1
295
+ end
296
+
297
+ # If a local branch exists with the name source_branch, check that it has the
298
+ # same contents as the remote source branch. If not, it must be reconciled
299
+ # manually.
300
+ remote_source_branch = "#{source_remote}/#{source_branch}"
301
+ if (not run_test_output_empty "git branch --list #{source_branch}" and not run_test_output_empty "git diff #{remote_source_branch} #{source_branch}")
302
+ puts "Local branch (#{source_branch}) differs from remote branch (#{remote_source_branch}). Please reconcile before continuing.".red
303
+ exit -1
304
+ end
305
+
306
+ # Check out the remote source branch using a temporary branch name,
307
+ # failing if the temporary name already exists.
308
+ rebase_branch = "#{source_branch}-rebase"
309
+ if not run_test_output_empty "git branch --list #{rebase_branch}"
310
+ puts "Local rebase branch (#{rebase_branch}) already exists. Please remove before continuing.".red
311
+ exit -1
312
+ end
313
+ run "git checkout -b #{rebase_branch} #{remote_source_branch}"
314
+
315
+ # Rebase the rebase branch on top of the target branch
316
+ run "git rebase #{target_branch}", :failure => lambda {
317
+ puts "Conflict detected in rebase. Please rebase manually, update PR, and re-run.".red
318
+ run "git rebase --abort"
319
+ run "git checkout #{target_branch}"
320
+ run "git branch -D #{rebase_branch}"
321
+ }
322
+
323
+ # Force push the rebased branch to the source remote.
324
+ run "git push -f #{source_remote.name} HEAD:#{source_branch}"
325
+
326
+ # Merge the source branch into the target. Use --no-ff so that an explicit
327
+ # merge commit is created.
328
+ run "git checkout #{target_branch}"
329
+ run "git merge --no-ff #{rebase_branch} -m 'Merge #{pull_summary(pull)}'"
330
+
331
+ # Now that the rebase branch is merged, we can safely delete it.
332
+ run "git branch -D #{rebase_branch}"
333
+
334
+ # Print a log of the merge with branch structure visible. Jump through hoops to
335
+ # get the right branch to start the log revision range with. If origin/develop
336
+ # is a merge commit, we need the right parent of the merge.
337
+ #
338
+ # The goal is to get output like this:
339
+ #
340
+ # * 5be2a77 (HEAD, develop) PR #1269. Merge branch floatplane/feature/categories into develop.
341
+ # |\
342
+ # | * 2242141 (floatplane/feature/categories, feature/categories) Process CR feedback. Remove StaticCreatorListDataSource, will just rework Streamed* version to meet needs instead.
343
+ # | * d7cf231 Implement StaticCreatorListDataSource for categories, rename CreatorListDataSource => StreamedCreatorListDataSource
344
+ # | * ef034d0 Don't animate profile pic transitions when we're re-using a cell and needing to replace someone else's picture. Only animate from the blank thumbnail to an actual picture.
345
+ # | * 25cda8b Refactor CreatorListViewController.
346
+ # | * 682b7ba Adjust search dialog size and default position. Remove temp close button. Stub categories into search dialog.
347
+ # | * e8ba0b1 Rename CollaboratorsListViewController => CreatorListViewController. Add CollaboratorListViewController as a subclass of CreatorListViewController, will refactor behavior into it in future commits.
348
+ # | * e901256 Make dismissWithBackgroundTouch work for all CustomModalDialogs, even those that don't set useCustomPopover. Fix latent bug in ApplicationInfoNavigationController's implementation of the same.
349
+ # |/
350
+ # * 8d5ecbc (origin/develop, origin/HEAD) Merge branch 'feature/schemaUpgradeUtils' into develop
351
+ #
352
+ # where the log stops at origin/develop, no matter whether it's a merge commit or not.
353
+ #
354
+ origin_parent = `git rev-list --abbrev-commit --parents -n 1 origin/#{target_branch}`.split().last
355
+ run "git log --graph --decorate --pretty=oneline --abbrev-commit --color #{target_branch} #{origin_parent}..#{target_branch}"
356
+
357
+ def get_char
358
+ state = `stty -g`
359
+ `stty raw -echo -icanon isig`
360
+
361
+ STDIN.getc.chr
362
+ ensure
363
+ `stty #{state}`
364
+ puts ""
365
+ end
366
+
367
+ print "Do you want to proceed with the merge (y/n)? ".cyan
368
+ if get_char.downcase == 'y'
369
+ puts "Pushing changes to #{target_remote}"
370
+ run "git push #{target_remote} #{target_branch}"
371
+ print "Do you want to delete the feature branch (y/n)? ".cyan
372
+ if get_char.downcase == 'y'
373
+ run "git push #{source_remote} :#{source_branch}"
374
+ run "git branch -d #{source_branch}"
375
+ end
376
+ puts "Merge complete!".cyan
377
+ else
378
+ puts "Undoing local merge"
379
+ run "git reset --hard #{target_remote}/#{target_branch}"
380
+ end
data/git_pr.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'git_pr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "git_pr"
8
+ spec.version = GitPr::VERSION
9
+ spec.authors = ["Brian Sharon"]
10
+ spec.email = ["brian@floatplane.us"]
11
+ spec.summary = %q{A tool for listing and merging GitHub pull requests.}
12
+ spec.description = %q{}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ [ "colorize", "tty", "git", "netrc", "octokit", "highline" ].each do |dep|
22
+ spec.add_runtime_dependency dep
23
+ end
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.6"
26
+ spec.add_development_dependency "rake"
27
+ end
@@ -0,0 +1,3 @@
1
+ module GitPr
2
+ VERSION = "0.0.1"
3
+ end
data/lib/git_pr.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "git_pr/version"
2
+
3
+ module GitPr
4
+ # Your code goes here...
5
+ end
metadata ADDED
@@ -0,0 +1,166 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: git_pr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Sharon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: git
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: netrc
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: octokit
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: highline
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ~>
102
+ - !ruby/object:Gem::Version
103
+ version: '1.6'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ~>
109
+ - !ruby/object:Gem::Version
110
+ version: '1.6'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: ''
126
+ email:
127
+ - brian@floatplane.us
128
+ executables:
129
+ - git-pr
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - Gemfile
135
+ - LICENSE.txt
136
+ - README.md
137
+ - Rakefile
138
+ - bin/git-pr
139
+ - git_pr.gemspec
140
+ - lib/git_pr.rb
141
+ - lib/git_pr/version.rb
142
+ homepage: ''
143
+ licenses:
144
+ - MIT
145
+ metadata: {}
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 2.0.14
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: A tool for listing and merging GitHub pull requests.
166
+ test_files: []