Skip to content

Latest commit

 

History

History
166 lines (130 loc) · 7.13 KB

File metadata and controls

166 lines (130 loc) · 7.13 KB

Contributing to openapi-to-rust

Thanks for helping make real-world OpenAPI documents easier to use from Rust. Bug reproductions with a small schema are especially valuable: generated-code problems are much faster to review when the wire shape is visible in a fixture.

Before you start

  • Use GitHub Discussions for usage questions and design exploration.
  • Use the issue forms for reproducible bugs and concrete feature requests.
  • For a larger generated-API or configuration change, open an issue before investing in an implementation so compatibility tradeoffs can be discussed.
  • Follow the Code of Conduct and report vulnerabilities through SECURITY.md, not a public issue.

Development setup

The project requires Rust 1.88 or newer, Git, and Bash. Clone with submodules so the vendored JSON Schema conformance corpus is available:

git clone --recurse-submodules https://github.com/gpu-cli/openapi-to-rust.git
cd openapi-to-rust
cargo test

External contributors do not need the maintainers' Beads issue-tracking tool. Reference the public GitHub issue in your pull request when one exists.

Repository map

  • src/analysis.rs converts OpenAPI schemas and operations into generator IR.
  • src/generator.rs emits models and coordinates generated files.
  • src/client_generator.rs emits HTTP/SSE client operations.
  • src/server/ emits and manages opt-in Axum scaffolding.
  • src/type_mapping.rs owns format strategies and dependency requirements.
  • tests/fixtures/ contains focused regression documents.
  • tests/conformance/ contains the compatibility catalog and reports.
  • specs/ contains the real-world corpus used by the compile gate.
  • tests/corpus-manifest.txt hashes the code that corpus generates, so an unintended change to real-world output fails CI.

Making a change

  1. Add the smallest fixture that reproduces the OpenAPI shape.
  2. Add a behavioral assertion, snapshot, or generated scratch-crate compile test. Prefer behavior assertions when a full-file snapshot would be noisy.
  3. Implement the change without hand-editing checked-in generated examples.
  4. Run the checks proportional to the change.
  5. Explain generated API or wire-format compatibility in the pull request.

For insta snapshots:

cargo insta test
cargo insta review

Review every changed snapshot. Do not accept broad snapshot churn without explaining why unrelated generated output changed.

Checks

Run the standard gate before opening a pull request:

cargo fmt --check
cargo clippy --all-features -- -D warnings
cargo nextest run --all-features
cargo test --doc --all-features
RUSTDOCFLAGS=-Dwarnings cargo doc --no-deps --all-features

The suite runs under nextest (cargo install cargo-nextest --locked), which runs each test in its own process. It cannot run doctests, so those keep going through the built-in harness in the second command — running only cargo nextest run silently skips them.

Also run the relevant distribution or corpus gate when touching these areas:

scripts/install-smoke.sh                 # packaging, CLI, or dependencies
scripts/spec-compile.sh anthropic openai # generator/client output
scripts/spec-compile.sh                  # broad generator/type changes
scripts/untyped-census.sh                # anything that changes which fields get typed

Corpus output diffs

Nothing generated is checked in, but generation is byte-deterministic and the specs under specs/ are pinned, so any earlier revision's output can be rebuilt on demand:

scripts/gen-diff.sh                # vs the merge base with main
scripts/gen-diff.sh v0.15.0        # vs a release
GEN_DIFF_SPECS="anthropic openai" scripts/gen-diff.sh HEAD~1

It builds the generator at that ref in a throwaway worktree, regenerates the corpus on both sides, and prints per-spec churn plus any public item that appeared or disappeared. Full per-spec diffs land in tmp/gen-diff/report/. The base side is cached per commit, so repeat runs only pay for the working tree. A cold full-corpus run is roughly a minute and a half.

tests/corpus-manifest.txt is the committed tripwire for the same thing: one hashed line per generated file. When a change legitimately moves output, inspect it with gen-diff.sh, then refresh the manifest with scripts/corpus-manifest.sh so the review shows which specs moved. The Generated by openapi-to-rust vX.Y.Z stamp is normalized away, so a version bump alone never touches the manifest.

CI runs both. A pull request gets the corpus-diff job, which diffs against the base of the pull request, puts the per-spec table in the job summary, uploads the full diffs as an artifact, and then checks the manifest against the corpus it already generated (--from tmp/gen-diff/head). Pushes to main and scheduled runs get the manifest check on its own.

Both cover the types and client output. Server scaffolding is generated from per-spec [server].operations selectors, so it has no uniform corpus pass yet.

scripts/untyped-census.sh rewrites tests/conformance/untyped-report.md, which counts every generated field that carries serde_json::Value and says why. Regenerate it when a change types fields that used to be opaque (or stops typing ones that were), so the corpus delta is visible in review; scripts/untyped-census.sh --check fails when it is stale. A recoverable row means the schema carried type information the generator dropped — those are defects with a fix, not shapes the spec left open.

The full corpus generates and compile-checks 55 OpenAPI documents and can take several minutes. CI runs a fast generation tier on pull requests and the full compile tier weekly or on manual dispatch.

Compile runs also generate deterministic, schema-valid JSON samples for each representable component model. Each sample is independently validated against the source OpenAPI JSON Schema, hydrated into the generated Rust type, serialized, validated again, and round-tripped a second time to require a stable wire representation. Start with one production spec while iterating:

scripts/spec-compile.sh anthropic

The full scripts/spec-compile.sh command applies the same check across the 55-spec compile suite. Its summary reports component and sample coverage plus explicit schema skips. Set SPEC_COMPILE_SCHEMA_ROUNDTRIP=0 only when isolating an unrelated compile failure; parse-only runs skip model round trips because they do not compile generated Rust. Failed scratch crates and logs are retained under tmp/spec-compile/.

Compatibility expectations

Until 1.0, a minor release may correct generated Rust APIs that were incomplete or wrong on the wire. Even so, changes should be additive where practical. Call out all of the following in the pull request when applicable:

  • generated method or model signature changes;
  • serialized query, path, header, or body changes;
  • new generated runtime dependencies or features;
  • configuration migrations or default changes;
  • OpenAPI constructs that remain unsupported.

Keep commits focused and use clear imperative messages. Maintainers may squash on merge.