git_reflow 0.3.5 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/Gemfile.lock +67 -35
- data/Rakefile +8 -0
- data/git_reflow.gemspec +5 -4
- data/lib/git_reflow/commands/setup.rb +8 -1
- data/lib/git_reflow/commands/start.rb +2 -2
- data/lib/git_reflow/config.rb +23 -0
- data/lib/git_reflow/git_helpers.rb +65 -0
- data/lib/git_reflow/git_server/base.rb +88 -0
- data/lib/git_reflow/git_server/git_hub.rb +184 -0
- data/lib/git_reflow/git_server.rb +52 -0
- data/lib/git_reflow/sandbox.rb +39 -0
- data/lib/git_reflow/version.rb +1 -1
- data/lib/git_reflow.rb +48 -273
- data/spec/fixtures/git/git_config +7 -0
- data/spec/fixtures/issues/comments.json +29 -0
- data/spec/fixtures/pull_requests/comments.json +47 -0
- data/spec/fixtures/pull_requests/pull_request.json +123 -0
- data/spec/fixtures/pull_requests/pull_request_exists_error.json +32 -0
- data/spec/fixtures/pull_requests/pull_requests.json +117 -0
- data/spec/fixtures/repositories/statuses.json +31 -0
- data/spec/git_reflow_spec.rb +386 -0
- data/spec/lib/git_reflow/config_spec.rb +18 -0
- data/spec/lib/git_reflow/git_helpers_spec.rb +146 -0
- data/spec/lib/git_reflow/git_server_spec.rb +94 -0
- data/spec/lib/git_server/git_hub_spec.rb +236 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/command_line_helpers.rb +99 -0
- data/spec/support/fixtures.rb +8 -0
- data/spec/support/github_helpers.rb +98 -0
- data/spec/support/rspec_stub_helpers.rb +7 -0
- data/spec/support/web_mocks.rb +39 -0
- metadata +104 -62
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
|
-
|
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
|
-
|
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
|
-
|
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 = "#{
|
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(
|
135
|
-
:destination_branch
|
89
|
+
merge_feature_branch(feature_branch,
|
90
|
+
:destination_branch => options['base'],
|
136
91
|
:pull_request_number => existing_pull_request.number,
|
137
|
-
:
|
138
|
-
|
139
|
-
|
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
|
205
|
-
|
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 ==
|
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,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
|
+
}
|