SuperClaude/scripts/validate_pypi_ready.py
NomenAK e8afb94163 Add comprehensive PyPI publishing infrastructure
## Version Management & Consistency
- Update to version 4.0.0b1 (proper beta versioning for PyPI)
- Add __version__ attribute to SuperClaude/__init__.py
- Ensure version consistency across pyproject.toml, __main__.py, setup/__init__.py

## Enhanced Package Configuration
- Improve pyproject.toml with comprehensive PyPI classifiers
- Add proper license specification and enhanced metadata
- Configure package discovery with inclusion/exclusion patterns
- Add development and test dependencies

## Publishing Scripts & Tools
- scripts/build_and_upload.py: Advanced Python script for building and uploading
- scripts/publish.sh: User-friendly shell wrapper for common operations
- scripts/validate_pypi_ready.py: Comprehensive validation and readiness checker
- All scripts executable with proper error handling and validation

## GitHub Actions Automation
- .github/workflows/publish-pypi.yml: Complete CI/CD pipeline
- Automatic publishing on GitHub releases
- Manual workflow dispatch for TestPyPI uploads
- Package validation and installation testing

## Documentation & Security
- PUBLISHING.md: Comprehensive PyPI publishing guide
- scripts/README.md: Detailed script usage documentation
- .env.example: Environment variable template
- Secure token handling with both .pypirc and environment variables

## Features
 Version consistency validation across all files
 Comprehensive PyPI metadata and classifiers
 Multi-environment publishing (TestPyPI + PyPI)
 Automated GitHub Actions workflow
 Security best practices for API token handling
 Complete documentation and troubleshooting guides
 Enterprise-grade validation and error handling

The SuperClaude Framework is now fully prepared for PyPI publication
with professional-grade automation, validation, and documentation.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-15 15:15:51 +02:00

220 lines
7.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
PyPI Readiness Validation Script
Checks if SuperClaude project is ready for PyPI publication
"""
import sys
import toml
from pathlib import Path
from typing import List, Tuple
# Project root
PROJECT_ROOT = Path(__file__).parent.parent
def check_file_exists(file_path: Path, description: str) -> bool:
"""Check if a required file exists"""
if file_path.exists():
print(f"{description}: {file_path}")
return True
else:
print(f"❌ Missing {description}: {file_path}")
return False
def check_version_consistency() -> bool:
"""Check if versions are consistent across files"""
print("\n🔍 Checking version consistency...")
versions = {}
# Check pyproject.toml
try:
pyproject_path = PROJECT_ROOT / "pyproject.toml"
with open(pyproject_path, 'r') as f:
pyproject = toml.load(f)
versions['pyproject.toml'] = pyproject['project']['version']
print(f"📋 pyproject.toml version: {versions['pyproject.toml']}")
except Exception as e:
print(f"❌ Error reading pyproject.toml: {e}")
return False
# Check SuperClaude/__init__.py
try:
sys.path.insert(0, str(PROJECT_ROOT))
from SuperClaude import __version__
versions['SuperClaude/__init__.py'] = __version__
print(f"📦 Package version: {versions['SuperClaude/__init__.py']}")
except Exception as e:
print(f"❌ Error importing SuperClaude version: {e}")
return False
# Check setup/__init__.py
try:
from setup import __version__ as setup_version
versions['setup/__init__.py'] = setup_version
print(f"🔧 Setup version: {versions['setup/__init__.py']}")
except Exception as e:
print(f"❌ Error importing setup version: {e}")
return False
# Check consistency
all_versions = list(versions.values())
if len(set(all_versions)) == 1:
print(f"✅ All versions consistent: {all_versions[0]}")
return True
else:
print(f"❌ Version mismatch: {versions}")
return False
def check_package_structure() -> bool:
"""Check if package structure is correct"""
print("\n🏗️ Checking package structure...")
required_structure = [
("SuperClaude/__init__.py", "Main package __init__.py"),
("SuperClaude/__main__.py", "Main entry point"),
("SuperClaude/Core/__init__.py", "Core module __init__.py"),
("SuperClaude/Commands/__init__.py", "Commands module __init__.py"),
("SuperClaude/Agents/__init__.py", "Agents module __init__.py"),
("SuperClaude/Modes/__init__.py", "Modes module __init__.py"),
("SuperClaude/MCP/__init__.py", "MCP module __init__.py"),
("setup/__init__.py", "Setup package __init__.py"),
]
all_good = True
for file_path, description in required_structure:
full_path = PROJECT_ROOT / file_path
if not check_file_exists(full_path, description):
all_good = False
return all_good
def check_required_files() -> bool:
"""Check if all required files are present"""
print("\n📄 Checking required files...")
required_files = [
("pyproject.toml", "Package configuration"),
("README.md", "Project README"),
("LICENSE", "License file"),
("MANIFEST.in", "Package manifest"),
("setup.py", "Setup script"),
]
all_good = True
for file_path, description in required_files:
full_path = PROJECT_ROOT / file_path
if not check_file_exists(full_path, description):
all_good = False
return all_good
def check_pyproject_config() -> bool:
"""Check pyproject.toml configuration"""
print("\n⚙️ Checking pyproject.toml configuration...")
try:
pyproject_path = PROJECT_ROOT / "pyproject.toml"
with open(pyproject_path, 'r') as f:
pyproject = toml.load(f)
project = pyproject.get('project', {})
# Required fields
required_fields = ['name', 'version', 'description', 'authors']
for field in required_fields:
if field in project:
print(f"{field}: {project[field]}")
else:
print(f"❌ Missing required field: {field}")
return False
# Check entry points
scripts = project.get('scripts', {})
if 'SuperClaude' in scripts:
print(f"✅ CLI entry point: {scripts['SuperClaude']}")
else:
print("❌ Missing CLI entry point")
return False
# Check classifiers
classifiers = project.get('classifiers', [])
if len(classifiers) > 0:
print(f"{len(classifiers)} PyPI classifiers defined")
else:
print("⚠️ No PyPI classifiers defined")
return True
except Exception as e:
print(f"❌ Error reading pyproject.toml: {e}")
return False
def check_import_test() -> bool:
"""Test if the package can be imported"""
print("\n🧪 Testing package import...")
try:
sys.path.insert(0, str(PROJECT_ROOT))
import SuperClaude
print(f"✅ SuperClaude import successful")
print(f"📦 Version: {SuperClaude.__version__}")
print(f"👤 Author: {SuperClaude.__author__}")
return True
except Exception as e:
print(f"❌ Import failed: {e}")
return False
def main():
"""Main validation function"""
print("🔍 SuperClaude PyPI Readiness Validation")
print(f"📁 Project root: {PROJECT_ROOT}")
print("=" * 50)
checks = [
("Required Files", check_required_files),
("Package Structure", check_package_structure),
("Version Consistency", check_version_consistency),
("PyProject Configuration", check_pyproject_config),
("Import Test", check_import_test),
]
results = []
for name, check_func in checks:
try:
result = check_func()
results.append((name, result))
except Exception as e:
print(f"{name} check failed with exception: {e}")
results.append((name, False))
# Summary
print("\n" + "=" * 50)
print("📊 VALIDATION SUMMARY")
print("=" * 50)
passed = 0
total = len(results)
for name, result in results:
status = "✅ PASS" if result else "❌ FAIL"
print(f"{status} {name}")
if result:
passed += 1
print(f"\n📈 Overall: {passed}/{total} checks passed")
if passed == total:
print("🎉 Project is ready for PyPI publication!")
print("\nNext steps:")
print("1. ./scripts/publish.sh test # Test on TestPyPI")
print("2. ./scripts/publish.sh prod # Publish to PyPI")
return True
else:
print("❌ Project needs fixes before PyPI publication")
return False
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)