Skip to content

Latest commit

 

History

History
145 lines (113 loc) · 5.96 KB

File metadata and controls

145 lines (113 loc) · 5.96 KB

Contributing to connect-rust

See docs/guide.md for the user-facing handler/client API and the README for the workspace layout.

Prerequisites

  • Rust 1.88+ (MSRV; the codebase uses let-chains).
  • protoc v27+ — the test and example protos use editions syntax (edition = "2023"). Ubuntu's apt protobuf-compiler (v21) is too old; install from the protobuf releases page or via arduino/setup-protoc in CI. task generate:all and the connectrpc-build consumers need it.
  • buf — used to drive regeneration of the checked-in code (the buf.gen.yaml files invoke locally-built plugins).
  • task (go-task) — the repo's command runner. task --list shows everything.

Change Size

Keep each change to ≤ 250 lines net (additions minus deletions, excluding test files and */generated/*) wherever possible. If a task naturally exceeds that, split it into focused, self-contained PRs or commits.

Test Coverage

Every change must include unit tests. Target ≥ 80% line coverage for new code. Reaching 100% is not required when the remaining paths would require artificial tests, but coverage gaps must be intentional and justified. Tests live in #[cfg(test)] modules colocated with the code they test; the tests/streaming crate is the in-workspace e2e consumer of connectrpc-build.

Rust Conventions

  • Run task lint and task test before every commit (or task ci to also run docs, minimal-features, and the multiservice example).
  • Public API items require doc comments (///); include # Errors / # Panics sections where applicable.
  • Every unsafe block requires a // SAFETY: comment explaining the invariant.
  • Avoid .unwrap() outside tests and provably-safe paths.
  • #[inline] only with full-path profiling evidence.

Code Generation (connectrpc-codegen)

All code generation uses quote! blocks rather than string manipulation; prettyplease formats the final TokenStream into readable Rust source. The pipeline mirrors buffa's: accumulate TokenStreamsyn::parse2prettyplease::unparse.

Key rules:

  • Regular // comments are not tokens and are silently dropped by quote!. Only doc comments (///#[doc = "..."]) survive.
  • Identifiers must go through format_ident! (or Ident::new_raw for Rust keywords). Never interpolate raw strings as identifiers.
  • Type paths resolved from the descriptor context use rust_path_to_tokens (which wraps syn::parse_str::<syn::Path>).
  • Generated code uses fully-qualified paths everywhere (::connectrpc::..., ::buffa::...) — no use statements at module scope. This lets multiple generated files be include!d into the same Rust module without E0252 collisions.

Conformance Tests

The Connect protocol conformance suite runs against both server and client implementations. task conformance:download fetches the runner; task conformance:build builds the binaries.

Suite Task Tests
Server default (all protocols) task conformance:test 3600
Server Connect-only task conformance:test-connect-only 1192
Server Connect+TLS task conformance:test-connect-tls 2396
Client Connect task conformance:test-client-connect-only 2580
Client gRPC task conformance:test-client-grpc-only 1454
Client gRPC-Web task conformance:test-client-grpc-web-only 2838

A healthy run ends with N passed, 0 failed. CI runs the server-default and the three client suites.

Checked-In Generated Code

Five directories contain checked-in buf generate output and must be regenerated whenever connectrpc-codegen output changes (or the buffa dependency is bumped):

  • conformance/src/generated/
  • examples/eliza/src/generated/
  • examples/multiservice/src/generated/
  • benches/rpc/src/generated/
  • connectrpc-health/src/generated/

Regenerate all of them with:

task generate:all

This rebuilds protoc-gen-connect-rust (and the sibling buffa plugins from ../buffa) in release mode, then runs buf generate in each directory. CI runs a separate generated-code check that fails when these checked-in files are stale.

Building Against a Local buffa Checkout

To test combined speculative changes across both repos:

task buffa:link     # writes .cargo/config.toml pointing at ../buffa
task buffa:unlink   # removes the override; reverts to crates.io / [patch]

The override is gitignored and never reaches CI or cargo publish.

Continuous Integration

GitHub Actions CI (.github/workflows/ci.yml) runs on every push to main and on all pull requests. Jobs:

  • Checkcargo check --workspace --all-features --all-targets with RUSTFLAGS=-Dwarnings
  • Testcargo test --workspace
  • Clippy — workspace, all targets, -D warnings, on a pinned toolchain (currently 1.95) so new-stable lints don't break CI unannounced
  • Formatcargo +nightly-2026-02-27 fmt --check. Nightly is required because format_generated_files = false in rustfmt.toml is a nightly-only option; the date is pinned because rustfmt output drifts across releases. Use the same dated nightly locally (rustup toolchain install nightly-2026-02-27 -c rustfmt); bump it together with the fmt job in .github/workflows/ci.yml
  • Check generated code — runs task generate:all and verifies the checked-in generated directories have no diff
  • Documentationcargo doc with broken-intra-doc-links denied
  • MSRV (1.88)cargo check on the pinned minimum toolchain
  • Examples — builds and runs the example crates
  • Minimal featurescargo check -p connectrpc --no-default-features
  • Wasmwasm32-unknown-unknown build of the client example
  • Conformance (server) / Conformance (client) — full suites