Skip to content

Commit

Permalink
Refactor errors that are raised by this gem
Browse files Browse the repository at this point in the history
Signed-off-by: James Couball <jcouball@yahoo.com>
  • Loading branch information
jcouball committed May 6, 2024
1 parent 7e99b17 commit 7376d76
Show file tree
Hide file tree
Showing 18 changed files with 328 additions and 321 deletions.
52 changes: 9 additions & 43 deletions README.md
Expand Up @@ -104,56 +104,22 @@ Pass the `--all` option to `git log` as follows:

## Errors Raised By This Gem

This gem raises custom errors that derive from `Git::Error`. These errors are
arranged in the following class heirarchy:
The git gem will only raise an `ArgumentError` or an error that is a subclass of
`Git::Error`. It does not explicitly raise any other types of errors.

Error heirarchy:

```text
Error
└── CommandLineError
├── FailedError
└── SignaledError
└── TimeoutError
```

Other standard errors may also be raised like `ArgumentError`. Each method should
document the errors it may raise.

Description of each Error class:

* `Error`: This catch-all error serves as the base class for other custom errors in this
gem. Errors of this class are raised when no more approriate specific error to
raise.
* `CommandLineError`: This error is raised when there's a problem executing the git
command line. This gem will raise a more specific error depending on how the
command line failed.
* `FailedError`: This error is raised when the git command line exits with a non-zero
status code that is not expected by the git gem.
* `SignaledError`: This error is raised when the git command line is terminated as a
result of receiving a signal. This could happen if the process is forcibly
terminated or if there is a serious system error.
* `TimeoutError`: This is a specific type of `SignaledError` that is raised when the
git command line operation times out and is killed via the SIGKILL signal. This
happens if the operation takes longer than the timeout duration configured in
`Git.config.timeout` or via the `:timeout` parameter given in git methods that
support this parameter.

`Git::GitExecuteError` remains as an alias for `Git::Error`. It is considered
deprecated as of git-2.0.0.

Here is an example of catching errors when using the git gem:
It is recommended to rescue `Git::Error` to catch any runtime error raised by
this gem unless you need more specific error handling.

```ruby
begin
timeout_duration = 0.001 # seconds
repo = Git.clone('https://github.com/ruby-git/ruby-git', 'ruby-git-temp', timeout: timeout_duration)
rescue Git::TimeoutError => e # Catch the more specific error first!
puts "Git clone took too long and timed out #{e}"
# some git operation
rescue Git::Error => e
puts "Received the following error: #{e}"
puts "An error occurred: #{e.message}"
end
```

See [`Git::Error`](https://rubydoc.info/gems/git/Git/Error) for more information.

## Specifying And Handling Timeouts

The timeout feature was added in git gem version `2.0.0`.
Expand Down
1 change: 1 addition & 0 deletions git.gemspec
Expand Up @@ -27,6 +27,7 @@ Gem::Specification.new do |s|
s.required_ruby_version = '>= 3.0.0'
s.requirements = ['git 2.28.0 or greater']

s.add_runtime_dependency 'activesupport', '>= 5.0'
s.add_runtime_dependency 'addressable', '~> 2.8'
s.add_runtime_dependency 'process_executer', '~> 1.1'
s.add_runtime_dependency 'rchardet', '~> 1.8'
Expand Down
17 changes: 7 additions & 10 deletions lib/git.rb
@@ -1,34 +1,31 @@
# Add the directory containing this file to the start of the load path if it
# isn't there already.
$:.unshift(File.dirname(__FILE__)) unless
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
require 'active_support'
require 'active_support/deprecation'

module Git
Deprecation = ActiveSupport::Deprecation.new('3.0', 'Git')
end

require 'git/author'
require 'git/base'
require 'git/branch'
require 'git/branches'
require 'git/command_line_error'
require 'git/command_line_result'
require 'git/command_line'
require 'git/config'
require 'git/diff'
require 'git/encoding_utils'
require 'git/error'
require 'git/errors'
require 'git/escaped_path'
require 'git/failed_error'
require 'git/git_execute_error'
require 'git/index'
require 'git/lib'
require 'git/log'
require 'git/object'
require 'git/path'
require 'git/remote'
require 'git/repository'
require 'git/signaled_error'
require 'git/status'
require 'git/stash'
require 'git/stashes'
require 'git/timeout_error'
require 'git/url'
require 'git/version'
require 'git/working_directory'
Expand Down
15 changes: 8 additions & 7 deletions lib/git/command_line.rb
Expand Up @@ -2,8 +2,7 @@

require 'git/base'
require 'git/command_line_result'
require 'git/failed_error'
require 'git/signaled_error'
require 'git/errors'
require 'stringio'

module Git
Expand Down Expand Up @@ -186,7 +185,7 @@ def initialize(env, binary_path, global_opts, logger)
#
# @raise [Git::FailedError] if the command returned a non-zero exitstatus
#
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
# @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
#
# @raise [Git::TimeoutError] if the command times out
#
Expand Down Expand Up @@ -260,14 +259,14 @@ def post_process_all(writers, normalize, chomp)
# @param pipe_name [Symbol] the name of the pipe that raised the exception
# @param pipe [ProcessExecuter::MonitoredPipe] the pipe that raised the exception
#
# @raise [Git::GitExecuteError]
# @raise [Git::ProcessIOError]
#
# @return [void] this method always raises an error
#
# @api private
#
def raise_pipe_error(git_cmd, pipe_name, pipe)
raise Git::GitExecuteError.new("Pipe Exception for #{git_cmd}: #{pipe_name}"), cause: pipe.exception
raise Git::ProcessIOError.new("Pipe Exception for #{git_cmd}: #{pipe_name}"), cause: pipe.exception
end

# Execute the git command and collect the output
Expand All @@ -281,7 +280,7 @@ def raise_pipe_error(git_cmd, pipe_name, pipe)
#
# If the command does not respond to SIGKILL, it will hang this method.
#
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
# @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
# @raise [Git::TimeoutError] if the command times out
#
# @return [ProcessExecuter::Status] the status of the completed subprocess
Expand Down Expand Up @@ -334,6 +333,8 @@ def writers(out, err)
#
# @raise [Git::FailedError] if the command failed
# @raise [Git::SignaledError] if the command was signaled
# @raise [Git::TimeoutError] if the command times out
# @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
#
# @api private
#
Expand Down Expand Up @@ -361,7 +362,7 @@ def process_result(git_cmd, status, out, err, normalize, chomp, timeout)
#
# If the command does not respond to SIGKILL, it will hang this method.
#
# @raise [Git::GitExecuteError] if an exception was raised while collecting subprocess output
# @raise [Git::ProcessIOError] if an exception was raised while collecting subprocess output
# @raise [Git::TimeoutError] if the command times out
#
# @return [Git::CommandLineResult] the result of the command to return to the caller
Expand Down
59 changes: 0 additions & 59 deletions lib/git/command_line_error.rb

This file was deleted.

7 changes: 0 additions & 7 deletions lib/git/error.rb

This file was deleted.

0 comments on commit 7376d76

Please sign in to comment.