Initial Open Source release of hyper-api-rust #3
Workflow file for this run
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: release | |
| # Tag-triggered publish to crates.io. Stable tags (v0.1.0) mark the | |
| # GitHub release as latest; pre-release tags (v0.1.0-rc.1) mark it as | |
| # prerelease so it doesn't show as "Latest release" on the repo home. | |
| # | |
| # Publishing is destructive — version numbers on crates.io are | |
| # permanent. This workflow re-runs the full test matrix before | |
| # touching crates.io, and publishes crates strictly in dependency | |
| # order with a small settle delay between each so the index is | |
| # consistent for downstream crates. | |
| on: | |
| push: | |
| tags: | |
| - "v*.*.*-rc.*" | |
| - "v*.*.*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Tag to release (e.g. v0.1.0-rc.1). Must already exist." | |
| required: true | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUST_BACKTRACE: 1 | |
| jobs: | |
| verify: | |
| name: verify | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 60 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| - name: Install system libraries | |
| run: sudo apt-get update -q && sudo apt-get install -y libfontconfig1-dev mold protobuf-compiler | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: release-verify | |
| - name: Cache hyperd binary | |
| id: hyperd-cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: .hyperd | |
| key: hyperd-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('hyperdb-bootstrap/hyperd-version.toml') }} | |
| - name: Download hyperd | |
| if: steps.hyperd-cache.outputs.cache-hit != 'true' | |
| run: cargo run --release -p hyperdb-bootstrap --bin hyperdb-bootstrap -- download | |
| - name: Workspace tests | |
| env: | |
| HYPERD_PATH: ${{ github.workspace }}/.hyperd/current | |
| run: | | |
| cargo test --workspace \ | |
| --exclude hyperdb-api-node \ | |
| --exclude hyperdb-bootstrap | |
| - name: hyperdb-bootstrap tests | |
| run: cargo test -p hyperdb-bootstrap | |
| - name: Verify pinned hyperd release URLs still resolve | |
| run: cargo run --release -p hyperdb-bootstrap --bin hyperdb-bootstrap -- verify | |
| build-binaries: | |
| name: build-binaries (${{ matrix.target }}) | |
| needs: verify | |
| timeout-minutes: 45 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, ext: tar.gz } | |
| - { os: macos-14, target: aarch64-apple-darwin, ext: tar.gz } | |
| - { os: macos-14, target: x86_64-apple-darwin, ext: tar.gz } | |
| - { os: windows-latest, target: x86_64-pc-windows-msvc, ext: zip } | |
| runs-on: ${{ matrix.os }} | |
| defaults: | |
| run: | |
| # Git Bash on Windows keeps the packaging step single-codepath | |
| # (`tar` / `shasum -a 256` / string munging are all POSIX). | |
| shell: bash | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| - name: Install system libraries (Linux) | |
| if: runner.os == 'Linux' | |
| run: sudo apt-get update -q && sudo apt-get install -y libfontconfig1-dev mold protobuf-compiler | |
| - name: Install protobuf (macOS) | |
| if: runner.os == 'macOS' | |
| run: brew install protobuf | |
| - name: Install protobuf (Windows) | |
| if: runner.os == 'Windows' | |
| run: choco install protoc -y | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: release-bin-${{ matrix.target }} | |
| - name: Resolve tag name | |
| id: tag | |
| env: | |
| # Route user-supplied values through env: (not into the shell | |
| # command body) so they cannot be interpreted as shell syntax | |
| # before the regex validator below rejects malformed inputs. | |
| REF_NAME: ${{ github.ref_name }} | |
| INPUT_TAG: ${{ github.event.inputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| TAG="${INPUT_TAG:-$REF_NAME}" | |
| # Defense in depth — same regex as the publish job below. | |
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-(rc|alpha|beta)\.[0-9]+)?$ ]]; then | |
| echo "::error::Invalid tag name: $TAG (expected vX.Y.Z or vX.Y.Z-rc.N)" >&2 | |
| exit 1 | |
| fi | |
| echo "name=$TAG" >> "$GITHUB_OUTPUT" | |
| - name: Build release binaries | |
| env: | |
| TARGET: ${{ matrix.target }} | |
| run: | | |
| cargo build --release --target "$TARGET" \ | |
| -p hyperdb-mcp -p hyperdb-bootstrap | |
| - name: Package archives | |
| env: | |
| TAG: ${{ steps.tag.outputs.name }} | |
| TARGET: ${{ matrix.target }} | |
| EXT: ${{ matrix.ext }} | |
| run: | | |
| set -euo pipefail | |
| mkdir -p dist staging | |
| EXE="" | |
| if [[ "$EXT" == "zip" ]]; then | |
| EXE=".exe" | |
| fi | |
| for BIN in hyperdb-mcp hyperdb-bootstrap; do | |
| STAGE="staging/${BIN}-${TAG}-${TARGET}" | |
| mkdir -p "$STAGE" | |
| cp "target/${TARGET}/release/${BIN}${EXE}" "$STAGE/" | |
| cp README.md LICENSE-APACHE.txt LICENSE-MIT.txt "$STAGE/" | |
| if [[ "$EXT" == "zip" ]]; then | |
| # 7z ships on windows-latest runners; avoids PowerShell quoting. | |
| ( cd staging && 7z a -bd "../dist/${BIN}-${TAG}-${TARGET}.zip" "${BIN}-${TAG}-${TARGET}" ) | |
| else | |
| tar -C staging -czf "dist/${BIN}-${TAG}-${TARGET}.tar.gz" "${BIN}-${TAG}-${TARGET}" | |
| fi | |
| ( cd dist && shasum -a 256 "${BIN}-${TAG}-${TARGET}.${EXT}" > "${BIN}-${TAG}-${TARGET}.${EXT}.sha256" ) | |
| done | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: release-binaries-${{ matrix.target }} | |
| path: dist/* | |
| if-no-files-found: error | |
| retention-days: 7 | |
| publish: | |
| name: publish to crates.io | |
| needs: [verify, build-binaries] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| ref: ${{ github.event.inputs.tag || github.ref }} | |
| - name: Install system libraries | |
| run: sudo apt-get update -q && sudo apt-get install -y libfontconfig1-dev mold protobuf-compiler | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: release-publish | |
| - name: Resolve tag name | |
| id: tag | |
| env: | |
| REF_NAME: ${{ github.ref_name }} | |
| INPUT_TAG: ${{ github.event.inputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| TAG="${INPUT_TAG:-$REF_NAME}" | |
| # Defense in depth: tags coming from workflow_dispatch are | |
| # user-supplied. Enforce a strict `vX.Y.Z` / `vX.Y.Z-rc.N` | |
| # shape before letting the name flow into cargo/git commands. | |
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-(rc|alpha|beta)\.[0-9]+)?$ ]]; then | |
| echo "::error::Invalid tag name: $TAG (expected vX.Y.Z or vX.Y.Z-rc.N)" >&2 | |
| exit 1 | |
| fi | |
| echo "name=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=${TAG#v}" >> "$GITHUB_OUTPUT" | |
| - name: Confirm tag matches workspace version | |
| # All publishable crates are in lockstep. Use hyperdb-api-core as | |
| # the bellwether (it's the foundation every other crate depends on). | |
| env: | |
| EXPECTED: ${{ steps.tag.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| ACTUAL=$(cargo metadata --no-deps --format-version 1 \ | |
| | jq -r '.packages[] | select(.name=="hyperdb-api-core") | .version') | |
| if [[ "$EXPECTED" != "$ACTUAL" ]]; then | |
| echo "::error::Tag version ($EXPECTED) does not match hyperdb-api-core Cargo.toml ($ACTUAL). Bump all workspace Cargo.tomls to match the tag before releasing." >&2 | |
| exit 1 | |
| fi | |
| - name: Publish in dependency order | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| publish() { | |
| local crate="$1" | |
| echo "::group::Publishing $crate" | |
| cargo publish -p "$crate" | |
| echo "::endgroup::" | |
| # crates.io index propagation: downstream crates' own | |
| # `cargo publish` verification step resolves their deps | |
| # against the live index. 45s is the empirically-safe | |
| # window for small crates. | |
| sleep 45 | |
| } | |
| publish hyperdb-api-core | |
| publish hyperdb-api-salesforce | |
| publish hyperdb-api | |
| publish hyperdb-mcp | |
| publish hyperdb-bootstrap | |
| publish sea-query-hyperdb | |
| - name: Download pre-built binary archives | |
| uses: actions/download-artifact@v4 | |
| with: | |
| pattern: release-binaries-* | |
| merge-multiple: true | |
| path: dist | |
| - name: Combine per-archive sha256 sidecars into SHA256SUMS.txt | |
| run: | | |
| set -euo pipefail | |
| cd dist | |
| # 4 targets × 2 binaries = 8 archives. One combined file users | |
| # can `sha256sum -c SHA256SUMS.txt` against. | |
| sha256sum *.tar.gz *.zip > SHA256SUMS.txt | |
| - name: Create GitHub release | |
| # NOTE on re-runs: action-gh-release@v2 appends to an existing | |
| # release with the same tag but does NOT overwrite same-named | |
| # assets. After a partial failure, delete stale assets manually | |
| # with `gh release delete-asset` before re-running. | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: ${{ steps.tag.outputs.name }} | |
| # Any tag with -rc./-alpha./-beta. in it is a prerelease. | |
| prerelease: ${{ contains(steps.tag.outputs.name, '-rc.') || contains(steps.tag.outputs.name, '-alpha.') || contains(steps.tag.outputs.name, '-beta.') }} | |
| generate_release_notes: true | |
| files: | | |
| dist/*.tar.gz | |
| dist/*.zip | |
| dist/SHA256SUMS.txt |