convoy 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (109) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.irbrc +3 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +8 -0
  7. data/Gemfile +4 -0
  8. data/LICENSE +22 -0
  9. data/README.md +705 -0
  10. data/Rakefile +1 -0
  11. data/convoy.gemspec +24 -0
  12. data/examples/.my_apprc +24 -0
  13. data/examples/basic +10 -0
  14. data/examples/basic_config_file +16 -0
  15. data/examples/basic_conflicts +17 -0
  16. data/examples/basic_depends_on +25 -0
  17. data/examples/basic_flags +15 -0
  18. data/examples/basic_options +14 -0
  19. data/examples/basic_options_multi +15 -0
  20. data/examples/basic_require_arguments +17 -0
  21. data/examples/basic_texts +21 -0
  22. data/examples/basic_validations +21 -0
  23. data/examples/basic_with_everything +30 -0
  24. data/examples/commands/example_command.rb +13 -0
  25. data/examples/suite_complex +65 -0
  26. data/examples/suite_simple +19 -0
  27. data/examples/suite_with_sub_commands +94 -0
  28. data/lib/convoy.rb +83 -0
  29. data/lib/convoy/action_command/base.rb +85 -0
  30. data/lib/convoy/action_command/escort_utility_command.rb +53 -0
  31. data/lib/convoy/app.rb +127 -0
  32. data/lib/convoy/arguments.rb +20 -0
  33. data/lib/convoy/auto_options.rb +71 -0
  34. data/lib/convoy/error/error.rb +33 -0
  35. data/lib/convoy/formatter/command.rb +87 -0
  36. data/lib/convoy/formatter/commands.rb +37 -0
  37. data/lib/convoy/formatter/cursor_position.rb +29 -0
  38. data/lib/convoy/formatter/default_help_formatter.rb +117 -0
  39. data/lib/convoy/formatter/global_command.rb +17 -0
  40. data/lib/convoy/formatter/option.rb +152 -0
  41. data/lib/convoy/formatter/options.rb +28 -0
  42. data/lib/convoy/formatter/shell_command_executor.rb +49 -0
  43. data/lib/convoy/formatter/stream_output_formatter.rb +88 -0
  44. data/lib/convoy/formatter/string_grid.rb +108 -0
  45. data/lib/convoy/formatter/string_splitter.rb +50 -0
  46. data/lib/convoy/formatter/terminal.rb +30 -0
  47. data/lib/convoy/global_pre_parser.rb +43 -0
  48. data/lib/convoy/logger.rb +75 -0
  49. data/lib/convoy/option_dependency_validator.rb +82 -0
  50. data/lib/convoy/option_parser.rb +155 -0
  51. data/lib/convoy/setup/configuration/generator.rb +75 -0
  52. data/lib/convoy/setup/configuration/instance.rb +34 -0
  53. data/lib/convoy/setup/configuration/loader.rb +43 -0
  54. data/lib/convoy/setup/configuration/locator/base.rb +19 -0
  55. data/lib/convoy/setup/configuration/locator/chaining.rb +29 -0
  56. data/lib/convoy/setup/configuration/locator/descending_to_home.rb +23 -0
  57. data/lib/convoy/setup/configuration/locator/executing_script_directory.rb +15 -0
  58. data/lib/convoy/setup/configuration/locator/specified_directory.rb +21 -0
  59. data/lib/convoy/setup/configuration/merge_tool.rb +38 -0
  60. data/lib/convoy/setup/configuration/reader.rb +36 -0
  61. data/lib/convoy/setup/configuration/writer.rb +46 -0
  62. data/lib/convoy/setup/dsl/action.rb +17 -0
  63. data/lib/convoy/setup/dsl/command.rb +67 -0
  64. data/lib/convoy/setup/dsl/config_file.rb +13 -0
  65. data/lib/convoy/setup/dsl/global.rb +29 -0
  66. data/lib/convoy/setup/dsl/options.rb +81 -0
  67. data/lib/convoy/setup_accessor.rb +206 -0
  68. data/lib/convoy/trollop.rb +861 -0
  69. data/lib/convoy/utils.rb +21 -0
  70. data/lib/convoy/validator.rb +45 -0
  71. data/spec/integration/basic_config_file_spec.rb +126 -0
  72. data/spec/integration/basic_conflicts_spec.rb +47 -0
  73. data/spec/integration/basic_depends_on_spec.rb +275 -0
  74. data/spec/integration/basic_options_spec.rb +41 -0
  75. data/spec/integration/basic_options_with_multi_spec.rb +30 -0
  76. data/spec/integration/basic_spec.rb +38 -0
  77. data/spec/integration/basic_validations_spec.rb +77 -0
  78. data/spec/integration/basic_with_arguments_spec.rb +35 -0
  79. data/spec/integration/basic_with_text_fields_spec.rb +21 -0
  80. data/spec/integration/suite_simple_spec.rb +45 -0
  81. data/spec/integration/suite_sub_command_spec.rb +51 -0
  82. data/spec/lib/convoy/action_command/base_spec.rb +200 -0
  83. data/spec/lib/convoy/formatter/command_spec.rb +238 -0
  84. data/spec/lib/convoy/formatter/global_command_spec.rb +50 -0
  85. data/spec/lib/convoy/formatter/option_spec.rb +300 -0
  86. data/spec/lib/convoy/formatter/shell_command_executor_spec.rb +59 -0
  87. data/spec/lib/convoy/formatter/stream_output_formatter_spec.rb +214 -0
  88. data/spec/lib/convoy/formatter/string_grid_spec.rb +59 -0
  89. data/spec/lib/convoy/formatter/string_splitter_spec.rb +50 -0
  90. data/spec/lib/convoy/formatter/terminal_spec.rb +19 -0
  91. data/spec/lib/convoy/setup/configuration/generator_spec.rb +101 -0
  92. data/spec/lib/convoy/setup/configuration/loader_spec.rb +79 -0
  93. data/spec/lib/convoy/setup/configuration/locator/chaining_spec.rb +81 -0
  94. data/spec/lib/convoy/setup/configuration/locator/descending_to_home_spec.rb +57 -0
  95. data/spec/lib/convoy/setup/configuration/locator/executing_script_directory_spec.rb +29 -0
  96. data/spec/lib/convoy/setup/configuration/locator/specified_directory_spec.rb +33 -0
  97. data/spec/lib/convoy/setup/configuration/merge_tool_spec.rb +41 -0
  98. data/spec/lib/convoy/setup/configuration/reader_spec.rb +41 -0
  99. data/spec/lib/convoy/setup/configuration/writer_spec.rb +75 -0
  100. data/spec/lib/convoy/setup_accessor_spec.rb +226 -0
  101. data/spec/lib/convoy/utils_spec.rb +30 -0
  102. data/spec/spec_helper.rb +29 -0
  103. data/spec/support/integration_helpers.rb +2 -0
  104. data/spec/support/matchers/execute_action_for_command_matcher.rb +21 -0
  105. data/spec/support/matchers/execute_action_with_arguments_matcher.rb +25 -0
  106. data/spec/support/matchers/execute_action_with_options_matcher.rb +29 -0
  107. data/spec/support/matchers/exit_with_code_matcher.rb +29 -0
  108. data/spec/support/shared_contexts/integration_setup.rb +34 -0
  109. metadata +292 -0
data/lib/convoy.rb ADDED
@@ -0,0 +1,83 @@
1
+ autoload :Nesty, "nesty"
2
+
3
+ module Convoy
4
+ autoload :Trollop, "convoy/trollop"
5
+ autoload :Utils, "convoy/utils"
6
+ autoload :Arguments, "convoy/arguments"
7
+ autoload :Logger, "convoy/logger"
8
+ autoload :SetupAccessor, "convoy/setup_accessor"
9
+ autoload :OptionDependencyValidator, "convoy/option_dependency_validator"
10
+ autoload :Validator, "convoy/validator"
11
+ autoload :AutoOptions, "convoy/auto_options"
12
+ autoload :GlobalPreParser, "convoy/global_pre_parser"
13
+ autoload :OptionParser, "convoy/option_parser"
14
+ autoload :App, "convoy/app"
15
+
16
+ autoload :Error, "convoy/error/error"
17
+ autoload :BaseError, "convoy/error/error"
18
+ autoload :UserError, "convoy/error/error"
19
+ autoload :InternalError, "convoy/error/error"
20
+ autoload :ClientError, "convoy/error/error"
21
+ autoload :TransientError, "convoy/error/error"
22
+
23
+ module Formatter
24
+ autoload :Option, "convoy/formatter/option"
25
+ autoload :Options, "convoy/formatter/options"
26
+ autoload :Command, "convoy/formatter/command"
27
+ autoload :Commands, "convoy/formatter/commands"
28
+ autoload :GlobalCommand, "convoy/formatter/global_command"
29
+ autoload :ShellCommandExecutor, "convoy/formatter/shell_command_executor"
30
+ autoload :Terminal, "convoy/formatter/terminal"
31
+ autoload :StringSplitter, "convoy/formatter/string_splitter"
32
+ autoload :CursorPosition, "convoy/formatter/cursor_position"
33
+ autoload :StreamOutputFormatter, "convoy/formatter/stream_output_formatter"
34
+ autoload :StringGrid, "convoy/formatter/string_grid"
35
+ autoload :DefaultHelpFormatter, "convoy/formatter/default_help_formatter"
36
+ end
37
+
38
+ module Setup
39
+ module Dsl
40
+ autoload :Options, "convoy/setup/dsl/options"
41
+ autoload :Action, "convoy/setup/dsl/action"
42
+ autoload :Command, "convoy/setup/dsl/command"
43
+ autoload :ConfigFile, "convoy/setup/dsl/config_file"
44
+ autoload :Global, "convoy/setup/dsl/global"
45
+ end
46
+
47
+ module Configuration
48
+ module Locator
49
+ autoload :Base, "convoy/setup/configuration/locator/base"
50
+ autoload :DescendingToHome, "convoy/setup/configuration/locator/descending_to_home"
51
+ autoload :ExecutingScriptDirectory, "convoy/setup/configuration/locator/executing_script_directory"
52
+ autoload :SpecifiedDirectory, "convoy/setup/configuration/locator/specified_directory"
53
+ autoload :Chaining, "convoy/setup/configuration/locator/chaining"
54
+ end
55
+
56
+ autoload :MergeTool, "convoy/setup/configuration/merge_tool"
57
+ autoload :Instance, "convoy/setup/configuration/instance"
58
+ autoload :Reader, "convoy/setup/configuration/reader"
59
+ autoload :Writer, "convoy/setup/configuration/writer"
60
+ autoload :Generator, "convoy/setup/configuration/generator"
61
+ autoload :Loader, "convoy/setup/configuration/loader"
62
+ end
63
+ end
64
+
65
+ module ActionCommand
66
+ autoload :Base, "convoy/action_command/base"
67
+ autoload :ConvoyUtilityCommand, "convoy/action_command/convoy_utility_command"
68
+ end
69
+ end
70
+
71
+ at_exit do
72
+ Convoy::Logger.close
73
+ end
74
+
75
+ def error_logger
76
+ Convoy::Logger.error
77
+ end
78
+
79
+ def output_logger
80
+ Convoy::Logger.output
81
+ end
82
+
83
+
@@ -0,0 +1,85 @@
1
+ module Convoy
2
+ module ActionCommand
3
+ class Base
4
+ attr_reader :options, :arguments, :config
5
+
6
+ def initialize(options, arguments, config={})
7
+ @options = options
8
+ @arguments = arguments
9
+ @config = config
10
+ @command_context = nil
11
+ @command_options = nil
12
+ @parent_options = nil
13
+ @grandparent_options = nil
14
+ @global_options = nil
15
+ end
16
+
17
+ protected
18
+
19
+ def command_context
20
+ return @command_context if @command_context
21
+ @command_context = []
22
+ options[:global] ||= {}
23
+ current_command_hash = options[:global][:commands] || {}
24
+ until current_command_hash.keys.empty?
25
+ key = current_command_hash.keys.first
26
+ @command_context << key
27
+ current_command_hash = current_command_hash[key][:commands] || {}
28
+ end
29
+ @command_context
30
+ end
31
+
32
+ def command_name
33
+ command_context.last || :global
34
+ end
35
+
36
+ def command_options
37
+ @command_options ||= context_hash(command_context)[:options] || {}
38
+ end
39
+
40
+ def global_options
41
+ @global_options ||= (options[:global] || {})[:options] || {}
42
+ end
43
+
44
+ def parent_options
45
+ @parent_options ||= ensure_parent { |parent_context| context_hash(parent_context)[:options] || {} }
46
+ end
47
+
48
+ def grandparent_options
49
+ @grandparent_options ||= ensure_grandparent { |grandparent_context| context_hash(grandparent_context)[:options] || {} }
50
+ end
51
+
52
+ #generation_number 1 is parent, 2 is grandparent and so on
53
+ #default is 3 for great grandparent
54
+ def ancestor_options(generation_number = 3)
55
+ ensure_ancestor(generation_number) { |ancestor_context| context_hash(ancestor_context)[:options] || {} }
56
+ end
57
+
58
+ private
59
+
60
+ def context_hash(context)
61
+ context_hash = options[:global]
62
+ context.each do |command_name|
63
+ context_hash = context_hash[:commands][command_name]
64
+ end
65
+ context_hash
66
+ end
67
+
68
+ def ensure_parent(&block)
69
+ ensure_ancestor(1, &block)
70
+ end
71
+
72
+ def ensure_grandparent(&block)
73
+ ensure_ancestor(2, &block)
74
+ end
75
+
76
+ def ensure_ancestor(generation_number, &block)
77
+ return {} if generation_number < 0
78
+ #return {} if generation_number == 0
79
+ return {} unless command_context.size >= generation_number
80
+ ancestor_context = command_context.dup.slice(0, command_context.size - generation_number)
81
+ block.call(ancestor_context)
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,53 @@
1
+ module Convoy
2
+ module ActionCommand
3
+ class ConvoyUtilityCommand < Base
4
+ attr_reader :setup
5
+
6
+ def initialize(setup, options, arguments, config = {})
7
+ super(options, arguments, config)
8
+ @setup = setup
9
+ end
10
+
11
+ def execute
12
+ current_command_options = command_options
13
+ if current_command_options[:create_config_given]
14
+ create_config(current_command_options[:create_config])
15
+ elsif current_command_options[:create_default_config_given]
16
+ create_default_config
17
+ elsif current_command_options[:update_config_given]
18
+ update_config(current_command_options[:update_config])
19
+ elsif current_command_options[:update_default_config_given]
20
+ update_default_config
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def create_config(path)
27
+ config_path = absolute_path(path)
28
+ Convoy::Setup::Configuration::Writer.new(config_path, Convoy::Setup::Configuration::Generator.new(setup).default_data).write
29
+ end
30
+
31
+ def create_default_config
32
+ Convoy::Setup::Configuration::Writer.new(default_config_path, Convoy::Setup::Configuration::Generator.new(setup).default_data).write
33
+ end
34
+
35
+ def update_config(path)
36
+ config_path = absolute_path(path)
37
+ Convoy::Setup::Configuration::Writer.new(config_path, Convoy::Setup::Configuration::Generator.new(setup).default_data).update
38
+ end
39
+
40
+ def update_default_config
41
+ Convoy::Setup::Configuration::Writer.new(default_config_path, Convoy::Setup::Configuration::Generator.new(setup).default_data).update
42
+ end
43
+
44
+ def absolute_path(path)
45
+ File.expand_path(path)
46
+ end
47
+
48
+ def default_config_path
49
+ Convoy::Setup::Configuration::Loader.new(setup, nil).default_config_path
50
+ end
51
+ end
52
+ end
53
+ end
data/lib/convoy/app.rb ADDED
@@ -0,0 +1,127 @@
1
+ module Convoy
2
+ class App
3
+ #TODO ensure that every command must have an action
4
+ class << self
5
+ def create(option_string = '', &block)
6
+ self.new(option_string, &block).setup_application.execute
7
+ exit(0)
8
+ end
9
+ end
10
+
11
+ attr_reader :setup, :option_string
12
+
13
+ def initialize(option_string, &block)
14
+ @option_string = option_string
15
+ @setup = nil
16
+ @block = block
17
+ end
18
+
19
+ def setup_application
20
+ old_error_sev_threshold = error_logger.sev_threshold
21
+ begin
22
+ error_logger.sev_threshold = ::Logger::DEBUG
23
+ cli_app_configuration = Convoy::Setup::Dsl::Global.new(&@block)
24
+ @setup = Convoy::SetupAccessor.new(cli_app_configuration)
25
+ self
26
+ rescue => e
27
+ handle_convoy_error(e)
28
+ ensure
29
+ error_logger.sev_threshold = old_error_sev_threshold
30
+ end
31
+ end
32
+
33
+ def execute
34
+ begin
35
+ AutoOptions.augment(setup)
36
+
37
+ cli_options = current_cli_options(option_string)
38
+
39
+ auto_options = Convoy::GlobalPreParser.new(setup).parse(cli_options.dup)
40
+ Convoy::Logger.setup_error_logger(auto_options)
41
+
42
+ #now we can start doing error logging everything above here has to be rock solid
43
+
44
+ configuration = Convoy::Setup::Configuration::Loader.new(setup, auto_options).configuration
45
+
46
+ invoked_options, arguments = Convoy::OptionParser.new(configuration, setup).parse(cli_options)
47
+ context = context_from_options(invoked_options[:global])
48
+ action = setup.action_for(context)
49
+ current_command = context.empty? ? :global : context.last
50
+ raise Convoy::ClientError.new("No action defined for command '#{current_command}'") unless action
51
+ actual_arguments = Convoy::Arguments.read(arguments, setup.arguments_required_for(context))
52
+ rescue => e
53
+ handle_convoy_error(e)
54
+ end
55
+ execute_action(action, invoked_options, actual_arguments, configuration.user)
56
+ end
57
+
58
+ private
59
+
60
+ def current_cli_options(option_string)
61
+ passed_in_options = Convoy::Utils.tokenize_option_string(option_string)
62
+ passed_in_options.empty? ? ARGV.dup : passed_in_options
63
+ end
64
+
65
+ def execute_action(action, options, arguments, user_config)
66
+ begin
67
+ #execute before servants here
68
+ action.call(options, arguments, user_config)
69
+ #execute after servants here
70
+ rescue => e
71
+ handle_action_error(e)
72
+ end
73
+ end
74
+
75
+ def context_from_options(options)
76
+ commands_in_order(options)
77
+ end
78
+
79
+ def commands_in_order(options, commands = [])
80
+ if options[:commands].keys.empty?
81
+ commands
82
+ else
83
+ command = options[:commands].keys.first
84
+ commands << command
85
+ commands_in_order(options[:commands][command], commands)
86
+ end
87
+ end
88
+
89
+ def handle_convoy_error(e)
90
+ if e.kind_of?(Convoy::UserError)
91
+ print_stacktrace(e)
92
+ error_logger.debug {'Convoy app failed to execute successfully, due to user error'}
93
+ exit(Convoy::USER_ERROR_EXIT_CODE)
94
+ elsif e.kind_of?(Convoy::ClientError)
95
+ print_stacktrace(e)
96
+ error_logger.debug {'Convoy app failed to execute successfully, due to client setup error'}
97
+ exit(Convoy::CLIENT_ERROR_EXIT_CODE)
98
+ else
99
+ print_convoy_error_message(e)
100
+ error_logger.debug {'Convoy app failed to execute successfully, due to internal error'}
101
+ exit(Convoy::INTERNAL_ERROR_EXIT_CODE)
102
+ end
103
+ end
104
+
105
+ def handle_action_error(e)
106
+ if e.kind_of?(Convoy::Error)
107
+ print_convoy_error_message(e)
108
+ error_logger.debug {'Convoy app failed to execute successfully, due to internal error'}
109
+ exit(Convoy::INTERNAL_ERROR_EXIT_CODE)
110
+ else
111
+ print_stacktrace(e)
112
+ error_logger.debug {'Convoy app failed to execute successfully, due to unknown error'}
113
+ exit(Convoy::EXTERNAL_ERROR_EXIT_CODE)
114
+ end
115
+ end
116
+
117
+ def print_stacktrace(e)
118
+ error_logger.error { e.message }
119
+ error_logger.debug { e }
120
+ end
121
+
122
+ def print_convoy_error_message(e)
123
+ print_stacktrace(e)
124
+ error_logger.warn {"\n \x1B[48;5;196m ERROR \x1B[0m An internal Convoy error occurred.\n\n You should probably report it to \x1B[38;5;222mAlbert Rannetsperger\x1B[0m or create an issue on his \x1B[38;5;222mGitHub\x1B[0m page (https://github.com/alb3rtuk).\n Make sure to include the stacktrace above (although it probably won't be very helpful).bp\n\n"}
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,20 @@
1
+ require 'readline'
2
+
3
+ module Convoy
4
+ class Arguments
5
+ class << self
6
+ def read(arguments, requires_arguments=false)
7
+ if arguments.empty? && requires_arguments
8
+ while command = Readline.readline("> ", true)
9
+ arguments << command
10
+ end
11
+ arguments = arguments.compact.keep_if { |value| value.length > 0 }
12
+ if arguments.empty?
13
+ raise Convoy::UserError.new("You must provide some arguments to this script")
14
+ end
15
+ end
16
+ arguments
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,71 @@
1
+ module Convoy
2
+ class AutoOptions
3
+ class << self
4
+ def augment(setup)
5
+ if setup.has_config_file?
6
+ setup.add_global_option :config, "Configuration file to use for this execution", :short => :none, :long => '--config', :type => :string
7
+
8
+ setup.add_global_command :convoy, :aliases => [] do |command|
9
+ command.summary "Auto created utility command"
10
+ command.description "Auto created utility command"
11
+ command.requires_arguments false
12
+
13
+ command.options do |opts|
14
+ opts.opt :create_config, "Create configuration file at specified location", :short => :none, :long => '--create-config', :type => :string
15
+ opts.opt :create_default_config, "Create a default configuration file", :short => :none, :long => '--create-default-config', :type => :boolean, :default => false
16
+ opts.opt :update_config, "Update configuration file at specified location", :short => :none, :long => '--update-config', :type => :string
17
+ opts.opt :update_default_config, "Update the default configuration file", :short => :none, :long => '--update-default-config', :type => :boolean, :default => false
18
+
19
+ opts.conflict :create_config, :create_default_config, :update_config, :update_default_config
20
+ end
21
+
22
+ command.action do |options, arguments|
23
+ ActionCommand::ConvoyUtilityCommand.new(setup, options, arguments).execute
24
+ end
25
+ end
26
+ end
27
+ setup.add_global_option :verbosity, 'Verbosity level of output for current execution (e.g. INFO, DEBUG)', :short => :none, :long => '--verbosity', :type => :string, :default => 'WARN'
28
+ setup.add_global_option :error_output_format, 'The format to use when outputting errors (e.g. basic, advanced)', :short => :none, :long => '--error-output-format', :type => :string, :default => 'basic'
29
+ end
30
+ end
31
+
32
+ attr_reader :options
33
+
34
+ def initialize(options)
35
+ @options = options
36
+ end
37
+
38
+ def non_default_config_path
39
+ if options[:config_given] && File.exists?(config_path)
40
+ config_path
41
+ elsif !options[:config_given]
42
+ nil
43
+ else
44
+ error_logger.warn "The given config file '#{options[:config]}' does not exist, falling back to default"
45
+ nil
46
+ end
47
+ end
48
+
49
+ def verbosity
50
+ error_verbosity.upcase
51
+ end
52
+
53
+ def error_formatter
54
+ error_output_format.to_sym
55
+ end
56
+
57
+ private
58
+
59
+ def config_path
60
+ File.expand_path(options[:config])
61
+ end
62
+
63
+ def error_output_format
64
+ options[:error_output_format]
65
+ end
66
+
67
+ def error_verbosity
68
+ options[:verbosity]
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ module Convoy
2
+ INTERNAL_ERROR_EXIT_CODE = 1
3
+ CLIENT_ERROR_EXIT_CODE = 2
4
+ USER_ERROR_EXIT_CODE = 3
5
+ EXTERNAL_ERROR_EXIT_CODE = 10
6
+
7
+ #module to tag all exceptions coming out of Convoy with
8
+ module Error
9
+ end
10
+
11
+ #all our exceptions will supported nesting other exceptions
12
+ #also all our exception will be a kind_of? Convoy::Error
13
+ class BaseError < StandardError
14
+ include Nesty::NestedError
15
+ include Error
16
+ end
17
+
18
+ #user did something invalid
19
+ class UserError < BaseError
20
+ end
21
+
22
+ #for errors with convoy itself
23
+ class InternalError < BaseError
24
+ end
25
+
26
+ #for errors with how convoy is being used
27
+ class ClientError < BaseError
28
+ end
29
+
30
+ #a dependency is temporarily unavailable
31
+ class TransientError < BaseError
32
+ end
33
+ end