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.
- 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
|
+
}
|