Files
gh-action-readme/internal/errorhandler.go
Ismo Vuorinen f9823eef3e feat: add interactive wizard, contextual errors, and code improvements
- Add interactive configuration wizard with auto-detection and multi-format export
- Implement contextual error system with 14 error codes and actionable suggestions
- Add centralized progress indicators with consistent theming
- Fix all cyclomatic complexity issues (8 functions refactored)
- Eliminate code duplication with centralized utilities and error handling
- Add comprehensive test coverage for all new components
- Update TODO.md with completed tasks and accurate completion dates
2025-08-04 23:33:28 +03:00

112 lines
2.8 KiB
Go

// Package internal provides centralized error handling utilities.
package internal
import (
"os"
"github.com/ivuorinen/gh-action-readme/internal/errors"
)
// ErrorHandler provides centralized error handling and exit management.
type ErrorHandler struct {
output *ColoredOutput
}
// NewErrorHandler creates a new error handler.
func NewErrorHandler(output *ColoredOutput) *ErrorHandler {
return &ErrorHandler{
output: output,
}
}
// HandleError handles contextual errors and exits with appropriate code.
func (eh *ErrorHandler) HandleError(err *errors.ContextualError) {
eh.output.ErrorWithSuggestions(err)
os.Exit(1)
}
// HandleFatalError handles fatal errors with contextual information.
func (eh *ErrorHandler) HandleFatalError(code errors.ErrorCode, message string, context map[string]string) {
suggestions := errors.GetSuggestions(code, context)
helpURL := errors.GetHelpURL(code)
contextualErr := errors.New(code, message).
WithSuggestions(suggestions...).
WithHelpURL(helpURL)
if len(context) > 0 {
contextualErr = contextualErr.WithDetails(context)
}
eh.HandleError(contextualErr)
}
// HandleSimpleError handles simple errors with automatic context detection.
func (eh *ErrorHandler) HandleSimpleError(message string, err error) {
code := errors.ErrCodeUnknown
context := make(map[string]string)
// Try to determine appropriate error code based on error content
if err != nil {
context["error"] = err.Error()
code = eh.determineErrorCode(err)
}
eh.HandleFatalError(code, message, context)
}
// determineErrorCode attempts to determine appropriate error code from error content.
func (eh *ErrorHandler) determineErrorCode(err error) errors.ErrorCode {
errStr := err.Error()
switch {
case contains(errStr, "no such file or directory"):
return errors.ErrCodeFileNotFound
case contains(errStr, "permission denied"):
return errors.ErrCodePermission
case contains(errStr, "yaml"):
return errors.ErrCodeInvalidYAML
case contains(errStr, "github"):
return errors.ErrCodeGitHubAPI
case contains(errStr, "config"):
return errors.ErrCodeConfiguration
default:
return errors.ErrCodeUnknown
}
}
// contains checks if a string contains a substring (case-insensitive).
func contains(s, substr string) bool {
// Simple implementation - could use strings.Contains with strings.ToLower
// but avoiding extra imports for now
sLen := len(s)
substrLen := len(substr)
if substrLen > sLen {
return false
}
for i := 0; i <= sLen-substrLen; i++ {
match := true
for j := 0; j < substrLen; j++ {
if toLower(s[i+j]) != toLower(substr[j]) {
match = false
break
}
}
if match {
return true
}
}
return false
}
// toLower converts a byte to lowercase.
func toLower(b byte) byte {
if b >= 'A' && b <= 'Z' {
return b + ('a' - 'A')
}
return b
}