cargo-semver-checks

repository·main·Indexed 23 days ago

https://github.com/obi1kenobi/cargo-semver-checks

A tool for scanning Rust crates to detect potential semantic versioning (SemVer) violations by linting API changes. It supports baseline specification via crates.io, git revisions, or local manifests, and can be integrated into CI pipelines via the obi1kenobi/cargo-semver-checks-action@v2 GitHub Action. Users can customize lint levels (deny, warn, allow) and required version updates (major, minor) in Cargo.toml.

Tokens
15.6K
Snippets
37
Records
95
Agent score
81%

What's inside cargo-semver-checks

  1. How the testing crate pairs work

    main

    The testing infrastructure for cargo-semver-checks uses pairs of crates to validate lints. Each pair consists of a new crate (the current version being tested) and an old crate (the baseline version).

    When a lint is executed, it runs against all crate pairs in the test_crates directory. The resulting output is stored in the ../test_outputs directory and is structured as a map where the keys are the crate pair paths and the values are sorted lists of the query outputs. The output represents the raw results of the query, comparing the new crate against the old baseline.

  2. Understand witness checks in semver lints

    main

    Some lints use a "witness": a minimal downstream code example.

    • For some lints, cargo-semver-checks creates and checks these witnesses automatically to ensure precision.
    • For others, witnesses act as an optional self-consistency check to increase certainty.

    If a witness check fails for reasons unrelated to SemVer, the tool may exit with a non-zero code and retain the generated witness code for inspection.

  3. Override workspace lint configurations in a package

    main

    When a package opts into workspace lints via workspace = true, you can still override specific settings for that package. The hierarchy of precedence is:

    1. Package configuration (highest priority)
    2. Workspace configuration
    3. Built-in defaults (lowest priority)

    If you override a single property (like required-update) in a package, the other properties (like level) will still be inherited from the workspace configuration.

    # Workspace configuration
    [workspace.metadata.cargo-semver-checks.lints]
    function_missing = { level = "warn", required-update = "minor" }
    
    # Package configuration overriding workspace
    [package.metadata.cargo-semver-checks.lints]
    workspace = true
    function_missing = "deny" 
    # Result for function_missing: level = "deny", required-update = "minor"
  4. Install cargo-semver-checks

    main

    You can install cargo-semver-checks using cargo-binstall for faster installation, or via standard cargo install with the --locked flag to ensure dependency consistency.

    # If you already use `cargo-binstall` for faster tool installations:
    $ cargo binstall cargo-semver-checks
    
    # Otherwise:
    $ cargo install cargo-semver-checks --locked
  5. Configure lints for an entire workspace

    main

    To define a shared lint configuration for all crates in a workspace, use the [workspace.metadata.cargo-semver-checks.lints] table in your workspace root Cargo.toml.

    To opt individual packages into this workspace configuration, add one of the following to the package's Cargo.toml:

    • [package.metadata.cargo-semver-checks.lints].workspace = true
    • Or, if using the standard cargo workspace linting pattern: [lints].workspace = true.

    To opt-out of workspace lints, simply omit these keys from the package's Cargo.toml.

    # In workspace root Cargo.toml
    [workspace.metadata.cargo-semver-checks.lints]
    function_must_use_added = { level = "warn" }
    
    # In individual package Cargo.toml
    [package.metadata.cargo-semver-checks.lints]
    workspace = true
  6. SemVer breakage: Marking struct fields as deprecated

    main

    In cargo-semver-checks, marking a previously public struct field as #[deprecated] is considered a SemVer breaking change. This applies to both standard fields and tuple struct fields.

    Note that if a field is already marked with #[doc(hidden)], adding a #[deprecated] attribute will not trigger a lint, as the field was already effectively removed from the public API surface.

  7. How the baseline version is chosen

    main

    When performing semver checks, a 'baseline' version is compared against the 'current' version. The logic for choosing this baseline follows these rules:

    1. If a current version is provided: The tool looks for the highest version in the registry that is less than or equal to the current version.
    2. Preference for stable releases: It prioritizes 'normal' versions (those that are not yanked and are not pre-releases).
    3. Fallback: If no stable version is found, it falls back to the highest available version (even if it is a pre-release or yanked).
    4. If no current version is provided: It simply picks the highest 'normal' version available in the registry.