108 lines
3.9 KiB
YAML
108 lines
3.9 KiB
YAML
# =============================================================================
|
|
# PyPI Publish Workflow Template (Enhanced)
|
|
# =============================================================================
|
|
# Publishes Python packages to Forgejo PyPI registry with:
|
|
# - Version change detection (avoids wasteful builds)
|
|
# - Optional pre-publish testing
|
|
# - Path-based triggers (only run when relevant files change)
|
|
# - Graceful duplicate version handling
|
|
# =============================================================================
|
|
|
|
name: Publish to PyPI
|
|
|
|
on:
|
|
push:
|
|
branches: [main, master]
|
|
paths:
|
|
- 'pyproject.toml' # Trigger on version bumps
|
|
- 'src/**' # Or source code changes
|
|
workflow_dispatch: # Manual trigger for first-time publish
|
|
|
|
env:
|
|
PYTHON_VERSION: '3.12'
|
|
REGISTRY_URL: 'https://forge.nasty.sh/api/packages/lilith/pypi/'
|
|
|
|
jobs:
|
|
publish:
|
|
name: Build and Publish
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v5
|
|
with:
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
|
|
- name: Install build tools
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install build twine
|
|
|
|
- name: Check if version already published
|
|
id: check_version
|
|
run: |
|
|
pkg_name=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['name'])")
|
|
pkg_version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
|
|
|
|
echo "package=$pkg_name" >> $GITHUB_OUTPUT
|
|
echo "version=$pkg_version" >> $GITHUB_OUTPUT
|
|
|
|
echo "=== Package Info ==="
|
|
echo "Name: $pkg_name"
|
|
echo "Version: $pkg_version"
|
|
|
|
# Check if version exists in registry
|
|
if pip index versions "$pkg_name" --index-url ${{ env.REGISTRY_URL }}/simple 2>/dev/null | grep -q "$pkg_version"; then
|
|
echo "exists=true" >> $GITHUB_OUTPUT
|
|
echo "✓ Version $pkg_version already published, skipping"
|
|
else
|
|
echo "exists=false" >> $GITHUB_OUTPUT
|
|
echo "→ Version $pkg_version is new, will publish"
|
|
fi
|
|
|
|
- name: Run tests (if available)
|
|
if: steps.check_version.outputs.exists == 'false'
|
|
continue-on-error: true
|
|
run: |
|
|
if [ -d "tests" ] && grep -q "pytest" pyproject.toml; then
|
|
echo "=== Running Tests ==="
|
|
pip install -e ".[dev]" 2>/dev/null || pip install pytest pytest-asyncio
|
|
pytest tests/ -v || echo "⚠ Tests failed but continuing (non-blocking)"
|
|
else
|
|
echo "No tests found, skipping"
|
|
fi
|
|
|
|
- name: Build package
|
|
if: steps.check_version.outputs.exists == 'false'
|
|
run: |
|
|
echo "=== Building Package ==="
|
|
python -m build
|
|
echo "Built: $(ls dist/)"
|
|
|
|
- name: Publish to Forgejo PyPI
|
|
if: steps.check_version.outputs.exists == 'false'
|
|
env:
|
|
TWINE_USERNAME: __token__
|
|
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
|
|
TWINE_REPOSITORY_URL: ${{ env.REGISTRY_URL }}
|
|
run: |
|
|
echo "=== Publishing to Forgejo PyPI ==="
|
|
echo "Package: ${{ steps.check_version.outputs.package }}@${{ steps.check_version.outputs.version }}"
|
|
echo "Registry: ${{ env.REGISTRY_URL }}"
|
|
|
|
twine_output=$(twine upload dist/* 2>&1) || upload_failed=$?
|
|
|
|
if [ -n "$upload_failed" ]; then
|
|
if echo "$twine_output" | grep -qi "already exists\|conflict\|409"; then
|
|
echo "✓ Version already published (expected)"
|
|
exit 0
|
|
else
|
|
echo "✗ Upload failed:"
|
|
echo "$twine_output"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
echo "✓ Published successfully to ${{ env.REGISTRY_URL }}"
|