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