Skip to content

Commit 6bcc8f2

Browse files
committed
Adding Query Validation Workflow
1 parent 500db22 commit 6bcc8f2

File tree

3 files changed

+111
-0
lines changed

3 files changed

+111
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Validate SumoLogic Queries
2+
on: [pull_request, push]
3+
4+
jobs:
5+
validate-sql:
6+
runs-on: ubuntu-latest
7+
steps:
8+
- uses: actions/checkout@v4
9+
10+
- name: Set up Python
11+
uses: actions/setup-python@v4
12+
with:
13+
python-version: "3.10"
14+
15+
- name: Install dependencies
16+
run: |
17+
pip install requests pyyaml
18+
19+
- name: Run validation
20+
env:
21+
SUMO_LOGIC_ACCESS_ID: ${{ secrets.SUMO_LOGIC_ACCESS_ID }}
22+
SUMO_LOGIC_ACCESS_KEY: ${{ secrets.SUMO_LOGIC_ACCESS_KEY }}
23+
run: |
24+
python scripts/validate_queries.py

scripts/sumologic_client.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import os
2+
import requests
3+
from datetime import datetime, timedelta
4+
5+
class SumoLogicClient:
6+
def __init__(self):
7+
self.base_url = "https://api.sumologic.com/api/v1"
8+
self.session = requests.Session()
9+
self.session.auth = (
10+
os.getenv("SUMO_LOGIC_ACCESS_ID"),
11+
os.getenv("SUMO_LOGIC_ACCESS_KEY")
12+
)
13+
14+
def test_query(self, query):
15+
"""Execute a query in Sumo Logic and check for results"""
16+
job_id = self._create_search_job(query)
17+
status = self._wait_for_job(job_id)
18+
return self._check_results(job_id) if status == "DONE GATHERING RESULTS" else False
19+
20+
def _create_search_job(self, query):
21+
end_time = datetime.utcnow()
22+
start_time = end_time - timedelta(hours=24)
23+
payload = {
24+
"query": query,
25+
"from": start_time.isoformat() + "Z",
26+
"to": end_time.isoformat() + "Z",
27+
"timeZone": "UTC"
28+
}
29+
response = self.session.post(f"{self.base_url}/search/jobs", json=payload)
30+
response.raise_for_status()
31+
return response.json()["id"]
32+
33+
def _wait_for_job(self, job_id, max_attempts=10):
34+
for _ in range(max_attempts):
35+
response = self.session.get(f"{self.base_url}/search/jobs/{job_id}")
36+
response.raise_for_status()
37+
status = response.json()["state"]
38+
if status in ["DONE GATHERING RESULTS", "CANCELLED"]:
39+
return status
40+
time.sleep(3)
41+
return "TIMEOUT"
42+
43+
def _check_results(self, job_id):
44+
response = self.session.get(f"{self.base_url}/search/jobs/{job_id}/messages")
45+
response.raise_for_status()
46+
return len(response.json()["messages"]) > 0

scripts/validate_queries.sh

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/usr/bin/env python3
2+
import re
3+
import sys
4+
from pathlib import Path
5+
from sumologic_client import SumoLogicClient
6+
7+
def find_sql_blocks_in_pr():
8+
"""Detect changed SQL blocks without file modifications"""
9+
changed_files = sys.argv[1:] if len(sys.argv) > 1 else [
10+
str(p) for p in Path("docs").rglob("*.md")
11+
if "search-query-language" in str(p)
12+
]
13+
14+
sql_blocks = []
15+
for file in changed_files:
16+
content = Path(file).read_text()
17+
sql_blocks.extend([
18+
(file, sql.strip())
19+
for sql in re.findall(r'```sql\n(.*?)```', content, re.DOTALL)
20+
])
21+
return sql_blocks
22+
23+
def validate_queries():
24+
client = SumoLogicClient()
25+
failed = False
26+
27+
for file, query in find_sql_blocks_in_pr():
28+
print(f"Validating SQL in {file}...")
29+
try:
30+
if not client.test_query(query):
31+
print(f"::error file={file},title=Query Validation Failed::Query returned no results")
32+
failed = True
33+
except Exception as e:
34+
print(f"::error file={file},title=Query Execution Failed::{str(e)}")
35+
failed = True
36+
37+
if failed:
38+
sys.exit(1)
39+
40+
if __name__ == "__main__":
41+
validate_queries()

0 commit comments

Comments
 (0)