@@ -217,6 +217,13 @@ func (c *Config) getPackageConfigMap(ctx context.Context, packageName string) (m
217
217
return emptyMap , nil
218
218
219
219
}
220
+
221
+ // GetPackageConfig returns a struct representation of the package's config
222
+ // as provided in yaml. If the package did not specify a config section,
223
+ // this method will inject the top-level config into the package's config.
224
+ // This is especially useful as it allows us to lazily evaluate a package's
225
+ // config. If the package does specify config, this method takes care to merge
226
+ // the top-level config with the values specified for this package.
220
227
func (c * Config ) GetPackageConfig (ctx context.Context , packageName string ) (* Config , error ) {
221
228
log := zerolog .Ctx (ctx ).With ().Str ("package-path" , packageName ).Logger ()
222
229
@@ -228,13 +235,10 @@ func (c *Config) GetPackageConfig(ctx context.Context, packageName string) (*Con
228
235
return pkgConf , nil
229
236
}
230
237
231
- //pkgConfig := reflect.New(reflect.ValueOf(c).Elem().Type()).Interface()
232
238
pkgConfig := & Config {}
233
239
if err := copier .Copy (pkgConfig , c ); err != nil {
234
240
return nil , fmt .Errorf ("failed to copy config: %w" , err )
235
241
}
236
- //pkgConfigTyped := pkgConfig.(*Config)
237
- pkgConfigTyped := pkgConfig
238
242
239
243
configMap , err := c .getPackageConfigMap (ctx , packageName )
240
244
if err != nil {
@@ -245,18 +249,23 @@ func (c *Config) GetPackageConfig(ctx context.Context, packageName string) (*Con
245
249
if ! ok {
246
250
log .Debug ().Msg ("config section not provided for package" )
247
251
configMap ["config" ] = deepCopyConfigMap (c ._cfgAsMap )
248
- return pkgConfigTyped , nil
252
+ c .pkgConfigCache [packageName ] = pkgConfig
253
+ return pkgConfig , nil
249
254
}
250
255
251
- decoder , err := c .getDecoder (pkgConfigTyped )
256
+ // We know that the package specified config that is overriding the top-level
257
+ // config. We use a mapstructure decoder to decode the values in the yaml
258
+ // into the pkgConfig struct. This has the effect of merging top-level
259
+ // config with package-level config.
260
+ decoder , err := c .getDecoder (pkgConfig )
252
261
if err != nil {
253
262
return nil , stackerr .NewStackErrf (err , "failed to get decoder" )
254
263
}
255
264
if err := decoder .Decode (configSection ); err != nil {
256
265
return nil , err
257
266
}
258
- c .pkgConfigCache [packageName ] = pkgConfigTyped
259
- return pkgConfigTyped , nil
267
+ c .pkgConfigCache [packageName ] = pkgConfig
268
+ return pkgConfig , nil
260
269
}
261
270
262
271
func (c * Config ) ExcludePath (path string ) bool {
@@ -355,16 +364,15 @@ func (c *Config) GetInterfaceConfig(ctx context.Context, packageName string, int
355
364
}
356
365
357
366
// Copy the package-level config to our interface-level config
358
- pkgConfigCopy := reflect . New ( reflect . ValueOf ( pkgConfig ). Elem (). Type ()). Interface ()
367
+ pkgConfigCopy := & Config {}
359
368
if err := copier .Copy (pkgConfigCopy , pkgConfig ); err != nil {
360
369
return nil , stackerr .NewStackErrf (err , "failed to create a copy of package config" )
361
370
}
362
- baseConfigTyped := pkgConfigCopy .(* Config )
363
371
364
372
interfaceSection , ok := interfacesSection [interfaceName ]
365
373
if ! ok {
366
374
log .Debug ().Msg ("interface not defined in package configuration" )
367
- return []* Config {baseConfigTyped }, nil
375
+ return []* Config {pkgConfigCopy }, nil
368
376
}
369
377
370
378
interfaceSectionTyped , ok := interfaceSection .(map [string ]any )
@@ -373,7 +381,7 @@ func (c *Config) GetInterfaceConfig(ctx context.Context, packageName string, int
373
381
// the interface but not provide any additional config beyond what
374
382
// is provided at the package level
375
383
if reflect .ValueOf (& interfaceSection ).Elem ().IsZero () {
376
- return []* Config {baseConfigTyped }, nil
384
+ return []* Config {pkgConfigCopy }, nil
377
385
}
378
386
msgString := "bad type provided for interface config"
379
387
log .Error ().Msgf (msgString )
@@ -384,11 +392,11 @@ func (c *Config) GetInterfaceConfig(ctx context.Context, packageName string, int
384
392
if ok {
385
393
log .Debug ().Msg ("config section exists for interface" )
386
394
// if `config` is provided, we'll overwrite the values in our
387
- // baseConfigTyped struct to act as the "new" base config.
395
+ // pkgConfigCopy struct to act as the "new" base config.
388
396
// This will allow us to set the default values for the interface
389
397
// but override them further for each mock defined in the
390
398
// `configs` section.
391
- decoder , err := c .getDecoder (baseConfigTyped )
399
+ decoder , err := c .getDecoder (pkgConfigCopy )
392
400
if err != nil {
393
401
return nil , stackerr .NewStackErrf (err , "unable to create mapstructure decoder" )
394
402
}
@@ -405,8 +413,8 @@ func (c *Config) GetInterfaceConfig(ctx context.Context, packageName string, int
405
413
configsSectionTyped := configsSection .([]any )
406
414
for _ , configMap := range configsSectionTyped {
407
415
// Create a copy of the package-level config
408
- currentInterfaceConfig := reflect .New (reflect .ValueOf (baseConfigTyped ).Elem ().Type ()).Interface ()
409
- if err := copier .Copy (currentInterfaceConfig , baseConfigTyped ); err != nil {
416
+ currentInterfaceConfig := reflect .New (reflect .ValueOf (pkgConfigCopy ).Elem ().Type ()).Interface ()
417
+ if err := copier .Copy (currentInterfaceConfig , pkgConfigCopy ); err != nil {
410
418
return nil , stackerr .NewStackErrf (err , "failed to copy package config" )
411
419
}
412
420
@@ -426,7 +434,7 @@ func (c *Config) GetInterfaceConfig(ctx context.Context, packageName string, int
426
434
log .Debug ().Msg ("configs section doesn't exist for interface" )
427
435
428
436
if len (configs ) == 0 {
429
- configs = append (configs , baseConfigTyped )
437
+ configs = append (configs , pkgConfigCopy )
430
438
}
431
439
return configs , nil
432
440
}
@@ -674,14 +682,14 @@ func contains[T comparable](slice []T, elem T) bool {
674
682
}
675
683
676
684
func deepCopyConfigMap (src map [string ]any ) map [string ]any {
677
- new := map [string ]any {}
685
+ newMap := map [string ]any {}
678
686
for key , val := range src {
679
687
if contains ([]string {"packages" , "config" , "interfaces" }, key ) {
680
688
continue
681
689
}
682
- new [key ] = val
690
+ newMap [key ] = val
683
691
}
684
- return new
692
+ return newMap
685
693
}
686
694
687
695
// mergeInConfig takes care of merging inheritable configuration
0 commit comments