Class: Makit::Services::ErrorHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/makit/services/error_handler.rb

Overview

Service class responsible for handling and formatting errors Provides user-friendly error messages and recovery suggestions

Constant Summary collapse

ERROR_MESSAGES =

Error message templates with suggestions

{
  invalid_url: {
    message: "The repository URL '%<url>s' is not valid.",
    suggestions: [
      "Use HTTPS format: https://github.com/user/repo.git",
      "Use SSH format: [email protected]:user/repo.git",
      "Use simple format: user/repo",
      "Ensure the URL points to a git repository",
    ],
  },
  invalid_directory: {
    message: "The directory path '%<directory>s' is not valid.",
    suggestions: [
      "Use absolute paths like /path/to/directory",
      "Use relative paths like ./relative/path",
      "Ensure the path doesn't contain null characters",
      "Keep directory paths under 255 characters",
    ],
  },
  invalid_commit: {
    message: "The commit '%<commit>s' is not valid.",
    suggestions: [
      "Use 'latest' for the most recent commit",
      "Use a full 40-character commit hash",
      "Use a short 7+ character commit hash",
      "Verify the commit exists in the repository",
    ],
  },
  directory_not_found: {
    message: "The directory '%<directory>s' does not exist or is not accessible.",
    suggestions: [
      "Check that the directory path is correct",
      "Verify you have read permissions for the directory",
      "Create the directory first if it doesn't exist",
      "Use 'makit init' to create a new project directory",
    ],
  },
  git_command_failed: {
    message: "Git command failed: %<command>s",
    suggestions: [
      "Check that git is installed and available in PATH",
      "Verify you have network connectivity for remote operations",
      "Ensure you have proper permissions for the repository",
      "Check that the remote repository URL is accessible",
    ],
  },
  clone_failed: {
    message: "Failed to clone repository '%<url>s'.",
    suggestions: [
      "Check that the repository URL is correct and accessible",
      "Verify your network connectivity",
      "Ensure you have proper authentication (SSH keys, tokens)",
      "Check that you have write permissions to the destination directory",
    ],
  },
  pull_failed: {
    message: "Failed to pull changes from repository.",
    suggestions: [
      "Check that you have network connectivity",
      "Verify the remote repository is accessible",
      "Ensure your local repository is in a clean state",
      "Try 'git status' to check for conflicts",
    ],
  },
  build_failed: {
    message: "Build process failed for repository '%<url>s' at commit '%<commit>s'.",
    suggestions: [
      "Check the build logs for specific error messages",
      "Verify all dependencies are installed",
      "Ensure the commit hash is valid and exists",
      "Try building manually to isolate the issue",
    ],
  },
}.freeze

Class Method Summary collapse

Class Method Details

.format_error(error_type, details = {}, original_error = nil) ⇒ String

Format an error with user-friendly message and suggestions

Parameters:

  • error_type (Symbol)

    the type of error from ERROR_MESSAGES

  • details (Hash) (defaults to: {})

    details to interpolate into the message

  • original_error (Exception) (defaults to: nil)

    the original exception (optional)

Returns:

  • (String)

    formatted error message with suggestions



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/makit/services/error_handler.rb', line 91

def format_error(error_type, details = {}, original_error = nil)
  error_config = ERROR_MESSAGES[error_type]
  return "Unknown error type: #{error_type}" unless error_config

  message = error_config[:message] % details
  suggestions = error_config[:suggestions]

  formatted_message = ["❌ Error: #{message}"]

  if suggestions && !suggestions.empty?
    formatted_message << ""
    formatted_message << "💡 Suggestions:"
    suggestions.each_with_index do |suggestion, index|
      formatted_message << "  #{index + 1}. #{suggestion}"
    end
  end

  if original_error && !original_error.message.empty?
    formatted_message << ""
    formatted_message << "🔍 Technical details:"
    formatted_message << "  #{original_error.class}: #{original_error.message}"
  end

  formatted_message.join("\n")
end

.handle_argument_error(error, context = {}) ⇒ String

Handle ArgumentError exceptions with user-friendly formatting

Parameters:

  • error (ArgumentError)

    the argument error to format

  • context (Hash) (defaults to: {})

    additional context about where the error occurred

Returns:

  • (String)

    formatted error message



122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/makit/services/error_handler.rb', line 122

def handle_argument_error(error, context = {})
  case error.message
  when /URL parameter cannot be nil|URL parameter cannot be empty|Invalid URL format/
    format_error(:invalid_url, { url: context[:url] || "unknown" }, error)
  when /directory parameter cannot be nil|directory parameter cannot be empty|directory path/
    format_error(:invalid_directory, { directory: context[:directory] || "unknown" }, error)
  when /commit parameter cannot be nil|commit parameter cannot be empty|Invalid commit format/
    format_error(:invalid_commit, { commit: context[:commit] || "unknown" }, error)
  else
    "❌ Error: #{error.message}\n💡 Please check your input parameters and try again."
  end
end

.handle_makit_error(error, context = {}) ⇒ String

Handle Makit-specific exceptions with user-friendly formatting

Parameters:

  • error (Makit::Error)

    the Makit error to format

  • context (Hash) (defaults to: {})

    additional context about where the error occurred

Returns:

  • (String)

    formatted error message



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/makit/services/error_handler.rb', line 140

def handle_makit_error(error, context = {})
  case error
  when Makit::DirectoryError
    format_error(:directory_not_found, { directory: context[:directory] || "unknown" }, error)
  when Makit::CloneError
    format_error(:clone_failed, { url: context[:url] || "unknown" }, error)
  when Makit::PullError
    format_error(:pull_failed, {}, error)
  when Makit::BuildError
    format_error(:build_failed, { url: context[:url] || "unknown", commit: context[:commit] || "unknown" },
                 error)
  when Makit::GitError
    format_error(:git_command_failed, { command: context[:command] || "unknown" }, error)
  else
    "❌ Error: #{error.message}\n💡 Please refer to the documentation or run with --verbose for more details."
  end
end

.log_error(error, context = {}) ⇒ Object

Log error with context for debugging

Parameters:

  • error (Exception)

    the error to log

  • context (Hash) (defaults to: {})

    additional context information



162
163
164
165
166
167
168
# File 'lib/makit/services/error_handler.rb', line 162

def log_error(error, context = {})
  return unless defined?(Makit::LOGGER) && Makit::LOGGER

  Makit::LOGGER.error "Error occurred: #{error.class} - #{error.message}"
  Makit::LOGGER.error "Context: #{context.inspect}" unless context.empty?
  Makit::LOGGER.debug "Backtrace: #{error.backtrace&.join("\n")}" if error.backtrace
end

.validate_inputs(validations) ⇒ Object

Validate input and provide helpful error messages

Examples:

validate_inputs([
  { value: url, validator: :url, name: 'repository URL' },
  { value: commit, validator: :commit, name: 'commit hash' }
])

Parameters:

  • validations (Array<Hash>)

    array of validation rules



199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/makit/services/error_handler.rb', line 199

def validate_inputs(validations)
  validations.each do |validation|
    value = validation[:value]
    validator = validation[:validator]
    name = validation[:name] || "parameter"

    case validator
    when :url
      Validator.validate_url_parameter(value)
    when :directory
      Validator.validate_directory_parameter(value)
    when :commit
      Validator.validate_commit_parameter(value)
    when :required_string
      Validator.validate_required_string(value, name)
    when :boolean
      Validator.validate_boolean_parameter(value, name)
    end
  rescue ArgumentError => e
    context = { validator => value }
    formatted_message = handle_argument_error(e, context)
    raise Makit::ValidationError, formatted_message
  end
end

.with_error_handling(context = {}) { ... } ⇒ Object

Wrap a block with comprehensive error handling

Parameters:

  • context (Hash) (defaults to: {})

    context information for error messages

Yields:

  • block to execute with error handling

Returns:

  • (Object)

    the result of the block



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/makit/services/error_handler.rb', line 175

def with_error_handling(context = {})
  yield
rescue ArgumentError => e
  log_error(e, context)
  formatted_message = handle_argument_error(e, context)
  raise Makit::ValidationError, formatted_message
rescue Makit::Error => e
  log_error(e, context)
  formatted_message = handle_makit_error(e, context)
  raise e.class, formatted_message
rescue StandardError => e
  log_error(e, context)
  formatted_message = "❌ An unexpected error occurred: #{e.message}\n💡 Please check the logs or run with --verbose for more details."
  raise Makit::Error, formatted_message
end