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
@@ -14,9 +14,6 @@ require 'shellwords'
14
14
 
15
15
  module GitProc
16
16
 
17
- #
18
- # Assumes that there are two attributes defined: error_message, lib
19
- #
20
17
  module AbstractErrorBuilder
21
18
 
22
19
  def commands
@@ -19,32 +19,34 @@ module GitProc
19
19
  #
20
20
  # Provides support for prompting the user when the dir/index is dirty.
21
21
  #
22
- # = Assumes =
23
- # log_level
24
- # workdir
25
- #
26
- module ChangeFileHelper
27
- include GitLib
22
+ #noinspection RubyControlFlowConversionInspection,RubyClassMethodNamingConvention,RubyInstanceMethodNamingConvention
23
+ class ChangeFileHelper
24
+
25
+ # @param [GitLib] gitlib
26
+ def initialize(gitlib)
27
+ @gitlib = gitlib
28
+ end
28
29
 
29
30
 
30
31
  def offer_to_help_uncommitted_changes
31
- stat = status
32
+ stat = gitlib.status
32
33
 
33
34
  if stat.unmerged.empty?
34
35
  handle_unknown_files(stat)
35
- handle_changed_files(status) # refresh status in case it changed earlier
36
+ handle_changed_files(gitlib.status) # refresh status in case it changed earlier
36
37
  else
37
- logger.info { "Can not offer to auto-add unmerged files: #{stat.unmerged.inspect}" }
38
+ gitlib.logger.info { "Can not offer to auto-add unmerged files: #{stat.unmerged.inspect}" }
38
39
  raise UncommittedChangesError.new
39
40
  end
40
41
  end
41
42
 
42
43
 
44
+ #noinspection RubyControlFlowConversionInspection
43
45
  def handle_unknown_files(stat)
44
46
  if not stat.unknown.empty?
45
- resp = ask_how_to_handle_unknown_files(stat)
47
+ resp = ChangeFileHelper.ask_how_to_handle_unknown_files(stat)
46
48
  if resp == :add
47
- add(stat.unknown)
49
+ gitlib.add(stat.unknown)
48
50
  end
49
51
  end
50
52
  end
@@ -52,26 +54,25 @@ module GitProc
52
54
 
53
55
  def handle_changed_files(stat)
54
56
  if not stat.modified.empty? or not stat.added.empty? or not stat.deleted.empty?
55
- resp = ask_how_to_handle_changed_files(stat)
57
+ resp = ChangeFileHelper.ask_how_to_handle_changed_files(stat)
56
58
  if resp == :commit
57
59
  changed_files = (stat.added + stat.modified - stat.deleted).sort.uniq
58
60
 
59
- add(changed_files) unless changed_files.empty?
60
- remove(stat.deleted) unless stat.deleted.empty?
61
+ gitlib.add(changed_files) unless changed_files.empty?
62
+ gitlib.remove(stat.deleted) unless stat.deleted.empty?
61
63
 
62
- commit(nil)
64
+ gitlib.commit(nil)
63
65
  else
64
- stash_save
65
- @stash_pushed = true
66
+ gitlib.stash_save
66
67
  end
67
68
  end
68
69
  end
69
70
 
70
71
 
71
- def ask_how_to_handle_unknown_files(stat)
72
+ def self.ask_how_to_handle_unknown_files(stat)
72
73
  show_changes(:unknown, stat)
73
- resp = ask("Would you like to (a)dd them or (i)gnore them? ") do |q|
74
- q.responses[:not_valid] = "Please respond with either (a)dd or (i)gnore. (Ctl-C to abort.) "
74
+ resp = ask('Would you like to (a)dd them or (i)gnore them? ') do |q|
75
+ q.responses[:not_valid] = 'Please respond with either (a)dd or (i)gnore. (Ctl-C to abort.) '
75
76
  q.case = :down
76
77
  q.validate = /a|i/i
77
78
  end
@@ -80,7 +81,7 @@ module GitProc
80
81
  end
81
82
 
82
83
 
83
- def show_changes(type, stat)
84
+ def self.show_changes(type, stat)
84
85
  files = stat.send(type)
85
86
 
86
87
  if type != :deleted
@@ -93,10 +94,10 @@ module GitProc
93
94
  end
94
95
 
95
96
 
96
- def ask_how_to_handle_changed_files(stat)
97
+ def self.ask_how_to_handle_changed_files(stat)
97
98
  [:added, :modified, :deleted].each { |t| show_changes(t, stat) }
98
- resp = ask("Would you like to (c)ommit them or (s)tash them? ") do |q|
99
- q.responses[:not_valid] = "Please respond with either (c)ommit or (s)tash. (Ctl-C to abort.) "
99
+ resp = ask('Would you like to (c)ommit them or (s)tash them? ') do |q|
100
+ q.responses[:not_valid] = 'Please respond with either (c)ommit or (s)tash. (Ctl-C to abort.) '
100
101
  q.case = :down
101
102
  q.validate = /c|s/i
102
103
  end
@@ -104,6 +105,11 @@ module GitProc
104
105
  resp == 'c' ? :commit : :stash
105
106
  end
106
107
 
108
+
109
+ def gitlib
110
+ @gitlib
111
+ end
112
+
107
113
  end
108
114
 
109
115
  end
@@ -15,12 +15,19 @@ require 'shellwords'
15
15
 
16
16
  module GitProc
17
17
 
18
- #
19
- # Assumes that there are three attributes defined: error_message, lib, continue_command
20
- #
21
- module AbstractMergeErrorBuilder
18
+ #noinspection RubyTooManyInstanceVariablesInspection
19
+ class AbstractMergeErrorBuilder
22
20
  include GitProc::AbstractErrorBuilder
23
21
 
22
+ attr_reader :gitlib, :error_message, :continue_command
23
+
24
+
25
+ def initialize(gitlib, error_message, continue_command)
26
+ @gitlib = gitlib
27
+ @error_message = error_message
28
+ @continue_command = continue_command
29
+ end
30
+
24
31
 
25
32
  def resolved_files
26
33
  @resolved_files ||= find_resolved_files
@@ -53,7 +60,7 @@ module GitProc
53
60
  end
54
61
  end
55
62
 
56
- unless lib.rerere_enabled?
63
+ unless config.rerere_enabled?
57
64
  msg << "\n\nConsider turning on 'rerere'.\nSee http://git-scm.com/2010/03/08/rerere.html for more information."
58
65
  end
59
66
 
@@ -70,13 +77,13 @@ module GitProc
70
77
  def build_commands
71
78
  commands = []
72
79
 
73
- commands << 'git config --global rerere.enabled true' unless lib.rerere_enabled?
80
+ commands << 'git config --global rerere.enabled true' unless config.rerere_enabled?
74
81
 
75
82
  resolved_files.each do |file|
76
83
  commands << "# Verify that 'rerere' did the right thing for '#{file}'."
77
84
  end
78
85
 
79
- unless resolved_files.empty? or lib.rerere_autoupdate?
86
+ unless resolved_files.empty? or config.rerere_autoupdate?
80
87
  escaped_files = shell_escaped_files(resolved_files)
81
88
  commands << "git add #{escaped_files}"
82
89
  end
@@ -103,22 +110,35 @@ module GitProc
103
110
 
104
111
 
105
112
  def unmerged
106
- @unmerged ||= lib.status.unmerged
113
+ @unmerged ||= status.unmerged
107
114
  end
108
115
 
109
116
 
110
117
  def added
111
- @added ||= lib.status.added
118
+ @added ||= status.added
112
119
  end
113
120
 
114
121
 
115
122
  def deleted
116
- @deleted ||= lib.status.deleted
123
+ @deleted ||= status.deleted
117
124
  end
118
125
 
119
126
 
120
127
  def modified
121
- @modified ||= lib.status.modified
128
+ @modified ||= status.modified
129
+ end
130
+
131
+
132
+ private
133
+
134
+
135
+ def config
136
+ gitlib.config
137
+ end
138
+
139
+
140
+ def status
141
+ @status ||= gitlib.status
122
142
  end
123
143
 
124
144
  end
@@ -86,6 +86,11 @@ module GitProc
86
86
  end
87
87
 
88
88
 
89
+ def upstream(upstream_name)
90
+ @lib.branch(@name, :upstream => upstream_name)
91
+ end
92
+
93
+
89
94
  def contains_all_of(branch_name)
90
95
  @lib.rev_list(@name, branch_name, :oneline => true, :num_revs => 1) == ''
91
96
  end
@@ -0,0 +1,153 @@
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_logger'
14
+ require 'git-process/git_branch'
15
+ require 'git-process/git_branches'
16
+ require 'git-process/git_status'
17
+ require 'git-process/git_process_error'
18
+
19
+
20
+ class String
21
+
22
+ def to_boolean
23
+ return false if self == false || self.nil? || self =~ (/(false|f|no|n|0)$/i)
24
+ return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
25
+ raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
26
+ end
27
+
28
+ end
29
+
30
+
31
+ class NilClass
32
+ def to_boolean
33
+ false
34
+ end
35
+ end
36
+
37
+
38
+ module GitProc
39
+
40
+ #
41
+ # Provides Git configuration
42
+ #
43
+ class GitConfig
44
+
45
+ def initialize(lib)
46
+ @lib = lib
47
+ end
48
+
49
+
50
+ def [](key)
51
+ value = config_hash[key]
52
+ unless value
53
+ value = @lib.command(:config, ['--get', key])
54
+ value = nil if value.empty?
55
+ config_hash[key] = value unless config_hash.empty?
56
+ end
57
+ value
58
+ end
59
+
60
+
61
+ def []=(key, value)
62
+ @lib.command(:config, [key, value])
63
+ config_hash[key] = value unless config_hash.empty?
64
+ value
65
+ end
66
+
67
+
68
+ def set_global(key, value)
69
+ @lib.command(:config, ['--global', key, value])
70
+ config_hash[key] = value unless config_hash.empty?
71
+ value
72
+ end
73
+
74
+
75
+ def gitlib
76
+ @lib
77
+ end
78
+
79
+
80
+ def logger
81
+ gitlib.logger
82
+ end
83
+
84
+
85
+ def master_branch
86
+ @master_branch ||= self['gitProcess.integrationBranch'] || 'master'
87
+ end
88
+
89
+
90
+ def remote_master_branch
91
+ remote.master_branch_name
92
+ end
93
+
94
+
95
+ def integration_branch
96
+ remote.exists? ? remote_master_branch : self.master_branch
97
+ end
98
+
99
+
100
+ def rerere_enabled?
101
+ re = self['rerere.enabled']
102
+ re && re.to_boolean
103
+ end
104
+
105
+
106
+ def rerere_enabled(re, global = true)
107
+ if global
108
+ set_global('rerere.enabled', re)
109
+ else
110
+ self['rerere.enabled'] = re
111
+ end
112
+ end
113
+
114
+
115
+ def rerere_enabled=(re)
116
+ rerere_enabled(re, false)
117
+ end
118
+
119
+
120
+ def rerere_autoupdate?
121
+ re = self['rerere.autoupdate']
122
+ re && re.to_boolean
123
+ end
124
+
125
+
126
+ def rerere_autoupdate(re, global = true)
127
+ if global
128
+ set_global('rerere.autoupdate', re)
129
+ else
130
+ self['rerere.autoupdate'] = re
131
+ end
132
+ end
133
+
134
+
135
+ def rerere_autoupdate=(re)
136
+ rerere_autoupdate(re, false)
137
+ end
138
+
139
+
140
+ private
141
+
142
+ def remote
143
+ gitlib.remote
144
+ end
145
+
146
+
147
+ def config_hash
148
+ @config_hash ||= {}
149
+ end
150
+
151
+ end
152
+
153
+ end
@@ -13,28 +13,11 @@
13
13
  require 'logger'
14
14
  require 'git-process/git_branch'
15
15
  require 'git-process/git_branches'
16
+ require 'git-process/git_remote'
16
17
  require 'git-process/git_status'
17
18
  require 'git-process/git_process_error'
18
19
 
19
20
 
20
- class String
21
-
22
- def to_boolean
23
- return false if self == false || self.nil? || self =~ (/(false|f|no|n|0)$/i)
24
- return true if self == true || self =~ (/(true|t|yes|y|1)$/i)
25
- raise ArgumentError.new("invalid value for Boolean: \"#{self}\"")
26
- end
27
-
28
- end
29
-
30
-
31
- class NilClass
32
- def to_boolean
33
- false
34
- end
35
- end
36
-
37
-
38
21
  module GitProc
39
22
 
40
23
  class GitExecuteError < GitProcessError
@@ -44,41 +27,95 @@ module GitProc
44
27
  #
45
28
  # Provides Git commands
46
29
  #
47
- # = Assumes =
48
- # log_level
49
- # workdir
50
- #
51
- module GitLib
30
+ #noinspection RubyTooManyMethodsInspection
31
+ class GitLib
32
+
33
+ # @param [Dir] dir
34
+ def initialize(dir, opts)
35
+ self.log_level = GitLib.log_level(opts)
36
+ self.workdir = dir
37
+ end
38
+
52
39
 
53
40
  def logger
54
41
  if @logger.nil?
55
- @logger = Logger.new(STDOUT)
56
- @logger.level = log_level || Logger::WARN
57
- @logger.datetime_format = "%Y-%m-%d %H:%M:%S"
58
- @logger.formatter = proc do |_, _, _, msg|
59
- "#{msg}\n"
60
- end
42
+ @logger = GitLogger.new(log_level)
61
43
  end
62
44
  @logger
63
45
  end
64
46
 
65
47
 
66
- def server_name
67
- @server_name ||= remote_name
48
+ def self.log_level(opts)
49
+ if opts[:log_level]
50
+ opts[:log_level]
51
+ elsif opts[:quiet]
52
+ Logger::ERROR
53
+ elsif opts[:verbose]
54
+ Logger::DEBUG
55
+ else
56
+ Logger::INFO
57
+ end
58
+ end
59
+
60
+
61
+ def log_level
62
+ @log_level || Logger::WARN
63
+ end
64
+
65
+
66
+ def log_level=(lvl)
67
+ @log_level = lvl
68
+ end
69
+
70
+
71
+ def workdir
72
+ @workdir
73
+ end
74
+
75
+
76
+ def workdir=(dir)
77
+ workdir = GitLib.find_workdir(dir)
78
+ if workdir.nil?
79
+ @workdir = dir
80
+ logger.info { "Initializing new repository at #{dir}" }
81
+ command(:init)
82
+ else
83
+ @workdir = workdir
84
+ logger.debug { "Opening existing repository at #{dir}" }
85
+ end
86
+ end
87
+
88
+
89
+ def self.find_workdir(dir)
90
+ if dir == File::SEPARATOR
91
+ nil
92
+ elsif File.directory?(File.join(dir, '.git'))
93
+ dir
94
+ else
95
+ find_workdir(File.expand_path("#{dir}#{File::SEPARATOR}.."))
96
+ end
97
+ end
98
+
99
+
100
+ def config
101
+ if @config.nil?
102
+ @config = GitConfig.new(self)
103
+ end
104
+ @config
68
105
  end
69
106
 
70
107
 
71
- def master_branch
72
- @master_branch ||= config('gitProcess.integrationBranch') || 'master'
108
+ def remote
109
+ if @remote.nil?
110
+ @remote = GitProc::GitRemote.new(config)
111
+ end
112
+ @remote
73
113
  end
74
114
 
75
115
 
76
116
  # @return [Boolean] does this have a remote defined?
77
117
  def has_a_remote?
78
- if @has_remote == nil
79
- @has_remote = (command(:remote) != '')
80
- end
81
- @has_remote
118
+ remote.exists?
82
119
  end
83
120
 
84
121
 
@@ -89,7 +126,7 @@ module GitProc
89
126
 
90
127
 
91
128
  def commit(msg = nil)
92
- logger.info "Committing changes"
129
+ logger.info 'Committing changes'
93
130
  command(:commit, msg.nil? ? nil : ['-m', msg])
94
131
  end
95
132
 
@@ -113,9 +150,60 @@ module GitProc
113
150
  end
114
151
 
115
152
 
116
- def fetch(name = remote_name)
117
- logger.info "Fetching the latest changes from the server"
118
- command(:fetch, ['-p', name])
153
+ def fetch(name = remote.name)
154
+ logger.info 'Fetching the latest changes from the server'
155
+ output = self.command(:fetch, ['-p', name])
156
+
157
+ log_fetch_changes(fetch_changes(output))
158
+
159
+ output
160
+ end
161
+
162
+
163
+ # @param [Hash] changes a hash of the changes that were made
164
+ #
165
+ # @return [void]
166
+ def log_fetch_changes(changes)
167
+ changes.each do |key, v|
168
+ unless v.empty?
169
+ logger.info { " #{key.to_s.sub(/_/, ' ')}: #{v.join(', ')}" }
170
+ end
171
+ end
172
+ end
173
+
174
+
175
+ # @return [Hash]
176
+ def fetch_changes(output)
177
+ changed = output.split("\n")
178
+
179
+ changes = {:new_branch => [], :new_tag => [], :force_updated => [], :deleted => [], :updated => []}
180
+
181
+ line = changed.shift
182
+
183
+ until line.nil? do
184
+ case line
185
+ when /^\s\s\s/
186
+ m = /^\s\s\s(\S+)\s+(\S+)\s/.match(line)
187
+ changes[:updated] << "#{m[2]} (#{m[1]})"
188
+ when /^\s\*\s\[new branch\]/
189
+ m = /^\s\*\s\[new branch\]\s+(\S+)\s/.match(line)
190
+ changes[:new_branch] << m[1]
191
+ when /^\s\*\s\[new tag\]/
192
+ m = /^\s\*\s\[new tag\]\s+(\S+)\s/.match(line)
193
+ changes[:new_tag] << m[1]
194
+ when /^\sx\s/
195
+ m = /^\sx\s\[deleted\]\s+\(none\)\s+->\s+[^\/]+\/(\S+)/.match(line)
196
+ changes[:deleted] << m[1]
197
+ when /^\s\+\s/
198
+ m = /^\s\+\s(\S+)\s+(\S+)\s/.match(line)
199
+ changes[:force_updated] << "#{m[2]} (#{m[1]})"
200
+ else
201
+ # ignore the line
202
+ end
203
+ line = changed.shift
204
+ end
205
+
206
+ changes
119
207
  end
120
208
 
121
209
 
@@ -134,38 +222,27 @@ module GitProc
134
222
  # @option opts [Boolean] :all list all branches, local and remote
135
223
  # @option opts [Boolean] :no_color force not using any ANSI color codes
136
224
  # @option opts [String] :rename the new name for the branch
225
+ # @option opts [String] :upstream the new branch to track
137
226
  # @option opts [String] :base_branch the branch to base the new branch off of;
138
227
  # defaults to 'master'
139
228
  #
140
229
  # @return [String] the output of running the git command
141
230
  def branch(branch_name, opts = {})
142
- args = []
143
231
  if opts[:delete]
144
- logger.info { "Deleting local branch '#{branch_name}'." } unless branch_name == '_parking_'
145
-
146
- args << (opts[:force] ? '-D' : '-d')
147
- args << branch_name
232
+ delete_branch(branch_name, opts[:force])
148
233
  elsif opts[:rename]
149
- logger.info { "Renaming branch '#{branch_name}' to '#{opts[:rename]}'." }
150
-
151
- args << '-m' << branch_name << opts[:rename]
234
+ rename_branch(branch_name, opts[:rename])
235
+ elsif opts[:upstream]
236
+ set_upstream_branch(branch_name, opts[:upstream])
152
237
  elsif branch_name
153
238
  if opts[:force]
154
- raise ArgumentError.new("Need :base_branch when using :force for a branch.") unless opts[:base_branch]
155
- logger.info { "Changing branch '#{branch_name}' to point to '#{opts[:base_branch]}'." }
156
-
157
- args << '-f' << branch_name << opts[:base_branch]
239
+ change_branch(branch_name, opts[:base_branch])
158
240
  else
159
- logger.info { "Creating new branch '#{branch_name}' based on '#{opts[:base_branch]}'." }
160
-
161
- args << branch_name
162
- args << (opts[:base_branch] ? opts[:base_branch] : 'master')
241
+ create_branch(branch_name, opts[:base_branch])
163
242
  end
164
243
  else
165
- args << '-a' if opts[:all]
166
- args << '--no-color' if opts[:no_color]
244
+ list_branches(opts[:all], opts[:no_color])
167
245
  end
168
- command(:branch, args)
169
246
  end
170
247
 
171
248
 
@@ -195,10 +272,10 @@ module GitProc
195
272
  elsif !(opts[:delete].is_a? TrueClass)
196
273
  rb = opts[:delete]
197
274
  else
198
- raise ArgumentError.new("Need a branch name to delete.")
275
+ raise ArgumentError.new('Need a branch name to delete.')
199
276
  end
200
277
 
201
- int_branch = master_branch
278
+ int_branch = config.master_branch
202
279
  if rb == int_branch
203
280
  raise GitProc::GitProcessError.new("Can not delete the integration branch '#{int_branch}'")
204
281
  end
@@ -278,69 +355,6 @@ module GitProc
278
355
  end
279
356
 
280
357
 
281
- def config_hash
282
- @config_hash ||= {}
283
- end
284
-
285
-
286
- private :config_hash
287
-
288
-
289
- def config(key = nil, value = nil, global = false)
290
- if key and value
291
- args = global ? %w(--global) : []
292
- args << key << value
293
- command(:config, args)
294
- config_hash[key] = value unless config_hash.empty?
295
- value
296
- elsif key
297
- value = config_hash[key]
298
- unless value
299
- value = command(:config, ['--get', key])
300
- value = nil if value.empty?
301
- config_hash[key] = value unless config_hash.empty?
302
- end
303
- value
304
- else
305
- if config_hash.empty?
306
- str = command(:config, '--list')
307
- lines = str.split("\n")
308
- lines.each do |line|
309
- (key, *values) = line.split('=')
310
- config_hash[key] = values.join('=')
311
- end
312
- end
313
- config_hash
314
- end
315
- end
316
-
317
-
318
- def repo_name
319
- unless @repo_name
320
- origin_url = config("remote.#{remote_name}.url")
321
- raise GitProc::Process::GitProcessError.new("There is no #{remote_name} url set up.") if origin_url.empty?
322
- @repo_name = origin_url.sub(/^.*:(.*?)(.git)?$/, '\1')
323
- end
324
- @repo_name
325
- end
326
-
327
-
328
- def remote_name
329
- unless @remote_name
330
- @remote_name = config('gitProcess.remoteName')
331
- if @remote_name.nil? or @remote_name.empty?
332
- remote_str = command(:remote)
333
- unless remote_str == nil or remote_str.empty?
334
- @remote_name = remote_str.split(/\n/)[0]
335
- raise "!@remote_name.is_a? String" unless @remote_name.is_a? String
336
- end
337
- end
338
- logger.debug { "Using remote name of '#@remote_name'" }
339
- end
340
- @remote_name
341
- end
342
-
343
-
344
358
  #
345
359
  # Returns the status of the git repository.
346
360
  #
@@ -367,28 +381,6 @@ module GitProc
367
381
  end
368
382
 
369
383
 
370
- def rerere_enabled?
371
- re = config('rerere.enabled')
372
- re && re.to_boolean
373
- end
374
-
375
-
376
- def rerere_enabled(re, global = true)
377
- config('rerere.enabled', re, global)
378
- end
379
-
380
-
381
- def rerere_autoupdate?
382
- re = config('rerere.autoupdate')
383
- re && re.to_boolean
384
- end
385
-
386
-
387
- def rerere_autoupdate(re, global = true)
388
- config('rerere.autoupdate', re, global)
389
- end
390
-
391
-
392
384
  def rev_list(start_revision, end_revision, opts ={})
393
385
  args = []
394
386
  args << "-#{opts[:num_revs]}" if opts[:num_revs]
@@ -406,40 +398,52 @@ module GitProc
406
398
  alias sha rev_parse
407
399
 
408
400
 
409
- def add_remote(remote_name, url)
410
- command(:remote, ['add', remote_name, url])
401
+ # @return [String]
402
+ def command(cmd, opts = [], chdir = true, redirect = '', &block)
403
+ ENV['GIT_INDEX_FILE'] = File.join(workdir, '.git', 'index')
404
+ ENV['GIT_DIR'] = File.join(workdir, '.git')
405
+ ENV['GIT_WORK_TREE'] = workdir
406
+ path = workdir
407
+
408
+ git_cmd = create_git_command(cmd, opts, redirect)
409
+
410
+ out = command_git_cmd(path, git_cmd, chdir, block)
411
+
412
+ if logger
413
+ logger.debug(git_cmd)
414
+ logger.debug(out)
415
+ end
416
+
417
+ handle_exitstatus($?, git_cmd, out)
411
418
  end
412
419
 
413
420
 
414
421
  private
415
422
 
416
423
 
417
- def command(cmd, opts = [], chdir = true, redirect = '', &block)
418
- ENV['GIT_DIR'] = File.join(workdir, '.git')
419
- ENV['GIT_INDEX_FILE'] = File.join(workdir, '.git', 'index')
420
- ENV['GIT_WORK_TREE'] = workdir
421
- path = workdir
422
-
424
+ def create_git_command(cmd, opts, redirect)
423
425
  opts = [opts].flatten.map { |s| escape(s) }.join(' ')
424
- git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"
426
+ "git #{cmd} #{opts} #{redirect} 2>&1"
427
+ end
425
428
 
429
+
430
+ def command_git_cmd(path, git_cmd, chdir, block)
426
431
  out = nil
427
432
  if chdir and (Dir.getwd != path)
428
433
  Dir.chdir(path) { out = run_command(git_cmd, &block) }
429
434
  else
430
435
  out = run_command(git_cmd, &block)
431
436
  end
437
+ out
438
+ end
432
439
 
433
- if logger
434
- logger.debug(git_cmd)
435
- logger.debug(out)
436
- end
437
440
 
438
- if $?.exitstatus > 0
439
- if $?.exitstatus == 1 && out == ''
440
- return ''
441
+ # @return [String]
442
+ def handle_exitstatus(proc_status, git_cmd, out)
443
+ if proc_status.exitstatus > 0
444
+ unless proc_status.exitstatus == 1 && out == ''
445
+ raise GitProc::GitExecuteError.new(git_cmd + ':' + out.to_s)
441
446
  end
442
- raise GitProc::GitExecuteError.new(git_cmd + ':' + out.to_s)
443
447
  end
444
448
  out
445
449
  end
@@ -459,6 +463,50 @@ module GitProc
459
463
  %Q{"#{escaped}"}
460
464
  end
461
465
 
466
+
467
+ def change_branch(branch_name, base_branch)
468
+ raise ArgumentError.new('Need :base_branch when using :force for a branch.') unless base_branch
469
+ logger.info { "Changing branch '#{branch_name}' to point to '#{base_branch}'." }
470
+
471
+ command(:branch, ['-f', branch_name, base_branch])
472
+ end
473
+
474
+
475
+ def create_branch(branch_name, base_branch)
476
+ logger.info { "Creating new branch '#{branch_name}' based on '#{base_branch}'." }
477
+
478
+ command(:branch, [branch_name, (base_branch || 'master')])
479
+ end
480
+
481
+
482
+ def list_branches(all_branches, no_color)
483
+ args = []
484
+ args << '-a' if all_branches
485
+ args << '--no-color' if no_color
486
+ command(:branch, args)
487
+ end
488
+
489
+
490
+ def delete_branch(branch_name, force)
491
+ logger.info { "Deleting local branch '#{branch_name}'." } unless branch_name == '_parking_'
492
+
493
+ command(:branch, [force ? '-D' : '-d', branch_name])
494
+ end
495
+
496
+
497
+ def rename_branch(branch_name, new_name)
498
+ logger.info { "Renaming branch '#{branch_name}' to '#{new_name}'." }
499
+
500
+ command(:branch, ['-m', branch_name, new_name])
501
+ end
502
+
503
+
504
+ def set_upstream_branch(branch_name, upstream)
505
+ logger.info { "Setting upstream/tracking for branch '#{branch_name}' to '#{upstream}'." }
506
+
507
+ command(:branch, ['--set-upstream-to', upstream, branch_name])
508
+ end
509
+
462
510
  end
463
511
 
464
512
  end