git_pr 0.0.1

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: 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: []