git-process-lib 2.0.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 (69) hide show
  1. data/CHANGELOG.md +123 -0
  2. data/Gemfile +21 -0
  3. data/Gemfile.lock +57 -0
  4. data/LICENSE +193 -0
  5. data/README.md +342 -0
  6. data/Rakefile +32 -0
  7. data/bin/git-new-fb +39 -0
  8. data/bin/git-pull-request +63 -0
  9. data/bin/git-sync +38 -0
  10. data/bin/git-to-master +44 -0
  11. data/docs/git-new-fb.1.adoc +83 -0
  12. data/docs/git-process.1.adoc +227 -0
  13. data/docs/git-pull-request.1.adoc +166 -0
  14. data/docs/git-sync.1.adoc +120 -0
  15. data/docs/git-to-master.1.adoc +172 -0
  16. data/git-new-fb.gemspec +20 -0
  17. data/git-process-lib.gemspec +25 -0
  18. data/git-process.gemspec +22 -0
  19. data/git-pull-request.gemspec +20 -0
  20. data/git-sync.gemspec +20 -0
  21. data/git-to-master.gemspec +20 -0
  22. data/lib/git-process/abstract_error_builder.rb +53 -0
  23. data/lib/git-process/changed_file_helper.rb +115 -0
  24. data/lib/git-process/git_abstract_merge_error_builder.rb +130 -0
  25. data/lib/git-process/git_branch.rb +105 -0
  26. data/lib/git-process/git_branches.rb +81 -0
  27. data/lib/git-process/git_config.rb +135 -0
  28. data/lib/git-process/git_lib.rb +646 -0
  29. data/lib/git-process/git_logger.rb +84 -0
  30. data/lib/git-process/git_merge_error.rb +28 -0
  31. data/lib/git-process/git_process.rb +159 -0
  32. data/lib/git-process/git_process_error.rb +18 -0
  33. data/lib/git-process/git_process_options.rb +101 -0
  34. data/lib/git-process/git_rebase_error.rb +30 -0
  35. data/lib/git-process/git_remote.rb +222 -0
  36. data/lib/git-process/git_status.rb +108 -0
  37. data/lib/git-process/github_configuration.rb +298 -0
  38. data/lib/git-process/github_pull_request.rb +165 -0
  39. data/lib/git-process/new_fb.rb +49 -0
  40. data/lib/git-process/parked_changes_error.rb +41 -0
  41. data/lib/git-process/pull_request.rb +136 -0
  42. data/lib/git-process/pull_request_error.rb +25 -0
  43. data/lib/git-process/rebase_to_master.rb +148 -0
  44. data/lib/git-process/sync_process.rb +55 -0
  45. data/lib/git-process/syncer.rb +157 -0
  46. data/lib/git-process/uncommitted_changes_error.rb +23 -0
  47. data/lib/git-process/version.rb +22 -0
  48. data/local-build.rb +24 -0
  49. data/spec/FileHelpers.rb +19 -0
  50. data/spec/GitRepoHelper.rb +123 -0
  51. data/spec/changed_file_helper_spec.rb +127 -0
  52. data/spec/git_abstract_merge_error_builder_spec.rb +64 -0
  53. data/spec/git_branch_spec.rb +123 -0
  54. data/spec/git_config_spec.rb +45 -0
  55. data/spec/git_lib_spec.rb +176 -0
  56. data/spec/git_logger_spec.rb +66 -0
  57. data/spec/git_process_spec.rb +208 -0
  58. data/spec/git_remote_spec.rb +227 -0
  59. data/spec/git_status_spec.rb +122 -0
  60. data/spec/github_configuration_spec.rb +152 -0
  61. data/spec/github_pull_request_spec.rb +117 -0
  62. data/spec/github_test_helper.rb +49 -0
  63. data/spec/new_fb_spec.rb +126 -0
  64. data/spec/pull_request_helper.rb +94 -0
  65. data/spec/pull_request_spec.rb +137 -0
  66. data/spec/rebase_to_master_spec.rb +362 -0
  67. data/spec/spec_helper.rb +21 -0
  68. data/spec/sync_spec.rb +1474 -0
  69. metadata +249 -0
@@ -0,0 +1,49 @@
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'
14
+
15
+ module GitProc
16
+
17
+ class NewFeatureBranch < Process
18
+
19
+ def initialize(dir, opts)
20
+ @branch_name = opts[:branch_name]
21
+ @local_only = opts[:local]
22
+ super
23
+ end
24
+
25
+
26
+ def runner
27
+ mybranches = gitlib.branches()
28
+ on_parking = (mybranches.parking == mybranches.current)
29
+
30
+ base_branch = if on_parking and not mybranches[config.integration_branch].contains_all_of(mybranches.parking.name)
31
+ '_parking_'
32
+ else
33
+ config.integration_branch
34
+ end
35
+
36
+ gitlib.fetch if gitlib.has_a_remote? and not @local_only
37
+
38
+ logger.info { "Creating #{@branch_name} off of #{base_branch}" }
39
+ new_branch = gitlib.checkout(@branch_name, :new_branch => base_branch)
40
+
41
+ branches = gitlib.branches()
42
+ branches[@branch_name].upstream(config.integration_branch)
43
+ branches.parking.delete! if on_parking
44
+ new_branch
45
+ end
46
+
47
+ end
48
+
49
+ end
@@ -0,0 +1,41 @@
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 ParkedChangesError < GitProcessError
18
+ include GitProc::AbstractErrorBuilder
19
+
20
+ attr_reader :error_message, :lib
21
+
22
+
23
+ def initialize(lib)
24
+ @lib = lib
25
+ msg = build_message
26
+ super(msg)
27
+ end
28
+
29
+
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.'
32
+ end
33
+
34
+
35
+ def build_commands
36
+ ['git branch -m _parking_ my_feature_branch']
37
+ end
38
+
39
+ end
40
+
41
+ end
@@ -0,0 +1,136 @@
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'
14
+ require 'git-process/github_pull_request'
15
+ require 'git-process/pull_request_error'
16
+ require 'git-process/syncer'
17
+ require 'highline/import'
18
+
19
+
20
+ module GitProc
21
+
22
+ class PullRequest < Process
23
+
24
+ def initialize(dir, opts)
25
+ super
26
+ @base_branch = opts[:base_branch]
27
+ @head_branch = opts[:head_branch]
28
+ @_repo_name = opts[:repo_name]
29
+ @_remote_name = opts[:server]
30
+ @pr_number = opts[:prNumber]
31
+ @title = opts[:title]
32
+ @description = opts[:description]
33
+ @user = opts[:user]
34
+ @password = opts[:password]
35
+ end
36
+
37
+
38
+ def runner
39
+ if @pr_number.nil? or @pr_number.empty?
40
+ pr = create_pull_request
41
+ logger.info { "Created pull request at #{pr.html_url}" }
42
+ else
43
+ checkout_pull_request
44
+ end
45
+ end
46
+
47
+
48
+ def create_pull_request_client(remote_name, repo_name)
49
+ PullRequest.create_pull_request_client(self, remote_name, repo_name, @user, @password)
50
+ end
51
+
52
+
53
+ def create_pull_request
54
+ current_branch = gitlib.branches.current.name
55
+ base_branch = @base_branch || config.master_branch
56
+ head_branch = @head_branch || current_branch
57
+ title = @title || current_branch
58
+ description = @description || ''
59
+
60
+ PullRequest.create_pull_request(gitlib, remote.name, remote.name, remote.repo_name, current_branch, base_branch, head_branch, title, description, logger, @user, @password)
61
+ end
62
+
63
+
64
+ def checkout_pull_request
65
+ PullRequest.checkout_pull_request(gitlib, @pr_number, remote.name, remote.repo_name, @user, @password, logger)
66
+ end
67
+
68
+
69
+ class << self
70
+
71
+ def create_pull_request_client(lib, remote_name, repo_name, username, password)
72
+ GitHub::PullRequest.new(lib, remote_name, repo_name, {:user => username, :password => password})
73
+ end
74
+
75
+
76
+ def create_pull_request(lib, server_name, remote_name, repo_name, current_branch, base_branch, head_branch, title, description, logger, username, password)
77
+ if base_branch == head_branch
78
+ raise PullRequestError.new("Can not create a pull request where the base branch and head branch are the same: #{base_branch}")
79
+ end
80
+
81
+ lib.push(server_name, current_branch, current_branch, :force => false)
82
+ pr = create_pull_request_client(lib, remote_name, repo_name, username, password)
83
+ pr.create(base_branch, head_branch, title, description)
84
+ end
85
+
86
+
87
+ def checkout_pull_request(lib, pr_number, remote_name, repo_name, username, password, logger)
88
+ logger.info { 'Getting #pr_number' }
89
+
90
+ lib.fetch(remote_name)
91
+
92
+ pr = create_pull_request_client(lib, remote_name, repo_name, username, password)
93
+ json = pr.pull_request(pr_number)
94
+ head_branch_name = json.head.ref
95
+ base_branch_name = json.base.ref
96
+
97
+ remote_head_server_name = match_remote_to_pr_remote(lib, json.head.repo.ssh_url)
98
+ remote_base_server_name = match_remote_to_pr_remote(lib, json.base.repo.ssh_url)
99
+ lib.checkout(head_branch_name, :new_branch => "#{remote_head_server_name}/#{head_branch_name}")
100
+ lib.branch(head_branch_name, :upstream => "#{remote_base_server_name}/#{base_branch_name}")
101
+ #logger.info(json.to_hash)
102
+
103
+ lib.fetch(remote_base_server_name) if remote_head_server_name != remote_base_server_name
104
+ Syncer.rebase_sync(lib, true)
105
+ end
106
+
107
+
108
+ def match_remote_to_pr_remote(lib, pr_remote)
109
+ pr_url = lib.remote.expanded_url(nil, pr_remote)
110
+ servers = lib.remote.remote_names
111
+ server_urls = servers.collect { |s| {:server_name => s, :url => lib.remote.expanded_url(s)} }
112
+
113
+ pair = server_urls.find do |su|
114
+ url = su[:url]
115
+ uri = URI.parse(url)
116
+ host = uri.host
117
+ path = uri.path
118
+
119
+ pr_uri = URI.parse(lib.remote.expanded_url(nil, pr_url))
120
+ pr_host = pr_uri.host
121
+ pr_path = pr_uri.path
122
+
123
+ pr_host == host and pr_path == path
124
+ end
125
+
126
+ if pair.nil?
127
+ 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(', ')}")
128
+ end
129
+
130
+ pair[:server_name]
131
+ end
132
+
133
+ end
134
+
135
+ end
136
+ 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
@@ -0,0 +1,148 @@
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'
14
+ require 'git-process/git_rebase_error'
15
+ require 'git-process/git_process_error'
16
+ require 'git-process/parked_changes_error'
17
+ require 'git-process/uncommitted_changes_error'
18
+ require 'git-process/github_pull_request'
19
+ require 'git-process/pull_request'
20
+ require 'git-process/syncer'
21
+
22
+
23
+ module GitProc
24
+
25
+ class RebaseToMaster < Process
26
+
27
+ def initialize(dir, opts)
28
+ @keep = opts[:keep]
29
+ @pr_number = opts[:prNumber]
30
+ @user = opts[:user]
31
+ @password = opts[:password]
32
+ super
33
+ end
34
+
35
+
36
+ def verify_preconditions
37
+ super
38
+
39
+ raise UncommittedChangesError.new unless gitlib.status.clean?
40
+ raise ParkedChangesError.new(gitlib) if is_parked?
41
+ end
42
+
43
+
44
+ def runner
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
+ Syncer.rebase_sync(gitlib, true)
53
+ current = gitlib.branches.current.name
54
+ gitlib.push(remote.name, current, config.master_branch)
55
+
56
+ unless @keep
57
+ close_pull_request
58
+ remove_feature_branch
59
+ gitlib.delete_sync_control_file!(current) if gitlib.sync_control_file_exists?(current)
60
+ end
61
+ else
62
+ Syncer.rebase_sync(gitlib, true)
63
+ end
64
+ end
65
+
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
+
72
+ def remove_feature_branch
73
+ mybranches = gitlib.branches
74
+
75
+ remote_master = mybranches[remote.master_branch_name]
76
+ current_branch = mybranches.current
77
+ logger.debug { "Removing feature branch (#{current_branch})" }
78
+
79
+ unless remote_master.contains_all_of(current_branch.name)
80
+ raise GitProcessError.new("Branch '#{current_branch.name}' has not been merged into '#{remote.master_branch_name}'")
81
+ end
82
+
83
+ parking_branch = mybranches['_parking_']
84
+ if parking_branch
85
+ if parking_branch.is_ahead_of(remote_master.name) and
86
+ !current_branch.contains_all_of(parking_branch.name)
87
+
88
+ parking_branch.rename('_parking_OLD_')
89
+
90
+ logger.warn { bad_parking_branch_msg }
91
+ else
92
+ parking_branch.delete!
93
+ end
94
+ end
95
+ remote_master.checkout_to_new('_parking_', :no_track => true)
96
+
97
+ current_branch.delete!(true)
98
+ if mybranches["#{remote.name}/#{current_branch.name}"]
99
+ gitlib.push(remote.name, nil, nil, :delete => current_branch.name)
100
+ end
101
+ end
102
+
103
+
104
+ def close_pull_request
105
+ pr = GitHub::PullRequest.new(gitlib, remote.name, remote.repo_name)
106
+
107
+ # Assume that if we haven't done something that would create the
108
+ # GitHub auth token, then this likely isn't a GitHub-based repo.
109
+ # (Or at least the user isn't using pull requests)
110
+ if pr.configuration.get_config_auth_token
111
+ begin
112
+ if @pr_number
113
+ pr.close(@pr_number)
114
+ else
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
122
+ end
123
+ rescue GitHubService::NoRemoteRepository => exp
124
+ logger.debug exp.to_s
125
+ end
126
+ else
127
+ logger.debug 'There is no GitHub auth token defined, so not trying to close a pull request.'
128
+ end
129
+ end
130
+
131
+
132
+ private
133
+
134
+
135
+ def bad_parking_branch_msg
136
+ hl = HighLine.new
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)
144
+ end
145
+
146
+ end
147
+
148
+ end
@@ -0,0 +1,55 @@
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'
14
+ require 'git-process/parked_changes_error'
15
+ require 'git-process/syncer'
16
+ require 'git-process/changed_file_helper'
17
+
18
+
19
+ module GitProc
20
+
21
+ class Sync < Process
22
+
23
+ def initialize(base, opts)
24
+ super
25
+
26
+ @opts = opts
27
+
28
+ self
29
+ end
30
+
31
+
32
+ #noinspection RubyControlFlowConversionInspection
33
+ def verify_preconditions
34
+ super
35
+
36
+ if not gitlib.status.clean?
37
+ change_file_helper.offer_to_help_uncommitted_changes
38
+ end
39
+
40
+ raise ParkedChangesError.new(self) if gitlib.is_parked?
41
+ end
42
+
43
+
44
+ def cleanup
45
+ gitlib.stash_pop if @stash_pushed
46
+ end
47
+
48
+
49
+ def runner
50
+ GitProc::Syncer.do_sync(gitlib, @opts)
51
+ end
52
+
53
+ end
54
+
55
+ end