Release version 0.1.1 #10
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Publish Python Packages | |
| on: | |
| push: | |
| branches: [br_release] | |
| permissions: | |
| contents: write | |
| env: | |
| # Version is read from pyproject.toml - update with: python scripts/update_version.py <version> | |
| DRY_RUN: 'false' | |
| jobs: | |
| download-binaries: | |
| name: Download gopher-orch binaries | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.version.outputs.version }} | |
| version_tag: ${{ steps.version.outputs.version_tag }} | |
| dry_run: ${{ steps.version.outputs.dry_run }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Read version from pyproject.toml | |
| id: version | |
| run: | | |
| # Extract version from pyproject.toml using Python | |
| VERSION=$(python -c "import re; content=open('pyproject.toml').read(); print(re.search(r'version\s*=\s*\"([^\"]+)\"', content).group(1))") | |
| # Convert PEP 440 dev version to tag format | |
| # e.g., 0.1.0.dev20260225132506 -> v0.1.0-20260225-132506 | |
| if [[ "$VERSION" =~ ^([0-9]+\.[0-9]+\.[0-9]+)\.dev([0-9]{8})([0-9]{6})$ ]]; then | |
| BASE_VERSION="${BASH_REMATCH[1]}" | |
| DATE="${BASH_REMATCH[2]}" | |
| TIME="${BASH_REMATCH[3]}" | |
| VERSION_TAG="v${BASE_VERSION}-${DATE}-${TIME}" | |
| else | |
| # Fallback for simple versions like 0.1.0 | |
| VERSION_TAG="v${VERSION}" | |
| fi | |
| echo "version=${VERSION}" >> $GITHUB_OUTPUT | |
| echo "version_tag=${VERSION_TAG}" >> $GITHUB_OUTPUT | |
| echo "dry_run=${{ env.DRY_RUN }}" >> $GITHUB_OUTPUT | |
| echo "Version: ${VERSION}" | |
| echo "Version Tag: ${VERSION_TAG}" | |
| - name: Download all release assets | |
| env: | |
| GH_TOKEN: ${{ secrets.GOPHER_ORCH_TOKEN }} | |
| run: | | |
| # Download all assets from the private gopher-orch repo | |
| gh release download ${{ steps.version.outputs.version_tag }} \ | |
| -R GopherSecurity/gopher-orch \ | |
| -D downloads | |
| # Extract to platform-specific directories | |
| mkdir -p artifacts/linux-x64 artifacts/linux-arm64 | |
| mkdir -p artifacts/darwin-x64 artifacts/darwin-arm64 | |
| mkdir -p artifacts/win32-x64 artifacts/win32-arm64 | |
| tar -xzf downloads/libgopher-orch-linux-x64.tar.gz -C artifacts/linux-x64 | |
| tar -xzf downloads/libgopher-orch-linux-arm64.tar.gz -C artifacts/linux-arm64 | |
| tar -xzf downloads/libgopher-orch-macos-x64.tar.gz -C artifacts/darwin-x64 | |
| tar -xzf downloads/libgopher-orch-macos-arm64.tar.gz -C artifacts/darwin-arm64 | |
| unzip -o downloads/libgopher-orch-windows-x64.zip -d artifacts/win32-x64 | |
| unzip -o downloads/libgopher-orch-windows-arm64.zip -d artifacts/win32-arm64 | |
| - name: List downloaded artifacts | |
| run: | | |
| echo "=== Downloaded artifacts ===" | |
| find artifacts -type f \( -name "*.so" -o -name "*.dylib" -o -name "*.dll" \) | head -20 | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: native-binaries | |
| path: artifacts/ | |
| retention-days: 1 | |
| publish-platform-packages: | |
| name: Publish ${{ matrix.platform }} package | |
| needs: download-binaries | |
| runs-on: ubuntu-latest | |
| strategy: | |
| max-parallel: 1 | |
| matrix: | |
| include: | |
| - platform: darwin-arm64 | |
| lib_pattern: "*.dylib" | |
| pkg_name: gopher_mcp_python_native_darwin_arm64 | |
| - platform: darwin-x64 | |
| lib_pattern: "*.dylib" | |
| pkg_name: gopher_mcp_python_native_darwin_x64 | |
| - platform: linux-arm64 | |
| lib_pattern: "*.so*" | |
| pkg_name: gopher_mcp_python_native_linux_arm64 | |
| - platform: linux-x64 | |
| lib_pattern: "*.so*" | |
| pkg_name: gopher_mcp_python_native_linux_x64 | |
| - platform: win32-arm64 | |
| lib_pattern: "*.dll" | |
| pkg_name: gopher_mcp_python_native_win32_arm64 | |
| - platform: win32-x64 | |
| lib_pattern: "*.dll" | |
| pkg_name: gopher_mcp_python_native_win32_x64 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install build tools | |
| run: | | |
| pip install build twine | |
| - name: Download artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: native-binaries | |
| path: artifacts/ | |
| - name: Copy binaries to package | |
| run: | | |
| PKG_DIR="packages/${{ matrix.platform }}/${{ matrix.pkg_name }}/lib" | |
| mkdir -p "$PKG_DIR" | |
| # Copy library files (handle various directory structures) | |
| # Check lib/ directory | |
| if [ -d "artifacts/${{ matrix.platform }}/lib" ]; then | |
| cp artifacts/${{ matrix.platform }}/lib/${{ matrix.lib_pattern }} "$PKG_DIR/" 2>/dev/null || true | |
| fi | |
| # Check bin/ directory (Windows DLLs might be here) | |
| if [ -d "artifacts/${{ matrix.platform }}/bin" ]; then | |
| cp artifacts/${{ matrix.platform }}/bin/${{ matrix.lib_pattern }} "$PKG_DIR/" 2>/dev/null || true | |
| fi | |
| # Check flat structure | |
| cp artifacts/${{ matrix.platform }}/${{ matrix.lib_pattern }} "$PKG_DIR/" 2>/dev/null || true | |
| # List what we copied | |
| echo "=== Package contents for ${{ matrix.platform }} ===" | |
| ls -la "$PKG_DIR/" | |
| - name: Update package version | |
| run: | | |
| cd packages/${{ matrix.platform }} | |
| VERSION="${{ needs.download-binaries.outputs.version }}" | |
| # Update version in pyproject.toml | |
| sed -i "s/version = \".*\"/version = \"${VERSION}\"/" pyproject.toml | |
| # Update version in __init__.py | |
| sed -i "s/__version__ = \".*\"/__version__ = \"${VERSION}\"/" ${{ matrix.pkg_name }}/__init__.py | |
| echo "Updated pyproject.toml:" | |
| cat pyproject.toml | |
| - name: Build package | |
| run: | | |
| cd packages/${{ matrix.platform }} | |
| python -m build | |
| - name: Publish to PyPI | |
| if: needs.download-binaries.outputs.dry_run != 'true' | |
| run: | | |
| cd packages/${{ matrix.platform }} | |
| twine upload --skip-existing dist/* --username __token__ --password ${{ secrets.PYPI_TOKEN }} | |
| - name: Dry run - show package contents | |
| if: needs.download-binaries.outputs.dry_run == 'true' | |
| run: | | |
| cd packages/${{ matrix.platform }} | |
| echo "=== Would publish package ===" | |
| cat pyproject.toml | |
| echo "" | |
| echo "=== Built packages ===" | |
| ls -la dist/ | |
| publish-main-package: | |
| name: Publish main package | |
| needs: [download-binaries, publish-platform-packages] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: '3.11' | |
| - name: Install build tools | |
| run: | | |
| pip install build twine | |
| - name: Verify package version | |
| run: | | |
| VERSION="${{ needs.download-binaries.outputs.version }}" | |
| PKG_VERSION=$(python -c "import re; content=open('pyproject.toml').read(); print(re.search(r'version\s*=\s*\"([^\"]+)\"', content).group(1))") | |
| echo "Expected version: ${VERSION}" | |
| echo "Package version: ${PKG_VERSION}" | |
| if [ "${VERSION}" != "${PKG_VERSION}" ]; then | |
| echo "Version mismatch! Updating pyproject.toml..." | |
| sed -i "s/version = \".*\"/version = \"${VERSION}\"/" pyproject.toml | |
| sed -i "s/__version__ = \".*\"/__version__ = \"${VERSION}\"/" gopher_mcp_python/__init__.py | |
| fi | |
| echo "Final version:" | |
| grep version pyproject.toml | |
| - name: Build package | |
| run: | | |
| python -m build | |
| - name: Publish to PyPI | |
| if: needs.download-binaries.outputs.dry_run != 'true' | |
| run: | | |
| twine upload --skip-existing dist/* --username __token__ --password ${{ secrets.PYPI_TOKEN }} | |
| - name: Dry run - show package info | |
| if: needs.download-binaries.outputs.dry_run == 'true' | |
| run: | | |
| echo "=== Would publish main package ===" | |
| cat pyproject.toml | |
| echo "" | |
| echo "=== Built packages ===" | |
| ls -la dist/ | |
| create-release: | |
| name: Create GitHub Release | |
| needs: [download-binaries, publish-main-package] | |
| runs-on: ubuntu-latest | |
| if: needs.download-binaries.outputs.dry_run != 'true' | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Generate release notes | |
| run: | | |
| VERSION="${{ needs.download-binaries.outputs.version }}" | |
| VERSION_TAG="${{ needs.download-binaries.outputs.version_tag }}" | |
| # Build Information | |
| cat > RELEASE_NOTES.md << EOF | |
| ## Build Information | |
| - **Date:** $(date -u +"%Y-%m-%d %H:%M:%S UTC") | |
| - **Commit:** ${{ github.sha }} | |
| - **Version:** ${VERSION} | |
| - **PyPI package:** \`gopher-mcp-python==${VERSION}\` | |
| EOF | |
| # Extract What's Changed from CHANGELOG.md | |
| echo "## What's Changed" >> RELEASE_NOTES.md | |
| echo "" >> RELEASE_NOTES.md | |
| if [ -f "CHANGELOG.md" ]; then | |
| # Extract content from [Unreleased] section (between ## [Unreleased] and next ## [) | |
| sed -n '/^## \[Unreleased\]/,/^## \[/p' CHANGELOG.md | \ | |
| grep -v "^## \[" | \ | |
| sed '/^$/d' >> RELEASE_NOTES.md || true | |
| # If Unreleased section is empty, try to get the latest version section | |
| if [ ! -s RELEASE_NOTES.md ] || [ $(wc -l < RELEASE_NOTES.md) -le 10 ]; then | |
| echo "" >> RELEASE_NOTES.md | |
| # Get content from the first versioned section | |
| sed -n '/^## \[0-9\]/,/^## \[/p' CHANGELOG.md | \ | |
| head -50 | \ | |
| grep -v "^## \[" >> RELEASE_NOTES.md || true | |
| fi | |
| else | |
| echo "No CHANGELOG.md found, listing recent commits..." >> RELEASE_NOTES.md | |
| echo "" >> RELEASE_NOTES.md | |
| git log --pretty=format:"* %s (%h)" --no-merges -20 >> RELEASE_NOTES.md || true | |
| fi | |
| # Add full changelog link | |
| PREV_TAG=$(git tag --sort=-creatordate | grep -v "^${VERSION_TAG}$" | head -1) | |
| if [ -n "$PREV_TAG" ]; then | |
| echo "" >> RELEASE_NOTES.md | |
| echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREV_TAG}...${VERSION_TAG}" >> RELEASE_NOTES.md | |
| fi | |
| echo "" | |
| echo "=== Release Notes ===" | |
| cat RELEASE_NOTES.md | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v1 | |
| with: | |
| tag_name: ${{ needs.download-binaries.outputs.version_tag }} | |
| name: gopher-mcp-python ${{ needs.download-binaries.outputs.version_tag }} | |
| body_path: RELEASE_NOTES.md | |
| draft: false | |
| prerelease: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |