@@ -74,19 +74,25 @@ def _collect_tf_dirs_and_sources(tf_files: list[Path]) -> tuple[set[Path], set[s
7474 return tf_dirs , module_sources
7575
7676
77+ def _resolve_module_paths (src : str , tf_dirs : set [Path ], repo_root : Path | None ) -> list [Path ]:
78+ paths : list [Path ] = []
79+ for tf_dir in tf_dirs :
80+ try :
81+ paths .append ((tf_dir / src ).resolve ())
82+ except (ValueError , OSError ):
83+ pass
84+ if repo_root :
85+ try :
86+ paths .append ((repo_root / src .lstrip ("./" )).resolve ())
87+ except (ValueError , OSError ):
88+ pass
89+ return paths
90+
91+
7792def _is_in_module (candidate : Path , module_sources : set [str ], tf_dirs : set [Path ], repo_root : Path | None = None ) -> bool :
7893 for src in module_sources :
79- for tf_dir in tf_dirs :
80- try :
81- module_path = (tf_dir / src ).resolve ()
82- if candidate .is_relative_to (module_path ):
83- return True
84- except (ValueError , OSError ):
85- pass
86- if repo_root :
94+ for module_path in _resolve_module_paths (src , tf_dirs , repo_root ):
8795 try :
88- clean_src = src .lstrip ("./" )
89- module_path = (repo_root / clean_src ).resolve ()
9096 if candidate .is_relative_to (module_path ):
9197 return True
9298 except (ValueError , OSError ):
@@ -134,7 +140,10 @@ def _extract_qualified_defs(content: str) -> set[str]:
134140)
135141
136142
137- def _candidate_references_changed_defs_strict (content : str , changed_defs : set [str ]) -> bool :
143+ _TF_RESOURCE_SKIP_TYPES = frozenset ({"var" , "local" , "data" , "module" , "path" , "terraform" , "each" , "self" , "count" })
144+
145+
146+ def _has_non_generic_var_local_ref (content : str , changed_defs : set [str ]) -> bool :
138147 for match in _TF_VAR_REF_RE .finditer (content ):
139148 name = match .group (1 )
140149 if name in changed_defs and name not in _TF_GENERIC_NAMES :
@@ -143,23 +152,29 @@ def _candidate_references_changed_defs_strict(content: str, changed_defs: set[st
143152 name = match .group (1 )
144153 if name in changed_defs and name not in _TF_GENERIC_NAMES :
145154 return True
155+ return False
156+
157+
158+ def _has_data_module_resource_ref (content : str , changed_defs : set [str ]) -> bool :
146159 for match in _TF_DATA_REF_RE .finditer (content ):
147160 data_type , data_name = match .group (1 ), match .group (2 )
148161 if f"{ data_type } .{ data_name } " in changed_defs or data_name in changed_defs :
149162 return True
150163 for match in _TF_MODULE_REF_RE .finditer (content ):
151164 if match .group (1 ) in changed_defs :
152165 return True
153- skip_types = {"var" , "local" , "data" , "module" , "path" , "terraform" , "each" , "self" , "count" }
154166 for match in _TF_RESOURCE_REF_RE .finditer (content ):
155167 res_type , res_name , _ = match .groups ()
156- if res_type in skip_types :
157- continue
158- if f"{ res_type } .{ res_name } " in changed_defs or res_name in changed_defs :
159- return True
168+ if res_type not in _TF_RESOURCE_SKIP_TYPES :
169+ if f"{ res_type } .{ res_name } " in changed_defs or res_name in changed_defs :
170+ return True
160171 return False
161172
162173
174+ def _candidate_references_changed_defs_strict (content : str , changed_defs : set [str ]) -> bool :
175+ return _has_non_generic_var_local_ref (content , changed_defs ) or _has_data_module_resource_ref (content , changed_defs )
176+
177+
163178class _TFIndex :
164179 var_defs : dict [str , list [FragmentId ]]
165180 resource_defs : dict [str , list [FragmentId ]]
@@ -203,28 +218,37 @@ def discover_related_files(
203218 pass
204219
205220 changed_set = set (changed_files )
206- discovered : list [Path ] = []
207-
208- for candidate in all_candidate_files :
209- if candidate in changed_set or not _is_terraform_file (candidate ):
210- continue
211- if _is_in_module (candidate , module_sources , tf_dirs , repo_root ):
212- discovered .append (candidate )
213- continue
214- if candidate .parent not in tf_dirs :
215- continue
216- try :
217- content = candidate .read_text (encoding = "utf-8" )
218- except (OSError , UnicodeDecodeError ):
219- continue
220- if _candidate_references_changed_defs_strict (content , changed_defs ):
221- discovered .append (candidate )
222- continue
223- candidate_defs = _extract_qualified_defs (content )
224- if candidate_defs and any (_candidate_references_changed_defs_strict (c , candidate_defs ) for c in changed_contents ):
225- discovered .append (candidate )
226-
227- return discovered
221+ return [
222+ c
223+ for c in all_candidate_files
224+ if c not in changed_set
225+ and _is_terraform_file (c )
226+ and self ._is_related (c , module_sources , tf_dirs , repo_root , changed_defs , changed_contents )
227+ ]
228+
229+ def _is_related (
230+ self ,
231+ candidate : Path ,
232+ module_sources : set [str ],
233+ tf_dirs : set [Path ],
234+ repo_root : Path | None ,
235+ changed_defs : set [str ],
236+ changed_contents : list [str ],
237+ ) -> bool :
238+ if _is_in_module (candidate , module_sources , tf_dirs , repo_root ):
239+ return True
240+ if candidate .parent not in tf_dirs :
241+ return False
242+ try :
243+ content = candidate .read_text (encoding = "utf-8" )
244+ except (OSError , UnicodeDecodeError ):
245+ return False
246+ if _candidate_references_changed_defs_strict (content , changed_defs ):
247+ return True
248+ candidate_defs = _extract_qualified_defs (content )
249+ return bool (candidate_defs ) and any (
250+ _candidate_references_changed_defs_strict (c , candidate_defs ) for c in changed_contents
251+ )
228252
229253 def build (self , fragments : list [Fragment ], repo_root : Path | None = None ) -> EdgeDict :
230254 tf_frags = [f for f in fragments if _is_terraform_file (f .path )]
0 commit comments