Skip to content

Conversation

@loispostula
Copy link

@loispostula loispostula commented Nov 28, 2025

Description

Fixes #2734
Fixes #2927

Fix runner validation to skip disabled dependencies when resolving unit dependencies. Previously, when a dependency block had enabled = false but a valid config_path, the path was still validated against discovered units, causing UnrecognizedDependencyError. Now getDependenciesForUnit checks TerragruntDependencies for the enabled flag before erroring on missing paths.

TODOs

Read the Gruntwork contribution guidelines.

  • I authored this code entirely myself
  • I am submitting code based on open source software (e.g. MIT, MPL-2.0, Apache)]
  • I am adding or upgrading a dependency or adapted code and confirm it has a compatible open source license
  • Update the docs.
  • Run the relevant tests successfully, including pre-commit checks.
  • Include release notes. If this PR is backward incompatible, include a migration guide.

Release Notes (draft)

Updated disabled dependency management

Migration Guide

Summary by CodeRabbit

  • Bug Fixes

    • Improved dependency path validation by skipping empty, current-directory, or disabled dependency paths during resolution instead of causing errors.
    • Enhanced dependency resolution to gracefully handle missing or disabled dependencies, resulting in more tolerant processing.
  • Tests

    • Added comprehensive test coverage for disabled dependency handling and invalid path skipping scenarios.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 28, 2025

@loispostula is attempting to deploy a commit to the Gruntwork Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 28, 2025

📝 Walkthrough

Walkthrough

This pull request adds guards to skip empty string and "." dependency paths in both the discovery and runner phases of dependency resolution, and implements logic to skip disabled dependencies. These changes prevent invalid or placeholder paths from being processed during Terragrunt configuration dependency extraction and unit graph construction.

Changes

Cohort / File(s) Summary
Discovery phase updates
internal/discovery/discovery.go, internal/discovery/discovery_test.go
Adds guards in extractDependencyPaths to skip empty or "." dependency paths from both TerragruntDependencies and Dependencies.Paths. Updates existing test and adds TestDiscoverySkipsEmptyDependencyPaths to validate skipping of invalid paths and discovery of multiple environment-specific components.
Runner unit resolution updates
internal/runner/common/unit.go, internal/runner/common/unit_test.go
Introduces skipping logic for empty/"." paths and disabled dependencies in getDependenciesForUnit. Adds isDisabledDependency helper method to detect disabled Terragrunt dependencies. Adds TestUnitsMap_ConvertDiscoveryToRunner_SkipsDisabledDependencies test and imports cty package for test construction.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Logic changes across multiple phases: Guards and skip conditions added in both discovery and runner modules require verification for consistency
  • New helper method: isDisabledDependency logic should be reviewed for correctness in detecting disabled dependencies
  • Test coverage: New tests validate the skip behavior but require careful review of test scenarios and assertions

Possibly related PRs

Suggested reviewers

  • denis256
  • ThisGuyCodes
  • yhakbar

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: improving disabled dependency management by skipping disabled dependencies during validation.
Description check ✅ Passed The description provides clear context about the fix, references an issue, includes checklist items, and draft release notes, aligning well with the template requirements.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
internal/runner/common/unit.go (1)

241-252: Consider canonicalizing paths for more robust comparison.

The current implementation compares dependencyPath (from Dependencies.Paths) directly with dep.ConfigPath.AsString() (from TerragruntDependencies). If the same dependency is specified in different path formats (e.g., "../foo" vs "${get_terragrunt_dir()}/../foo"), the comparison might fail to match.

While the test cases suggest same-format usage is expected, canonicalizing both paths before comparison would make this more robust:

 func (unit *Unit) isDisabledDependency(dependencyPath string) bool {
+	canonicalDepPath, err := util.CanonicalPath(dependencyPath, unit.Path)
+	if err != nil {
+		return false
+	}
 	for _, dep := range unit.Config.TerragruntDependencies {
 		if dep.Enabled != nil && !*dep.Enabled {
 			depPath := dep.ConfigPath.AsString()
+			canonicalConfigPath, err := util.CanonicalPath(depPath, unit.Path)
+			if err != nil {
+				continue
+			}
-			if depPath == dependencyPath {
+			if canonicalConfigPath == canonicalDepPath {
 				return true
 			}
 		}
 	}
 	return false
 }
internal/runner/common/unit_test.go (1)

150-172: LGTM! Test correctly validates disabled dependency skipping.

The test properly exercises the fix by creating a scenario where a unit has both an enabled dependency (fooPath) and a disabled dependency (disabledDepPath), then verifying that only the enabled dependency is included after conversion.

Optional enhancement: Consider adding more specific assertions to make test failures clearer:

 	units, err := m.ConvertDiscoveryToRunner([]string{fooPath, barPath})
 	require.NoError(t, err)
-	assert.Len(t, units[0].Dependencies, 1)
+	require.Len(t, units, 2)
+	// units[0] is barPath (alphabetically first)
+	assert.Len(t, units[0].Dependencies, 1, "bar should have only 1 dependency")
+	assert.Equal(t, fooPath, units[0].Dependencies[0].Path, "bar should depend on foo only")
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3f8b187 and 553886b.

📒 Files selected for processing (4)
  • internal/discovery/discovery.go (2 hunks)
  • internal/discovery/discovery_test.go (2 hunks)
  • internal/runner/common/unit.go (3 hunks)
  • internal/runner/common/unit_test.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

Review the Go code for quality and correctness. Make sure that the Go code follows best practices, is performant, and is easy to understand and maintain.

Files:

  • internal/discovery/discovery_test.go
  • internal/discovery/discovery.go
  • internal/runner/common/unit_test.go
  • internal/runner/common/unit.go
🧠 Learnings (3)
📚 Learning: 2025-08-19T16:05:54.723Z
Learnt from: Resonance1584
Repo: gruntwork-io/terragrunt PR: 4683
File: go.mod:86-90
Timestamp: 2025-08-19T16:05:54.723Z
Learning: When analyzing Go module dependencies for removal, always check for both direct imports and API usage across all Go files in the repository, not just a quick search. The github.com/mattn/go-zglob library is used for filesystem walking and glob expansion in multiple Terragrunt files including util/file.go, format commands, and AWS provider patch functionality.

Applied to files:

  • internal/discovery/discovery.go
  • internal/runner/common/unit_test.go
📚 Learning: 2025-02-10T13:36:19.542Z
Learnt from: levkohimins
Repo: gruntwork-io/terragrunt PR: 3723
File: cli/commands/stack/action.go:160-160
Timestamp: 2025-02-10T13:36:19.542Z
Learning: The project uses a custom error package `github.com/gruntwork-io/terragrunt/internal/errors` which provides similar functionality to `fmt.Errorf` but includes stack traces. Prefer using this package's error functions (e.g., `errors.Errorf`, `errors.New`) over the standard library's error handling.

Applied to files:

  • internal/runner/common/unit_test.go
📚 Learning: 2025-04-17T13:02:28.098Z
Learnt from: yhakbar
Repo: gruntwork-io/terragrunt PR: 4169
File: cli/commands/hcl/validate/cli.go:29-60
Timestamp: 2025-04-17T13:02:28.098Z
Learning: Avoid shadowing imported packages with local variables in Go code, such as using a variable named `flags` when the `github.com/gruntwork-io/terragrunt/cli/flags` package is imported. Use more specific variable names like `flagSet` instead.

Applied to files:

  • internal/runner/common/unit_test.go
🧬 Code graph analysis (2)
internal/discovery/discovery_test.go (4)
internal/errors/export.go (1)
  • Join (17-19)
options/options.go (1)
  • NewTerragruntOptions (380-382)
test/helpers/logger/logger.go (1)
  • CreateLogger (9-14)
internal/discovery/constructor.go (1)
  • NewDiscovery (153-172)
internal/runner/common/unit_test.go (2)
internal/runner/common/unit.go (2)
  • UnitsMap (57-57)
  • Unit (26-36)
config/config.go (2)
  • TerragruntConfig (140-166)
  • ModuleDependencies (796-798)
🔇 Additional comments (6)
internal/runner/common/unit.go (2)

207-210: LGTM! Good defensive check for conditional dependencies.

The guard correctly handles empty or current-directory paths that can occur when conditional dependencies are disabled or resolve to non-existent paths. This aligns with the similar checks added in discovery.go.


222-225: Correctly implements the disabled dependency check.

This properly addresses the PR objective by checking if a missing dependency is disabled before returning an error. The logic correctly skips disabled dependencies instead of throwing UnrecognizedDependencyError.

internal/discovery/discovery.go (1)

1390-1392: LGTM! Consistent guards prevent invalid paths from being processed.

The guards correctly filter out empty or current-directory paths for both TerragruntDependencies and Dependencies.Paths, ensuring only valid dependency paths enter the deduped set. This prevents issues during subsequent dependency resolution and aligns with the similar guards added in the runner layer.

Also applies to: 1402-1404

internal/runner/common/unit_test.go (1)

9-9: LGTM! Import is necessary for test setup.

The cty import is required to construct ConfigPath values using cty.StringVal in the new test case.

internal/discovery/discovery_test.go (2)

1003-1010: LGTM! More realistic test setup using HCL locals.

The change to compute the enabled flag via a local variable makes the test more realistic and better exercises the HCL evaluation path. The test still correctly validates that disabled dependencies don't create cycles.


1045-1128: LGTM! Comprehensive test for conditional dependency paths.

This test thoroughly validates the core PR functionality with a realistic multi-environment setup:

  • Uses fileexists() to conditionally enable dependencies based on whether the dependency exists
  • Tests that empty or non-existent config_path values are properly skipped during discovery
  • Verifies that conditional dependencies don't cause false cycle detection
  • Covers multiple environment-specific components (prod/dev) with both shallow and deep merge strategies

The test provides strong coverage for the empty path skipping logic introduced in this PR.

@loispostula
Copy link
Author

@denis256 I'm not sure what's missing on this pr?

@yhakbar
Copy link
Collaborator

yhakbar commented Dec 9, 2025

Hey @loispostula ,

I'm not sure this is the right solution for this. Should dependencies with config_path of "" or "." be blindly skipped when found? Should an error be thrown instead? I agree that disabled dependencies should definitely be ignored.

There are also conflicts in your branch that need to be resolved before review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants