Skip to content

Commit 29df8ab

Browse files
authored
Merge pull request #63 from github/config-updates
Config Updates
2 parents 73cc4ed + 6753d31 commit 29df8ab

File tree

7 files changed

+70
-39
lines changed

7 files changed

+70
-39
lines changed

Gemfile.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
PATH
22
remote: .
33
specs:
4-
hooks-ruby (0.4.0)
4+
hooks-ruby (0.5.0)
55
dry-schema (~> 1.14, >= 1.14.1)
66
grape (~> 2.3)
77
puma (~> 6.6)

docs/design.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export HOOKS_ROOT_PATH="/webhooks"
109109
export HOOKS_LOG_LEVEL=info
110110

111111
# Paths
112-
export HOOKS_HANDLER_DIR=./handlers
112+
export HOOKS_HANDLER_PLUGIN_DIR=./handlers
113113
export HOOKS_HEALTH_PATH=/health
114114
export HOOKS_VERSION_PATH=/version
115115

@@ -163,7 +163,7 @@ lib/hooks/
163163
```yaml
164164
# config/endpoints/team1.yaml
165165
path: /team1 # Mounted at <root_path>/team1
166-
handler: Team1Handler # Class in handler_dir
166+
handler: Team1Handler # Class in handler_plugin_dir
167167

168168
# Signature validation
169169
auth:
@@ -181,7 +181,7 @@ opts: # Freeform user-defined options
181181
182182
```yaml
183183
# config/config.yaml
184-
handler_dir: ./handlers # handler class directory
184+
handler_plugin_dir: ./handlers # handler class directory
185185
log_level: info # debug | info | warn | error
186186

187187
# Request handling
@@ -345,7 +345,7 @@ app = Hooks.build(
345345

346346
**Handler & Plugin Discovery:**
347347

348-
* Handler classes are auto-discovered from `handler_dir` using file naming convention
348+
* Handler classes are auto-discovered from `handler_plugin_dir` using file naming convention
349349
* File `team1_handler.rb` → class `Team1Handler`
350350
* Plugin classes are loaded from `plugin_dir` and registered based on class inheritance
351351
* All classes must inherit from appropriate base classes to be recognized

lib/hooks/core/config_loader.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,24 @@ class ConfigLoader
3232
#
3333
# @param config_path [String, Hash] Path to config file or config hash
3434
# @return [Hash] Merged configuration
35+
# @raise [ArgumentError] if config file path is provided but file doesn't exist
36+
# @raise [RuntimeError] if config file exists but fails to load
3537
def self.load(config_path: nil)
3638
config = DEFAULT_CONFIG.dup
3739
overrides = []
3840

3941
# Load from file if path provided
40-
if config_path.is_a?(String) && File.exist?(config_path)
42+
if config_path.is_a?(String)
43+
unless File.exist?(config_path)
44+
raise ArgumentError, "Configuration file not found: #{config_path}"
45+
end
46+
4147
file_config = load_config_file(config_path)
4248
if file_config
4349
overrides << "file config"
4450
config.merge!(file_config)
51+
else
52+
raise RuntimeError, "Failed to load configuration from file: #{config_path}"
4553
end
4654
end
4755

@@ -127,7 +135,6 @@ def self.load_env_config
127135
env_config = {}
128136

129137
env_mappings = {
130-
"HOOKS_HANDLER_DIR" => :handler_dir,
131138
"HOOKS_HANDLER_PLUGIN_DIR" => :handler_plugin_dir,
132139
"HOOKS_AUTH_PLUGIN_DIR" => :auth_plugin_dir,
133140
"HOOKS_LIFECYCLE_PLUGIN_DIR" => :lifecycle_plugin_dir,

lib/hooks/core/config_validator.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,17 @@ class ValidationError < StandardError; end
1212

1313
# Global configuration schema
1414
GLOBAL_CONFIG_SCHEMA = Dry::Schema.Params do
15-
optional(:handler_dir).filled(:string) # For backward compatibility
16-
optional(:handler_plugin_dir).filled(:string)
15+
required(:handler_plugin_dir).filled(:string)
1716
optional(:auth_plugin_dir).maybe(:string)
1817
optional(:lifecycle_plugin_dir).maybe(:string)
1918
optional(:instruments_plugin_dir).maybe(:string)
20-
optional(:log_level).filled(:string, included_in?: %w[debug info warn error])
19+
required(:log_level).filled(:string, included_in?: %w[debug info warn error])
2120
optional(:request_limit).filled(:integer, gt?: 0)
2221
optional(:request_timeout).filled(:integer, gt?: 0)
23-
optional(:root_path).filled(:string)
22+
required(:root_path).filled(:string)
2423
optional(:health_path).filled(:string)
2524
optional(:version_path).filled(:string)
26-
optional(:environment).filled(:string, included_in?: %w[development production])
25+
required(:environment).filled(:string, included_in?: %w[development production])
2726
optional(:endpoints_dir).filled(:string)
2827
optional(:use_catchall_route).filled(:bool)
2928
optional(:normalize_headers).filled(:bool)

lib/hooks/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
module Hooks
55
# Current version of the Hooks webhook framework
66
# @return [String] The version string following semantic versioning
7-
VERSION = "0.4.0".freeze
7+
VERSION = "0.5.0".freeze
88
end

spec/unit/lib/hooks/core/config_loader_spec.rb

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,10 @@
101101
context "when file does not exist" do
102102
let(:config_file) { File.join(temp_dir, "nonexistent.yml") }
103103

104-
it "returns default configuration" do
105-
config = described_class.load(config_path: config_file)
106-
107-
expect(config[:log_level]).to eq("info")
108-
expect(config[:environment]).to eq("production")
109-
expect(config[:production]).to be true
104+
it "raises ArgumentError" do
105+
expect {
106+
described_class.load(config_path: config_file)
107+
}.to raise_error(ArgumentError, "Configuration file not found: #{config_file}")
110108
end
111109
end
112110

@@ -117,11 +115,10 @@
117115
File.write(config_file, "invalid: yaml: content: [")
118116
end
119117

120-
it "returns default configuration" do
121-
config = described_class.load(config_path: config_file)
122-
123-
expect(config[:log_level]).to eq("info")
124-
expect(config[:environment]).to eq("production")
118+
it "raises RuntimeError" do
119+
expect {
120+
described_class.load(config_path: config_file)
121+
}.to raise_error(RuntimeError, "Failed to load configuration from file: #{config_file}")
125122
end
126123
end
127124

@@ -132,11 +129,10 @@
132129
File.write(config_file, "log_level: debug")
133130
end
134131

135-
it "returns default configuration" do
136-
config = described_class.load(config_path: config_file)
137-
138-
expect(config[:log_level]).to eq("info")
139-
expect(config[:environment]).to eq("production")
132+
it "raises RuntimeError" do
133+
expect {
134+
described_class.load(config_path: config_file)
135+
}.to raise_error(RuntimeError, "Failed to load configuration from file: #{config_file}")
140136
end
141137
end
142138
end

spec/unit/lib/hooks/core/config_validator_spec.rb

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
context "with valid configuration" do
66
it "returns validated configuration with all optional fields" do
77
config = {
8-
handler_dir: "./custom_handlers",
8+
handler_plugin_dir: "./custom_handlers",
99
log_level: "debug",
1010
request_limit: 2_048_000,
1111
request_timeout: 45,
@@ -24,15 +24,25 @@
2424
end
2525

2626
it "returns validated configuration with minimal fields" do
27-
config = {}
27+
config = {
28+
handler_plugin_dir: "/path/to/handlers",
29+
log_level: "info",
30+
root_path: "/app",
31+
environment: "development"
32+
}
2833

2934
result = described_class.validate_global_config(config)
3035

31-
expect(result).to eq({})
36+
expect(result).to eq(config)
3237
end
3338

3439
it "accepts production environment" do
35-
config = { environment: "production" }
40+
config = {
41+
environment: "production",
42+
handler_plugin_dir: "/path/to/handlers",
43+
log_level: "info",
44+
root_path: "/app"
45+
}
3646

3747
result = described_class.validate_global_config(config)
3848

@@ -41,7 +51,12 @@
4151

4252
it "accepts valid log levels" do
4353
%w[debug info warn error].each do |log_level|
44-
config = { log_level: log_level }
54+
config = {
55+
log_level: log_level,
56+
handler_plugin_dir: "/path/to/handlers",
57+
root_path: "/app",
58+
environment: "development"
59+
}
4560

4661
result = described_class.validate_global_config(config)
4762

@@ -101,7 +116,7 @@
101116

102117
it "raises ValidationError for empty string values" do
103118
config = {
104-
handler_dir: "",
119+
handler_plugin_dir: "",
105120
root_path: "",
106121
health_path: ""
107122
}
@@ -114,7 +129,11 @@
114129
it "coerces boolean-like string values" do
115130
config = {
116131
use_catchall_route: "true",
117-
normalize_headers: "1"
132+
normalize_headers: "1",
133+
handler_plugin_dir: "/path/to/handlers",
134+
log_level: "info",
135+
root_path: "/app",
136+
environment: "development"
118137
}
119138

120139
result = described_class.validate_global_config(config)
@@ -125,7 +144,7 @@
125144

126145
it "raises ValidationError for non-string paths" do
127146
config = {
128-
handler_dir: 123,
147+
handler_plugin_dir: 123,
129148
root_path: [],
130149
endpoints_dir: {}
131150
}
@@ -138,7 +157,11 @@
138157
it "coerces string numeric values" do
139158
config = {
140159
request_limit: "1024",
141-
request_timeout: "30"
160+
request_timeout: "30",
161+
handler_plugin_dir: "/path/to/handlers",
162+
log_level: "info",
163+
root_path: "/app",
164+
environment: "development"
142165
}
143166

144167
result = described_class.validate_global_config(config)
@@ -164,7 +187,13 @@
164187
end
165188

166189
it "coerces float values to integers by truncating" do
167-
config = { request_timeout: 30.5 }
190+
config = {
191+
request_timeout: 30.5,
192+
handler_plugin_dir: "/path/to/handlers",
193+
log_level: "info",
194+
root_path: "/app",
195+
environment: "development"
196+
}
168197

169198
result = described_class.validate_global_config(config)
170199

0 commit comments

Comments
 (0)