Skip to content

Upgrade to ProcessExecuter 4.x #811

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion git.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Gem::Specification.new do |s|

s.add_runtime_dependency 'activesupport', '>= 5.0'
s.add_runtime_dependency 'addressable', '~> 2.8'
s.add_runtime_dependency 'process_executer', '~> 1.3'
s.add_runtime_dependency 'process_executer', '~> 4.0'
s.add_runtime_dependency 'rchardet', '~> 1.9'

s.add_development_dependency 'create_github_release', '~> 2.1'
Expand Down
21 changes: 11 additions & 10 deletions lib/git/command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,13 @@ def initialize(env, binary_path, global_opts, logger)
def run(*args, out: nil, err: nil, normalize:, chomp:, merge:, chdir: nil, timeout: nil)
git_cmd = build_git_cmd(args)
begin
result = ProcessExecuter.run(env, *git_cmd, out: out, err: err, merge:, chdir: (chdir || :not_set), timeout: timeout, raise_errors: false)
rescue ProcessExecuter::Command::ProcessIOError => e
options = { chdir: (chdir || :not_set), timeout_after: timeout, raise_errors: false }
options[:out] = out unless out.nil?
options[:err] = err unless err.nil?
options[:merge_output] = merge unless merge.nil?

result = ProcessExecuter.run_with_capture(env, *git_cmd, **options)
rescue ProcessExecuter::ProcessIOError => e
raise Git::ProcessIOError.new(e.message), cause: e.exception.cause
end
process_result(result, normalize, chomp, timeout)
Expand Down Expand Up @@ -274,14 +279,10 @@ def post_process_all(raw_outputs, normalize, chomp)
# @api private
#
def post_process(raw_output, normalize, chomp)
if raw_output.respond_to?(:string)
output = raw_output.string.dup
output = output.lines.map { |l| Git::EncodingUtils.normalize_encoding(l) }.join if normalize
output.chomp! if chomp
output
else
nil
end
output = raw_output.dup
output = output.lines.map { |l| Git::EncodingUtils.normalize_encoding(l) }.join if normalize
output.chomp! if chomp
output
end
end
end
12 changes: 9 additions & 3 deletions lib/git/command_line_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,21 @@ class CommandLineResult
# result = Git::CommandLineResult.new(git_cmd, status, stdout, stderr)
#
# @param git_cmd [Array<String>] the git command that was executed
# @param status [Process::Status] the status of the process
# @param stdout [String] the output of the process
# @param stderr [String] the error output of the process
# @param status [ProcessExecuter::ResultWithCapture] the status of the process
# @param stdout [String] the processed stdout of the process
# @param stderr [String] the processed stderr of the process
#
def initialize(git_cmd, status, stdout, stderr)
@git_cmd = git_cmd
@status = status
@stdout = stdout
@stderr = stderr

# ProcessExecuter::ResultWithCapture changed the timeout? method to timed_out?
# in version 4.x. This is a compatibility layer to maintain the old method name
# for backward compatibility.
#
status.define_singleton_method(:timeout?) { timed_out? }
end

# @attribute [r] git_cmd
Expand Down
38 changes: 4 additions & 34 deletions tests/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -171,31 +171,6 @@ def windows_platform?
RUBY_PLATFORM =~ win_platform_regex || RUBY_DESCRIPTION =~ win_platform_regex
end

require 'delegate'

# A wrapper around a ProcessExecuter::Status that also includes command output
# @api public
class CommandResult < SimpleDelegator
# Create a new CommandResult
# @example
# status = ProcessExecuter.spawn(*command, timeout:, out:, err:)
# CommandResult.new(status, out_buffer.string, err_buffer.string)
# @param status [ProcessExecuter::Status] The status of the process
# @param out [String] The standard output of the process
# @param err [String] The standard error of the process
def initialize(status, out, err)
super(status)
@out = out
@err = err
end

# @return [String] The stdout output of the process
attr_reader :out

# @return [String] The stderr output of the process
attr_reader :err
end

# Run a command and return the status including stdout and stderr output
#
# @example
Expand All @@ -213,17 +188,12 @@ def initialize(status, out, err)
#
# @return [CommandResult] The result of running
#
def run_command(*command, timeout: nil, raise_errors: true, error_message: "#{command[0]} failed")
out_buffer = StringIO.new
out = ProcessExecuter::MonitoredPipe.new(out_buffer)
err_buffer = StringIO.new
err = ProcessExecuter::MonitoredPipe.new(err_buffer)

status = ProcessExecuter.spawn(*command, timeout: timeout, out: out, err: err)
def run_command(*command, raise_errors: true, error_message: "#{command[0]} failed")
result = ProcessExecuter.run_with_capture(*command, raise_errors: false)

raise "#{error_message}: #{err_buffer.string}" if raise_errors && !status.success?
raise "#{error_message}: #{result.stderr}" if raise_errors && !result.success?

CommandResult.new(status, out_buffer.string, err_buffer.string)
result
end
end

Expand Down
9 changes: 3 additions & 6 deletions tests/units/test_command_line.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def merge
command_line = Git::CommandLine.new(env, binary_path, global_opts, logger)
args = []
error = assert_raise ArgumentError do
command_line.run(*args, out: out_writer, err: err_writer, normalize: normalize, chomp: chomp, merge: merge, timeout: 'not a number')
command_line.run(*args, normalize: normalize, chomp: chomp, timeout_after: 'not a number')
end
end

Expand Down Expand Up @@ -97,7 +97,6 @@ def merge
assert_equal([{}, 'ruby', 'bin/command_line_test', '--stdout=stdout output', '--stderr=stderr output'], result.git_cmd)
assert_equal('stdout output', result.stdout.chomp)
assert_equal('stderr output', result.stderr.chomp)
assert(result.status.is_a? ProcessExecuter::Command::Result)
assert_equal(0, result.status.exitstatus)
end

Expand Down Expand Up @@ -239,10 +238,8 @@ def write(*args)
command_line = Git::CommandLine.new(env, binary_path, global_opts, logger)
args = ['--stderr=ERROR: fatal error', '--stdout=STARTING PROCESS']
Tempfile.create do |f|
err_writer = f
result = command_line.run(*args, out: out_writer, err: err_writer, normalize: normalize, chomp: chomp, merge: merge)
f.rewind
assert_equal('ERROR: fatal error', f.read.chomp)
result = command_line.run(*args, normalize: normalize, chomp: chomp, merge: merge)
assert_equal('ERROR: fatal error', result.stderr.chomp)
end
end

Expand Down