Skip to content

Commit 5fabbba

Browse files
committed
wip add org traces
1 parent f402547 commit 5fabbba

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

organize_traces.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Script to organize Playwright trace folders by framework, feature, and test name.
4+
"""
5+
6+
import os
7+
import re
8+
import shutil
9+
import argparse
10+
from pathlib import Path
11+
from collections import defaultdict
12+
13+
def extract_test_info(error_context_path):
14+
"""Extract framework, feature, and test name from error-context.md file."""
15+
try:
16+
with open(error_context_path, 'r', encoding='utf-8') as f:
17+
content = f.read()
18+
19+
# Extract test name
20+
# Handle both formats: "[Framework] Test Name" and "Feature >> [Framework] Test Name"
21+
name_match = re.search(r'- Name: (?:.*? >> )?\[([^\]]+)\]\s*(.+)', content)
22+
if not name_match:
23+
return None, None, None
24+
25+
framework_bracket = name_match.group(1)
26+
test_name = name_match.group(2).strip()
27+
28+
# Extract location to get framework and feature
29+
location_match = re.search(r'- Location: .*?/tests/([^/]+)/([^:]+)\.spec\.ts', content)
30+
if not location_match:
31+
return None, None, None
32+
33+
framework_from_path = location_match.group(1)
34+
feature_file = location_match.group(2)
35+
36+
# Clean up framework name (remove 'Tests' suffix if present)
37+
framework = framework_from_path.replace('Tests', '').lower()
38+
39+
# Extract feature name from filename
40+
feature = feature_file
41+
42+
return framework, feature, test_name
43+
44+
except Exception as e:
45+
print(f"Error reading {error_context_path}: {e}")
46+
return None, None, None
47+
48+
def analyze_traces_folder(traces_path):
49+
"""Analyze the traces folder and return the planned folder structure."""
50+
traces_path = Path(traces_path)
51+
52+
if not traces_path.exists():
53+
print(f"Error: {traces_path} does not exist")
54+
return None
55+
56+
structure = defaultdict(lambda: defaultdict(list))
57+
unknown_folders = []
58+
59+
for folder in traces_path.iterdir():
60+
if not folder.is_dir():
61+
continue
62+
63+
error_context_path = folder / "error-context.md"
64+
65+
if error_context_path.exists():
66+
framework, feature, test_name = extract_test_info(error_context_path)
67+
68+
if framework and feature and test_name:
69+
structure[framework][feature].append((test_name, folder.name))
70+
else:
71+
unknown_folders.append(folder.name)
72+
else:
73+
unknown_folders.append(folder.name)
74+
75+
return structure, unknown_folders
76+
77+
def print_planned_structure(structure, unknown_folders):
78+
"""Print the planned folder structure."""
79+
print("Planned folder structure:")
80+
print("=" * 50)
81+
82+
for framework in sorted(structure.keys()):
83+
print(f"\n{framework}/")
84+
for feature in sorted(structure[framework].keys()):
85+
print(f" {feature}/")
86+
for test_name, folder_name in structure[framework][feature]:
87+
print(f" {test_name}/")
88+
print(f" -> {folder_name}")
89+
90+
if unknown_folders:
91+
print(f"\nunknown/")
92+
for folder_name in sorted(unknown_folders):
93+
print(f" -> {folder_name}")
94+
95+
print("\n" + "=" * 50)
96+
97+
def execute_reorganization(traces_path, structure, unknown_folders):
98+
"""Execute the folder reorganization."""
99+
traces_path = Path(traces_path)
100+
101+
# Create framework folders and move test folders
102+
for framework, features in structure.items():
103+
framework_path = traces_path / framework
104+
framework_path.mkdir(exist_ok=True)
105+
106+
for feature, tests in features.items():
107+
feature_path = framework_path / feature
108+
feature_path.mkdir(exist_ok=True)
109+
110+
for test_name, folder_name in tests:
111+
test_path = feature_path / test_name
112+
test_path.mkdir(exist_ok=True)
113+
114+
source_folder = traces_path / folder_name
115+
if source_folder.exists():
116+
# Move the entire folder
117+
shutil.move(str(source_folder), str(test_path / folder_name))
118+
print(f"Moved {folder_name} to {framework}/{feature}/{test_name}/")
119+
120+
# Move unknown folders
121+
if unknown_folders:
122+
unknown_path = traces_path / "unknown"
123+
unknown_path.mkdir(exist_ok=True)
124+
125+
for folder_name in unknown_folders:
126+
source_folder = traces_path / folder_name
127+
if source_folder.exists():
128+
shutil.move(str(source_folder), str(unknown_path / folder_name))
129+
print(f"Moved {folder_name} to unknown/")
130+
131+
def main():
132+
parser = argparse.ArgumentParser(description='Organize Playwright trace folders by framework, feature, and test name.')
133+
parser.add_argument('--dry-run', action='store_true', help='Show planned structure without making changes')
134+
args = parser.parse_args()
135+
136+
traces_path = Path.home() / "Downloads" / "playwright-traces-8"
137+
138+
print(f"Analyzing traces folder: {traces_path}")
139+
140+
# Analyze the current structure
141+
result = analyze_traces_folder(traces_path)
142+
if result is None:
143+
return
144+
145+
structure, unknown_folders = result
146+
147+
if not structure and not unknown_folders:
148+
print("No folders found to organize.")
149+
return
150+
151+
# Print planned structure
152+
print_planned_structure(structure, unknown_folders)
153+
154+
if args.dry_run:
155+
print("\nDRY RUN MODE: No changes were made.")
156+
return
157+
158+
# Ask for confirmation
159+
response = input("\nDo you want to proceed with the reorganization? (y/N): ")
160+
if response.lower() not in ['y', 'yes']:
161+
print("Operation cancelled.")
162+
return
163+
164+
# Execute the reorganization
165+
print("\nExecuting reorganization...")
166+
execute_reorganization(traces_path, structure, unknown_folders)
167+
print("\nReorganization complete!")
168+
169+
if __name__ == "__main__":
170+
main()

0 commit comments

Comments
 (0)