chore: update benchmark results #5
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
| # SPDX-License-Identifier: Apache-2.0 | |
| # Copyright 2026 Tom F. | |
| # | |
| # Release pipeline for a2a-rust | |
| # | |
| # Triggered by pushing a semver tag (e.g. `git tag -a v0.2.0 -m "Release v0.2.0" && git push origin v0.2.0`). | |
| # See RELEASING.md for the complete release runbook. | |
| # | |
| # Job dependency graph: | |
| # | |
| # validate ──┬──► ci (matrix) ──┬──► package ─────────┬──► github-release ──► publish | |
| # └──► security ────┘ │ (crates-io env) | |
| # └──► publish-dry-run ─┘ | |
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - "v[0-9]+.[0-9]+.[0-9]+" # stable: v1.2.3 | |
| - "v[0-9]+.[0-9]+.[0-9]+-*" # pre-release: v1.2.3-alpha.1 | |
| # Prevent concurrent releases for the same ref. | |
| concurrency: | |
| group: release-${{ github.ref }} | |
| cancel-in-progress: false | |
| # Minimal default — individual jobs escalate only what they need. | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_TERM_COLOR: always | |
| RUSTFLAGS: "-D warnings" | |
| RUSTDOCFLAGS: "-D warnings" | |
| # ── Job 1: Validate tag & extract metadata ──────────────────────────────────── | |
| jobs: | |
| validate: | |
| name: Validate release tag | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.meta.outputs.version }} | |
| is_prerelease: ${{ steps.meta.outputs.is_prerelease }} | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Extract version metadata | |
| id: meta | |
| shell: bash | |
| run: | | |
| TAG="${GITHUB_REF_NAME}" | |
| VERSION="${TAG#v}" | |
| echo "::group::Tag metadata" | |
| printf 'Tag: %s\n' "$TAG" | |
| printf 'Version: %s\n' "$VERSION" | |
| # Validate semver (X.Y.Z with optional pre-release and build metadata) | |
| SEMVER_RE='^[0-9]+\.[0-9]+\.[0-9]+(-[A-Za-z0-9.]+)?(\+[A-Za-z0-9.]+)?$' | |
| if [[ ! "$VERSION" =~ $SEMVER_RE ]]; then | |
| echo "::error::Tag '$TAG' is not a valid semantic version." | |
| echo "Expected format: vX.Y.Z or vX.Y.Z-pre.1" | |
| exit 1 | |
| fi | |
| # Detect pre-release (contains a hyphen after X.Y.Z) | |
| if [[ "$VERSION" =~ - ]]; then | |
| IS_PRE=true | |
| else | |
| IS_PRE=false | |
| fi | |
| printf 'Pre-release:%s\n' "$IS_PRE" | |
| echo "::endgroup::" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "is_prerelease=$IS_PRE" >> "$GITHUB_OUTPUT" | |
| - name: Verify all crate versions match tag | |
| shell: bash | |
| run: | | |
| TAG_VER="${{ steps.meta.outputs.version }}" | |
| FAILED=0 | |
| echo "::group::Version consistency" | |
| for toml in crates/a2a-types/Cargo.toml crates/a2a-client/Cargo.toml crates/a2a-server/Cargo.toml crates/a2a-sdk/Cargo.toml; do | |
| CARGO_VER=$(grep '^version' "$toml" | head -1 | sed 's/.*"\(.*\)".*/\1/') | |
| if [[ "$CARGO_VER" != "$TAG_VER" ]]; then | |
| echo "::error file=$toml::$toml version ($CARGO_VER) != tag ($TAG_VER)." | |
| echo "Update $toml to match the tag before releasing." | |
| FAILED=1 | |
| else | |
| printf '✓ %s: %s\n' "$toml" "$CARGO_VER" | |
| fi | |
| done | |
| echo "::endgroup::" | |
| if [[ "$FAILED" -eq 1 ]]; then | |
| exit 1 | |
| fi | |
| echo "::notice::All crate versions match tag: $TAG_VER" | |
| - name: Verify CHANGELOG entry exists | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.meta.outputs.version }}" | |
| if ! grep -qE "^## \[$VERSION\]" CHANGELOG.md; then | |
| echo "::error file=CHANGELOG.md::No '## [$VERSION]' entry in CHANGELOG.md." | |
| echo "Add release notes before tagging." | |
| exit 1 | |
| fi | |
| echo "::notice::CHANGELOG.md entry found for v$VERSION" | |
| # ── Job 2: Full CI gate (parallel matrix) ──────────────────────────────────── | |
| ci: | |
| name: CI / ${{ matrix.name }} | |
| needs: validate | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| include: | |
| - name: "test · Linux" | |
| os: ubuntu-latest | |
| toolchain: stable | |
| command: cargo test --workspace --all-features | |
| - name: "test · macOS" | |
| os: macos-latest | |
| toolchain: stable | |
| command: cargo test --workspace --all-features | |
| - name: "test · Windows" | |
| os: windows-latest | |
| toolchain: stable | |
| command: cargo test --workspace --all-features | |
| - name: "clippy" | |
| os: ubuntu-latest | |
| toolchain: stable | |
| components: clippy | |
| command: cargo clippy --workspace --all-targets --all-features -- -D warnings | |
| - name: "fmt" | |
| os: ubuntu-latest | |
| toolchain: stable | |
| components: rustfmt | |
| command: cargo fmt --all -- --check | |
| - name: "doc" | |
| os: ubuntu-latest | |
| toolchain: stable | |
| command: cargo doc --workspace --no-deps | |
| - name: "MSRV 1.93" | |
| os: ubuntu-latest | |
| toolchain: "1.93" | |
| command: cargo check --workspace | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: dtolnay/rust-toolchain@master | |
| with: | |
| toolchain: ${{ matrix.toolchain }} | |
| components: ${{ matrix.components || '' }} | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| - name: Install protoc (for gRPC feature) | |
| uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: ${{ matrix.name }} | |
| run: ${{ matrix.command }} | |
| # ── Job 3: Security audit ───────────────────────────────────────────────────── | |
| security: | |
| name: Security audit (cargo-deny) | |
| needs: validate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: EmbarkStudios/cargo-deny-action@82eb9f621fbc699dd0918f3ea06864c14cc84246 # v2 | |
| with: | |
| command: check | |
| # ── Job 4: Package crates and generate provenance ───────────────────────────── | |
| package: | |
| name: Package and attest | |
| needs: [ci, security] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write # OIDC token for SLSA attestation | |
| attestations: write # write attestation to the repository | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| - name: Install protoc (for gRPC feature) | |
| uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Package all publishable crates | |
| shell: bash | |
| run: | | |
| echo "::group::Package contents" | |
| cargo package --workspace --exclude echo-agent --exclude agent-team --exclude multi-lang-team --exclude rig-a2a-agent --exclude genai-a2a-agent --exclude a2a-tck --exclude a2a-benchmarks --list --no-verify | |
| echo "::endgroup::" | |
| echo "::group::Build .crate archives" | |
| cargo package --workspace --exclude echo-agent --exclude agent-team --exclude multi-lang-team --exclude rig-a2a-agent --exclude genai-a2a-agent --exclude a2a-tck --exclude a2a-benchmarks --no-verify | |
| echo "::endgroup::" | |
| echo "::group::Archive sizes" | |
| ls -lh target/package/*.crate | |
| echo "::endgroup::" | |
| - name: Generate SHA-256 checksums | |
| shell: bash | |
| run: | | |
| cd target/package | |
| sha256sum ./*.crate | tee SHA256SUMS | |
| echo "::notice::SHA-256 checksums written to SHA256SUMS" | |
| # SLSA Level 2 build provenance — creates signed attestations linking | |
| # the .crate artifacts to this workflow run, verifiable with `gh attestation verify`. | |
| - name: Attest build provenance (SLSA) | |
| uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0 | |
| with: | |
| subject-path: target/package/*.crate | |
| - name: Upload release artifacts | |
| uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 | |
| with: | |
| name: release-artifacts | |
| path: | | |
| target/package/*.crate | |
| target/package/SHA256SUMS | |
| retention-days: 90 | |
| if-no-files-found: error | |
| # ── Job 5: Package verification (validates packages are publishable) ────────── | |
| publish-dry-run: | |
| name: Package verification | |
| needs: [ci, security] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| - name: Install protoc (for gRPC feature) | |
| uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Verify packages are publishable | |
| shell: bash | |
| run: | | |
| # Use `cargo package` instead of `cargo publish --dry-run` because | |
| # publish --dry-run resolves dependencies from the crates.io index, | |
| # which fails for workspace crates whose new versions aren't published yet. | |
| # `cargo package` resolves workspace dependencies locally. | |
| echo "::group::cargo package (all publishable crates)" | |
| cargo package --workspace --exclude echo-agent --exclude agent-team --exclude multi-lang-team --exclude rig-a2a-agent --exclude genai-a2a-agent --exclude a2a-tck --exclude a2a-benchmarks | |
| echo "::endgroup::" | |
| echo "::notice::Package verification succeeded — all crates pass validation" | |
| # ── Job 6: Create GitHub release with artifacts & release notes ─────────────── | |
| github-release: | |
| name: Create GitHub release | |
| needs: [validate, package, publish-dry-run] | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write # create release, upload assets | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - name: Download release artifacts | |
| uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 | |
| with: | |
| name: release-artifacts | |
| path: release-artifacts/ | |
| - name: Extract CHANGELOG section for this version | |
| id: notes | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.validate.outputs.version }}" | |
| echo "::group::Extracting release notes for v$VERSION" | |
| # Extract everything between ## [VERSION] and the next ## [ heading | |
| awk " | |
| /^## \[$VERSION\]/ { found=1; next } | |
| found && /^## \[/ { exit } | |
| found { print } | |
| " CHANGELOG.md > release_notes.md | |
| if [[ ! -s release_notes.md ]]; then | |
| echo "::error::Empty release notes extracted for $VERSION" | |
| echo "Ensure CHANGELOG.md has a non-empty ## [$VERSION] section." | |
| exit 1 | |
| fi | |
| echo "Release notes preview:" | |
| cat release_notes.md | |
| echo "::endgroup::" | |
| - name: List release artifacts | |
| shell: bash | |
| run: | | |
| echo "::group::Artifacts to attach" | |
| ls -lh release-artifacts/ | |
| echo "::endgroup::" | |
| - name: Create or update GitHub release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.validate.outputs.version }}" | |
| IS_PRE="${{ needs.validate.outputs.is_prerelease }}" | |
| TAG="v${VERSION}" | |
| PRE_FLAG="" | |
| [[ "$IS_PRE" == "true" ]] && PRE_FLAG="--prerelease" | |
| RELEASE_URL="https://github.com/${{ github.repository }}/releases/tag/${TAG}" | |
| # Idempotent: if a release already exists (e.g. created by GitHub | |
| # Desktop or the web UI when pushing a tag), update it in place | |
| # instead of failing. | |
| if gh release view "$TAG" &>/dev/null; then | |
| echo "::warning::Release ${TAG} already exists — updating it." | |
| echo "::group::Updating GitHub release ${TAG}" | |
| gh release edit "$TAG" \ | |
| $PRE_FLAG \ | |
| --title "a2a-rust ${TAG}" \ | |
| --notes-file release_notes.md | |
| # Upload assets (--clobber overwrites if they already exist) | |
| gh release upload "$TAG" \ | |
| --clobber \ | |
| release-artifacts/*.crate \ | |
| release-artifacts/SHA256SUMS | |
| echo "::endgroup::" | |
| echo "::notice::GitHub release updated: $RELEASE_URL" | |
| else | |
| echo "::group::Creating GitHub release ${TAG}" | |
| gh release create "$TAG" \ | |
| $PRE_FLAG \ | |
| --title "a2a-rust ${TAG}" \ | |
| --notes-file release_notes.md \ | |
| release-artifacts/*.crate \ | |
| release-artifacts/SHA256SUMS | |
| echo "::endgroup::" | |
| echo "::notice::GitHub release created: $RELEASE_URL" | |
| fi | |
| # ── Step summary ────────────────────────────────────────────────── | |
| { | |
| echo "## Release v${VERSION} created" | |
| echo "" | |
| echo "| Field | Value |" | |
| echo "|-------|-------|" | |
| echo "| Version | \`${VERSION}\` |" | |
| echo "| Pre-release | \`${IS_PRE}\` |" | |
| echo "| GitHub Release | [v${VERSION}](${RELEASE_URL}) |" | |
| echo "" | |
| echo "### Artifacts" | |
| echo "\`\`\`" | |
| ls -lh release-artifacts/ | |
| echo "\`\`\`" | |
| echo "" | |
| echo "### Next step" | |
| echo "Approve the **crates-io** deployment environment to publish to crates.io." | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| # ── Job 7: Publish to crates.io (protected environment, requires approval) ──── | |
| publish: | |
| name: Publish to crates.io | |
| needs: [validate, github-release] | |
| runs-on: ubuntu-latest | |
| # The 'crates-io' environment requires a manual approval step. | |
| # Configure it at: Settings → Environments → crates-io → Required reviewers | |
| environment: | |
| name: crates-io | |
| url: https://crates.io/crates/a2a-protocol-sdk/${{ needs.validate.outputs.version }} | |
| permissions: | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| - name: Install protoc (for gRPC feature) | |
| uses: arduino/setup-protoc@c65c819552d16ad3c9b72d9dfd5ba5237b9c906b # v3.0.0 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Publish crates (dependency order) | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} | |
| shell: bash | |
| run: | | |
| VERSION="${{ needs.validate.outputs.version }}" | |
| # Helper: idempotent publish that treats "already uploaded" as success. | |
| publish_crate() { | |
| local crate="$1" | |
| echo "::group::cargo publish — $crate v$VERSION" | |
| if ! cargo publish -p "$crate" 2>&1 | tee /tmp/publish-${crate}.log; then | |
| if grep -q "already uploaded" /tmp/publish-${crate}.log; then | |
| echo "::warning::$crate v$VERSION is already published — skipping." | |
| else | |
| echo "::error::cargo publish -p $crate failed" | |
| cat /tmp/publish-${crate}.log | |
| exit 1 | |
| fi | |
| fi | |
| echo "::endgroup::" | |
| } | |
| # Tier 1: no workspace dependencies | |
| publish_crate a2a-protocol-types | |
| echo "Waiting for crates.io index to update..." | |
| sleep 30 | |
| # Tier 2: depends on a2a-protocol-types | |
| publish_crate a2a-protocol-client | |
| publish_crate a2a-protocol-server | |
| echo "Waiting for crates.io index to update..." | |
| sleep 30 | |
| # Tier 3: depends on all of the above | |
| publish_crate a2a-protocol-sdk | |
| echo "::notice::All crates published successfully" | |
| # ── Step summary ────────────────────────────────────────────────── | |
| { | |
| echo "## Published to crates.io" | |
| echo "" | |
| echo "| Crate | Link |" | |
| echo "|-------|------|" | |
| echo "| a2a-protocol-types | [crates.io](https://crates.io/crates/a2a-protocol-types/${VERSION}) |" | |
| echo "| a2a-protocol-client | [crates.io](https://crates.io/crates/a2a-protocol-client/${VERSION}) |" | |
| echo "| a2a-protocol-server | [crates.io](https://crates.io/crates/a2a-protocol-server/${VERSION}) |" | |
| echo "| a2a-protocol-sdk | [crates.io](https://crates.io/crates/a2a-protocol-sdk/${VERSION}) |" | |
| echo "" | |
| echo "> docs.rs may take a few minutes to build and index the documentation." | |
| } >> "$GITHUB_STEP_SUMMARY" |