Skip to content

Commit b802271

Browse files
authored
Support relative paths in include_patterns and exclude_patterns (#2286)
* Make it possible to resolve relative paths from project directory Signed-off-by: golemiso <[email protected]> * update docs about include/exclude patterns --------- Signed-off-by: golemiso <[email protected]>
1 parent b2dd212 commit b802271

File tree

3 files changed

+81
-29
lines changed

3 files changed

+81
-29
lines changed

docs/ce/howto/include-exclude-patterns.mdx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,35 @@ modules/
1515
```
1616

1717
<Note>
18-
The path of include / exclude patterns is relative to the digger.yml location - NOT the project location
18+
Patterns starting with `.` (e.g., `./modules/**` or `../modules/**`) are resolved relative to the **project directory**. All other patterns are resolved relative to the **digger.yml location**.
1919
</Note>
2020

2121
If you wanted to trigger plans for all `modules/` folder in both dev and prod projects you would include them in the `include_patterns` key. Similarly you put anything which you want to ignore in the `exclude_patterns` key ( exclude takes precedence over includes).
2222

23+
Example using patterns relative to project directory:
24+
25+
```yml
26+
projects:
27+
- name: dev
28+
dir: ./development
29+
include_patterns: ["../modules/**"] # Resolved from ./development/
30+
workflow: default_workflow
31+
- name: prod
32+
dir: ./production
33+
include_patterns: ["../modules/**"] # Resolved from ./production/
34+
exclude_patterns: ["../modules/dev_only_module/**"]
35+
```
36+
37+
Example using patterns relative to digger.yml location:
38+
2339
```yml
2440
projects:
2541
- name: dev
2642
dir: ./development
27-
include_patterns: ["./modules/**"]
43+
include_patterns: ["modules/**"] # Resolved from digger.yml location
2844
workflow: default_workflow
2945
- name: prod
3046
dir: ./production
31-
include_patterns: ["./modules/**"]
32-
exclude_patterns: ["./modules/dev_only_module/**"]
47+
include_patterns: ["modules/**"]
48+
exclude_patterns: ["modules/dev_only_module/**"]
3349
```

libs/digger_config/digger_config.go

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,11 @@ type DirWalker interface {
2222
GetDirs(workingDir string, config DiggerConfigYaml) ([]string, error)
2323
}
2424

25-
type FileSystemTopLevelTerraformDirWalker struct {
26-
}
25+
type FileSystemTopLevelTerraformDirWalker struct{}
2726

28-
type FileSystemTerragruntDirWalker struct {
29-
}
27+
type FileSystemTerragruntDirWalker struct{}
3028

31-
type FileSystemModuleDirWalker struct {
32-
}
29+
type FileSystemModuleDirWalker struct{}
3330

3431
func ReadDiggerYmlFileContents(dir string) (string, error) {
3532
var diggerYmlBytes []byte
@@ -366,11 +363,10 @@ func HandleYamlProjectGeneration(config *DiggerConfigYaml, terraformDir string,
366363
}
367364
return newConfig, nil
368365
} else if config.GenerateProjectsConfig != nil {
369-
var dirWalker = &FileSystemTopLevelTerraformDirWalker{}
366+
dirWalker := &FileSystemTopLevelTerraformDirWalker{}
370367

371368
slog.Info("finding terraform directories for project generation", "terraformDir", terraformDir)
372369
dirs, err := dirWalker.GetDirs(terraformDir, config)
373-
374370
if err != nil {
375371
slog.Error("error walking through directories", "error", err, "terraformDir", terraformDir)
376372
return nil, fmt.Errorf("error while walking through directories: %v", err)
@@ -617,7 +613,6 @@ func ValidateDiggerConfigYaml(configYaml *DiggerConfigYaml, fileName string) err
617613
}
618614

619615
func checkThatOnlyOneIacSpecifiedPerProject(project *Project) error {
620-
621616
nOfIac := 0
622617
if project.Terragrunt {
623618
nOfIac++
@@ -686,7 +681,7 @@ func validateApplyRequirements(applyRequirements []string) error {
686681
return fmt.Errorf("found duplicate element: %v", dups)
687682
}
688683
validValues := []string{ApplyRequirementsApproved, ApplyRequirementsMergeable, ApplyRequirementsUndiverged}
689-
var validSet = func() map[string]struct{} {
684+
validSet := func() map[string]struct{} {
690685
m := make(map[string]struct{}, len(validValues))
691686
for _, v := range validValues {
692687
m[v] = struct{}{}
@@ -873,7 +868,6 @@ func hydrateDiggerConfigYamlWithTerragrunt(configYaml *DiggerConfigYaml, parsing
873868
// normalize paths
874869
projectDir := path.Join(pathPrefix, atlantisProject.Dir)
875870
atlantisProject.Autoplan.WhenModified, err = GetPatternsRelativeToRepo(projectDir, atlantisProject.Autoplan.WhenModified)
876-
877871
if err != nil {
878872
slog.Error("could not normalize patterns",
879873
"error", err,
@@ -957,16 +951,31 @@ func (c *DiggerConfig) GetModifiedProjects(changedFiles []string) ([]Project, ma
957951
sourceChangesForProject := make([]string, 0)
958952
isProjectAdded := false
959953

960-
for _, changedFile := range changedFiles {
961-
includePatterns := project.IncludePatterns
962-
excludePatterns := project.ExcludePatterns
954+
var includePatterns, excludePatterns []string
963955

964-
if !project.Terragrunt {
965-
includePatterns = append(includePatterns, filepath.Join(project.Dir, "**", "*"))
956+
// resolve relative paths from project dir
957+
for _, pattern := range project.IncludePatterns {
958+
if strings.HasPrefix(pattern, ".") {
959+
includePatterns = append(includePatterns, filepath.Join(project.Dir, pattern))
966960
} else {
967-
includePatterns = append(includePatterns, filepath.Join(project.Dir, "*"))
961+
includePatterns = append(includePatterns, pattern)
968962
}
963+
}
964+
for _, pattern := range project.ExcludePatterns {
965+
if strings.HasPrefix(pattern, ".") {
966+
excludePatterns = append(excludePatterns, filepath.Join(project.Dir, pattern))
967+
} else {
968+
excludePatterns = append(excludePatterns, pattern)
969+
}
970+
}
969971

972+
if !project.Terragrunt {
973+
includePatterns = append(includePatterns, filepath.Join(project.Dir, "**", "*"))
974+
} else {
975+
includePatterns = append(includePatterns, filepath.Join(project.Dir, "*"))
976+
}
977+
978+
for _, changedFile := range changedFiles {
970979
// all our patterns are the globale dir pattern + the include patterns specified by user
971980
if MatchIncludeExcludePatternsToFile(changedFile, includePatterns, excludePatterns) {
972981
if !isProjectAdded {

libs/digger_config/digger_config_test.go

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ func TestDiggerConfigWhenCustomFileName(t *testing.T) {
6868
assert.Equal(t, configPath, path.Join(tempDir, "digger-custom.yml"))
6969

7070
os.Unsetenv("DIGGER_FILENAME")
71-
7271
}
7372

7473
func TestDiggerConfigWhenOnlyYamlExists(t *testing.T) {
@@ -579,7 +578,6 @@ workflows:
579578
assert.NotNil(t, workflow)
580579
assert.NotNil(t, workflow.Plan)
581580
assert.NotNil(t, workflow.Apply)
582-
583581
}
584582

585583
func TestDiggerConfigMissingProjectsWorkflow(t *testing.T) {
@@ -603,7 +601,6 @@ workflows:
603601

604602
_, _, _, _, err := LoadDiggerConfig(tempDir, true, nil, nil)
605603
assert.Equal(t, "failed to find workflow digger_config 'my_custom_workflow' for project 'my-first-app'", err.Error())
606-
607604
}
608605

609606
func TestDiggerConfigWithEmptyInitBlock(t *testing.T) {
@@ -1309,15 +1306,15 @@ projects:
13091306
func TestGetModifiedProjectsReturnsCorrectSourceMappingWithDotFile(t *testing.T) {
13101307
changedFiles := []string{"prod/main.tf", "dev/test/main.tf"}
13111308
projects := []Project{
1312-
Project{
1309+
{
13131310
Name: "dev",
13141311
Dir: ".",
13151312
},
13161313
}
13171314
c := DiggerConfig{
13181315
Projects: projects,
13191316
}
1320-
//expectedImpactingLocations := map[string]ProjectToSourceMapping{}
1317+
// expectedImpactingLocations := map[string]ProjectToSourceMapping{}
13211318
// TODO: this behaviour doesn't make much sense, we should re-evaluate when we make it configurable
13221319
impactedProjects, _ := c.GetModifiedProjects(changedFiles)
13231320
assert.Equal(t, 1, len(impactedProjects))
@@ -1326,7 +1323,7 @@ func TestGetModifiedProjectsReturnsCorrectSourceMappingWithDotFile(t *testing.T)
13261323
func TestShouldDetectNestedFilesAsImpacted(t *testing.T) {
13271324
changedFiles := []string{"services/backend/files/config.json"}
13281325
projects := []Project{
1329-
Project{
1326+
{
13301327
Name: "services_backend",
13311328
Dir: "services/backend",
13321329
},
@@ -1341,12 +1338,12 @@ func TestShouldDetectNestedFilesAsImpacted(t *testing.T) {
13411338
func TestGetModifiedProjectsReturnsCorrectSourceMapping(t *testing.T) {
13421339
changedFiles := []string{"modules/bucket/main.tf", "dev/main.tf"}
13431340
projects := []Project{
1344-
Project{
1341+
{
13451342
Name: "dev",
13461343
Dir: "dev",
13471344
IncludePatterns: []string{"modules/**"},
13481345
},
1349-
Project{
1346+
{
13501347
Name: "prod",
13511348
Dir: "prod",
13521349
IncludePatterns: []string{"modules/**"},
@@ -1367,7 +1364,37 @@ func TestGetModifiedProjectsReturnsCorrectSourceMapping(t *testing.T) {
13671364
assert.Equal(t, 1, len(projectSourceMapping["prod"].ImpactingLocations))
13681365
assert.Equal(t, expectedImpactingLocations["dev"].ImpactingLocations, projectSourceMapping["dev"].ImpactingLocations)
13691366
assert.Equal(t, expectedImpactingLocations["prod"].ImpactingLocations, projectSourceMapping["prod"].ImpactingLocations)
1367+
}
13701368

1369+
func TestGetModifiedProjectsReturnsCorrectSourceMappingWithRelativePaths(t *testing.T) {
1370+
changedFiles := []string{"terraform/modules/bucket/main.tf", "terraform/dev/main.tf"}
1371+
projects := []Project{
1372+
{
1373+
Name: "dev",
1374+
Dir: "terraform/dev",
1375+
IncludePatterns: []string{"../modules/**"},
1376+
},
1377+
{
1378+
Name: "prod",
1379+
Dir: "terraform/prod",
1380+
IncludePatterns: []string{"../modules/**"},
1381+
},
1382+
}
1383+
c := DiggerConfig{
1384+
Projects: projects,
1385+
}
1386+
expectedImpactingLocations := map[string]ProjectToSourceMapping{
1387+
"dev": {ImpactingLocations: []string{"terraform/modules/bucket", "terraform/dev"}},
1388+
"prod": {ImpactingLocations: []string{"terraform/modules/bucket"}},
1389+
}
1390+
1391+
impactedProjects, projectSourceMapping := c.GetModifiedProjects(changedFiles)
1392+
assert.Equal(t, 2, len(impactedProjects))
1393+
assert.Equal(t, 2, len(projectSourceMapping))
1394+
assert.Equal(t, 2, len(projectSourceMapping["dev"].ImpactingLocations))
1395+
assert.Equal(t, 1, len(projectSourceMapping["prod"].ImpactingLocations))
1396+
assert.Equal(t, expectedImpactingLocations["dev"].ImpactingLocations, projectSourceMapping["dev"].ImpactingLocations)
1397+
assert.Equal(t, expectedImpactingLocations["prod"].ImpactingLocations, projectSourceMapping["prod"].ImpactingLocations)
13711398
}
13721399

13731400
func TestCognitoTokenSetFromMinConfig(t *testing.T) {

0 commit comments

Comments
 (0)