Skip to content

chore: update benchmark results #5

chore: update benchmark results

chore: update benchmark results #5

Workflow file for this run

# 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"