Refactor code structure and optimize performance across multiple modules
This commit is contained in:
130
devops/scripts/add-testkit-reference.py
Normal file
130
devops/scripts/add-testkit-reference.py
Normal file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Adds StellaOps.TestKit ProjectReference to test projects that use TestCategories
|
||||
but are missing the reference.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_relative_path_to_testkit(csproj_path: Path) -> str:
|
||||
"""Calculate relative path from csproj to TestKit project."""
|
||||
# TestKit is at src/__Libraries/StellaOps.TestKit/StellaOps.TestKit.csproj
|
||||
csproj_dir = csproj_path.parent
|
||||
src_root = None
|
||||
|
||||
# Walk up to find src directory
|
||||
current = csproj_dir
|
||||
depth = 0
|
||||
while current.name != 'src' and depth < 10:
|
||||
current = current.parent
|
||||
depth += 1
|
||||
|
||||
if current.name == 'src':
|
||||
src_root = current
|
||||
else:
|
||||
return None
|
||||
|
||||
# Calculate relative path from csproj to src/__Libraries/StellaOps.TestKit
|
||||
rel_path = os.path.relpath(
|
||||
src_root / '__Libraries' / 'StellaOps.TestKit' / 'StellaOps.TestKit.csproj',
|
||||
csproj_dir
|
||||
)
|
||||
# Normalize to forward slashes for XML
|
||||
return rel_path.replace('\\', '/')
|
||||
|
||||
|
||||
def project_uses_testkit(csproj_dir: Path) -> bool:
|
||||
"""Check if any .cs file in the project directory uses TestCategories."""
|
||||
for cs_file in csproj_dir.rglob('*.cs'):
|
||||
if '/obj/' in str(cs_file) or '/bin/' in str(cs_file):
|
||||
continue
|
||||
try:
|
||||
content = cs_file.read_text(encoding='utf-8-sig', errors='ignore')
|
||||
if 'TestCategories.' in content:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
||||
def project_has_testkit_reference(content: str) -> bool:
|
||||
"""Check if csproj already references TestKit."""
|
||||
return 'StellaOps.TestKit' in content
|
||||
|
||||
|
||||
def add_testkit_reference(csproj_path: Path, dry_run: bool = False) -> bool:
|
||||
"""Add TestKit reference to csproj if needed."""
|
||||
try:
|
||||
content = csproj_path.read_text(encoding='utf-8')
|
||||
except Exception as e:
|
||||
print(f" Error reading {csproj_path}: {e}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
if project_has_testkit_reference(content):
|
||||
return False
|
||||
|
||||
if not project_uses_testkit(csproj_path.parent):
|
||||
return False
|
||||
|
||||
rel_path = get_relative_path_to_testkit(csproj_path)
|
||||
if not rel_path:
|
||||
print(f" Could not determine path to TestKit from {csproj_path}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
# Find a good place to insert the reference - look for existing ProjectReference
|
||||
if '<ProjectReference' in content:
|
||||
# Insert before the last </ItemGroup> that contains ProjectReference
|
||||
pattern = r'( <ProjectReference [^>]+/>\s*\n)( </ItemGroup>)'
|
||||
replacement = f'\\1 <ProjectReference Include="{rel_path}" />\n\\2'
|
||||
fixed = re.sub(pattern, replacement, content, count=1)
|
||||
else:
|
||||
# No ProjectReference, add a new ItemGroup before </Project>
|
||||
pattern = r'(</Project>)'
|
||||
new_item_group = f''' <ItemGroup>
|
||||
<ProjectReference Include="{rel_path}" />
|
||||
</ItemGroup>
|
||||
\\1'''
|
||||
fixed = re.sub(pattern, new_item_group, content)
|
||||
|
||||
if fixed == content:
|
||||
print(f" Could not find insertion point in {csproj_path}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
if not dry_run:
|
||||
csproj_path.write_text(fixed, encoding='utf-8')
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser(description='Add TestKit reference to test projects')
|
||||
parser.add_argument('--path', default='src', help='Path to scan')
|
||||
parser.add_argument('--dry-run', action='store_true', help='Show what would be fixed')
|
||||
args = parser.parse_args()
|
||||
|
||||
root = Path(args.path)
|
||||
fixed_count = 0
|
||||
|
||||
# Find all test project files
|
||||
for csproj in root.rglob('*.Tests.csproj'):
|
||||
if add_testkit_reference(csproj, dry_run=args.dry_run):
|
||||
print(f"{'Would add' if args.dry_run else 'Added'} TestKit reference to: {csproj}")
|
||||
fixed_count += 1
|
||||
|
||||
# Also check *UnitTests, *SmokeTests, etc.
|
||||
for pattern in ['*UnitTests.csproj', '*IntegrationTests.csproj', '*SmokeTests.csproj', '*FixtureTests.csproj']:
|
||||
for csproj in root.rglob(pattern):
|
||||
if add_testkit_reference(csproj, dry_run=args.dry_run):
|
||||
print(f"{'Would add' if args.dry_run else 'Added'} TestKit reference to: {csproj}")
|
||||
fixed_count += 1
|
||||
|
||||
print(f"\nAdded TestKit reference to: {fixed_count} projects")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user