2626import xml .etree .ElementTree as ET
2727
2828class Project :
29- def __init__ (self , identifier : str , module_path : str , parent_pom : str ):
29+ def __init__ (self , identifier : str , directory_path : str , module_path : str , parent_pom : str ):
3030 self .identifier = identifier
31+ self .directory_path = directory_path
3132 self .module_path = module_path
3233 self .parent_pom = parent_pom
3334 self .dependencies : List [str ] = []
@@ -41,7 +42,7 @@ def add_dependent(self, dependent: str):
4142 if dependent not in self .dependents :
4243 self .dependents .append (dependent )
4344
44- default_project = Project (None , None , None )
45+ default_project = Project (None , None , None , None )
4546
4647# azure-client-sdk-parent, azure-perf-test-parent, spring-boot-starter-parent, and azure-spring-boot-test-parent are
4748# valid parent POMs for Track 2 libraries.
@@ -79,7 +80,7 @@ def add_dependent(self, dependent: str):
7980maven_xml_namespace = '{http://maven.apache.org/POM/4.0.0}'
8081
8182# Function that creates the aggregate POM.
82- def create_from_source_pom (project_list : str , set_pipeline_variable : str ):
83+ def create_from_source_pom (project_list : str , set_pipeline_variable : str , set_skip_linting_projects : str ):
8384 project_list_identifiers = project_list .split (',' )
8485
8586 # Get the artifact identifiers from client_versions.txt to act as our source of truth.
@@ -101,14 +102,14 @@ def create_from_source_pom(project_list: str, set_pipeline_variable: str):
101102 for project_identifier in dependent_modules :
102103 dependency_modules = resolve_project_dependencies (project_identifier , dependency_modules , projects )
103104
104- modules : Set [str ] = set ()
105+ source_projects : Set [Project ] = set ()
105106
106- # Finally map the project identifiers to relative module paths .
107- add_module_paths ( modules , project_list_identifiers , projects )
108- add_module_paths ( modules , dependent_modules , projects )
109- add_module_paths ( modules , dependency_modules , projects )
110-
111- modules = sorted (modules )
107+ # Finally map the project identifiers to projects .
108+ add_source_projects ( source_projects , project_list_identifiers , projects )
109+ add_source_projects ( source_projects , dependent_modules , projects )
110+ add_source_projects ( source_projects , dependency_modules , projects )
111+
112+ modules = list ( set ( sorted ([ p . module_path for p in source_projects ])) )
112113 with open (file = client_from_source_pom_path , mode = 'w' ) as fromSourcePom :
113114 fromSourcePom .write (pom_file_start )
114115
@@ -118,7 +119,18 @@ def create_from_source_pom(project_list: str, set_pipeline_variable: str):
118119 fromSourcePom .write (pom_file_end )
119120
120121 if set_pipeline_variable :
121- print ('##vso[task.setvariable variable={};]{}' .format (set_pipeline_variable , json .dumps (modules )))
122+ checkout_paths = list (set (sorted ([p .directory_path for p in source_projects ])))
123+ print ('##vso[task.setvariable variable={};]{}' .format (set_pipeline_variable , json .dumps (checkout_paths )))
124+
125+ # Sets the DevOps variable that is used to skip certain projects during linting validation.
126+ if set_skip_linting_projects :
127+ skip_linting_projects = []
128+ for maven_identifier in sorted ([p .identifier for p in source_projects ]):
129+ if not project_uses_client_parent (projects .get (maven_identifier ), projects ):
130+ skip_linting_projects .append ('!' + maven_identifier )
131+
132+ print ('##vso[task.setvariable variable={};]{}' .format (set_skip_linting_projects , ',' .join (list (set (skip_linting_projects )))))
133+
122134
123135# Function that loads and parses client_versions.txt into a artifact identifier - source version mapping.
124136def load_client_artifact_identifiers () -> Dict [str , str ]:
@@ -174,18 +186,19 @@ def create_project_for_pom(pom_path: str, project_list_identifiers: list, artifa
174186 tree_root = tree .getroot ()
175187
176188 project_identifier = create_artifact_identifier (tree_root )
177- module_path = os .path .dirname (pom_path ).replace (root_path , '' ).replace ('\\ ' , '/' )
189+ module_path = pom_path .replace (root_path , '' ).replace ('\\ ' , '/' )
190+ directory_path = module_path [:module_path .rindex ('/' )]
178191 parent_pom = get_parent_pom (tree_root )
179192
180193 # If this is one of the parent POMs, retain it as a project.
181194 if project_identifier in parent_pom_identifiers :
182- return Project (project_identifier , module_path , parent_pom )
195+ return Project (project_identifier , directory_path , module_path , parent_pom )
183196
184197 # If the project isn't a track 2 POM skip it and not one of the project list identifiers.
185198 if not project_identifier in project_list_identifiers and not parent_pom in valid_parents :
186199 return
187200
188- project = Project (project_identifier , module_path , parent_pom )
201+ project = Project (project_identifier , directory_path , module_path , parent_pom )
189202
190203 dependencies = {child :parent for parent in tree_root .iter () for child in parent if child .tag == maven_xml_namespace + 'dependency' }
191204
@@ -262,25 +275,34 @@ def get_dependency_version(element: ET.Element):
262275def element_find (element : ET .Element , path : str ):
263276 return element .find (maven_xml_namespace + path )
264277
265- def add_module_paths ( module_paths : Set [str ], project_identifiers : Iterable [str ], projects : Dict [str , Project ]):
278+ def add_source_projects ( source_projects : Set [Project ], project_identifiers : Iterable [str ], projects : Dict [str , Project ]):
266279 for project_identifier in project_identifiers :
267280 project = projects [project_identifier ]
268- module_paths .add (project . module_path )
281+ source_projects .add (project )
269282
270283 while project .parent_pom is not None :
271284 project = projects .get (project .parent_pom , default_project )
272285 if project .module_path is not None :
273- module_paths .add (project .module_path )
286+ source_projects .add (project )
287+
288+ def project_uses_client_parent (project : Project , projects : Dict [str , Project ]) -> bool :
289+ while project .parent_pom is not None :
290+ if project .parent_pom == 'com.azure:azure-client-sdk-parent' :
291+ return True
292+ project = projects .get (project .parent_pom , default_project )
293+
294+ return False
274295
275296def main ():
276297 parser = argparse .ArgumentParser (description = 'Generated an aggregate POM for a From Source run.' )
277298 parser .add_argument ('--project-list' , '--pl' , type = str )
278299 parser .add_argument ('--set-pipeline-variable' , type = str )
300+ parser .add_argument ('--set-skip-linting-projects' , type = str )
279301 args = parser .parse_args ()
280302 if args .project_list == None :
281303 raise ValueError ('Missing project list.' )
282304 start_time = time .time ()
283- create_from_source_pom (args .project_list , args .set_pipeline_variable )
305+ create_from_source_pom (args .project_list , args .set_pipeline_variable , args . set_skip_linting_projects )
284306 elapsed_time = time .time () - start_time
285307
286308 print ('Effective From Source POM File' )
0 commit comments