Skip to content

Commit 0112c2b

Browse files
committed
Add stric include
1 parent 2fc92be commit 0112c2b

2 files changed

Lines changed: 406 additions & 7 deletions

File tree

internal/discovery/discovery.go

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,15 @@ type Discovery struct {
104104

105105
// includeHiddenDirs is a list of hidden directory names that should be included in discovery.
106106
includeHiddenDirs []string
107+
108+
// includeDirs is a list of directory patterns to include in discovery (for strict include mode).
109+
includeDirs []string
110+
111+
// strictInclude determines whether to use strict include mode (only include directories that match includeDirs).
112+
strictInclude bool
113+
114+
// excludeByDefault determines whether to exclude configurations by default (triggered by include flags).
115+
excludeByDefault bool
107116
}
108117

109118
// DiscoveryOption is a function that modifies a Discovery.
@@ -117,6 +126,8 @@ func NewDiscovery(dir string, opts ...DiscoveryOption) *Discovery {
117126
discovery := &Discovery{
118127
workingDir: dir,
119128
hidden: false,
129+
// Include .terragrunt-stack by default, similar to the runner pool builder
130+
includeHiddenDirs: []string{config.StackDir},
120131
}
121132

122133
for _, opt := range opts {
@@ -211,6 +222,24 @@ func (d *Discovery) WithIncludeHiddenDirs(dirs []string) *Discovery {
211222
return d
212223
}
213224

225+
// WithIncludeDirs sets the includeDirs field to the given list.
226+
func (d *Discovery) WithIncludeDirs(dirs []string) *Discovery {
227+
d.includeDirs = dirs
228+
return d
229+
}
230+
231+
// WithStrictInclude sets the strictInclude flag to true.
232+
func (d *Discovery) WithStrictInclude() *Discovery {
233+
d.strictInclude = true
234+
return d
235+
}
236+
237+
// WithExcludeByDefault sets the excludeByDefault flag to true.
238+
func (d *Discovery) WithExcludeByDefault() *Discovery {
239+
d.excludeByDefault = true
240+
return d
241+
}
242+
214243
// String returns a string representation of a DiscoveredConfig.
215244
func (c *DiscoveredConfig) String() string {
216245
return c.Path
@@ -311,6 +340,38 @@ func (d *Discovery) isInHiddenDirectory(path string) bool {
311340
return false
312341
}
313342

343+
// matchesIncludePatterns returns true if the path matches any of the include directory patterns.
344+
func (d *Discovery) matchesIncludePatterns(path string) bool {
345+
if len(d.includeDirs) == 0 {
346+
return true
347+
}
348+
349+
// Get the relative path from the working directory
350+
relPath, err := filepath.Rel(d.workingDir, path)
351+
if err != nil {
352+
// If we can't get a relative path, use the absolute path
353+
relPath = path
354+
}
355+
relPathSlash := filepath.ToSlash(relPath)
356+
357+
for _, pattern := range d.includeDirs {
358+
// Convert pattern to slash format
359+
patternSlash := filepath.ToSlash(pattern)
360+
361+
// Check if the relative path matches the pattern as a glob
362+
if matched, err := filepath.Match(patternSlash, relPathSlash); err == nil && matched {
363+
return true
364+
}
365+
366+
// Also check if the relative path is a subdirectory of the pattern
367+
if strings.HasPrefix(relPathSlash, patternSlash+"/") {
368+
return true
369+
}
370+
}
371+
372+
return false
373+
}
374+
314375
// Discover discovers Terragrunt configurations in the WorkingDir.
315376
func (d *Discovery) Discover(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) (DiscoveredConfigs, error) {
316377
var cfgs DiscoveredConfigs
@@ -337,14 +398,16 @@ func (d *Discovery) Discover(ctx context.Context, l log.Logger, opts *options.Te
337398
base := filepath.Base(path)
338399
for _, fname := range filenames {
339400
if base == fname {
401+
configDir := filepath.Dir(path)
402+
340403
cfgType := ConfigTypeUnit
341404
if fname == config.DefaultStackFile {
342405
cfgType = ConfigTypeStack
343406
}
344407

345408
cfg := &DiscoveredConfig{
346409
Type: cfgType,
347-
Path: filepath.Dir(path),
410+
Path: configDir,
348411
}
349412
if d.discoveryContext != nil {
350413
cfg.DiscoveryContext = d.discoveryContext
@@ -411,6 +474,14 @@ func (d *Discovery) Discover(ctx context.Context, l log.Logger, opts *options.Te
411474
dependencyDiscovery = dependencyDiscovery.WithSuppressParseErrors()
412475
}
413476

477+
// Pass include patterns and strict mode to dependency discovery
478+
if len(d.includeDirs) > 0 {
479+
dependencyDiscovery = dependencyDiscovery.WithIncludeDirs(d.includeDirs)
480+
}
481+
if d.strictInclude {
482+
dependencyDiscovery = dependencyDiscovery.WithStrictInclude()
483+
}
484+
414485
err := dependencyDiscovery.DiscoverAllDependencies(ctx, l, opts)
415486
if err != nil {
416487
l.Warnf("Parsing errors where encountered while discovering dependencies. They were suppressed, and can be found in the debug logs.")
@@ -462,6 +533,8 @@ type DependencyDiscovery struct {
462533
depthRemaining int
463534
discoverExternal bool
464535
suppressParseErrors bool
536+
includeDirs []string
537+
strictInclude bool
465538
}
466539

467540
// DependencyDiscoveryOption is a function that modifies a DependencyDiscovery.
@@ -494,6 +567,45 @@ func (d *DependencyDiscovery) WithDiscoveryContext(discoveryContext *DiscoveryCo
494567
return d
495568
}
496569

570+
// WithIncludeDirs sets the includeDirs field to the given list.
571+
func (d *DependencyDiscovery) WithIncludeDirs(dirs []string) *DependencyDiscovery {
572+
d.includeDirs = dirs
573+
return d
574+
}
575+
576+
// WithStrictInclude sets the strictInclude flag to true.
577+
func (d *DependencyDiscovery) WithStrictInclude() *DependencyDiscovery {
578+
d.strictInclude = true
579+
return d
580+
}
581+
582+
// matchesIncludePatterns returns true if the path matches any of the include directory patterns.
583+
func (d *DependencyDiscovery) matchesIncludePatterns(path string) bool {
584+
if len(d.includeDirs) == 0 {
585+
return true
586+
}
587+
588+
// Convert path to slash format for consistent matching
589+
pathSlash := filepath.ToSlash(path)
590+
591+
for _, pattern := range d.includeDirs {
592+
// Convert pattern to slash format
593+
patternSlash := filepath.ToSlash(pattern)
594+
595+
// Check if the path matches the pattern as a glob
596+
if matched, err := filepath.Match(patternSlash, pathSlash); err == nil && matched {
597+
return true
598+
}
599+
600+
// Also check if the path is a subdirectory of the pattern
601+
if strings.HasPrefix(pathSlash, patternSlash+"/") {
602+
return true
603+
}
604+
}
605+
606+
return false
607+
}
608+
497609
func (d *DependencyDiscovery) DiscoverAllDependencies(ctx context.Context, l log.Logger, opts *options.TerragruntOptions) error {
498610
errs := []error{}
499611

@@ -587,13 +699,23 @@ func (d *DependencyDiscovery) DiscoverDependencies(ctx context.Context, l log.Lo
587699
if c.Path == depPath {
588700
external = false
589701

702+
// In strict include mode, only add dependencies that match the include patterns
703+
if d.strictInclude && !d.matchesIncludePatterns(depPath) {
704+
continue
705+
}
706+
590707
dCfg.Dependencies = append(dCfg.Dependencies, c)
591708

592709
continue
593710
}
594711
}
595712

596713
if external {
714+
// In strict include mode, only add external dependencies that match the include patterns
715+
if d.strictInclude && !d.matchesIncludePatterns(depPath) {
716+
continue
717+
}
718+
597719
ext := &DiscoveredConfig{
598720
Type: ConfigTypeUnit,
599721
Path: depPath,

0 commit comments

Comments
 (0)