git_reflow 0.3.5 → 0.4.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.
data/lib/git_reflow.rb CHANGED
@@ -7,67 +7,22 @@ require 'json/pure'
7
7
  require 'colorize'
8
8
 
9
9
  require 'git_reflow/version.rb' unless defined?(GitReflow::VERSION)
10
+ require 'git_reflow/config'
11
+ require 'git_reflow/git_server'
12
+ require 'git_reflow/git_server/git_hub'
13
+ require 'git_reflow/sandbox'
14
+ require 'git_reflow/git_helpers'
10
15
 
11
16
  module GitReflow
17
+ include Sandbox
18
+ include GitHelpers
19
+
12
20
  extend self
13
21
 
14
22
  LGTM = /lgtm|looks good to me|:\+1:|:thumbsup:|:shipit:/i
15
23
 
16
- def setup(options = {})
17
- project_only = options.delete(:project_only)
18
- using_enterprise = options.delete(:enterprise)
19
- gh_site_url = github_site_url
20
- gh_api_endpoint = github_api_endpoint
21
-
22
- if using_enterprise
23
- gh_site_url = ask("Please enter your Enterprise site URL (e.g. https://github.company.com):")
24
- gh_api_endpoint = ask("Please enter your Enterprise API endpoint (e.g. https://github.company.com/api/v3):")
25
- end
26
-
27
- if project_only
28
- set_github_site_url(gh_site_url, local: true)
29
- set_github_api_endpoint(gh_api_endpoint, local: true)
30
- else
31
- set_github_site_url(gh_site_url)
32
- set_github_api_endpoint(gh_api_endpoint)
33
- end
34
-
35
- gh_user = ask("Please enter your GitHub username: ")
36
- gh_password = ask("Please enter your GitHub password (we do NOT store this): ") { |q| q.echo = false }
37
-
38
- begin
39
-
40
- github = Github.new do |config|
41
- config.basic_auth = "#{gh_user}:#{gh_password}"
42
- config.endpoint = GitReflow.github_api_endpoint
43
- config.site = GitReflow.github_site_url
44
- config.adapter = :net_http
45
- config.ssl = {:verify => false}
46
- end
47
-
48
- previous_authorizations = github.oauth.all.select {|auth| auth.note == "git-reflow (#{`hostname`.strip})" }
49
- if previous_authorizations.any?
50
- authorization = previous_authorizations.last
51
- else
52
- authorization = github.oauth.create scopes: ['repo'], note: "git-reflow (#{`hostname`.strip})"
53
- end
54
-
55
- oauth_token = authorization.token
56
-
57
- if project_only
58
- set_oauth_token(oauth_token, local: true)
59
- else
60
- set_oauth_token(oauth_token)
61
- end
62
- rescue StandardError => e
63
- puts "\nInvalid username or password"
64
- else
65
- puts "\nYour GitHub account was successfully setup!"
66
- end
67
- end
68
-
69
24
  def status(destination_branch)
70
- pull_request = find_pull_request( :from => current_branch, :to => destination_branch )
25
+ pull_request = git_server.find_pull_request( :from => current_branch, :to => destination_branch )
71
26
 
72
27
  if pull_request.nil?
73
28
  puts "\n[notice] No pull request exists for #{current_branch} -> #{destination_branch}"
@@ -84,25 +39,25 @@ module GitReflow
84
39
  fetch_destination options['base']
85
40
 
86
41
  begin
87
- puts push_current_branch
88
- pull_request = github.pull_requests.create(remote_user, remote_repo_name,
89
- 'title' => options['title'],
90
- 'body' => options['body'],
91
- 'head' => "#{remote_user}:#{current_branch}",
92
- 'base' => options['base'])
42
+ push_current_branch
93
43
 
94
- puts "Successfully created pull request ##{pull_request.number}: #{pull_request.title}\nPull Request URL: #{pull_request.html_url}\n"
95
- ask_to_open_in_browser(pull_request.html_url)
96
- rescue Github::Error::UnprocessableEntity => e
97
- error_message = e.to_s
98
- if error_message =~ /request already exists/i
99
- existing_pull_request = find_pull_request( :from => current_branch, :to => options['base'] )
44
+ if existing_pull_request = git_server.find_pull_request( from: current_branch, to: options['base'] )
100
45
  puts "A pull request already exists for these branches:"
101
46
  display_pull_request_summary(existing_pull_request)
102
47
  ask_to_open_in_browser(existing_pull_request.html_url)
103
48
  else
104
- puts error_message
49
+ pull_request = git_server.create_pull_request(title: options['title'],
50
+ body: options['body'],
51
+ head: "#{remote_user}:#{current_branch}",
52
+ base: options['base'])
53
+
54
+ puts "Successfully created pull request ##{pull_request.number}: #{pull_request.title}\nPull Request URL: #{pull_request.html_url}\n"
55
+ ask_to_open_in_browser(pull_request.html_url)
105
56
  end
57
+ rescue Github::Error::UnprocessableEntity => e
58
+ puts "Github Error: #{e.to_s}"
59
+ rescue StandardError => e
60
+ puts "Error: #{e.inspect}"
106
61
  end
107
62
  end
108
63
 
@@ -114,30 +69,29 @@ module GitReflow
114
69
  update_destination(current_branch)
115
70
 
116
71
  begin
117
- existing_pull_request = find_pull_request( :from => current_branch, :to => options['base'] )
72
+ existing_pull_request = git_server.find_pull_request( :from => current_branch, :to => options['base'] )
118
73
 
119
74
  if existing_pull_request.nil?
120
75
  puts "Error: No pull request exists for #{remote_user}:#{current_branch}\nPlease submit your branch for review first with \`git reflow review\`"
121
76
  else
122
77
 
123
- open_comment_authors = find_authors_of_open_pull_request_comments(existing_pull_request)
124
- has_comments = has_pull_request_comments?(existing_pull_request)
125
- status = get_build_status existing_pull_request.head.sha
78
+ open_comment_authors = git_server.find_authors_of_open_pull_request_comments(existing_pull_request)
79
+ has_comments = git_server.has_pull_request_comments?(existing_pull_request)
80
+ status = git_server.get_build_status existing_pull_request.head.sha
126
81
 
127
82
  # if there any comment_authors left, then they haven't given a lgtm after the last commit
128
83
  if ((status.nil? or status.state == "success") and has_comments and open_comment_authors.empty?) or options['skip_lgtm']
129
- lgtm_authors = comment_authors_for_pull_request(existing_pull_request, :with => LGTM)
130
- commit_message = "#{(existing_pull_request[:body] || get_first_commit_message)}"
84
+ lgtm_authors = git_server.comment_authors_for_pull_request(existing_pull_request, :with => LGTM)
85
+ commit_message = ("#{existing_pull_request[:body]}".length > 0) ? existing_pull_request[:body] : "#{get_first_commit_message}"
131
86
  puts "Merging pull request ##{existing_pull_request.number}: '#{existing_pull_request.title}', from '#{existing_pull_request.head.label}' into '#{existing_pull_request.base.label}'"
132
87
 
133
88
  update_destination(options['base'])
134
- merge_feature_branch(:feature_branch => feature_branch,
135
- :destination_branch => options['base'],
89
+ merge_feature_branch(feature_branch,
90
+ :destination_branch => options['base'],
136
91
  :pull_request_number => existing_pull_request.number,
137
- :message => "\nCloses ##{existing_pull_request.number}\n\nLGTM given by: @#{lgtm_authors.join(', @')}\n")
138
- append_to_squashed_commit_message(commit_message)
139
- puts "git commit".colorize(:green)
140
- committed = system('git commit')
92
+ :lgtm_authors => lgtm_authors,
93
+ :message => commit_message)
94
+ committed = run_command_with_label 'git commit', with_system: true
141
95
 
142
96
  if committed
143
97
  puts "Merge complete!"
@@ -147,11 +101,14 @@ module GitReflow
147
101
  run_command_with_label "git push origin :#{feature_branch}"
148
102
  run_command_with_label "git branch -D #{feature_branch}"
149
103
  puts "Nice job buddy."
104
+ else
105
+ puts "Cleanup haulted. Local changes were not pushed to remote repo.".colorize(:red)
106
+ puts "To reset and go back to your branch run \`git reset --hard origin/master && git checkout new-feature\`"
150
107
  end
151
108
  else
152
109
  puts "There were problems commiting your feature... please check the errors above and try again."
153
110
  end
154
- elsif status.state != "success"
111
+ elsif !status.nil? and status.state != "success"
155
112
  puts "[#{ 'deliver halted'.colorize(:red) }] #{status.description}: #{status.target_url}"
156
113
  elsif open_comment_authors.count > 0
157
114
  puts "[deliver halted] You still need a LGTM from: #{open_comment_authors.join(', ')}"
@@ -163,167 +120,12 @@ module GitReflow
163
120
  rescue Github::Error::UnprocessableEntity => e
164
121
  errors = JSON.parse(e.response_message[:body])
165
122
  error_messages = errors["errors"].collect {|error| "GitHub Error: #{error["message"].gsub(/^base\s/, '')}" unless error["message"].nil?}.compact.join("\n")
166
- puts error_messages
167
- end
168
- end
169
-
170
- def github
171
- @github ||= Github.new do |config|
172
- config.oauth_token = GitReflow.github_oauth_token
173
- config.endpoint = GitReflow.github_api_endpoint
174
- config.site = GitReflow.github_site_url
175
- end
176
- end
177
-
178
- def github_api_endpoint
179
- endpoint = `git config --get github.endpoint`.strip
180
- (endpoint.length > 0) ? endpoint : Github::Configuration::DEFAULT_ENDPOINT
181
- end
182
-
183
- def set_github_api_endpoint(api_endpoint, options = {local: false})
184
- if options[:local]
185
- `git config --replace-all github.endpoint #{api_endpoint}`
186
- else
187
- `git config --global --replace-all github.endpoint #{api_endpoint}`
188
- end
189
- end
190
-
191
- def github_site_url
192
- site_url = `git config --get github.site`.strip
193
- (site_url.length > 0) ? site_url : Github::Configuration::DEFAULT_SITE
194
- end
195
-
196
- def set_github_site_url(site_url, options = {local: false})
197
- if options[:local]
198
- `git config --replace-all github.site #{site_url}`
199
- else
200
- `git config --global --replace-all github.site #{site_url}`
123
+ puts "Github Error: #{error_messages}"
201
124
  end
202
125
  end
203
126
 
204
- def github_oauth_token
205
- `git config --get github.oauth-token`.strip
206
- end
207
-
208
- def current_branch
209
- `git branch --no-color | grep '^\* ' | grep -v 'no branch' | sed 's/^* //g'`.strip
210
- end
211
-
212
- def github_user
213
- `git config --get github.user`.strip
214
- end
215
-
216
- def remote_user
217
- gh_remote_user = `git config --get remote.origin.url`.strip
218
- gh_remote_user.slice!(/github\.com[\/:](\w|-|\.)+/i)[11..-1]
219
- end
220
-
221
- def remote_repo_name
222
- gh_repo = `git config --get remote.origin.url`.strip
223
- gh_repo.slice(/\/(\w|-|\.)+$/i)[1..-5]
224
- end
225
-
226
- def get_first_commit_message
227
- `git log --pretty=format:"%s" --no-merges -n 1`.strip
228
- end
229
-
230
- def set_oauth_token(oauth_token, options = {})
231
- if options.delete(:local)
232
- `git config --replace-all github.oauth-token #{oauth_token}`
233
- else
234
- `git config --global --replace-all github.oauth-token #{oauth_token}`
235
- end
236
- end
237
-
238
- def push_current_branch
239
- run_command_with_label "git push origin #{current_branch}"
240
- end
241
-
242
- def fetch_destination(destination_branch)
243
- run_command_with_label "git fetch origin #{destination_branch}"
244
- end
245
-
246
- def update_destination(destination_branch)
247
- origin_branch = current_branch
248
- run_command_with_label "git checkout #{destination_branch}"
249
- run_command_with_label "git pull origin #{destination_branch}"
250
- run_command_with_label "git checkout #{origin_branch}"
251
- end
252
-
253
- def merge_feature_branch(options = {})
254
- options[:destination_branch] ||= 'master'
255
- message = options[:message] || "\nCloses ##{options[:pull_request_number]}\n"
256
-
257
- run_command_with_label "git checkout #{options[:destination_branch]}"
258
- run_command_with_label "git merge --squash #{options[:feature_branch]}"
259
- # append pull request number to commit message
260
- append_to_squashed_commit_message(message)
261
- end
262
-
263
- def append_to_squashed_commit_message(message = '')
264
- `echo "#{message}" | cat - .git/SQUASH_MSG > ./tmp_squash_msg`
265
- `mv ./tmp_squash_msg .git/SQUASH_MSG`
266
- end
267
-
268
- def find_pull_request(options)
269
- existing_pull_request = nil
270
- github.pull_requests.all(remote_user, remote_repo_name, :state => 'open') do |pull_request|
271
- if pull_request.base.label == "#{remote_user}:#{options[:to]}" and
272
- pull_request.head.label == "#{remote_user}:#{options[:from]}"
273
- existing_pull_request = pull_request
274
- break
275
- end
276
- end
277
-
278
- existing_pull_request
279
- end
280
-
281
- def pull_request_comments(pull_request)
282
- comments = github.issues.comments.all remote_user, remote_repo_name, issue_id: pull_request.number
283
- review_comments = github.pull_requests.comments.all remote_user, remote_repo_name, request_id: pull_request.number
284
-
285
- review_comments.to_a + comments.to_a
286
- end
287
-
288
- def has_pull_request_comments?(pull_request)
289
- pull_request_comments(pull_request).count > 0
290
- end
291
-
292
- def get_build_status sha
293
- github.repos.statuses.all(remote_user, remote_repo_name, sha).first
294
- end
295
-
296
- def build_color status
297
- colorized_statuses = { pending: :yellow, success: :green, error: :red, failure: :red }
298
- colorized_statuses[status.state.to_sym]
299
- end
300
-
301
- def colorized_build_description status
302
- status.description.colorize( build_color status )
303
- end
304
-
305
- def find_authors_of_open_pull_request_comments(pull_request)
306
- # first we'll gather all the authors that have commented on the pull request
307
- pull_last_committed_at = get_commited_time(pull_request.head.sha)
308
- comment_authors = comment_authors_for_pull_request(pull_request)
309
- lgtm_authors = comment_authors_for_pull_request(pull_request, :with => LGTM, :after => pull_last_committed_at)
310
-
311
- comment_authors - lgtm_authors
312
- end
313
-
314
- def comment_authors_for_pull_request(pull_request, options = {})
315
- all_comments = pull_request_comments(pull_request)
316
- comment_authors = []
317
-
318
- all_comments.each do |comment|
319
- next if options[:after] and Time.parse(comment.created_at) < options[:after]
320
- if (options[:with].nil? or comment[:body] =~ options[:with])
321
- comment_authors |= [comment.user.login]
322
- end
323
- end
324
-
325
- # remove the current user from the list to check
326
- comment_authors -= [github_user]
127
+ def git_server
128
+ @git_server ||= GitServer.connect provider: 'GitHub', silent: true
327
129
  end
328
130
 
329
131
  def display_pull_request_summary(pull_request)
@@ -334,21 +136,21 @@ module GitReflow
334
136
  }
335
137
 
336
138
  notices = ""
337
- reviewed_by = comment_authors_for_pull_request(pull_request).map {|author| author.colorize(:red) }
139
+ reviewed_by = git_server.comment_authors_for_pull_request(pull_request).map {|author| author.colorize(:red) }
338
140
 
339
141
  # check for CI build status
340
- status = get_build_status pull_request.head.sha
142
+ status = git_server.get_build_status pull_request.head.sha
341
143
  if status
342
144
  notices << "[notice] Your build status is not successful: #{status.target_url}.\n" unless status.state == "success"
343
- summary_data.merge!( "Build status" => colorized_build_description(status) )
145
+ summary_data.merge!( "Build status" => git_server.colorized_build_description(status) )
344
146
  end
345
147
 
346
148
  # check for needed lgtm's
347
- pull_comments = pull_request_comments(pull_request)
348
- if pull_comments.reject {|comment| comment.user.login == github_user}.any?
349
- open_comment_authors = find_authors_of_open_pull_request_comments(pull_request)
350
- last_committed_at = get_commited_time(pull_request.head.sha)
351
- lgtm_authors = comment_authors_for_pull_request(pull_request, :with => LGTM, :after => last_committed_at)
149
+ pull_comments = git_server.pull_request_comments(pull_request)
150
+ if pull_comments.reject {|comment| comment.user.login == git_server.class.user}.any?
151
+ open_comment_authors = git_server.find_authors_of_open_pull_request_comments(pull_request)
152
+ last_committed_at = git_server.get_commited_time(pull_request.head.sha)
153
+ lgtm_authors = git_server.comment_authors_for_pull_request(pull_request, :with => LGTM, :after => last_committed_at)
352
154
 
353
155
  summary_data.merge!("Last comment" => pull_comments.last[:body].inspect)
354
156
 
@@ -371,31 +173,4 @@ module GitReflow
371
173
 
372
174
  puts "\n#{notices}" unless notices.empty?
373
175
  end
374
-
375
- def get_commited_time(commit_sha)
376
- last_commit = github.repos.commits.find remote_user, remote_repo_name, commit_sha
377
- Time.parse last_commit.commit.author[:date]
378
- end
379
-
380
- # WARNING: this currently only supports OS X and UBUNTU
381
- def ask_to_open_in_browser(url)
382
- if RUBY_PLATFORM =~ /darwin|linux/i
383
- open_in_browser = ask "Would you like to open it in your browser? "
384
- if open_in_browser =~ /^y/i
385
- if RUBY_PLATFORM =~ /darwin/i
386
- # OS X
387
- `open #{url}`
388
- else
389
- # Ubuntu
390
- `xdg-open #{url}`
391
- end
392
- end
393
- end
394
- end
395
-
396
- def run_command_with_label(command, options = {})
397
- label_color = options.delete(:color) || :green
398
- puts command.colorize(label_color)
399
- puts `#{command}`
400
- end
401
176
  end
@@ -0,0 +1,7 @@
1
+ [user]
2
+ name = Reenhanced
3
+ email = dev@reenhanced.com
4
+ [github]
5
+ user = reenhanced
6
+ token = 123456
7
+ oauth-token = 123456
@@ -0,0 +1,29 @@
1
+ [
2
+ {
3
+ "id": 1,
4
+ "url": "https://api.github.com/repos/reenhanced/repo/issues/comments/1",
5
+ "html_url": "https://github.com/reenhanced/repo/issues/1#issuecomment-1",
6
+ "body": "Me too",
7
+ "user": {
8
+ "login": "reenhanced",
9
+ "id": 1,
10
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
11
+ "gravatar_id": "somehexcode",
12
+ "url": "https://api.github.com/users/reenhanced",
13
+ "html_url": "https://github.com/reenhanced",
14
+ "followers_url": "https://api.github.com/users/reenhanced/followers",
15
+ "following_url": "https://api.github.com/users/reenhanced/following{/other_user}",
16
+ "gists_url": "https://api.github.com/users/reenhanced/gists{/gist_id}",
17
+ "starred_url": "https://api.github.com/users/reenhanced/starred{/owner}{/repo}",
18
+ "subscriptions_url": "https://api.github.com/users/reenhanced/subscriptions",
19
+ "organizations_url": "https://api.github.com/users/reenhanced/orgs",
20
+ "repos_url": "https://api.github.com/users/reenhanced/repos",
21
+ "events_url": "https://api.github.com/users/reenhanced/events{/privacy}",
22
+ "received_events_url": "https://api.github.com/users/reenhanced/received_events",
23
+ "type": "User",
24
+ "site_admin": false
25
+ },
26
+ "created_at": "2011-04-14T16:00:49Z",
27
+ "updated_at": "2011-04-14T16:00:49Z"
28
+ }
29
+ ]
@@ -0,0 +1,47 @@
1
+ [
2
+ {
3
+ "url": "https://api.github.com/repos/reenhanced/repo/pulls/comments/1",
4
+ "id": 1,
5
+ "diff_hunk": "@@ -16,33 +16,40 @@ public class Connection : IConnection...",
6
+ "path": "file1.txt",
7
+ "position": 1,
8
+ "original_position": 4,
9
+ "commit_id": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
10
+ "original_commit_id": "9c48853fa3dc5c1c3d6f1f1cd1f2743e72652840",
11
+ "user": {
12
+ "login": "reenhanced",
13
+ "id": 1,
14
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
15
+ "gravatar_id": "somehexcode",
16
+ "url": "https://api.github.com/users/reenhanced",
17
+ "html_url": "https://github.com/reenhanced",
18
+ "followers_url": "https://api.github.com/users/reenhanced/followers",
19
+ "following_url": "https://api.github.com/users/reenhanced/following{/other_user}",
20
+ "gists_url": "https://api.github.com/users/reenhanced/gists{/gist_id}",
21
+ "starred_url": "https://api.github.com/users/reenhanced/starred{/owner}{/repo}",
22
+ "subscriptions_url": "https://api.github.com/users/reenhanced/subscriptions",
23
+ "organizations_url": "https://api.github.com/users/reenhanced/orgs",
24
+ "repos_url": "https://api.github.com/users/reenhanced/repos",
25
+ "events_url": "https://api.github.com/users/reenhanced/events{/privacy}",
26
+ "received_events_url": "https://api.github.com/users/reenhanced/received_events",
27
+ "type": "User",
28
+ "site_admin": false
29
+ },
30
+ "body": "Great stuff",
31
+ "created_at": "2011-04-14T16:00:49Z",
32
+ "updated_at": "2011-04-14T16:00:49Z",
33
+ "html_url": "https://github.com/reenhanced/repo/pull/1#discussion-diff-1",
34
+ "pull_request_url": "https://api.github.com/repos/reenhanced/repo/pulls/1",
35
+ "_links": {
36
+ "self": {
37
+ "href": "https://api.github.com/repos/reenhanced/repo/pulls/comments/1"
38
+ },
39
+ "html": {
40
+ "href": "https://github.com/reenhanced/repo/pull/1#discussion-diff-1"
41
+ },
42
+ "pull_request": {
43
+ "href": "https://api.github.com/repos/reenhanced/repo/pulls/1"
44
+ }
45
+ }
46
+ }
47
+ ]
@@ -0,0 +1,123 @@
1
+ {
2
+ "url": "https://api.github.com/reenhanced/repo/pulls/1",
3
+ "html_url": "https://github.com/reenhanced/repo/pulls/1",
4
+ "diff_url": "https://github.com/reenhanced/repo/pulls/1.diff",
5
+ "patch_url": "https://github.com/reenhanced/repo/pulls/1.patch",
6
+ "issue_url": "https://github.com/reenhanced/repo/issue/1",
7
+ "number": 1,
8
+ "state": "open",
9
+ "title": "new-feature",
10
+ "body": "Please pull these awesome changes",
11
+ "created_at": "2011-01-26T19:01:12Z",
12
+ "updated_at": "2011-01-26T19:01:12Z",
13
+ "closed_at": "2011-01-26T19:01:12Z",
14
+ "merged_at": "2011-01-26T19:01:12Z",
15
+ "_links": {
16
+ "self": {
17
+ "href": "https://api.github.com/reenhanced/repo/pulls/1"
18
+ },
19
+ "html": {
20
+ "href": "https://github.com/reenhanced/repo/pull/1"
21
+ },
22
+ "comments": {
23
+ "href": "https://api.github.com/reenhanced/repo/issues/1/comments"
24
+ },
25
+ "review_comments": {
26
+ "href": "https://api.github.com/reenhanced/repo/pulls/1/comments"
27
+ }
28
+ },
29
+ "merged": false,
30
+ "mergeable": true,
31
+ "merged_by": {
32
+ "login": "reenhanced",
33
+ "id": 1,
34
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
35
+ "gravatar_id": "somehexcode",
36
+ "url": "https://api.github.com/users/reenhanced"
37
+ },
38
+ "comments": 10,
39
+ "commits": 3,
40
+ "additions": 100,
41
+ "deletions": 3,
42
+ "changed_files": 5,
43
+ "head": {
44
+ "label": "new-feature",
45
+ "ref": "new-feature",
46
+ "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
47
+ "user": {
48
+ "login": "reenhanced",
49
+ "id": 1,
50
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
51
+ "gravatar_id": "somehexcode",
52
+ "url": "https://api.github.com/users/reenhanced"
53
+ },
54
+ "repo": {
55
+ "url": "https://api.github.com/repos/reenhanced/repo",
56
+ "html_url": "https://github.com/reenhanced/repo",
57
+ "clone_url": "https://github.com/reenhanced/repo.git",
58
+ "git_url": "git://github.com/reenhanced/repo.git",
59
+ "ssh_url": "git@github.com:reenhanced/repo.git",
60
+ "svn_url": "https://svn.github.com/reenhanced/repo",
61
+ "owner": {
62
+ "login": "reenhanced",
63
+ "id": 1,
64
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
65
+ "gravatar_id": "somehexcode",
66
+ "url": "https://api.github.com/users/reenhanced"
67
+ },
68
+ "name": "repo",
69
+ "description": "This your first repo!",
70
+ "homepage": "https://github.com",
71
+ "language": null,
72
+ "private": false,
73
+ "fork": false,
74
+ "forks": 9,
75
+ "watchers": 80,
76
+ "size": 108,
77
+ "master_branch": "master",
78
+ "open_issues": 0,
79
+ "pushed_at": "2011-01-26T19:06:43Z",
80
+ "created_at": "2011-01-26T19:01:12Z"
81
+ }
82
+ },
83
+ "base": {
84
+ "label": "master",
85
+ "ref": "master",
86
+ "sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
87
+ "user": {
88
+ "login": "reenhanced",
89
+ "id": 1,
90
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
91
+ "gravatar_id": "somehexcode",
92
+ "url": "https://api.github.com/users/reenhanced"
93
+ },
94
+ "repo": {
95
+ "url": "https://api.github.com/repos/reenhanced/repo",
96
+ "html_url": "https://github.com/reenhanced/repo",
97
+ "clone_url": "https://github.com/reenhanced/repo.git",
98
+ "git_url": "git://github.com/reenhanced/repo.git",
99
+ "ssh_url": "git@github.com:reenhanced/repo.git",
100
+ "svn_url": "https://svn.github.com/reenhanced/repo",
101
+ "owner": {
102
+ "login": "reenhanced",
103
+ "id": 1,
104
+ "avatar_url": "https://github.com/images/error/octocat_happy.gif",
105
+ "gravatar_id": "somehexcode",
106
+ "url": "https://api.github.com/users/reenhanced"
107
+ },
108
+ "name": "repo",
109
+ "description": "This your first repo!",
110
+ "homepage": "https://github.com",
111
+ "language": null,
112
+ "private": false,
113
+ "fork": false,
114
+ "forks": 9,
115
+ "watchers": 80,
116
+ "size": 108,
117
+ "master_branch": "master",
118
+ "open_issues": 0,
119
+ "pushed_at": "2011-01-26T19:06:43Z",
120
+ "created_at": "2011-01-26T19:01:12Z"
121
+ }
122
+ }
123
+ }
@@ -0,0 +1,32 @@
1
+ {
2
+ :method => :post,
3
+ :body => "{
4
+ \"errors\" : [{
5
+ \"code\" : \"custom\",
6
+ \"field\" : \"base\",
7
+ \"message\" : \"base A pull request already exists for reenhanced:banana.\",
8
+ \"resource\" : \"PullRequest\" }],
9
+ \"message\" : \"Validation Failed\"}",
10
+ :url => "https://api.github.com/repos/reenhanced/gitreflow/pulls?access_token=12345",
11
+ :request_headers => {
12
+ "Content-Type" => "application/json",
13
+ "Authorization" => "Token token=\"12345\""
14
+ },
15
+ :parallel_manager => nil,
16
+ :request => {:proxy => nil},
17
+ :ssl => {},
18
+ :status => 422,
19
+ :response_headers => {
20
+ "server" => "nginx/1.0.13",
21
+ "date" => "Fri, 27 Apr 2012 13:02:49 GMT",
22
+ "content-type" => "application/json; charset=utf-8",
23
+ "connection" => "close",
24
+ "status" => "422 Unprocessable Entity",
25
+ "x-ratelimit-limit" => "5000",
26
+ "etag" => "\"ebdeb717fe19444c308e608728569d5a\"",
27
+ "x-oauth-scopes" => "repo",
28
+ "x-ratelimit-remaining" => "4996",
29
+ "x-accepted-oauth-scopes" => "repo",
30
+ "content-length" => "192"},
31
+ :response => ""
32
+ }