- Add continue-on-error to TestPyPI step - Check if TEST_PYPI_API_TOKEN exists before attempting upload - Add graceful failure handling with clear messages - Update docs to explain TestPyPI token configuration - Clarify that TestPyPI testing is optional Now the release won't fail if TestPyPI is not configured or upload fails
194 lines
6.8 KiB
YAML
194 lines
6.8 KiB
YAML
name: Manual Release
|
||
|
||
on:
|
||
workflow_dispatch:
|
||
inputs:
|
||
version:
|
||
description: 'Version to release (e.g., 0.1.1)'
|
||
required: true
|
||
type: string
|
||
test_pypi:
|
||
description: 'Test on TestPyPI first'
|
||
required: false
|
||
type: boolean
|
||
default: true
|
||
|
||
jobs:
|
||
validate-and-release:
|
||
runs-on: ubuntu-latest
|
||
permissions:
|
||
contents: write
|
||
actions: read
|
||
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
with:
|
||
token: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Check CI status
|
||
run: |
|
||
echo "ℹ️ This workflow will download build artifacts from the latest CI run."
|
||
echo " CI must have completed successfully on the current commit."
|
||
echo ""
|
||
|
||
- name: Validate version format
|
||
run: |
|
||
if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||
echo "❌ Invalid version format. Use semantic versioning (e.g., 0.1.1)"
|
||
exit 1
|
||
fi
|
||
echo "✅ Version format valid: ${{ inputs.version }}"
|
||
|
||
- name: Check if version already exists
|
||
run: |
|
||
if git tag | grep -q "^v${{ inputs.version }}$"; then
|
||
echo "❌ Version v${{ inputs.version }} already exists!"
|
||
exit 1
|
||
fi
|
||
echo "✅ Version is new"
|
||
|
||
- name: Set up Python
|
||
uses: actions/setup-python@v5
|
||
with:
|
||
python-version: '3.13'
|
||
|
||
- name: Install uv
|
||
run: |
|
||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||
echo "$HOME/.cargo/bin" >> $GITHUB_PATH
|
||
|
||
- name: Update versions
|
||
run: |
|
||
./scripts/bump_version.sh ${{ inputs.version }}
|
||
git config user.name "GitHub Actions"
|
||
git config user.email "actions@github.com"
|
||
git add packages/*/pyproject.toml
|
||
git commit -m "chore: release v${{ inputs.version }}"
|
||
|
||
- name: Get CI run ID
|
||
id: get-ci-run
|
||
run: |
|
||
# Get the latest successful CI run on the previous commit (before version bump)
|
||
COMMIT_SHA=$(git rev-parse HEAD~1)
|
||
RUN_ID=$(gh run list \
|
||
--workflow="CI - Build and Test" \
|
||
--status=success \
|
||
--commit=$COMMIT_SHA \
|
||
--json databaseId \
|
||
--jq '.[0].databaseId')
|
||
|
||
if [ -z "$RUN_ID" ]; then
|
||
echo "❌ No successful CI run found for commit $COMMIT_SHA"
|
||
echo ""
|
||
echo "This usually means:"
|
||
echo "1. CI hasn't run on the latest commit yet"
|
||
echo "2. CI failed on the latest commit"
|
||
echo ""
|
||
echo "Please ensure CI passes on main branch before releasing."
|
||
exit 1
|
||
fi
|
||
|
||
echo "✅ Found CI run: $RUN_ID"
|
||
echo "run-id=$RUN_ID" >> $GITHUB_OUTPUT
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Download artifacts from CI
|
||
run: |
|
||
echo "📦 Downloading artifacts from CI run ${{ steps.get-ci-run.outputs.run-id }}..."
|
||
|
||
# Download all wheel artifacts
|
||
gh run download ${{ steps.get-ci-run.outputs.run-id }} \
|
||
--pattern "wheels-*" \
|
||
--dir ./dist-downloads
|
||
|
||
# Consolidate all wheels into packages/*/dist/
|
||
mkdir -p packages/leann-core/dist
|
||
mkdir -p packages/leann-backend-hnsw/dist
|
||
mkdir -p packages/leann-backend-diskann/dist
|
||
mkdir -p packages/leann/dist
|
||
|
||
find ./dist-downloads -name "*.whl" -exec cp {} ./packages/ \;
|
||
|
||
# Move wheels to correct package directories
|
||
for wheel in packages/*.whl; do
|
||
if [[ $wheel == *"leann_core"* ]]; then
|
||
mv "$wheel" packages/leann-core/dist/
|
||
elif [[ $wheel == *"leann_backend_hnsw"* ]]; then
|
||
mv "$wheel" packages/leann-backend-hnsw/dist/
|
||
elif [[ $wheel == *"leann_backend_diskann"* ]]; then
|
||
mv "$wheel" packages/leann-backend-diskann/dist/
|
||
elif [[ $wheel == *"leann-"* ]] && [[ $wheel != *"backend"* ]] && [[ $wheel != *"core"* ]]; then
|
||
mv "$wheel" packages/leann/dist/
|
||
fi
|
||
done
|
||
|
||
# List downloaded wheels
|
||
echo "✅ Downloaded wheels:"
|
||
find packages/*/dist -name "*.whl" -type f | sort
|
||
env:
|
||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Test on TestPyPI (optional)
|
||
if: inputs.test_pypi
|
||
continue-on-error: true
|
||
env:
|
||
TWINE_USERNAME: __token__
|
||
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
||
run: |
|
||
if [ -z "$TWINE_PASSWORD" ]; then
|
||
echo "⚠️ TEST_PYPI_API_TOKEN not configured, skipping TestPyPI upload"
|
||
echo " To enable TestPyPI testing, add TEST_PYPI_API_TOKEN to repository secrets"
|
||
exit 0
|
||
fi
|
||
|
||
pip install twine
|
||
echo "📦 Uploading to TestPyPI..."
|
||
twine upload --repository testpypi packages/*/dist/* --verbose || {
|
||
echo "⚠️ TestPyPI upload failed, but continuing with release"
|
||
echo " This is optional and won't block the release"
|
||
exit 0
|
||
}
|
||
echo "✅ Test upload successful!"
|
||
echo "📋 Check packages at: https://test.pypi.org/user/your-username/"
|
||
echo ""
|
||
echo "To test installation:"
|
||
echo "pip install -i https://test.pypi.org/simple/ leann"
|
||
|
||
- name: Create and push tag
|
||
run: |
|
||
git tag "v${{ inputs.version }}"
|
||
git push origin main
|
||
git push origin "v${{ inputs.version }}"
|
||
echo "✅ Tag v${{ inputs.version }} created and pushed"
|
||
|
||
- name: Create GitHub Release
|
||
uses: softprops/action-gh-release@v1
|
||
with:
|
||
tag_name: v${{ inputs.version }}
|
||
name: Release v${{ inputs.version }}
|
||
body: |
|
||
## 🚀 Release v${{ inputs.version }}
|
||
|
||
### What's Changed
|
||
See the [full changelog](https://github.com/${{ github.repository }}/compare/...v${{ inputs.version }})
|
||
|
||
### Installation
|
||
```bash
|
||
pip install leann==${{ inputs.version }}
|
||
```
|
||
|
||
### Test Installation (if using TestPyPI)
|
||
```bash
|
||
pip install -i https://test.pypi.org/simple/ leann==${{ inputs.version }}
|
||
```
|
||
draft: false
|
||
prerelease: false
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- name: Trigger PyPI publish
|
||
run: |
|
||
echo "🚀 Triggering PyPI publish workflow..."
|
||
# The existing build-and-publish.yml will be triggered by the tag push
|
||
echo "✅ Release process completed! The publish workflow will run automatically." |