ruststream 0.2.4

Async messaging framework for Rust: broker-agnostic traits, router, codecs, and a conformance harness for broker authors.
Documentation
name: Release

on:
  release:
    types: [published]
  workflow_dispatch:

permissions: {}

jobs:
  crates-io:
    name: Publish to crates.io
    runs-on: ubuntu-latest
    environment: crates.io
    permissions:
      contents: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Verify ruststream version matches tag
        env:
          TAG: ${{ github.ref_name }}
        run: |
          TAG_VERSION="${TAG#v}"
          META=$(cargo metadata --format-version 1 --no-deps)
          # Only the main crate must match the tag. ruststream-macros may stay on an older,
          # already-published version when it did not change; the publish step skips it then,
          # and ruststream resolves it from crates.io by its semver dependency requirement.
          VERSION=$(echo "$META" | jq -r '.packages[] | select(.name == "ruststream") | .version')
          if [ "$TAG_VERSION" != "$VERSION" ]; then
            echo "Tag '${TAG}' does not match ruststream version '$VERSION'"
            exit 1
          fi
          echo "ruststream $VERSION verified against tag ${TAG}"
          MACROS=$(echo "$META" | jq -r '.packages[] | select(.name == "ruststream-macros") | .version')
          echo "ruststream-macros at $MACROS (published only if not already on crates.io)"

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Authenticate to crates.io via trusted publishing
        uses: rust-lang/crates-io-auth-action@v1
        id: auth

      - name: cargo publish (dependency order)
        env:
          CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
        run: |
          # Publish a crate only if its current version is not already on crates.io,
          # so re-running a release after a partial failure is safe. ruststream-macros
          # is a proc-macro crate and a dependency of ruststream, so it goes first.
          publish() {
            name="$1"; shift
            version=$(cargo metadata --format-version 1 --no-deps \
              | jq -r --arg n "$name" '.packages[] | select(.name == $n) | .version')
            index="https://index.crates.io/${name:0:2}/${name:2:2}/${name}"
            if curl -fsSL "$index" 2>/dev/null | grep -qF "\"vers\":\"${version}\""; then
              echo "$name $version already on crates.io, skipping"
            else
              cargo publish -p "$name" "$@"
            fi
          }
          publish ruststream-macros
          publish ruststream --all-features

      - name: Generate release notes
        if: github.event_name == 'release'
        env:
          TAG: ${{ github.ref_name }}
          GH_TOKEN: ${{ github.token }}
        run: |
          NOTES=$(gh api "repos/$GITHUB_REPOSITORY/releases/generate-notes" \
            -f tag_name="$TAG" -q .body)
          gh release edit "$TAG" --notes "$NOTES" --repo "$GITHUB_REPOSITORY"