git-process 1.0.11 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/CHANGELOG.md +37 -9
  2. data/Gemfile +2 -2
  3. data/Gemfile.lock +17 -17
  4. data/README.md +14 -7
  5. data/bin/git-new-fb +10 -2
  6. data/bin/git-pull-request +30 -6
  7. data/bin/git-sync +5 -2
  8. data/bin/git-to-master +62 -11
  9. data/git-process.gemspec +15 -15
  10. data/lib/git-process/abstract_error_builder.rb +0 -3
  11. data/lib/git-process/changed_file_helper.rb +30 -24
  12. data/lib/git-process/git_abstract_merge_error_builder.rb +31 -11
  13. data/lib/git-process/git_branch.rb +5 -0
  14. data/lib/git-process/git_config.rb +153 -0
  15. data/lib/git-process/git_lib.rb +212 -164
  16. data/lib/git-process/git_logger.rb +84 -0
  17. data/lib/git-process/git_merge_error.rb +3 -14
  18. data/lib/git-process/git_process.rb +44 -73
  19. data/lib/git-process/git_process_options.rb +6 -6
  20. data/lib/git-process/git_rebase_error.rb +4 -13
  21. data/lib/git-process/git_remote.rb +254 -0
  22. data/lib/git-process/github_configuration.rb +298 -0
  23. data/lib/git-process/github_pull_request.rb +65 -27
  24. data/lib/git-process/new_fb.rb +14 -4
  25. data/lib/git-process/parked_changes_error.rb +1 -1
  26. data/lib/git-process/pull_request.rb +100 -13
  27. data/lib/git-process/pull_request_error.rb +25 -0
  28. data/lib/git-process/rebase_to_master.rb +47 -27
  29. data/lib/git-process/sync.rb +48 -33
  30. data/lib/git-process/uncommitted_changes_error.rb +1 -1
  31. data/lib/git-process/version.rb +2 -2
  32. data/spec/GitRepoHelper.rb +48 -25
  33. data/spec/changed_file_helper_spec.rb +39 -58
  34. data/spec/git_abstract_merge_error_builder_spec.rb +42 -33
  35. data/spec/git_branch_spec.rb +30 -30
  36. data/spec/git_config_spec.rb +45 -0
  37. data/spec/git_lib_spec.rb +103 -122
  38. data/spec/git_logger_spec.rb +66 -0
  39. data/spec/git_process_spec.rb +81 -81
  40. data/spec/git_remote_spec.rb +188 -0
  41. data/spec/git_status_spec.rb +36 -36
  42. data/spec/github_configuration_spec.rb +152 -0
  43. data/spec/github_pull_request_spec.rb +39 -35
  44. data/spec/github_test_helper.rb +49 -0
  45. data/spec/new_fb_spec.rb +65 -24
  46. data/spec/pull_request_helper.rb +94 -0
  47. data/spec/pull_request_spec.rb +128 -0
  48. data/spec/rebase_to_master_spec.rb +241 -145
  49. data/spec/spec_helper.rb +20 -0
  50. data/spec/sync_spec.rb +115 -109
  51. metadata +34 -20
  52. data/lib/git-process/github_client.rb +0 -83
  53. data/lib/git-process/github_service.rb +0 -174
  54. 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"+"Please rename the branch to be a feature branch."
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
- current_branch = branches.current.name
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
- @base_branch = opts[:base_branch] || master_branch
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
- current_branch = branches.current
40
- push(server_name, current_branch, current_branch, :force => false)
41
- pr = GitHub::PullRequest.new(self, @repo_name, {:user => @user, :password => @password})
42
- pr.create(@base_branch, @head_branch, @title, @description)
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(self) if is_parked?
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 has_a_remote?
42
- fetch(server_name)
43
- proc_rebase(integration_branch)
44
- proc_rebase(integration_branch, :interactive => true) if @interactive
45
- push(server_name, branches.current, master_branch)
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[remote_master_branch]
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 '#{remote_master_branch}'")
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["#{server_name}/#{current_branch.name}"]
84
- push(server_name, nil, nil, :delete => current_branch.name)
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(self, repo_name)
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.config_auth_token
110
+ if pr.configuration.get_config_auth_token
96
111
  begin
97
- mybranches = branches()
98
- pull = pr.find_pull_request(master_branch, mybranches.current.name)
99
- if pull
100
- pr.close(pull[:number])
112
+ if @pr_number
113
+ pr.close(@pr_number)
101
114
  else
102
- logger.debug { "There is no pull request for #{mybranches.current.name} against #{master_branch}" }
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 "There is no GitHub auth token defined, so not trying to close a pull request."
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("\n***********************************************************************************************\n\n"+
119
- "There is an old '_parking_' branch with unacounted changes in it.\n"+
120
- "It has been renamed to '_parking_OLD_'.\n"+
121
- "Please rename the branch to what the changes are about (`git branch -m _parking_OLD_ my_fb_name`),\n"+
122
- " or remove it altogher (`git branch -D _parking_OLD_`).\n\n"+
123
- "***********************************************************************************************\n", :red, :bold)
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
@@ -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(":rebase is not set") if opts[:rebase].nil?
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 remote_has_changed
58
- old_sha = rev_parse(@remote_branch) rescue ''
59
- fetch(server_name) if has_a_remote?
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
- old_sha != new_sha
63
+
64
+ def current_branch
65
+ @current_branch ||= gitlib.branches.current
63
66
  end
64
67
 
65
68
 
66
69
  def runner
67
- @current_branch ||= branches.current
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
- @do_rebase ||= config('gitProcess.defaultRebaseSync').to_boolean
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("Not pushing to the server because the user selected local-only.")
95
- elsif not has_a_remote?
96
- logger.debug("Not pushing to the server because there is no remote.")
97
- elsif @current_branch == master_branch
98
- logger.warn("Not pushing to the server because the current branch is the mainline branch.")
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
- old_sha = rev_parse(@remote_branch) rescue ''
115
+ handle_remote_changed
101
116
 
102
- handle_remote_changed(old_sha)
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(old_sha)
110
- fetch(server_name)
111
- new_sha = rev_parse(@remote_branch) rescue ''
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("'#@current_branch' changed on '#{server_name}'"+
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