Skip to main content
Glama
validate_project_structure.py7.79 kB
#!/usr/bin/env python3 """ 프로젝트 구조 검증 스크립트 이 스크립트는 OpenRouter MCP 프로젝트의 파일/디렉토리 구조가 가이드라인을 준수하는지 자동으로 검증합니다. """ import os import sys import glob import re from pathlib import Path from typing import List, Tuple # Windows 인코딩 문제 해결 if sys.platform == "win32": import io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') class ProjectStructureValidator: def __init__(self, project_root: str = "."): self.project_root = Path(project_root).resolve() self.violations = [] self.warnings = [] def check_root_directory_cleanliness(self) -> None: """루트 디렉토리 정리 상태 검증""" print("🔍 루트 디렉토리 정리 상태 검사...") # 루트에 있으면 안 되는 파일 패턴들 forbidden_patterns = [ "test_*.py", "*_test.py", "*_results_*.json", "*_report_*.json", "*_report_*.md", "debug_*.py", "quick_*.py", "benchmark_*.json" ] for pattern in forbidden_patterns: matches = list(self.project_root.glob(pattern)) if matches: for match in matches: self.violations.append(f"❌ 루트에 금지된 파일: {match.name}") def check_api_key_security(self) -> None: """API 키 하드코딩 보안 검사""" print("🔒 API 키 보안 검사...") # 위험한 API 키 패턴 api_key_patterns = [ r'sk-or-v1-[a-f0-9]{64}', # OpenRouter API 키 r'sk-[a-zA-Z0-9]{48,}', # OpenAI 스타일 키 r'OPENROUTER_API_KEY\s*=\s*["\']sk-', # 환경변수 하드코딩 ] python_files = list(self.project_root.rglob("*.py")) for file_path in python_files: if ".git" in str(file_path): continue try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() for pattern in api_key_patterns: if re.search(pattern, content): self.violations.append(f"🚨 API 키 하드코딩 발견: {file_path.relative_to(self.project_root)}") except (UnicodeDecodeError, PermissionError): continue def check_test_file_organization(self) -> None: """테스트 파일 구조 검증""" print("🧪 테스트 파일 구조 검사...") tests_dir = self.project_root / "tests" if not tests_dir.exists(): self.violations.append("❌ tests/ 디렉토리가 존재하지 않습니다") return # tests/ 디렉토리 내 구조 검증 test_files = list(tests_dir.rglob("*.py")) if len(test_files) < 3: self.warnings.append("⚠️ tests/ 디렉토리에 테스트 파일이 부족할 수 있습니다") def check_documentation_structure(self) -> None: """문서 구조 검증""" print("📚 문서 구조 검사...") docs_dir = self.project_root / "docs" if not docs_dir.exists(): self.violations.append("❌ docs/ 디렉토리가 존재하지 않습니다") return # 필수 문서들 required_docs = ["README.md", "INSTALLATION.md", "API.md"] for doc in required_docs: if not (docs_dir / doc).exists(): self.warnings.append(f"⚠️ 권장 문서 누락: docs/{doc}") # 보고서 디렉토리 확인 reports_dir = docs_dir / "reports" if reports_dir.exists(): report_files = list(reports_dir.glob("*.md")) print(f"✅ 보고서 디렉토리: {len(report_files)}개 보고서 파일") else: self.warnings.append("⚠️ docs/reports/ 디렉토리가 없습니다") def check_gitignore_patterns(self) -> None: """gitignore 패턴 검증""" print("🙈 .gitignore 패턴 검사...") gitignore_path = self.project_root / ".gitignore" if not gitignore_path.exists(): self.violations.append("❌ .gitignore 파일이 없습니다") return with open(gitignore_path, 'r') as f: gitignore_content = f.read() # 필수 패턴들 required_patterns = [ "*_cache.json", "*_results_*.json", "benchmark_*.json", ".env" ] for pattern in required_patterns: if pattern not in gitignore_content: self.warnings.append(f"⚠️ .gitignore에 권장 패턴 누락: {pattern}") def count_file_statistics(self) -> dict: """파일 통계 수집""" stats = { 'root_files': len(list(self.project_root.glob("*"))), 'root_py_files': len(list(self.project_root.glob("*.py"))), 'root_md_files': len(list(self.project_root.glob("*.md"))), 'test_files': len(list((self.project_root / "tests").rglob("*.py"))) if (self.project_root / "tests").exists() else 0, 'doc_files': len(list((self.project_root / "docs").rglob("*.md"))) if (self.project_root / "docs").exists() else 0, } return stats def run_validation(self) -> bool: """전체 검증 실행""" print(f"🚀 OpenRouter MCP 프로젝트 구조 검증 시작") print(f"📁 프로젝트 경로: {self.project_root}") print("=" * 60) # 모든 검증 실행 self.check_root_directory_cleanliness() self.check_api_key_security() self.check_test_file_organization() self.check_documentation_structure() self.check_gitignore_patterns() # 통계 출력 stats = self.count_file_statistics() print(f"\n📊 프로젝트 통계:") print(f" • 루트 파일 수: {stats['root_files']}") print(f" • 루트 Python 파일: {stats['root_py_files']}") print(f" • 루트 문서 파일: {stats['root_md_files']}") print(f" • 테스트 파일: {stats['test_files']}") print(f" • 문서 파일: {stats['doc_files']}") # 결과 요약 print(f"\n📋 검증 결과:") if self.violations: print(f"❌ 위반사항 ({len(self.violations)}개):") for violation in self.violations: print(f" {violation}") else: print("✅ 구조 위반사항 없음") if self.warnings: print(f"\n⚠️ 개선 권장사항 ({len(self.warnings)}개):") for warning in self.warnings: print(f" {warning}") # 최종 판정 is_valid = len(self.violations) == 0 print("\n" + "=" * 60) if is_valid: print("🎉 프로젝트 구조 검증 통과!") else: print("💥 프로젝트 구조 개선이 필요합니다.") return is_valid def main(): """메인 실행 함수""" validator = ProjectStructureValidator() success = validator.run_validation() # 종료 코드 설정 (CI/CD에서 활용 가능) sys.exit(0 if success else 1) if __name__ == "__main__": main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/physics91/openrouter-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server