Unified Release (Rust + Python) #1
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: Unified Release (Rust + Python) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| bump_type: | |
| description: 'Version bump type' | |
| required: false | |
| type: choice | |
| default: 'patch' | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| force_version: | |
| description: 'Force a specific version (e.g., 0.1.2-beta.1)' | |
| required: false | |
| type: string | |
| skip_tests: | |
| description: 'Skip tests (use with caution)' | |
| required: false | |
| type: boolean | |
| default: false | |
| dry_run: | |
| description: 'Dry run - build everything but skip commits and publishing' | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| packages: write | |
| id-token: write | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| test: | |
| name: Run tests | |
| if: ${{ !inputs.skip_tests }} | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v2 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Run workspace tests | |
| run: cargo test --workspace --all-features | |
| bump-version: | |
| name: Bump version | |
| needs: [test] | |
| if: ${{ always() && (needs.test.result == 'success' || needs.test.result == 'skipped') }} | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.new.outputs.version }} | |
| py_version: ${{ steps.new.outputs.py_version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| token: ${{ secrets.PAT_TOKEN || secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 | |
| submodules: recursive | |
| - name: Get current version | |
| id: current | |
| run: | | |
| CURRENT=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/') | |
| echo "version=${CURRENT}" >> $GITHUB_OUTPUT | |
| echo "Current version: ${CURRENT}" | |
| - name: Calculate new version | |
| id: new | |
| run: | | |
| CURRENT="${{ steps.current.outputs.version }}" | |
| FORCE_VERSION="${{ inputs.force_version }}" | |
| BUMP_TYPE="${{ inputs.bump_type }}" | |
| if [[ -n "$FORCE_VERSION" ]]; then | |
| NEW_VERSION="$FORCE_VERSION" | |
| else | |
| NEW_VERSION=$(python3 scripts/version_tools.py bump --current "$CURRENT" --kind "$BUMP_TYPE") | |
| fi | |
| PY_VERSION=$(python3 scripts/version_tools.py pep440 --version "$NEW_VERSION") | |
| echo "version=${NEW_VERSION}" >> $GITHUB_OUTPUT | |
| echo "py_version=${PY_VERSION}" >> $GITHUB_OUTPUT | |
| echo "New version: ${NEW_VERSION} (Python: ${PY_VERSION})" | |
| - name: Update all version files | |
| run: | | |
| VERSION="${{ steps.new.outputs.version }}" | |
| # Update all version files using version_tools.py | |
| python3 scripts/version_tools.py update --version "$VERSION" | |
| # Refresh Cargo.lock | |
| cargo update --workspace | |
| - name: Commit version bump | |
| if: ${{ !inputs.dry_run }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Cargo.toml Cargo.lock bindings/python/pyproject.toml | |
| git commit -m "chore: bump version to ${{ steps.new.outputs.version }} [skip ci]" | |
| git tag "v${{ steps.new.outputs.version }}" | |
| git push origin HEAD:main --tags | |
| - name: Dry run summary | |
| if: ${{ inputs.dry_run }} | |
| run: | | |
| echo "=== DRY RUN MODE ===" | |
| echo "Version would be bumped to: ${{ steps.new.outputs.version }}" | |
| echo "Python version would be: ${{ steps.new.outputs.py_version }}" | |
| echo "" | |
| echo "Changes that would be committed:" | |
| git diff Cargo.toml bindings/python/pyproject.toml | |
| echo "" | |
| echo "Builds will proceed, but no commits or publishing will happen." | |
| build-rust-binaries: | |
| name: Build Rust ${{ matrix.target }} | |
| runs-on: ${{ matrix.os }} | |
| needs: [bump-version] | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| binary: sbc | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| binary: sbc | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| binary: sbc.exe | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.dry_run && github.ref || 'main' }} | |
| submodules: recursive | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v2 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Build CLI | |
| run: | | |
| cd cli | |
| cargo build --release --target ${{ matrix.target }} | |
| - name: Package binary | |
| shell: bash | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| if [[ "${{ matrix.os }}" == "windows-latest" ]]; then | |
| 7z a ../../../sbc-${{ matrix.target }}.zip ${{ matrix.binary }} | |
| else | |
| tar czf ../../../sbc-${{ matrix.target }}.tar.gz ${{ matrix.binary }} | |
| fi | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbc-${{ matrix.target }} | |
| path: sbc-${{ matrix.target }}.* | |
| publish-rust-crates: | |
| name: Publish Rust crates | |
| runs-on: ubuntu-latest | |
| needs: [bump-version, build-rust-binaries] | |
| if: ${{ !inputs.dry_run }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| submodules: recursive | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v2 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Publish protocol to crates.io | |
| run: cd protocol && cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| continue-on-error: true | |
| - name: Wait for protocol crate availability | |
| run: sleep 30 | |
| - name: Publish CLI to crates.io | |
| run: cd cli && cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| continue-on-error: true | |
| build-python-wheels: | |
| name: Build Python wheels ${{ matrix.target }} | |
| needs: [bump-version] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| manylinux: auto | |
| - os: ubuntu-24.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| manylinux: auto | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| manylinux: off | |
| - os: macos-15-intel | |
| target: x86_64-apple-darwin | |
| manylinux: off | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| manylinux: off | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.dry_run && github.ref || 'main' }} | |
| submodules: recursive | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v2 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Build wheels | |
| uses: PyO3/maturin-action@v1 | |
| with: | |
| working-directory: bindings/python | |
| target: ${{ matrix.target }} | |
| args: --release --out dist | |
| sccache: "true" | |
| manylinux: ${{ matrix.manylinux }} | |
| before-script-linux: | | |
| PROTOC_VERSION="28.3" | |
| ARCH="$(uname -m)" | |
| if [ "$ARCH" = "aarch64" ]; then | |
| PROTOC_ARCH="aarch_64" | |
| else | |
| PROTOC_ARCH="$ARCH" | |
| fi | |
| curl -LO "https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip" | |
| unzip -q protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip -d /usr/local | |
| rm protoc-${PROTOC_VERSION}-linux-${PROTOC_ARCH}.zip | |
| protoc --version | |
| - name: Upload wheels | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.target }} | |
| path: bindings/python/dist/*.whl | |
| build-python-sdist: | |
| name: Build Python sdist | |
| needs: [bump-version] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ inputs.dry_run && github.ref || 'main' }} | |
| submodules: recursive | |
| - name: Install protoc | |
| uses: arduino/setup-protoc@v2 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Build sdist | |
| uses: PyO3/maturin-action@v1 | |
| with: | |
| working-directory: bindings/python | |
| command: sdist | |
| args: --out dist | |
| - name: Upload sdist | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: sdist | |
| path: bindings/python/dist/*.tar.gz | |
| publish-python: | |
| name: Publish to PyPI | |
| needs: [build-python-wheels, build-python-sdist, publish-rust-crates] | |
| if: ${{ !inputs.dry_run }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download all wheels | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| pattern: wheels-* | |
| merge-multiple: true | |
| - name: Download sdist | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist | |
| name: sdist | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| packages-dir: dist/ | |
| password: ${{ secrets.PYPI_API_TOKEN }} | |
| create-github-release: | |
| name: Create GitHub Release | |
| runs-on: ubuntu-latest | |
| needs: [bump-version, build-rust-binaries, publish-rust-crates, publish-python] | |
| if: ${{ !inputs.dry_run }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: main | |
| submodules: recursive | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Create Release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| VERSION="${{ needs.bump-version.outputs.version }}" | |
| PY_VERSION="${{ needs.bump-version.outputs.py_version }}" | |
| NOTES_FILE=$(mktemp) | |
| cat > "$NOTES_FILE" <<EOF | |
| # SyftBox Crypto v${VERSION} | |
| Cryptographic protocol implementation for SyftBox using X3DH key agreement. | |
| ## Published Artifacts | |
| ### Rust Crates | |
| - \`syftbox-crypto-protocol ${VERSION}\` - [crates.io](https://crates.io/crates/syftbox-crypto-protocol/${VERSION}) | |
| - \`syftbox-crypto-cli ${VERSION}\` - [crates.io](https://crates.io/crates/syftbox-crypto-cli/${VERSION}) | |
| ### Python Package | |
| - \`syftbox-crypto-python ${PY_VERSION}\` - [PyPI](https://pypi.org/project/syftbox-crypto-python/${PY_VERSION}) | |
| ## Installation | |
| ### Rust | |
| \`\`\`bash | |
| cargo install syftbox-crypto-cli | |
| # or | |
| cargo add syftbox-crypto-protocol | |
| \`\`\` | |
| ### Python | |
| \`\`\`bash | |
| pip install syftbox-crypto-python | |
| \`\`\` | |
| ### From Binary | |
| Download the appropriate binary for your platform from the assets below. | |
| EOF | |
| gh release create "v${VERSION}" \ | |
| --title "Release v${VERSION}" \ | |
| --notes-file "$NOTES_FILE" \ | |
| --repo "${{ github.repository }}" \ | |
| --latest | |
| - name: Upload Release Assets | |
| run: | | |
| VERSION="${{ needs.bump-version.outputs.version }}" | |
| for file in artifacts/sbc-*/*.{tar.gz,zip}; do | |
| if [ -f "$file" ]; then | |
| echo "Uploading $(basename "$file")" | |
| gh release upload "v${VERSION}" "$file" --repo ${{ github.repository }} | |
| fi | |
| done | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |