mirror of
https://github.com/SuperClaude-Org/SuperClaude_Framework.git
synced 2025-12-17 09:46:06 +00:00
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>
This commit is contained in:
parent
8a594ed9d3
commit
e8afb94163
12
.env.example
Normal file
12
.env.example
Normal file
@ -0,0 +1,12 @@
|
||||
# SuperClaude Environment Variables
|
||||
# Copy this file to .env and fill in your actual values
|
||||
|
||||
# PyPI API Tokens
|
||||
PYPI_API_TOKEN=pypi-your-production-token-here
|
||||
TEST_PYPI_API_TOKEN=pypi-your-test-token-here
|
||||
|
||||
# GitHub Secrets (for CI/CD)
|
||||
# Add these to your GitHub repository settings:
|
||||
# Settings → Secrets and variables → Actions
|
||||
# PYPI_API_TOKEN=pypi-your-production-token-here
|
||||
# TEST_PYPI_API_TOKEN=pypi-your-test-token-here
|
||||
172
.github/workflows/publish-pypi.yml
vendored
Normal file
172
.github/workflows/publish-pypi.yml
vendored
Normal file
@ -0,0 +1,172 @@
|
||||
name: Publish to PyPI
|
||||
|
||||
on:
|
||||
# Trigger on new releases
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
# Allow manual triggering
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target:
|
||||
description: 'Publication target'
|
||||
required: true
|
||||
default: 'testpypi'
|
||||
type: choice
|
||||
options:
|
||||
- testpypi
|
||||
- pypi
|
||||
|
||||
# Restrict permissions for security
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build-and-publish:
|
||||
name: Build and publish Python package
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: ${{ github.event_name == 'release' && 'pypi' || 'testpypi' }}
|
||||
url: ${{ github.event_name == 'release' && 'https://pypi.org/p/SuperClaude' || 'https://test.pypi.org/p/SuperClaude' }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# Fetch full history for proper version detection
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install build dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install build twine
|
||||
|
||||
- name: Verify package structure
|
||||
run: |
|
||||
echo "📦 Checking package structure..."
|
||||
ls -la
|
||||
echo "🔍 Checking SuperClaude package..."
|
||||
ls -la SuperClaude/
|
||||
echo "🔍 Checking setup package..."
|
||||
ls -la setup/
|
||||
|
||||
# Verify version consistency
|
||||
echo "📋 Checking version consistency..."
|
||||
python -c "
|
||||
import toml
|
||||
import sys
|
||||
sys.path.insert(0, '.')
|
||||
|
||||
# Load pyproject.toml version
|
||||
with open('pyproject.toml', 'r') as f:
|
||||
pyproject = toml.load(f)
|
||||
pyproject_version = pyproject['project']['version']
|
||||
|
||||
# Load package version
|
||||
from SuperClaude import __version__
|
||||
|
||||
print(f'pyproject.toml version: {pyproject_version}')
|
||||
print(f'Package version: {__version__}')
|
||||
|
||||
if pyproject_version != __version__:
|
||||
print('❌ Version mismatch!')
|
||||
sys.exit(1)
|
||||
else:
|
||||
print('✅ Versions match')
|
||||
"
|
||||
|
||||
- name: Clean previous builds
|
||||
run: |
|
||||
rm -rf dist/ build/ *.egg-info/
|
||||
|
||||
- name: Build package
|
||||
run: |
|
||||
echo "🔨 Building package..."
|
||||
python -m build
|
||||
echo "📦 Built files:"
|
||||
ls -la dist/
|
||||
|
||||
- name: Validate package
|
||||
run: |
|
||||
echo "🔍 Validating package..."
|
||||
python -m twine check dist/*
|
||||
|
||||
# Upload to TestPyPI for testing (manual trigger or non-release)
|
||||
- name: Upload to TestPyPI
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||||
print-hash: true
|
||||
|
||||
# Upload to production PyPI (only on releases)
|
||||
- name: Upload to PyPI
|
||||
if: github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'pypi')
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
print-hash: true
|
||||
|
||||
- name: Create deployment summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "## 📦 SuperClaude Package Deployment" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Target | ${{ github.event_name == 'release' && 'PyPI (Production)' || github.event.inputs.target || 'TestPyPI' }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Trigger | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Version | $(python -c 'from SuperClaude import __version__; print(__version__)') |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "| Commit | ${{ github.sha }} |" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
if [ "${{ github.event_name }}" == "release" ]; then
|
||||
echo "🎉 **Production release published to PyPI!**" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Install with: \`pip install SuperClaude\`" >> $GITHUB_STEP_SUMMARY
|
||||
else
|
||||
echo "🧪 **Test release published to TestPyPI**" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Test install with: \`pip install --index-url https://test.pypi.org/simple/ SuperClaude\`" >> $GITHUB_STEP_SUMMARY
|
||||
fi
|
||||
|
||||
test-installation:
|
||||
name: Test package installation
|
||||
needs: build-and-publish
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
|
||||
|
||||
steps:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Test installation from TestPyPI
|
||||
run: |
|
||||
echo "🧪 Testing installation from TestPyPI..."
|
||||
|
||||
# Wait a bit for the package to be available
|
||||
sleep 30
|
||||
|
||||
# Install from TestPyPI
|
||||
pip install --index-url https://test.pypi.org/simple/ \
|
||||
--extra-index-url https://pypi.org/simple/ \
|
||||
SuperClaude
|
||||
|
||||
# Test basic import
|
||||
python -c "
|
||||
import SuperClaude
|
||||
print(f'✅ Successfully imported SuperClaude v{SuperClaude.__version__}')
|
||||
|
||||
# Test CLI entry point
|
||||
import subprocess
|
||||
result = subprocess.run(['SuperClaude', '--version'], capture_output=True, text=True)
|
||||
print(f'✅ CLI version: {result.stdout.strip()}')
|
||||
"
|
||||
|
||||
echo "✅ Installation test completed successfully!"
|
||||
293
PUBLISHING.md
Normal file
293
PUBLISHING.md
Normal file
@ -0,0 +1,293 @@
|
||||
# SuperClaude PyPI Publishing Guide
|
||||
|
||||
This guide covers the complete process for publishing SuperClaude to PyPI (Python Package Index).
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
### 1. Validate Project Readiness
|
||||
```bash
|
||||
python3 scripts/validate_pypi_ready.py
|
||||
```
|
||||
|
||||
### 2. Test Upload to TestPyPI
|
||||
```bash
|
||||
./scripts/publish.sh test
|
||||
```
|
||||
|
||||
### 3. Test Installation
|
||||
```bash
|
||||
./scripts/publish.sh test-install
|
||||
```
|
||||
|
||||
### 4. Production Upload
|
||||
```bash
|
||||
./scripts/publish.sh prod
|
||||
```
|
||||
|
||||
## 📋 Prerequisites
|
||||
|
||||
### 1. PyPI Accounts
|
||||
- **Production PyPI**: https://pypi.org/account/register/
|
||||
- **TestPyPI**: https://test.pypi.org/account/register/
|
||||
|
||||
### 2. API Tokens
|
||||
Generate tokens with appropriate permissions:
|
||||
- **PyPI**: https://pypi.org/manage/account/ → API tokens
|
||||
- **TestPyPI**: https://test.pypi.org/manage/account/ → API tokens
|
||||
|
||||
### 3. Local Configuration
|
||||
Create `~/.pypirc`:
|
||||
```ini
|
||||
[pypi]
|
||||
username = __token__
|
||||
password = pypi-[your-production-token-here]
|
||||
|
||||
[testpypi]
|
||||
repository = https://test.pypi.org/legacy/
|
||||
username = __token__
|
||||
password = pypi-[your-test-token-here]
|
||||
```
|
||||
|
||||
### 4. Install Required Tools
|
||||
```bash
|
||||
pip install --upgrade build twine toml
|
||||
```
|
||||
|
||||
## 📦 Package Information
|
||||
|
||||
- **Package Name**: `SuperClaude`
|
||||
- **Current Version**: `4.0.0b1` (beta release)
|
||||
- **Entry Points**:
|
||||
- `SuperClaude` → `SuperClaude.__main__:main`
|
||||
- `superclaude` → `SuperClaude.__main__:main`
|
||||
|
||||
## 🔧 Available Scripts
|
||||
|
||||
### Shell Script (Recommended)
|
||||
```bash
|
||||
# Test publishing
|
||||
./scripts/publish.sh test
|
||||
|
||||
# Test installation from TestPyPI
|
||||
./scripts/publish.sh test-install
|
||||
|
||||
# Production publishing
|
||||
./scripts/publish.sh prod
|
||||
|
||||
# Build package only
|
||||
./scripts/publish.sh build
|
||||
|
||||
# Clean build artifacts
|
||||
./scripts/publish.sh clean
|
||||
|
||||
# Validate project structure
|
||||
./scripts/publish.sh check
|
||||
```
|
||||
|
||||
### Python Script (Advanced)
|
||||
```bash
|
||||
# Basic TestPyPI upload
|
||||
python3 scripts/build_and_upload.py --testpypi
|
||||
|
||||
# TestPyPI with installation test
|
||||
python3 scripts/build_and_upload.py --testpypi --test-install
|
||||
|
||||
# Production upload
|
||||
python3 scripts/build_and_upload.py
|
||||
|
||||
# Skip validation (faster)
|
||||
python3 scripts/build_and_upload.py --skip-validation --testpypi
|
||||
|
||||
# Clean artifacts only
|
||||
python3 scripts/build_and_upload.py --clean
|
||||
```
|
||||
|
||||
### Validation Script
|
||||
```bash
|
||||
# Check if project is ready for publishing
|
||||
python3 scripts/validate_pypi_ready.py
|
||||
```
|
||||
|
||||
## 🤖 GitHub Actions Automation
|
||||
|
||||
The project includes automated publishing via GitHub Actions:
|
||||
|
||||
### Automatic Release Publishing
|
||||
1. Create a new release on GitHub
|
||||
2. GitHub Actions automatically builds and publishes to PyPI
|
||||
3. Package becomes available on PyPI within minutes
|
||||
|
||||
### Manual Publishing
|
||||
1. Go to GitHub Actions tab
|
||||
2. Select "Publish to PyPI" workflow
|
||||
3. Click "Run workflow"
|
||||
4. Choose target (testpypi or pypi)
|
||||
|
||||
### Required Secrets
|
||||
Set these in GitHub repository settings:
|
||||
- `PYPI_API_TOKEN`: Production PyPI token
|
||||
- `TEST_PYPI_API_TOKEN`: TestPyPI token
|
||||
|
||||
## 📈 Version Management
|
||||
|
||||
### Current Version: 4.0.0b1
|
||||
The project uses [semantic versioning](https://semver.org/) with beta notation:
|
||||
- `4.0.0b1` = Version 4.0.0, Beta 1
|
||||
- `4.0.0b2` = Version 4.0.0, Beta 2
|
||||
- `4.0.0` = Version 4.0.0, Stable Release
|
||||
|
||||
### Update Version Process
|
||||
1. Update version in:
|
||||
- `pyproject.toml`
|
||||
- `SuperClaude/__init__.py`
|
||||
- `SuperClaude/__main__.py`
|
||||
- `setup/__init__.py`
|
||||
|
||||
2. Validate consistency:
|
||||
```bash
|
||||
python3 scripts/validate_pypi_ready.py
|
||||
```
|
||||
|
||||
3. Commit and tag:
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Bump version to X.Y.Z"
|
||||
git tag vX.Y.Z
|
||||
git push origin main --tags
|
||||
```
|
||||
|
||||
## 🔍 Package Structure
|
||||
|
||||
The package includes:
|
||||
```
|
||||
SuperClaude/
|
||||
├── SuperClaude/ # Main package
|
||||
│ ├── __init__.py # Package metadata
|
||||
│ ├── __main__.py # CLI entry point
|
||||
│ ├── Core/ # Framework core files
|
||||
│ ├── Commands/ # Command definitions
|
||||
│ ├── Agents/ # Agent specifications
|
||||
│ ├── Modes/ # Behavioral modes
|
||||
│ └── MCP/ # MCP server configs
|
||||
├── setup/ # Installation system
|
||||
├── scripts/ # Publishing scripts
|
||||
├── pyproject.toml # Package configuration
|
||||
├── README.md # Project documentation
|
||||
├── LICENSE # MIT license
|
||||
└── MANIFEST.in # Package manifest
|
||||
```
|
||||
|
||||
## 🧪 Testing
|
||||
|
||||
### Local Testing
|
||||
```bash
|
||||
# Build package
|
||||
python3 -m build
|
||||
|
||||
# Check distribution
|
||||
python3 -m twine check dist/*
|
||||
|
||||
# Test local installation
|
||||
pip install dist/SuperClaude-4.0.0b1-py3-none-any.whl
|
||||
```
|
||||
|
||||
### TestPyPI Testing
|
||||
```bash
|
||||
# Upload to TestPyPI
|
||||
./scripts/publish.sh test
|
||||
|
||||
# Install from TestPyPI
|
||||
pip install --index-url https://test.pypi.org/simple/ \
|
||||
--extra-index-url https://pypi.org/simple/ \
|
||||
SuperClaude
|
||||
|
||||
# Test CLI
|
||||
SuperClaude --version
|
||||
```
|
||||
|
||||
## 🚨 Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### Version Already Exists
|
||||
PyPI doesn't allow re-uploading the same version. Increment version number:
|
||||
```bash
|
||||
# Current: 4.0.0b1
|
||||
# Next: 4.0.0b2 or 4.0.0
|
||||
```
|
||||
|
||||
#### Import Errors
|
||||
Check package structure and `__init__.py` files:
|
||||
```bash
|
||||
python3 scripts/validate_pypi_ready.py
|
||||
```
|
||||
|
||||
#### Upload Failures
|
||||
1. Check API tokens are correct
|
||||
2. Verify network connectivity
|
||||
3. Try TestPyPI first
|
||||
4. Check PyPI status page
|
||||
|
||||
#### Build Failures
|
||||
1. Ensure Python ≥3.8
|
||||
2. Update build tools: `pip install --upgrade build twine`
|
||||
3. Clean artifacts: `./scripts/publish.sh clean`
|
||||
|
||||
### Getting Help
|
||||
- PyPI Help: https://pypi.org/help/
|
||||
- Packaging Guide: https://packaging.python.org/
|
||||
- GitHub Issues: https://github.com/SuperClaude-Org/SuperClaude_Framework/issues
|
||||
|
||||
## 📊 Publication Checklist
|
||||
|
||||
Before publishing to production PyPI:
|
||||
|
||||
- [ ] All tests passing
|
||||
- [ ] Version number updated
|
||||
- [ ] Documentation updated
|
||||
- [ ] CHANGELOG.md updated
|
||||
- [ ] TestPyPI upload successful
|
||||
- [ ] TestPyPI installation test passed
|
||||
- [ ] GitHub release created (for automatic publishing)
|
||||
|
||||
## 🎯 Production Publishing
|
||||
|
||||
### Option 1: GitHub Release (Recommended)
|
||||
1. Push all changes to main branch
|
||||
2. Create new release on GitHub with tag `v4.0.0b1`
|
||||
3. GitHub Actions automatically publishes to PyPI
|
||||
|
||||
### Option 2: Manual Publishing
|
||||
```bash
|
||||
# Validate everything
|
||||
python3 scripts/validate_pypi_ready.py
|
||||
|
||||
# Test on TestPyPI first
|
||||
./scripts/publish.sh test
|
||||
./scripts/publish.sh test-install
|
||||
|
||||
# Publish to production
|
||||
./scripts/publish.sh prod
|
||||
```
|
||||
|
||||
## 🔐 Security Best Practices
|
||||
|
||||
- Store API tokens securely (use `~/.pypirc` or environment variables)
|
||||
- Never commit tokens to version control
|
||||
- Use minimal permission tokens
|
||||
- Regularly rotate API tokens
|
||||
- Use Trusted Publishing for GitHub Actions when possible
|
||||
|
||||
## 📝 Post-Publication
|
||||
|
||||
After successful publication:
|
||||
|
||||
1. **Update README badges** with new version
|
||||
2. **Announce release** on relevant channels
|
||||
3. **Monitor for issues** in GitHub Issues
|
||||
4. **Update documentation** if needed
|
||||
5. **Plan next release** based on feedback
|
||||
|
||||
---
|
||||
|
||||
*For questions or issues with publishing, please open an issue on GitHub or contact the maintainers.*
|
||||
@ -10,3 +10,8 @@ Usage:
|
||||
SuperClaude backup [options]
|
||||
SuperClaude --help
|
||||
"""
|
||||
|
||||
__version__ = "4.0.0b1"
|
||||
__author__ = "Mithun Gowda B, NomenAK"
|
||||
__email__ = "contact@superclaude.dev"
|
||||
__license__ = "MIT"
|
||||
|
||||
@ -97,7 +97,7 @@ Examples:
|
||||
parents=[global_parser]
|
||||
)
|
||||
|
||||
parser.add_argument("--version", action="version", version="SuperClaude 4.0.0-beta")
|
||||
parser.add_argument("--version", action="version", version="SuperClaude 4.0.0b1")
|
||||
|
||||
subparsers = parser.add_subparsers(
|
||||
dest="operation",
|
||||
|
||||
@ -4,27 +4,32 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "SuperClaude"
|
||||
version = "3.0.0"
|
||||
version = "4.0.0b1"
|
||||
authors = [
|
||||
{name = "Mithun Gowda B", email = "contact@superclaude.dev"},
|
||||
{name = "NomenAK"}
|
||||
]
|
||||
description = "SuperClaude Framework Management Hub"
|
||||
description = "SuperClaude Framework Management Hub - AI-enhanced development framework for Claude Code"
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
license = {text = "MIT"}
|
||||
requires-python = ">=3.8"
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Operating System :: OS Independent",
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Topic :: Software Development :: Code Generators",
|
||||
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
||||
"Environment :: Console",
|
||||
]
|
||||
keywords = ["claude", "ai", "automation", "framework", "mcp", "agents"]
|
||||
keywords = ["claude", "ai", "automation", "framework", "mcp", "agents", "development", "code-generation", "assistant"]
|
||||
dependencies = [
|
||||
"setuptools>=45.0.0",
|
||||
"importlib-metadata>=1.0.0; python_version<'3.8'"
|
||||
@ -55,12 +60,16 @@ test = [
|
||||
]
|
||||
|
||||
[tool.setuptools]
|
||||
packages = ["SuperClaude", "setup"]
|
||||
include-package-data = true
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["."]
|
||||
include = ["SuperClaude*", "setup*"]
|
||||
exclude = ["tests*", "*.tests*", "*.tests", ".git*", ".venv*", "*.egg-info*"]
|
||||
|
||||
[tool.setuptools.package-data]
|
||||
"setup" = ["data/*.json", "data/*.yaml", "data/*.yml"]
|
||||
"SuperClaude" = ["*.md", "*.txt"]
|
||||
"setup" = ["data/*.json", "data/*.yaml", "data/*.yml", "components/*.py", "**/*.py"]
|
||||
"SuperClaude" = ["*.md", "*.txt", "**/*.md", "**/*.txt", "**/*.json", "**/*.yaml", "**/*.yml"]
|
||||
|
||||
[tool.black]
|
||||
line-length = 88
|
||||
|
||||
138
scripts/README.md
Normal file
138
scripts/README.md
Normal file
@ -0,0 +1,138 @@
|
||||
# SuperClaude PyPI Publishing Scripts
|
||||
|
||||
This directory contains scripts for building and publishing SuperClaude to PyPI.
|
||||
|
||||
## Scripts
|
||||
|
||||
### `publish.sh` - Main Publishing Script
|
||||
Easy-to-use shell script for common publishing tasks:
|
||||
|
||||
```bash
|
||||
# Test upload to TestPyPI
|
||||
./scripts/publish.sh test
|
||||
|
||||
# Test installation from TestPyPI
|
||||
./scripts/publish.sh test-install
|
||||
|
||||
# Production upload to PyPI
|
||||
./scripts/publish.sh prod
|
||||
|
||||
# Build package only
|
||||
./scripts/publish.sh build
|
||||
|
||||
# Clean build artifacts
|
||||
./scripts/publish.sh clean
|
||||
|
||||
# Validate project structure
|
||||
./scripts/publish.sh check
|
||||
```
|
||||
|
||||
### `build_and_upload.py` - Advanced Build Script
|
||||
Python script with detailed control over the build and upload process:
|
||||
|
||||
```bash
|
||||
# Build and upload to TestPyPI
|
||||
python scripts/build_and_upload.py --testpypi
|
||||
|
||||
# Test installation from TestPyPI
|
||||
python scripts/build_and_upload.py --testpypi --test-install
|
||||
|
||||
# Production upload (with confirmation)
|
||||
python scripts/build_and_upload.py
|
||||
|
||||
# Skip validation (for faster builds)
|
||||
python scripts/build_and_upload.py --skip-validation --testpypi
|
||||
|
||||
# Clean only
|
||||
python scripts/build_and_upload.py --clean
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
1. **PyPI Account**: Register at https://pypi.org/account/register/
|
||||
2. **API Tokens**: Generate tokens at https://pypi.org/manage/account/
|
||||
3. **Configuration**: Create `~/.pypirc`:
|
||||
```ini
|
||||
[pypi]
|
||||
username = __token__
|
||||
password = pypi-[your-production-token]
|
||||
|
||||
[testpypi]
|
||||
repository = https://test.pypi.org/legacy/
|
||||
username = __token__
|
||||
password = pypi-[your-test-token]
|
||||
```
|
||||
|
||||
## GitHub Actions
|
||||
|
||||
The `.github/workflows/publish-pypi.yml` workflow automates publishing:
|
||||
|
||||
- **Automatic**: Publishes to PyPI when a GitHub release is created
|
||||
- **Manual**: Can be triggered manually for TestPyPI uploads
|
||||
- **Validation**: Includes package validation and installation testing
|
||||
|
||||
### Required Secrets
|
||||
|
||||
Set these in your GitHub repository settings → Secrets and variables → Actions:
|
||||
|
||||
- `PYPI_API_TOKEN`: Production PyPI token
|
||||
- `TEST_PYPI_API_TOKEN`: TestPyPI token
|
||||
|
||||
## Publishing Workflow
|
||||
|
||||
### 1. Development Release (TestPyPI)
|
||||
```bash
|
||||
# Test the build and upload process
|
||||
./scripts/publish.sh test
|
||||
|
||||
# Verify the package installs correctly
|
||||
./scripts/publish.sh test-install
|
||||
```
|
||||
|
||||
### 2. Production Release (PyPI)
|
||||
|
||||
#### Option A: Manual
|
||||
```bash
|
||||
# Upload directly (requires confirmation)
|
||||
./scripts/publish.sh prod
|
||||
```
|
||||
|
||||
#### Option B: GitHub Release (Recommended)
|
||||
1. Update version in code
|
||||
2. Commit and push changes
|
||||
3. Create a new release on GitHub
|
||||
4. GitHub Actions will automatically build and publish
|
||||
|
||||
## Version Management
|
||||
|
||||
Before publishing, ensure version consistency across:
|
||||
- `pyproject.toml`
|
||||
- `SuperClaude/__init__.py`
|
||||
- `SuperClaude/__main__.py`
|
||||
- `setup/__init__.py`
|
||||
|
||||
The build script validates version consistency automatically.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Failures
|
||||
- Check Python version compatibility (≥3.8)
|
||||
- Ensure all required files are present
|
||||
- Validate `pyproject.toml` syntax
|
||||
|
||||
### Upload Failures
|
||||
- Verify API tokens are correct
|
||||
- Check if version already exists on PyPI
|
||||
- Ensure package name is available
|
||||
|
||||
### Import Failures
|
||||
- Check package structure (`__init__.py` files)
|
||||
- Verify all dependencies are listed
|
||||
- Test local installation first
|
||||
|
||||
## Security Notes
|
||||
|
||||
- Never commit API tokens to version control
|
||||
- Use environment variables or `.pypirc` for credentials
|
||||
- Tokens should have minimal required permissions
|
||||
- Consider using Trusted Publishing for GitHub Actions
|
||||
246
scripts/build_and_upload.py
Executable file
246
scripts/build_and_upload.py
Executable file
@ -0,0 +1,246 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
PyPI Build and Upload Script for SuperClaude Framework
|
||||
Handles building, validation, and uploading to PyPI with proper error handling
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import Tuple, List, Optional
|
||||
|
||||
# Project root
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
DIST_DIR = PROJECT_ROOT / "dist"
|
||||
BUILD_DIR = PROJECT_ROOT / "build"
|
||||
|
||||
def run_command(cmd: List[str], description: str) -> Tuple[bool, str]:
|
||||
"""Run a command and return success status and output"""
|
||||
print(f"🔄 {description}...")
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
cwd=PROJECT_ROOT,
|
||||
check=True
|
||||
)
|
||||
print(f"✅ {description} completed successfully")
|
||||
return True, result.stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
print(f"❌ {description} failed:")
|
||||
print(f" Exit code: {e.returncode}")
|
||||
print(f" Error: {e.stderr}")
|
||||
return False, e.stderr
|
||||
except Exception as e:
|
||||
print(f"❌ {description} failed with exception: {e}")
|
||||
return False, str(e)
|
||||
|
||||
def clean_build_artifacts():
|
||||
"""Clean previous build artifacts"""
|
||||
artifacts = [DIST_DIR, BUILD_DIR, PROJECT_ROOT / "SuperClaude.egg-info"]
|
||||
|
||||
for artifact in artifacts:
|
||||
if artifact.exists():
|
||||
print(f"🧹 Removing {artifact}")
|
||||
if artifact.is_dir():
|
||||
shutil.rmtree(artifact)
|
||||
else:
|
||||
artifact.unlink()
|
||||
|
||||
def install_build_tools() -> bool:
|
||||
"""Install required build tools"""
|
||||
tools = ["build", "twine"]
|
||||
|
||||
for tool in tools:
|
||||
success, _ = run_command(
|
||||
[sys.executable, "-m", "pip", "install", "--upgrade", tool],
|
||||
f"Installing {tool}"
|
||||
)
|
||||
if not success:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def validate_project_structure() -> bool:
|
||||
"""Validate project structure before building"""
|
||||
required_files = [
|
||||
"pyproject.toml",
|
||||
"README.md",
|
||||
"LICENSE",
|
||||
"SuperClaude/__init__.py",
|
||||
"SuperClaude/__main__.py",
|
||||
"setup/__init__.py"
|
||||
]
|
||||
|
||||
print("🔍 Validating project structure...")
|
||||
|
||||
for file_path in required_files:
|
||||
full_path = PROJECT_ROOT / file_path
|
||||
if not full_path.exists():
|
||||
print(f"❌ Missing required file: {file_path}")
|
||||
return False
|
||||
|
||||
# Check if version is consistent
|
||||
try:
|
||||
from SuperClaude import __version__
|
||||
print(f"📦 Package version: {__version__}")
|
||||
except ImportError as e:
|
||||
print(f"❌ Could not import version from SuperClaude: {e}")
|
||||
return False
|
||||
|
||||
print("✅ Project structure validation passed")
|
||||
return True
|
||||
|
||||
def build_package() -> bool:
|
||||
"""Build the package"""
|
||||
return run_command(
|
||||
[sys.executable, "-m", "build"],
|
||||
"Building package distributions"
|
||||
)[0]
|
||||
|
||||
def validate_distribution() -> bool:
|
||||
"""Validate the built distribution"""
|
||||
if not DIST_DIR.exists():
|
||||
print("❌ Distribution directory does not exist")
|
||||
return False
|
||||
|
||||
dist_files = list(DIST_DIR.glob("*"))
|
||||
if not dist_files:
|
||||
print("❌ No distribution files found")
|
||||
return False
|
||||
|
||||
print(f"📦 Found distribution files:")
|
||||
for file in dist_files:
|
||||
print(f" - {file.name}")
|
||||
|
||||
# Check with twine
|
||||
return run_command(
|
||||
[sys.executable, "-m", "twine", "check"] + [str(f) for f in dist_files],
|
||||
"Validating distributions with twine"
|
||||
)[0]
|
||||
|
||||
def upload_to_testpypi() -> bool:
|
||||
"""Upload to TestPyPI for testing"""
|
||||
dist_files = list(DIST_DIR.glob("*"))
|
||||
return run_command(
|
||||
[sys.executable, "-m", "twine", "upload", "--repository", "testpypi"] + [str(f) for f in dist_files],
|
||||
"Uploading to TestPyPI"
|
||||
)[0]
|
||||
|
||||
def upload_to_pypi() -> bool:
|
||||
"""Upload to production PyPI"""
|
||||
dist_files = list(DIST_DIR.glob("*"))
|
||||
|
||||
# Check if we have API token in environment
|
||||
if os.getenv('PYPI_API_TOKEN'):
|
||||
cmd = [
|
||||
sys.executable, "-m", "twine", "upload",
|
||||
"--username", "__token__",
|
||||
"--password", os.getenv('PYPI_API_TOKEN')
|
||||
] + [str(f) for f in dist_files]
|
||||
else:
|
||||
# Fall back to .pypirc configuration
|
||||
cmd = [sys.executable, "-m", "twine", "upload"] + [str(f) for f in dist_files]
|
||||
|
||||
return run_command(cmd, "Uploading to PyPI")[0]
|
||||
|
||||
def test_installation_from_testpypi() -> bool:
|
||||
"""Test installation from TestPyPI"""
|
||||
print("🧪 Testing installation from TestPyPI...")
|
||||
print(" Note: This will install in a separate process")
|
||||
|
||||
success, output = run_command([
|
||||
sys.executable, "-m", "pip", "install",
|
||||
"--index-url", "https://test.pypi.org/simple/",
|
||||
"--extra-index-url", "https://pypi.org/simple/",
|
||||
"SuperClaude", "--force-reinstall", "--no-deps"
|
||||
], "Installing from TestPyPI")
|
||||
|
||||
if success:
|
||||
print("✅ Test installation successful")
|
||||
# Try to import the package
|
||||
try:
|
||||
import SuperClaude
|
||||
print(f"✅ Package import successful, version: {SuperClaude.__version__}")
|
||||
return True
|
||||
except ImportError as e:
|
||||
print(f"❌ Package import failed: {e}")
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Main execution function"""
|
||||
parser = argparse.ArgumentParser(description="Build and upload SuperClaude to PyPI")
|
||||
parser.add_argument("--testpypi", action="store_true", help="Upload to TestPyPI instead of PyPI")
|
||||
parser.add_argument("--test-install", action="store_true", help="Test installation from TestPyPI")
|
||||
parser.add_argument("--skip-build", action="store_true", help="Skip build step (use existing dist)")
|
||||
parser.add_argument("--skip-validation", action="store_true", help="Skip validation steps")
|
||||
parser.add_argument("--clean", action="store_true", help="Only clean build artifacts")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Change to project root
|
||||
os.chdir(PROJECT_ROOT)
|
||||
|
||||
if args.clean:
|
||||
clean_build_artifacts()
|
||||
return
|
||||
|
||||
print("🚀 SuperClaude PyPI Build and Upload Script")
|
||||
print(f"📁 Working directory: {PROJECT_ROOT}")
|
||||
|
||||
# Step 1: Clean previous builds
|
||||
clean_build_artifacts()
|
||||
|
||||
# Step 2: Install build tools
|
||||
if not install_build_tools():
|
||||
print("❌ Failed to install build tools")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 3: Validate project structure
|
||||
if not args.skip_validation and not validate_project_structure():
|
||||
print("❌ Project structure validation failed")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 4: Build package
|
||||
if not args.skip_build:
|
||||
if not build_package():
|
||||
print("❌ Package build failed")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 5: Validate distribution
|
||||
if not args.skip_validation and not validate_distribution():
|
||||
print("❌ Distribution validation failed")
|
||||
sys.exit(1)
|
||||
|
||||
# Step 6: Upload
|
||||
if args.testpypi:
|
||||
if not upload_to_testpypi():
|
||||
print("❌ Upload to TestPyPI failed")
|
||||
sys.exit(1)
|
||||
|
||||
# Test installation if requested
|
||||
if args.test_install:
|
||||
if not test_installation_from_testpypi():
|
||||
print("❌ Test installation failed")
|
||||
sys.exit(1)
|
||||
else:
|
||||
# Confirm production upload
|
||||
response = input("🚨 Upload to production PyPI? This cannot be undone! (yes/no): ")
|
||||
if response.lower() != "yes":
|
||||
print("❌ Upload cancelled")
|
||||
sys.exit(1)
|
||||
|
||||
if not upload_to_pypi():
|
||||
print("❌ Upload to PyPI failed")
|
||||
sys.exit(1)
|
||||
|
||||
print("✅ All operations completed successfully!")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
95
scripts/publish.sh
Executable file
95
scripts/publish.sh
Executable file
@ -0,0 +1,95 @@
|
||||
#!/bin/bash
|
||||
"""
|
||||
SuperClaude PyPI Publishing Helper Script
|
||||
Easy-to-use wrapper for the Python build and upload script
|
||||
"""
|
||||
|
||||
set -e # Exit on any error
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Get script directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
BUILD_SCRIPT="$SCRIPT_DIR/build_and_upload.py"
|
||||
|
||||
echo -e "${BLUE}🚀 SuperClaude PyPI Publishing Helper${NC}"
|
||||
echo -e "📁 Project root: $PROJECT_ROOT"
|
||||
|
||||
# Function to show usage
|
||||
show_usage() {
|
||||
echo -e "${YELLOW}Usage:${NC}"
|
||||
echo " $0 test - Build and upload to TestPyPI"
|
||||
echo " $0 test-install - Test installation from TestPyPI"
|
||||
echo " $0 prod - Build and upload to production PyPI"
|
||||
echo " $0 build - Only build the package"
|
||||
echo " $0 clean - Clean build artifacts"
|
||||
echo " $0 check - Validate project structure only"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Examples:${NC}"
|
||||
echo " $0 test # Upload to TestPyPI"
|
||||
echo " $0 test && $0 test-install # Upload and test"
|
||||
echo " $0 prod # Upload to production"
|
||||
}
|
||||
|
||||
# Check if Python script exists
|
||||
if [ ! -f "$BUILD_SCRIPT" ]; then
|
||||
echo -e "${RED}❌ Build script not found: $BUILD_SCRIPT${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Parse command
|
||||
case "${1:-}" in
|
||||
"test")
|
||||
echo -e "${YELLOW}📦 Building and uploading to TestPyPI...${NC}"
|
||||
python3 "$BUILD_SCRIPT" --testpypi
|
||||
echo -e "${GREEN}✅ Uploaded to TestPyPI! Test with:${NC}"
|
||||
echo -e " pip install --index-url https://test.pypi.org/simple/ SuperClaude"
|
||||
;;
|
||||
|
||||
"test-install")
|
||||
echo -e "${YELLOW}🧪 Testing installation from TestPyPI...${NC}"
|
||||
python3 "$BUILD_SCRIPT" --testpypi --test-install --skip-build
|
||||
;;
|
||||
|
||||
"prod"|"production")
|
||||
echo -e "${YELLOW}🚨 Building and uploading to PRODUCTION PyPI...${NC}"
|
||||
echo -e "${RED}⚠️ This cannot be undone!${NC}"
|
||||
python3 "$BUILD_SCRIPT"
|
||||
echo -e "${GREEN}✅ Uploaded to PyPI! Install with:${NC}"
|
||||
echo -e " pip install SuperClaude"
|
||||
;;
|
||||
|
||||
"build")
|
||||
echo -e "${YELLOW}🔨 Building package only...${NC}"
|
||||
python3 "$BUILD_SCRIPT" --skip-validation --testpypi --skip-upload
|
||||
echo -e "${GREEN}✅ Package built in dist/ directory${NC}"
|
||||
;;
|
||||
|
||||
"clean")
|
||||
echo -e "${YELLOW}🧹 Cleaning build artifacts...${NC}"
|
||||
python3 "$BUILD_SCRIPT" --clean
|
||||
echo -e "${GREEN}✅ Build artifacts cleaned${NC}"
|
||||
;;
|
||||
|
||||
"check"|"validate")
|
||||
echo -e "${YELLOW}🔍 Validating project structure...${NC}"
|
||||
python3 "$BUILD_SCRIPT" --skip-build --testpypi
|
||||
;;
|
||||
|
||||
"help"|"-h"|"--help"|"")
|
||||
show_usage
|
||||
;;
|
||||
|
||||
*)
|
||||
echo -e "${RED}❌ Unknown command: $1${NC}"
|
||||
echo ""
|
||||
show_usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
220
scripts/validate_pypi_ready.py
Executable file
220
scripts/validate_pypi_ready.py
Executable file
@ -0,0 +1,220 @@
|
||||
#!/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)
|
||||
@ -3,7 +3,7 @@ SuperClaude Installation Suite
|
||||
Pure Python installation system for SuperClaude framework
|
||||
"""
|
||||
|
||||
__version__ = "3.0.0"
|
||||
__version__ = "4.0.0b1"
|
||||
__author__ = "SuperClaude Team"
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user