git-process 1.0.11 → 1.1.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/CHANGELOG.md +37 -9
- data/Gemfile +2 -2
- data/Gemfile.lock +17 -17
- data/README.md +14 -7
- data/bin/git-new-fb +10 -2
- data/bin/git-pull-request +30 -6
- data/bin/git-sync +5 -2
- data/bin/git-to-master +62 -11
- data/git-process.gemspec +15 -15
- data/lib/git-process/abstract_error_builder.rb +0 -3
- data/lib/git-process/changed_file_helper.rb +30 -24
- data/lib/git-process/git_abstract_merge_error_builder.rb +31 -11
- data/lib/git-process/git_branch.rb +5 -0
- data/lib/git-process/git_config.rb +153 -0
- data/lib/git-process/git_lib.rb +212 -164
- data/lib/git-process/git_logger.rb +84 -0
- data/lib/git-process/git_merge_error.rb +3 -14
- data/lib/git-process/git_process.rb +44 -73
- data/lib/git-process/git_process_options.rb +6 -6
- data/lib/git-process/git_rebase_error.rb +4 -13
- data/lib/git-process/git_remote.rb +254 -0
- data/lib/git-process/github_configuration.rb +298 -0
- data/lib/git-process/github_pull_request.rb +65 -27
- data/lib/git-process/new_fb.rb +14 -4
- data/lib/git-process/parked_changes_error.rb +1 -1
- data/lib/git-process/pull_request.rb +100 -13
- data/lib/git-process/pull_request_error.rb +25 -0
- data/lib/git-process/rebase_to_master.rb +47 -27
- data/lib/git-process/sync.rb +48 -33
- data/lib/git-process/uncommitted_changes_error.rb +1 -1
- data/lib/git-process/version.rb +2 -2
- data/spec/GitRepoHelper.rb +48 -25
- data/spec/changed_file_helper_spec.rb +39 -58
- data/spec/git_abstract_merge_error_builder_spec.rb +42 -33
- data/spec/git_branch_spec.rb +30 -30
- data/spec/git_config_spec.rb +45 -0
- data/spec/git_lib_spec.rb +103 -122
- data/spec/git_logger_spec.rb +66 -0
- data/spec/git_process_spec.rb +81 -81
- data/spec/git_remote_spec.rb +188 -0
- data/spec/git_status_spec.rb +36 -36
- data/spec/github_configuration_spec.rb +152 -0
- data/spec/github_pull_request_spec.rb +39 -35
- data/spec/github_test_helper.rb +49 -0
- data/spec/new_fb_spec.rb +65 -24
- data/spec/pull_request_helper.rb +94 -0
- data/spec/pull_request_spec.rb +128 -0
- data/spec/rebase_to_master_spec.rb +241 -145
- data/spec/spec_helper.rb +20 -0
- data/spec/sync_spec.rb +115 -109
- metadata +34 -20
- data/lib/git-process/github_client.rb +0 -83
- data/lib/git-process/github_service.rb +0 -174
- data/spec/github_service_spec.rb +0 -211
@@ -28,7 +28,7 @@ module GitProc
|
|
28
28
|
|
29
29
|
|
30
30
|
def human_message
|
31
|
-
"You made your changes on the the '_parking_' branch instead of a feature branch.\n"+
|
31
|
+
"You made your changes on the the '_parking_' branch instead of a feature branch.\n"+'Please rename the branch to be a feature branch.'
|
32
32
|
end
|
33
33
|
|
34
34
|
|
@@ -12,36 +12,123 @@
|
|
12
12
|
|
13
13
|
require 'git-process/git_process'
|
14
14
|
require 'git-process/github_pull_request'
|
15
|
+
require 'git-process/pull_request_error'
|
15
16
|
require 'highline/import'
|
16
17
|
|
17
18
|
|
18
19
|
module GitProc
|
19
20
|
|
20
21
|
class PullRequest < Process
|
21
|
-
include GitLib
|
22
|
-
|
23
22
|
|
24
23
|
def initialize(dir, opts)
|
25
24
|
super
|
26
|
-
|
25
|
+
@base_branch = opts[:base_branch]
|
26
|
+
@head_branch = opts[:head_branch]
|
27
|
+
@_repo_name = opts[:repo_name]
|
28
|
+
@_remote_name = opts[:server]
|
29
|
+
@pr_number = opts[:prNumber]
|
27
30
|
@title = opts[:title]
|
28
|
-
@
|
29
|
-
@head_branch = opts[:head_branch] || current_branch
|
30
|
-
@repo_name = opts[:repo_name] || repo_name()
|
31
|
-
@title = opts[:title] || current_branch
|
32
|
-
@description = opts[:description] || ''
|
31
|
+
@description = opts[:description]
|
33
32
|
@user = opts[:user]
|
34
33
|
@password = opts[:password]
|
35
34
|
end
|
36
35
|
|
37
36
|
|
38
37
|
def runner
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
if @pr_number.nil? or @pr_number.empty?
|
39
|
+
pr = create_pull_request
|
40
|
+
logger.info { "Created pull request at #{pr.html_url}" }
|
41
|
+
else
|
42
|
+
checkout_pull_request
|
43
|
+
end
|
43
44
|
end
|
44
45
|
|
45
|
-
end
|
46
46
|
|
47
|
+
def create_pull_request_client(remote_name, repo_name)
|
48
|
+
PullRequest.create_pull_request_client(self, remote_name, repo_name, @user, @password)
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def create_pull_request
|
53
|
+
current_branch = gitlib.branches.current.name
|
54
|
+
base_branch = @base_branch || config.master_branch
|
55
|
+
head_branch = @head_branch || current_branch
|
56
|
+
title = @title || current_branch
|
57
|
+
description = @description || ''
|
58
|
+
|
59
|
+
PullRequest.create_pull_request(gitlib, remote.name, remote.name, remote.repo_name, current_branch, base_branch, head_branch, title, description, logger, @user, @password)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def checkout_pull_request
|
64
|
+
PullRequest.checkout_pull_request(gitlib, @pr_number, remote.name, remote.repo_name, @user, @password, logger)
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
class << self
|
69
|
+
|
70
|
+
def create_pull_request_client(lib, remote_name, repo_name, username, password)
|
71
|
+
GitHub::PullRequest.new(lib, remote_name, repo_name, {:user => username, :password => password})
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
def create_pull_request(lib, server_name, remote_name, repo_name, current_branch, base_branch, head_branch, title, description, logger, username, password)
|
76
|
+
if base_branch == head_branch
|
77
|
+
raise PullRequestError.new("Can not create a pull request where the base branch and head branch are the same: #{base_branch}")
|
78
|
+
end
|
79
|
+
|
80
|
+
lib.push(server_name, current_branch, current_branch, :force => false)
|
81
|
+
pr = create_pull_request_client(lib, remote_name, repo_name, username, password)
|
82
|
+
pr.create(base_branch, head_branch, title, description)
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def checkout_pull_request(lib, pr_number, remote_name, repo_name, username, password, logger)
|
87
|
+
logger.info { 'Getting #pr_number' }
|
88
|
+
|
89
|
+
lib.fetch(remote_name)
|
90
|
+
|
91
|
+
pr = create_pull_request_client(lib, remote_name, repo_name, username, password)
|
92
|
+
json = pr.pull_request(pr_number)
|
93
|
+
head_branch_name = json.head.ref
|
94
|
+
base_branch_name = json.base.ref
|
95
|
+
|
96
|
+
remote_head_server_name = match_remote_to_pr_remote(lib, json.head.repo.ssh_url)
|
97
|
+
remote_base_server_name = match_remote_to_pr_remote(lib, json.base.repo.ssh_url)
|
98
|
+
lib.checkout(head_branch_name, :new_branch => "#{remote_head_server_name}/#{head_branch_name}")
|
99
|
+
lib.branch(head_branch_name, :upstream => "#{remote_base_server_name}/#{base_branch_name}")
|
100
|
+
#logger.info(json.to_hash)
|
101
|
+
|
102
|
+
lib.fetch(remote_base_server_name) if remote_head_server_name != remote_base_server_name
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
def match_remote_to_pr_remote(lib, pr_remote)
|
107
|
+
pr_url = lib.remote.expanded_url(nil, pr_remote)
|
108
|
+
servers = lib.remote.remote_names
|
109
|
+
server_urls = servers.collect { |s| {:server_name => s, :url => lib.remote.expanded_url(s)} }
|
110
|
+
|
111
|
+
pair = server_urls.find do |su|
|
112
|
+
url = su[:url]
|
113
|
+
uri = URI.parse(url)
|
114
|
+
host = uri.host
|
115
|
+
path = uri.path
|
116
|
+
|
117
|
+
pr_uri = URI.parse(lib.remote.expanded_url(nil, pr_url))
|
118
|
+
pr_host = pr_uri.host
|
119
|
+
pr_path = pr_uri.path
|
120
|
+
|
121
|
+
pr_host == host and pr_path == path
|
122
|
+
end
|
123
|
+
|
124
|
+
if pair.nil?
|
125
|
+
raise GitHubService::NoRemoteRepository.new("Could not match pull request url (#{pr_url}) to any of the registered remote urls: #{server_urls.map {|s| '{' + s[:server_name] + ': ' + s[:url] + '}'}.join(', ')}")
|
126
|
+
end
|
127
|
+
|
128
|
+
pair[:server_name]
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
47
134
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
2
|
+
# you may not use this file except in compliance with the License.
|
3
|
+
# You may obtain a copy of the License at
|
4
|
+
#
|
5
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
6
|
+
#
|
7
|
+
# Unless required by applicable law or agreed to in writing, software
|
8
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
9
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
10
|
+
# See the License for the specific language governing permissions and
|
11
|
+
# limitations under the License.
|
12
|
+
|
13
|
+
require 'git-process/git_process_error'
|
14
|
+
|
15
|
+
module GitProc
|
16
|
+
|
17
|
+
class PullRequestError < GitProcessError
|
18
|
+
|
19
|
+
def initialize(msg)
|
20
|
+
super(msg)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -16,6 +16,7 @@ require 'git-process/git_process_error'
|
|
16
16
|
require 'git-process/parked_changes_error'
|
17
17
|
require 'git-process/uncommitted_changes_error'
|
18
18
|
require 'git-process/github_pull_request'
|
19
|
+
require 'git-process/pull_request'
|
19
20
|
|
20
21
|
|
21
22
|
module GitProc
|
@@ -25,6 +26,9 @@ module GitProc
|
|
25
26
|
def initialize(dir, opts)
|
26
27
|
@keep = opts[:keep]
|
27
28
|
@interactive = opts[:interactive]
|
29
|
+
@pr_number = opts[:prNumber]
|
30
|
+
@user = opts[:user]
|
31
|
+
@password = opts[:password]
|
28
32
|
super
|
29
33
|
end
|
30
34
|
|
@@ -32,37 +36,48 @@ module GitProc
|
|
32
36
|
def verify_preconditions
|
33
37
|
super
|
34
38
|
|
35
|
-
raise UncommittedChangesError.new unless status.clean?
|
36
|
-
raise ParkedChangesError.new(
|
39
|
+
raise UncommittedChangesError.new unless gitlib.status.clean?
|
40
|
+
raise ParkedChangesError.new(gitlib) if is_parked?
|
37
41
|
end
|
38
42
|
|
39
43
|
|
40
44
|
def runner
|
41
|
-
if
|
42
|
-
fetch(
|
43
|
-
|
44
|
-
|
45
|
-
|
45
|
+
if remote.exists?
|
46
|
+
gitlib.fetch(remote.name)
|
47
|
+
|
48
|
+
unless @pr_number.nil? or @pr_number.empty?
|
49
|
+
checkout_pull_request
|
50
|
+
end
|
51
|
+
|
52
|
+
proc_rebase(config.integration_branch)
|
53
|
+
proc_rebase(config.integration_branch, :interactive => true) if @interactive
|
54
|
+
current = gitlib.branches.current.name
|
55
|
+
gitlib.push(remote.name, current, config.master_branch)
|
46
56
|
|
47
57
|
unless @keep
|
48
58
|
close_pull_request
|
49
59
|
remove_feature_branch
|
50
60
|
end
|
51
61
|
else
|
52
|
-
proc_rebase(integration_branch)
|
62
|
+
proc_rebase(config.integration_branch)
|
53
63
|
end
|
54
64
|
end
|
55
65
|
|
56
66
|
|
67
|
+
def checkout_pull_request
|
68
|
+
PullRequest.checkout_pull_request(gitlib, @pr_number, remote.name, remote.repo_name, @user, @password, logger)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
57
72
|
def remove_feature_branch
|
58
|
-
mybranches = branches
|
73
|
+
mybranches = gitlib.branches
|
59
74
|
|
60
|
-
remote_master = mybranches[
|
75
|
+
remote_master = mybranches[remote.master_branch_name]
|
61
76
|
current_branch = mybranches.current
|
62
77
|
logger.debug { "Removing feature branch (#{current_branch})" }
|
63
78
|
|
64
79
|
unless remote_master.contains_all_of(current_branch.name)
|
65
|
-
raise GitProcessError.new("Branch '#{current_branch.name}' has not been merged into '#{
|
80
|
+
raise GitProcessError.new("Branch '#{current_branch.name}' has not been merged into '#{remote.master_branch_name}'")
|
66
81
|
end
|
67
82
|
|
68
83
|
parking_branch = mybranches['_parking_']
|
@@ -80,32 +95,36 @@ module GitProc
|
|
80
95
|
remote_master.checkout_to_new('_parking_', :no_track => true)
|
81
96
|
|
82
97
|
current_branch.delete!(true)
|
83
|
-
if mybranches["#{
|
84
|
-
push(
|
98
|
+
if mybranches["#{remote.name}/#{current_branch.name}"]
|
99
|
+
gitlib.push(remote.name, nil, nil, :delete => current_branch.name)
|
85
100
|
end
|
86
101
|
end
|
87
102
|
|
88
103
|
|
89
104
|
def close_pull_request
|
90
|
-
pr = GitHub::PullRequest.new(
|
105
|
+
pr = GitHub::PullRequest.new(gitlib, remote.name, remote.repo_name)
|
91
106
|
|
92
107
|
# Assume that if we haven't done something that would create the
|
93
108
|
# GitHub auth token, then this likely isn't a GitHub-based repo.
|
94
109
|
# (Or at least the user isn't using pull requests)
|
95
|
-
if pr.
|
110
|
+
if pr.configuration.get_config_auth_token
|
96
111
|
begin
|
97
|
-
|
98
|
-
|
99
|
-
if pull
|
100
|
-
pr.close(pull[:number])
|
112
|
+
if @pr_number
|
113
|
+
pr.close(@pr_number)
|
101
114
|
else
|
102
|
-
|
115
|
+
mybranches = gitlib.branches()
|
116
|
+
pull = pr.find_pull_request(config.master_branch, mybranches.current.name)
|
117
|
+
if pull
|
118
|
+
pr.close(pull[:number])
|
119
|
+
else
|
120
|
+
logger.debug { "There is no pull request for #{mybranches.current.name} against #{config.master_branch}" }
|
121
|
+
end
|
103
122
|
end
|
104
123
|
rescue GitHubService::NoRemoteRepository => exp
|
105
124
|
logger.debug exp.to_s
|
106
125
|
end
|
107
126
|
else
|
108
|
-
logger.debug
|
127
|
+
logger.debug 'There is no GitHub auth token defined, so not trying to close a pull request.'
|
109
128
|
end
|
110
129
|
end
|
111
130
|
|
@@ -115,12 +134,13 @@ module GitProc
|
|
115
134
|
|
116
135
|
def bad_parking_branch_msg
|
117
136
|
hl = HighLine.new
|
118
|
-
hl.color(
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
137
|
+
hl.color(
|
138
|
+
"\n***********************************************************************************************\n\n"+
|
139
|
+
"There is an old '_parking_' branch with unacounted changes in it.\n"+
|
140
|
+
"It has been renamed to '_parking_OLD_'.\n"+
|
141
|
+
"Please rename the branch to what the changes are about (`git branch -m _parking_OLD_ my_fb_name`),\n"+
|
142
|
+
" or remove it altogher (`git branch -D _parking_OLD_`).\n\n"+
|
143
|
+
"***********************************************************************************************\n", :red, :bold)
|
124
144
|
end
|
125
145
|
|
126
146
|
end
|
data/lib/git-process/sync.rb
CHANGED
@@ -20,20 +20,22 @@ require 'git-process/changed_file_helper'
|
|
20
20
|
module GitProc
|
21
21
|
|
22
22
|
class Sync < Process
|
23
|
-
include ChangeFileHelper
|
24
23
|
|
25
|
-
|
26
|
-
def initialize(dir, opts)
|
24
|
+
def initialize(base, opts)
|
27
25
|
if !opts[:merge].nil? and opts[:merge] == opts[:rebase]
|
28
26
|
raise ArgumentError.new(":merge = #{opts[:merge]} and :rebase = #{opts[:rebase]}")
|
29
27
|
end
|
30
28
|
|
31
|
-
raise ArgumentError.new(
|
29
|
+
raise ArgumentError.new(':rebase is not set') if opts[:rebase].nil?
|
32
30
|
|
33
31
|
@do_rebase = opts[:rebase]
|
34
32
|
@force = opts[:force]
|
35
33
|
@local = opts[:local]
|
34
|
+
|
36
35
|
super
|
36
|
+
|
37
|
+
@change_file_helper = ChangeFileHelper.new(gitlib)
|
38
|
+
self
|
37
39
|
end
|
38
40
|
|
39
41
|
|
@@ -41,8 +43,8 @@ module GitProc
|
|
41
43
|
def verify_preconditions
|
42
44
|
super
|
43
45
|
|
44
|
-
if not status.clean?
|
45
|
-
offer_to_help_uncommitted_changes
|
46
|
+
if not gitlib.status.clean?
|
47
|
+
@change_file_helper.offer_to_help_uncommitted_changes
|
46
48
|
end
|
47
49
|
|
48
50
|
raise ParkedChangesError.new(self) if is_parked?
|
@@ -50,37 +52,35 @@ module GitProc
|
|
50
52
|
|
51
53
|
|
52
54
|
def cleanup
|
53
|
-
stash_pop if @stash_pushed
|
55
|
+
gitlib.stash_pop if @stash_pushed
|
54
56
|
end
|
55
57
|
|
56
58
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
new_sha = rev_parse(@remote_branch) rescue ''
|
59
|
+
def remote_branch_sha
|
60
|
+
gitlib.rev_parse(@remote_branch) rescue ''
|
61
|
+
end
|
61
62
|
|
62
|
-
|
63
|
+
|
64
|
+
def current_branch
|
65
|
+
@current_branch ||= gitlib.branches.current
|
63
66
|
end
|
64
67
|
|
65
68
|
|
66
69
|
def runner
|
67
|
-
@
|
68
|
-
@remote_branch ||= "#{server_name}/#@current_branch"
|
70
|
+
@remote_branch ||= "#{remote.name}/#{current_branch}"
|
69
71
|
|
70
72
|
# if the remote branch has changed, merge those changes in before
|
71
73
|
# doing anything with the integration branch
|
72
|
-
if remote_has_changed
|
74
|
+
if remote_has_changed?
|
73
75
|
logger.info('There have been changes on this remote branch, so will merge them in.')
|
74
76
|
proc_merge(@remote_branch)
|
75
77
|
end
|
76
78
|
|
77
|
-
|
78
|
-
|
79
|
-
if @do_rebase
|
79
|
+
if do_rebase?
|
80
80
|
@force = true
|
81
|
-
proc_rebase(integration_branch)
|
81
|
+
proc_rebase(config.integration_branch)
|
82
82
|
else
|
83
|
-
proc_merge(integration_branch)
|
83
|
+
proc_merge(config.integration_branch)
|
84
84
|
end
|
85
85
|
|
86
86
|
push_to_server
|
@@ -89,28 +89,43 @@ module GitProc
|
|
89
89
|
|
90
90
|
private
|
91
91
|
|
92
|
+
|
93
|
+
def remote_has_changed?
|
94
|
+
old_sha = remote_branch_sha
|
95
|
+
fetch_remote_changes
|
96
|
+
new_sha = remote_branch_sha
|
97
|
+
|
98
|
+
old_sha != new_sha
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
def do_rebase?
|
103
|
+
@do_rebase ||= config['gitProcess.defaultRebaseSync'].to_boolean
|
104
|
+
end
|
105
|
+
|
106
|
+
|
92
107
|
def push_to_server
|
93
108
|
if @local
|
94
|
-
logger.debug(
|
95
|
-
elsif not has_a_remote?
|
96
|
-
logger.debug(
|
97
|
-
elsif @current_branch == master_branch
|
98
|
-
logger.warn(
|
109
|
+
logger.debug('Not pushing to the server because the user selected local-only.')
|
110
|
+
elsif not gitlib.has_a_remote?
|
111
|
+
logger.debug('Not pushing to the server because there is no remote.')
|
112
|
+
elsif @current_branch == config.master_branch
|
113
|
+
logger.warn('Not pushing to the server because the current branch is the mainline branch.')
|
99
114
|
else
|
100
|
-
|
115
|
+
handle_remote_changed
|
101
116
|
|
102
|
-
|
103
|
-
|
104
|
-
push(server_name, @current_branch, @current_branch, :force => @force)
|
117
|
+
gitlib.push(remote.name, @current_branch, @current_branch, :force => @force)
|
105
118
|
end
|
106
119
|
end
|
107
120
|
|
108
121
|
|
109
|
-
def handle_remote_changed
|
110
|
-
|
111
|
-
|
122
|
+
def handle_remote_changed
|
123
|
+
old_sha = remote_branch_sha
|
124
|
+
fetch_remote_changes
|
125
|
+
new_sha = remote_branch_sha
|
126
|
+
|
112
127
|
unless old_sha == new_sha
|
113
|
-
logger.warn("'
|
128
|
+
logger.warn("'#{@current_branch}' changed on '#{config.server_name}'"+
|
114
129
|
" [#{old_sha[0..5]}->#{new_sha[0..5]}]; trying sync again.")
|
115
130
|
runner # try again
|
116
131
|
end
|