@@ -29,7 +29,19 @@ def debug_environment():
2929
3030def get_changed_files (repo_root ):
3131 """Find Markdown files to validate"""
32- # Try GitHub PR context first
32+ # First try to read from changed_files.txt if it exists (from GitHub workflow)
33+ changed_files_path = repo_root / "changed_files.txt"
34+ if changed_files_path .exists ():
35+ try :
36+ with open (changed_files_path ) as f :
37+ files = [line .strip () for line in f if line .strip ()]
38+ if files :
39+ print (f"π¦ Found { len (files )} changed Markdown files from workflow" )
40+ return [str (repo_root / f ) for f in files ]
41+ except Exception as e :
42+ print (f"::warning::Couldn't read changed_files.txt: { e } " )
43+
44+ # Try GitHub PR context
3345 if "GITHUB_EVENT_PATH" in os .environ :
3446 try :
3547 with open (os .environ ["GITHUB_EVENT_PATH" ]) as f :
@@ -54,6 +66,96 @@ def get_changed_files(repo_root):
5466 print ("::error::No Markdown files found in docs/ directory" )
5567 return []
5668
69+ def extract_sql_queries (file_path ):
70+ """Extract SQL code blocks from markdown files"""
71+ try :
72+ with open (file_path , 'r' , encoding = 'utf-8' ) as f :
73+ content = f .read ()
74+
75+ # Find SQL code blocks using regex
76+ sql_pattern = r'```(?:sql|sumo)\s*(?:title="[^"]*")?\s*\n(.*?)```'
77+ sql_blocks = re .findall (sql_pattern , content , re .DOTALL | re .IGNORECASE )
78+
79+ queries = []
80+ for block in sql_blocks :
81+ # Clean up the query
82+ query = block .strip ()
83+ if query and not query .startswith ('#' ) and not query .startswith ('//' ):
84+ queries .append (query )
85+
86+ return queries
87+ except Exception as e :
88+ print (f"::error::Error reading file { file_path } : { e } " )
89+ return []
90+
91+ def validate_query_syntax (query ):
92+ """Basic syntax validation for SumoLogic queries"""
93+ errors = []
94+
95+ # Check for basic syntax issues
96+ if '|' in query :
97+ # Split by pipes to check operators
98+ parts = [part .strip () for part in query .split ('|' )]
99+ for i , part in enumerate (parts ):
100+ if not part :
101+ errors .append (f"Empty pipe section at position { i } " )
102+
103+ # Check for common operator patterns
104+ if i > 0 : # Skip the first part (search expression)
105+ if not any (op in part .lower () for op in [
106+ 'where' , 'parse' , 'json' , 'count' , 'sum' , 'avg' , 'max' , 'min' ,
107+ 'timeslice' , 'sort' , 'top' , 'bottom' , 'fields' , 'if' , 'lookup' ,
108+ 'join' , 'extract' , 'formatDate' , 'toLowerCase' , 'toUpperCase'
109+ ]):
110+ # This might be a custom function or valid operator we don't know about
111+ pass
112+
113+ # Check for unmatched quotes
114+ single_quotes = query .count ("'" ) - query .count ("\\ '" )
115+ double_quotes = query .count ('"' ) - query .count ('\\ "' )
116+
117+ if single_quotes % 2 != 0 :
118+ errors .append ("Unmatched single quotes" )
119+ if double_quotes % 2 != 0 :
120+ errors .append ("Unmatched double quotes" )
121+
122+ # Check for unmatched parentheses
123+ paren_count = query .count ('(' ) - query .count (')' )
124+ if paren_count != 0 :
125+ errors .append ("Unmatched parentheses" )
126+
127+ # Check for unmatched brackets
128+ bracket_count = query .count ('[' ) - query .count (']' )
129+ if bracket_count != 0 :
130+ errors .append ("Unmatched square brackets" )
131+
132+ return errors
133+
134+ def validate_file (file_path ):
135+ """Validate all SQL queries in a markdown file"""
136+ print (f"π Validating: { file_path } " )
137+
138+ queries = extract_sql_queries (file_path )
139+ if not queries :
140+ print (f" βΉοΈ No SQL queries found" )
141+ return True
142+
143+ print (f" π Found { len (queries )} SQL queries" )
144+
145+ all_valid = True
146+ for i , query in enumerate (queries , 1 ):
147+ errors = validate_query_syntax (query )
148+ if errors :
149+ all_valid = False
150+ print (f" β Query { i } has errors:" )
151+ for error in errors :
152+ print (f" - { error } " )
153+ print (f" Query preview: { query [:100 ]} ..." )
154+ else :
155+ print (f" β
Query { i } passed basic syntax validation" )
156+
157+ return all_valid
158+
57159def main ():
58160 repo_root = debug_environment ()
59161 changed_files = get_changed_files (repo_root )
@@ -62,8 +164,46 @@ def main():
62164 print ("::warning::No Markdown files to validate" )
63165 sys .exit (0 )
64166
65- print (f"Validating { len (changed_files )} files..." )
66- # Rest of your validation logic here
167+ print (f"π Validating { len (changed_files )} files..." )
168+
169+ validation_results = []
170+ total_queries = 0
171+
172+ for file_path in changed_files :
173+ if os .path .exists (file_path ):
174+ result = validate_file (file_path )
175+ validation_results .append ((file_path , result ))
176+
177+ # Count queries for summary
178+ queries = extract_sql_queries (file_path )
179+ total_queries += len (queries )
180+ else :
181+ print (f"::warning::File not found: { file_path } " )
182+
183+ # Summary
184+ print ("\n " + "=" * 60 )
185+ print ("π VALIDATION SUMMARY" )
186+ print ("=" * 60 )
187+
188+ passed_files = sum (1 for _ , result in validation_results if result )
189+ failed_files = len (validation_results ) - passed_files
190+
191+ print (f"π Files processed: { len (validation_results )} " )
192+ print (f"π Total SQL queries: { total_queries } " )
193+ print (f"β
Files passed: { passed_files } " )
194+ print (f"β Files failed: { failed_files } " )
195+
196+ if failed_files > 0 :
197+ print ("\n β Files with validation errors:" )
198+ for file_path , result in validation_results :
199+ if not result :
200+ print (f" - { file_path } " )
201+
202+ print ("\n ::error::SQL query validation failed!" )
203+ sys .exit (1 )
204+ else :
205+ print ("\n π All SQL queries passed validation!" )
206+ sys .exit (0 )
67207
68208if __name__ == "__main__" :
69209 main ()
0 commit comments