ci: add Forgejo Actions workflow for PyPI publishing
This commit is contained in:
parent
475359ee7e
commit
3588165488
1 changed files with 156 additions and 0 deletions
156
.forgejo/workflows/publish.yml
Normal file
156
.forgejo/workflows/publish.yml
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# =============================================================================
|
||||
# Forgejo Actions Workflow - Python Package Publishing
|
||||
# =============================================================================
|
||||
# Standardized template for Python packages published to Forgejo PyPI registry
|
||||
#
|
||||
# Features:
|
||||
# - Pre-publish version check (avoids wasteful builds)
|
||||
# - Optional testing (non-blocking)
|
||||
# - Path-based triggers (pyproject.toml, src/** changes only)
|
||||
# - Graceful duplicate version handling (409 Conflict)
|
||||
# - Python 3.12 standard environment
|
||||
#
|
||||
# Usage:
|
||||
# 1. Copy to: <package>/.forgejo/workflows/pypi-publish.yml
|
||||
# 2. Ensure pyproject.toml has [project] metadata (name, version)
|
||||
# 3. Commit and push to main/master
|
||||
#
|
||||
# Secrets required:
|
||||
# - PYPI_TOKEN: Forgejo PyPI registry token
|
||||
# =============================================================================
|
||||
|
||||
name: Publish to PyPI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, master]
|
||||
paths:
|
||||
- 'pyproject.toml' # Trigger on version bumps
|
||||
- 'src/**' # Or source code changes
|
||||
- 'setup.py' # Legacy setup files
|
||||
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: |
|
||||
echo "=== Installing build tools ==="
|
||||
python -m pip install --upgrade pip
|
||||
pip install build twine
|
||||
echo "✓ Build tools installed"
|
||||
|
||||
- name: Check if version already published
|
||||
id: check_version
|
||||
run: |
|
||||
echo "=== Reading package metadata ==="
|
||||
|
||||
# Read package name and version from pyproject.toml
|
||||
if [ -f "pyproject.toml" ]; then
|
||||
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'])")
|
||||
else
|
||||
echo "✗ Error: pyproject.toml not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "package=$pkg_name" >> $GITHUB_OUTPUT
|
||||
echo "version=$pkg_version" >> $GITHUB_OUTPUT
|
||||
|
||||
echo ""
|
||||
echo "Package: $pkg_name"
|
||||
echo "Version: $pkg_version"
|
||||
echo "Registry: ${{ env.REGISTRY_URL }}"
|
||||
echo ""
|
||||
|
||||
# Check if version exists in Forgejo PyPI registry
|
||||
echo "=== Checking if version already published ==="
|
||||
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 to registry"
|
||||
echo " No action needed"
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "→ Version $pkg_version not found in registry"
|
||||
echo " Will proceed with build and publish"
|
||||
fi
|
||||
|
||||
- name: Run tests (if available)
|
||||
if: steps.check_version.outputs.exists == 'false'
|
||||
continue-on-error: true
|
||||
run: |
|
||||
echo "=== Running tests ==="
|
||||
|
||||
# Check if tests directory exists and pytest is configured
|
||||
if [ -d "tests" ] && grep -q "pytest" pyproject.toml 2>/dev/null; then
|
||||
echo "Installing dev dependencies..."
|
||||
pip install -e ".[dev]" 2>/dev/null || pip install pytest pytest-asyncio
|
||||
|
||||
echo "Running pytest..."
|
||||
if pytest tests/ -v 2>&1; then
|
||||
echo "✓ All tests passed"
|
||||
else
|
||||
echo "⚠ Tests failed but continuing (non-blocking)"
|
||||
fi
|
||||
else
|
||||
echo "⊘ No tests found or pytest not configured, skipping"
|
||||
fi
|
||||
|
||||
- name: Build package
|
||||
if: steps.check_version.outputs.exists == 'false'
|
||||
run: |
|
||||
echo "=== Building package ==="
|
||||
python -m build
|
||||
echo ""
|
||||
echo "✓ Build complete"
|
||||
echo "Built artifacts:"
|
||||
ls -lh 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 }}"
|
||||
echo ""
|
||||
|
||||
# Attempt upload with graceful conflict handling
|
||||
if twine_output=$(twine upload dist/* 2>&1); then
|
||||
echo "$twine_output"
|
||||
echo ""
|
||||
echo "✓ Successfully published to Forgejo PyPI"
|
||||
echo " Package: ${{ steps.check_version.outputs.package }}"
|
||||
echo " Version: ${{ steps.check_version.outputs.version }}"
|
||||
echo " Install: pip install ${{ steps.check_version.outputs.package }} --index-url ${{ env.REGISTRY_URL }}/simple"
|
||||
else
|
||||
# Check if failure was due to version already existing (409 Conflict)
|
||||
if echo "$twine_output" | grep -qi "already exists\|conflict\|409"; then
|
||||
echo "$twine_output"
|
||||
echo ""
|
||||
echo "✓ Version already published (expected race condition)"
|
||||
echo " This can happen if multiple workflows run simultaneously"
|
||||
exit 0
|
||||
else
|
||||
echo "✗ Upload failed:"
|
||||
echo "$twine_output"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
Loading…
Add table
Reference in a new issue