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 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 this commit COMMIT_SHA=$(git rev-parse HEAD) RUN_ID=$(gh run list \ --workflow=ci.yml \ --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 "Please wait for CI to complete 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 env: TWINE_USERNAME: __token__ TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }} run: | pip install twine echo "📦 Uploading to TestPyPI..." twine upload --repository testpypi packages/*/dist/* --verbose 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."