GithubHelp home page GithubHelp logo

enselic / cargo-public-api Goto Github PK

View Code? Open in Web Editor NEW
372.0 6.0 23.0 4.06 MB

List and diff the public API of Rust library crates between releases and commits. Detect breaking API changes and semver violations via CI or a CLI.

Home Page: https://crates.io/crates/cargo-public-api

License: MIT License

Rust 98.74% Shell 1.26%
cargo-subcommand cargo-plugin rust cargo api diff semver rustdoc-json

cargo-public-api's Introduction

cargo-public-api

List and diff the public API of Rust library crates between releases and commits. Detect breaking API changes and semver violations via CI or a CLI. Relies on and automatically builds rustdoc JSON, for which a recent version of the Rust nightly toolchain must be installed.

Installation

Install the cargo public-api subcommand with a recent regular stable Rust toolchain:

cargo +stable install cargo-public-api --locked

Ensure nightly-2024-06-07 or later is installed (does not need to be the active toolchain) so cargo public-api can build rustdoc JSON for you:

rustup install nightly --profile minimal

Usage

List the Public API

This example lists the public API of the regex crate. First we clone the repo:

git clone https://github.com/rust-lang/regex ; cd regex

Now we can list the public API of regex by running

cargo public-api

which will print the public API of regex with one line per public item in the API:

colored output of listing a public api

Diff the Public API

… Against a Specific Published Version

To diff the public API of the regex crate in the current directory against published version 1.6.0 on crates.io:

cargo public-api diff 1.6.0

colored output of diffing a public api

… Against the Latest Published Version

cargo public-api diff latest

… Between Git Commits

cargo public-api diff ref1..ref2

… as a CI Check

With a regular cargo test that you run in CI you will be able to

  • prevent accidental changes to your public API
  • review the public API diff of deliberate changes

First add the latest versions of the recommended libraries to your [dev-dependencies]:

cargo add --dev \
    rustup-toolchain \
    rustdoc-json \
    public-api \
    expect-test

Then add the following test to your project. As the author of the below test code, I hereby associate it with CC0 and to the extent possible under law waive all copyright and related or neighboring rights to it:

#[test]
fn public_api() {
    // Install a compatible nightly toolchain if it is missing
    rustup_toolchain::install(public_api::MINIMUM_NIGHTLY_RUST_VERSION).unwrap();

    // Build rustdoc JSON
    let rustdoc_json = rustdoc_json::Builder::default()
        .toolchain(public_api::MINIMUM_NIGHTLY_RUST_VERSION)
        .build()
        .unwrap();

    // Derive the public API from the rustdoc JSON
    let public_api = public_api::Builder::from_rustdoc_json(rustdoc_json)
        .build()
        .unwrap();

    // Assert that the public API looks correct
    expect_test::expect_file!["public-api.txt"].assert_eq(&public_api.to_string());
}

Before you run the test the first time you need to bless the current public API:

UPDATE_EXPECT=1 cargo test public_api

This creates a tests/public-api.txt file in your project that you git add together with your other project files. Whenever you change the public API, you need to bless it again with the above command. If you forget to bless, the test will fail, together with instructions on how to bless.

Less Noisy Output

For completeness, items belonging to Blanket Implementations, Auto Trait Implementations, and Auto Derived Implementations, such as

  • impl<T, U> Into<U> for T where U: From<T>
  • impl Sync for ...
  • impl Debug for ... / #[derive(Debug)]

are included in the list of public items by default. Use

  • --omit blanket-impls
  • --omit auto-trait-impls
  • --omit auto-derived-impls

respectively to omit such items from the output to make it much less noisy:

cargo public-api --omit blanket-impls,auto-trait-impls,auto-derived-impls

For convenience you can also use -s (--simplified) to achieve the same thing. This is a shorter form of the above command:

cargo public-api -sss

Compatibility Matrix

Version Understands the rustdoc JSON output of
0.35.x — 0.36.x nightly-2024-06-07 —
0.32.x — 0.34.x nightly-2023-08-25 — nightly-2024-06-06
0.30.x — 0.31.x nightly-2023-05-24 — nightly-2023-08-24
earlier versions see here

Changelog

See CHANGELOG.md.

Contributing

See CONTRIBUTING.md.

Maintainers

cargo-public-api's People

Contributors

dependabot[bot] avatar dimpolo avatar dnaka91 avatar douweschulte avatar emilgardis avatar enselic avatar enseliccicd avatar fornwall avatar fraser999 avatar frondeus avatar inikulin avatar jake-shadle avatar kornelski avatar matthiasbeyer avatar mqudsi avatar nbraud avatar orium avatar repi avatar supercilex avatar tim-day-387 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

cargo-public-api's Issues

Add `--diff` that automatically selects `--diff-git-checkouts` or `--diff-rustdoc-json`

It quickly becomes tiresome to write out --diff-git-checkouts. It would be nice with an "intelligent" version called --diff, that based on if the args end in .json or not automatically selects the most appropriate diffing method.

So

  • cargo public-api --diff v0.2.0 v0.3.0 would be interpreted as cargo public-api --diff-git-checkouts v0.2.0 v0.3.0
  • cargo public-api --diff some_crate_v0.2.0.json some_crate_v0.3.0.json would be interpreted as cargo public-api --diff-rustdoc-json some_crate_v0.2.0.json some_crate_v0.3.0.json

And in the future for #124 we could maybe even have

Add --deny undocumented option

It would be nice to have --deny undocumented option that will complain if doc comments are missing for any of the public API values. #[deny(missing_docs)] doesn't work properly with workspaces that have multiple crates with the main crate defining API surfaces and re-exporting stuff from the internal crates - it captures undocumented API defined in the main crate itself. So, the only option is to add #[deny(missing_docs)] to all the internal crates, but it's not always feasible or practical.

I'm willing to implement this feature.

Proposal: Remove `--output-format markdown` support

I would like to remove all code related to Markdown output, including the --output-format arg itself. But before I do, I wanted to give others a chance to raise objections.

The thing is, I find myself never ever using --output-format markdown. So it makes me wonder if anyone uses it. If not, we should remove the code. Removing the code has the following benefits:

  • The test suite becomes faster to run because we can remove the Markdown tests
  • It becomes easier to develop new features because no regard has to be taken to markdown output
  • Maintenance becomes easier because there will be fewer tests to keep up to date. This is especially true for the "expected output" part of the tests, which changes quite frequently.
  • The code base becomes simpler

The downsides are:

  • If we ever want to add some other output format, we need to bring back --output-format again. I think that will be easy though.

The Markdown output format pre-dates the syntax highlighted/token based output format, which over time has turned out to be superior. So Markdown output is just old legacy cruft at this point. At least from my perspective.

If no objections are raised, I plan to remove the code approximately 1 week from now. If discussions arise then I will postpone or abort.

Re-exporting an external module does not include its public API

One of our crates, cervo, is a basic wrapper crate that depends on 4 other crates and just use them like this to have a single convenient crate with that includes the API of all of the 4 ones it depends on.

pub use cervo_asset as asset;
pub use cervo_core as core;
pub use cervo_nnef as nnef;
pub use cervo_onnx as onnx;

This results in this output:

pub mod cervo
pub use cervo::asset
pub use cervo::core
pub use cervo::nnef
pub use cervo::onnx

which is similar to the rustdoc output:

image

but it is not correct in the case of exhaustively describing the public API of the crate.

Think it would have to for re-exports instead of listing that just as a use statement in the output instead include the entire module output for each re-export?

Be able build for a specific target triple with `--target`

We have a set of crates with public APIs that we build and use only for a specific target, wasm32-unknown-unknown. Building with just cargo public-api results in no relevant API, as they require to be built with Cargo/rustdoc --target wasm32-unknown-unknown, so would be great to support such an option similar to how Cargo & rustdoc does itself.

Took a look at it and looks to be quite simple so may attempt it myself.

Related:

Diff sometimes unnecessarily big, caused by a off-by-one problem of sorts

Step-by-step

  1. Run cargo public-api --diff-git-checkouts v0.20.0 v0.21.0 in https://github.com/sharkdp/bat

Expected result

This diff is printed:

Removed items from the public API
=================================
(none)

Changed items in the public API
===============================
-pub enum variant bat::error::Error::SyntectError(::syntect::LoadingError)
+pub enum variant bat::error::Error::SyntectError(::syntect::Error)

Added items to the public API
=============================
+pub enum variant bat::error::Error::SyntectLoadingError(::syntect::LoadingError)
+pub enum variant bat::style::StyleComponent::Default
+pub fn bat::PrettyPrinter::show_nonprintable(&mut self, yes: bool) -> &mut Self
+pub fn bat::error::Error::from(source: ::syntect::Error) -> Self

Actual result

This diff is printed

Removed items from the public API
=================================
(none)

Changed items in the public API
===============================
-pub enum variant bat::error::Error::SyntectError(::syntect::LoadingError)
+pub enum variant bat::error::Error::SyntectError(::syntect::Error)
-pub fn bat::error::Error::from(s: &'static str) -> Self
+pub fn bat::error::Error::from(s: String) -> Self
-pub fn bat::error::Error::from(s: String) -> Self
+pub fn bat::error::Error::from(source: ::globset::Error) -> Self
-pub fn bat::error::Error::from(source: ::globset::Error) -> Self
+pub fn bat::error::Error::from(source: ::serde_yaml::Error) -> Self
-pub fn bat::error::Error::from(source: ::serde_yaml::Error) -> Self
+pub fn bat::error::Error::from(source: ::std::io::Error) -> Self
-pub fn bat::error::Error::from(source: ::std::io::Error) -> Self
+pub fn bat::error::Error::from(source: ::std::num::ParseIntError) -> Self
-pub fn bat::error::Error::from(source: ::std::num::ParseIntError) -> Self
+pub fn bat::error::Error::from(source: ::syntect::Error) -> Self

Added items to the public API
=============================
+pub enum variant bat::error::Error::SyntectLoadingError(::syntect::LoadingError)
+pub enum variant bat::style::StyleComponent::Default
+pub fn bat::PrettyPrinter::show_nonprintable(&mut self, yes: bool) -> &mut Self
+pub fn bat::error::Error::from(s: &'static str) -> Self

it is easy to see that the actual diff, while not wrong, is unnecessarily big. It seems to suffer from "off-by-one" error of sorts in the diffing algorithm.

I think I have a solution for this and will create a draft PR shortly.

trait supertrait is not rendered

the following code

pub trait T: private::Sealed + Send {}

impl T for () {}

mod private {
    pub trait Sealed {}
    impl Sealed for () {}
}

generates

pub mod krate
pub trait krate::T

the supertrait private::Sealed + Send should be rendered here.

one side note also, the implementor T for () should be rendered, is there an issue for that available?

Be able to enable `--features` / `--all-features` / `--no-default-features`

Would it be possible to add support for the Cargo --features / --all-features / --no-default-features options? Pipe them through to the underlying Cargo invocation.

We have multiple crates where we are both interested in the public API with --all-features enabled and also some where one wants to check for specific --features.

For example our puffin crate has a mutually exclusive features (not ideal) and fails to analyse:

$ cargo public-api --manifest-path ./puffin/Cargo.toml
    Checking once_cell v1.9.0
    Checking byteorder v1.4.3
 Documenting puffin v0.12.1 (/Users/repi/git/embark/puffin/puffin)
error: Either feature zstd or ruzstd must be enabled
   --> puffin/src/frame_data.rs:491:1
    |
491 | compile_error!("Either feature zstd or ruzstd must be enabled");
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: Compilation failed, aborting rustdoc

error: could not document `puffin`

Caused by:
  process didn't exit successfully: `rustdoc --edition=2018 --crate-type lib --crate-name puffin puffin/src/lib.rs -o /Users/repi/git/embark/puffin/target/doc --cfg 'feature="default"' --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat -Z unstable-options --output-format json --cap-lints warn -C metadata=00aac93aa62b9ad4 -L dependency=/Users/repi/git/embark/puffin/target/debug/deps --extern byteorder=/Users/repi/git/embark/puffin/target/debug/deps/libbyteorder-922739cc82a0baa2.rmeta --extern once_cell=/Users/repi/git/embark/puffin/target/debug/deps/libonce_cell-b334803526b5c51d.rmeta --crate-version 0.12.1` (exit status: 1)
Error: Failed to build rustdoc JSON. Stderr: See above

Add option to force git checkouts

I see from the --diff-git-checkouts option description that inability to do git checkout on a dirty tree is a feature. However, there are cases where it's not desirable. In our case rust build script produces some artefacts that are supposed to be checked in the repo. So, when the tool checks out the first commit and generates the docs the tree is not clean and the tools fails to checkout the second commit.

Would you accept a PR implementing an additional --force-git-checkouts option?

Group items in a more logical manner

Right now structs are in one group and struct fields are in another group. It would be much more logical to group a struct together with its struct fields. Same with enum and enum variants, struct and associated methods, etc.

Output is e.g. `&mut Write` instead of `&mut dyn Write`

Our integration test for bat contains this line:

pub fn bat::controller::Controller::run_with_error_handler(&self, inputs: Vec<Input<'_>>, handle_error: impl Fn(&Error, &mut Write)) -> Result<bool>

but it should be

pub fn bat::controller::Controller::run_with_error_handler(&self, inputs: Vec<Input<'_>>, handle_error: impl Fn(&Error, &mut dyn Write)) -> Result<bool>

which is what docs.rs displays.

From `nightly-2022-07-17`, re-exports from private modules show no type/kind

Consider this src/lib.rs:

mod private {
    pub fn f(x: usize) {}
}
pub use private::f;

With rustdoc JSON built by nightly-2022-07-16, our tooling will give this list of public items:

pub fn example_api::f(x: usize)
pub mod example_api

With rustdoc JSON built by nightly-2022-07-17, our tooling will give this list of public items:

pub mod example_api
pub use example_api::f

This is problematic for us, because e.g. doing an API diff after changing the parameter type of f(x: usize) to something else, the diff will show nothing, since the type is not part of the output any longer. It also deviates from the corresponding cargo doc HTML output, which performs inlining.

This was changed upstream by rust-lang/rust#99287 to fix a handful of ICEs, so there is good reason for it.

I think the fix from our side should be to manually inline items re-exported from private modules. I have done some prototyping and it does not seem that hard to do. I do however think rustdoc JSON should expose the parent of an item in a convenient way first (rust-lang/rust#93524). I will try to get that fixed.

Note that we do not need to bump MINIMUM_RUSTDOC_JSON_VERSION yet because of this, because we can still parse the output from both toolchains. The output has only changed form, not format (in an incompatible way).

Suggest the next version number automatically

Hi,

Thanks for this great tool! One thing I would find very useful would be a way to get cargo-public-api to look at all changes on the current branch since the latest git tag, and based on what those are, suggest what version number the next release should have. (i.e. Increment the latest git tag's minor version by one if no breaking changes were made since the tag, increment the major version if there are breaking changes in the public api etc.)

Motivation: each release would be semver compliant without the user publishing the release needing to think about it too much. If everyone would use this feature when publishing crates, there would theoretically be no semver-incompliant releases... ;)

Syntax highlighted output

It would be nice to syntax highlight the output. Should be pretty easy.

  1. Create a custom sublime syntax for the output format
  2. Use the bat library to highlight the output

Rename project to `cargo-public-api`

I would like to rename this project to cargo-public-api.

The main reason is that the term "public items" is not widely understood (because it requires people to know that the rustc term for many language constructs is "item"), whereas the term "public api" is widely understood.

So for example, we can simplify our project description from

List and diff public items (the public API) of Rust library crates.

to

List and diff the public API of Rust library crates.

Another benefit is that the project will be easier to find by people, who are more likely to search for a tool of our kind using the term "public api" than "public items".

And, cargo public-api --diff-git-checkouts makes better semantic sense IMO.

What about public_items?

I do not however think we should rename public_items to e.g. public_api. Mainly because that library is working with "rustc items", and not really with "apis". It makes sense for a tool called cargo-public-api to be a user-friendly tool that is implemented with a low-level library called public_items.

Besides, the API would become weird if we also renamed public_items:

  • public_api::public_items_from_rustdoc_json_str is annoyingly assymetrical
  • public_api::public_api_from_rustdoc_json_strdoes not make much sense

Add `--diff-git-checkouts` to diff public API conveniently across versions

To e.g. diff public API between v0.2.0 and v0.3.0 of this repo, one would simply do

cargo public-items --diff-between-git-commits v0.2.0 v0.3.0

which would

  1. checkout v0.2.0,
  2. list public items and save the result
  3. checkout v0.3.0
  4. run the tool and save the the result
  5. Print the diff between 2 and 4

[QUESTION] Could --rustdoc-json-toolchain be part of the public API?

My use case is that I'm caching a specific version of cargo-public-api in a CI job so that it won't be recompiled every run. The problem is that eventually nightly will be incompatible with the cached version. So I would like to tell cargo-public-api to use a pinned nightly version instead of the latest one. Looking through the repo, I realized that this flag would do the job, but it is undocumented. Could this feature be stabilized in some way?
Thank you for considering it!

Install fails unless --locked option is set

Hi!

This looks like a really great tool. I just tried to install it using the instructions in the README and hit the following issue:

$ cargo install cargo-public-api
    Updating crates.io index
  Downloaded cargo-public-api v0.12.0
  Downloaded 1 crate (14.4 KB) in 0.28s
  Installing cargo-public-api v0.12.0
  Downloaded clap_derive v3.2.6
  Downloaded clap v3.2.6
  Downloaded unicode-ident v1.0.1
  Downloaded indexmap v1.9.1
  Downloaded proc-macro2 v1.0.40
  Downloaded clap_lex v0.2.3
  Downloaded hashbrown v0.12.1
  Downloaded cargo_toml v0.11.5
  Downloaded anyhow v1.0.58
  Downloaded diff v0.1.12
  Downloaded public-api v0.12.0
  Downloaded hashbag v0.1.6
  Downloaded syn v1.0.98
  Downloaded quote v1.0.20
  Downloaded rustdoc-types v0.11.0
  Downloaded 15 crates (876.4 KB) in 0.93s
   Compiling proc-macro2 v1.0.40
   Compiling unicode-ident v1.0.1
   Compiling quote v1.0.20
   Compiling syn v1.0.98
   Compiling serde_derive v1.0.137
   Compiling serde v1.0.137
   Compiling version_check v0.9.4
   Compiling autocfg v1.1.0
   Compiling libc v0.2.126
   Compiling serde_json v1.0.81
   Compiling itoa v1.0.2
   Compiling ryu v1.0.10
   Compiling semver v1.0.10
   Compiling camino v1.0.9
   Compiling hashbrown v0.12.1
   Compiling heck v0.4.0
   Compiling os_str_bytes v6.1.0
   Compiling anyhow v1.0.58
   Compiling strsim v0.10.0
   Compiling bitflags v1.3.2
   Compiling termcolor v1.1.3
   Compiling textwrap v0.15.0
   Compiling hashbag v0.1.6
   Compiling once_cell v1.12.0
   Compiling diff v0.1.12
   Compiling ansi_term v0.12.1
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling indexmap v1.9.1
   Compiling clap_lex v0.2.3
   Compiling atty v0.2.14
   Compiling thiserror-impl v1.0.31
   Compiling clap_derive v3.2.6
   Compiling thiserror v1.0.31
   Compiling clap v3.2.6
   Compiling toml v0.5.9
   Compiling rustdoc-types v0.11.0
   Compiling cargo-platform v0.1.2
   Compiling cargo_metadata v0.14.2
   Compiling cargo_toml v0.11.5
   Compiling public-api v0.12.0
error[E0271]: type mismatch resolving `<impl Iterator<Item = (&PublicItem, usize)> as Iterator>::Item == &PublicItem`
   --> /Users/james.hallowell/.cargo/registry/src/github.com-1ecc6299db9ec823/public-api-0.12.0/src/diff.rs:70:48
    |
70  |         let mut removed_paths: ItemsWithPath = bag_to_path_map(all_removed);
    |                                                ^^^^^^^^^^^^^^^ expected `&PublicItem`, found tuple
    |
    = note: expected reference `&PublicItem`
                   found tuple `(&PublicItem, usize)`
note: required by a bound in `bag_to_path_map`
   --> /Users/james.hallowell/.cargo/registry/src/github.com-1ecc6299db9ec823/public-api-0.12.0/src/diff.rs:116:47
    |
116 | fn bag_to_path_map<'a>(hashbag: impl Iterator<Item = &'a PublicItem>) -> ItemsWithPath {
    |                                               ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bag_to_path_map`

error[E0271]: type mismatch resolving `<impl Iterator<Item = (&PublicItem, usize)> as Iterator>::Item == &PublicItem`
   --> /Users/james.hallowell/.cargo/registry/src/github.com-1ecc6299db9ec823/public-api-0.12.0/src/diff.rs:71:46
    |
71  |         let mut added_paths: ItemsWithPath = bag_to_path_map(all_added);
    |                                              ^^^^^^^^^^^^^^^ expected `&PublicItem`, found tuple
    |
    = note: expected reference `&PublicItem`
                   found tuple `(&PublicItem, usize)`
note: required by a bound in `bag_to_path_map`
   --> /Users/james.hallowell/.cargo/registry/src/github.com-1ecc6299db9ec823/public-api-0.12.0/src/diff.rs:116:47
    |
116 | fn bag_to_path_map<'a>(hashbag: impl Iterator<Item = &'a PublicItem>) -> ItemsWithPath {
    |                                               ^^^^^^^^^^^^^^^^^^^^^ required by this bound in `bag_to_path_map`

For more information about this error, try `rustc --explain E0271`.
error: could not compile `public-api` due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error: failed to compile `cargo-public-api v0.12.0`, intermediate artifacts can be found at `/var/folders/2j/z687lxf542q2syccnrr_2fx80000gn/T/cargo-installrUofUg

I had a look in the CI config for this repo and noticed the --locked flag is being passed in, so tried setting that, which did let me install the tool successfully:

$ cargo install cargo-public-api --locked
    Updating crates.io index
  Installing cargo-public-api v0.12.0
  Downloaded clap_derive v3.2.5
  Downloaded hashbag v0.1.5
  Downloaded clap_lex v0.2.2
  Downloaded indexmap v1.9.0
  Downloaded clap v3.2.5
  Downloaded 5 crates (313.7 KB) in 0.39s
   Compiling proc-macro2 v1.0.40
   Compiling unicode-ident v1.0.1
   Compiling quote v1.0.20
   Compiling syn v1.0.98
   Compiling serde_derive v1.0.137
   Compiling serde v1.0.137
   Compiling version_check v0.9.4
   Compiling autocfg v1.1.0
   Compiling libc v0.2.126
   Compiling serde_json v1.0.81
   Compiling itoa v1.0.2
   Compiling camino v1.0.9
   Compiling semver v1.0.10
   Compiling ryu v1.0.10
   Compiling hashbrown v0.12.1
   Compiling anyhow v1.0.58
   Compiling heck v0.4.0
   Compiling os_str_bytes v6.1.0
   Compiling hashbag v0.1.5
   Compiling textwrap v0.15.0
   Compiling termcolor v1.1.3
   Compiling bitflags v1.3.2
   Compiling once_cell v1.12.0
   Compiling strsim v0.10.0
   Compiling diff v0.1.12
   Compiling ansi_term v0.12.1
   Compiling proc-macro-error-attr v1.0.4
   Compiling proc-macro-error v1.0.4
   Compiling indexmap v1.9.0
   Compiling clap_lex v0.2.2
   Compiling atty v0.2.14
   Compiling thiserror-impl v1.0.31
   Compiling clap_derive v3.2.5
   Compiling thiserror v1.0.31
   Compiling clap v3.2.5
   Compiling rustdoc-types v0.11.0
   Compiling toml v0.5.9
   Compiling cargo-platform v0.1.2
   Compiling cargo_metadata v0.14.2
   Compiling cargo_toml v0.11.5
   Compiling public-api v0.12.0
   Compiling cargo-public-api v0.12.0
    Finished release [optimized] target(s) in 27.74s
  Installing /Users/james.hallowell/.cargo/bin/cargo-public-api
   Installed package `cargo-public-api v0.12.0` (executable `cargo-public-api`)

One difference appears to be the version of hashbag, it succeeds with hashbag v0.1.5, but failed on v0.1.6. Having a dig around in that repo it looks like possibly its something related to this change - jonhoo/hashbag@4b9fe77 - based on the compiler error I hit.

Let me know if I can provide any further information that would be useful.

Thanks!

Public member functions & trait impls are missing for wildcard `use`ed module

If one does a wildcard use of an internal module, such as use xx::* this will include public types and functions in that module, but it will miss any member functions or trait implementations of types inside that module if the module is not public.

Example

Given this code:

mod a {
    pub mod a1 {
        #[derive(Copy, Clone)]
        pub struct Test {}

        impl Test {
            pub fn test2() {}
        }

        pub fn test1() {}
    }
}

pub use a::*;

this generates this output which is missing the test2 member function and the derived clone member function:

pub fn api_test::a1::test1()
pub mod api_test
pub mod api_test::a1
pub struct api_test::a1::Test

but it should be:

pub fn api_test::a1::Test::clone(&self) -> api_test::a1::Test
pub fn api_test::a1::Test::test2()
pub fn api_test::a1::test1()
pub mod api_test
pub mod api_test::a
pub mod api_test::a1
pub mod api_test::a::a1
pub struct api_test::a1::Test
pub struct api_test::a::a1::Test

if one change mod a to pub mod a then the member functions are correctly included both under the a module and from the use a::* statement.

ICE when trying to list public API of e.g. `serde` or `diesel`

Step-by-step:

  1. git clone https://github.com/serde-rs/serde (another example is diesel
  2. cd serde
  3. cargo public-api

Expected:

Public API listed

Actual:

ICE: thread 'rustc' panicked at 'assertion failed: (left == right)

Technical analysis

This happens when cargo public-api invokes RUSTDOCFLAGS='-Z unstable-options --output-format json' cargo +nightly doc --lib --no-deps behind the scenes. Running that command manually also produces an ICE.

I have not verified it myself, but this seems like it will be fixed when rust-lang/rust#93518 lands.

Updated sort order

To keep related items instead of the current related kinds together it is proposed to sort based on the item path instead of the item string representation. See Enselic/public-api#53 (comment) for a possible implementation and more discussion.

Current situation:

- pub enum path::one::enum
- pub fn path::extra::enum::do_something()
- (possibly more fn)
- pub fn path::one::enum::do_something()

Proposed sorting

- pub fn path::extra::enum::do_something()
- pub enum path::one::enum
- pub fn path::one::enum::do_something()
- (possibly more fn)

`--with-blanket-implementations` test fails with `nightly-2022-06-29`

The nightly job detected a change with rustc 1.64.0-nightly (830880640 2022-06-28) with this diff:

-pub type example_api::Struct::Error = <U as TryFrom<T>>::Error
-pub type example_api::Struct::Error = Infallible
-pub type example_api::StructV2::Error = <U as TryFrom<T>>::Error
-pub type example_api::StructV2::Error = Infallible
+pub type example_api::Struct::Error
+pub type example_api::Struct::Error
+pub type example_api::StructV2::Error
+pub type example_api::StructV2::Error

this looks like a regression in rustdoc, so we should maybe fix this in rustdoc rather than update expected output in cargo-public-api. Requires more investigation. Main offending commit suspect is rust-lang/rust@c1c0d25.

Incorrect output for associated types in traits

With this code:

pub trait Trait {
    type Frobnicator;

    fn frobnicate(&self) -> Self::Frobnicator;
}

The output of cargo public-api is: (Note <Self as >)

pub fn public_api_test::Trait::frobnicate(&self) -> <Self as >::Frobnicator
pub mod public_api_test
pub trait public_api_test::Trait
pub type public_api_test::Trait::Frobnicator

I think the expected output should be: (Note <Self as Trait>)

pub fn public_api_test::Trait::frobnicate(&self) -> <Self as Trait>::Frobnicator
pub mod public_api_test
pub trait public_api_test::Trait
pub type public_api_test::Trait::Frobnicator

Include value of explicit enum discriminants?

It would be great to be able to include the value of explicit enum discriminants in the listings of enum variants, as that is often part of APIs/ABIs and with conversions to/from integers. So an API change to one such value could be breaking semver or ABI change.

We have for example an enum as part of our API & ABI that looks like this:

#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
#[repr(u32)]
#[non_exhaustive]
pub enum VirtualKeyCode {
    Key1 = 1,
    Key2 = 2,
    Key3 = 3,
    Key4 = 4,

    A = 10,
    B = 11,
    C = 12,
    D = 13,
}

this gives the listing output:

#[repr(u32)] #[non_exhaustive] pub enum public_api_tests::VirtualKeyCode
pub const public_api_tests::VirtualKeyCode::NAME: &'static str
pub enum variant public_api_tests::VirtualKeyCode::A
pub enum variant public_api_tests::VirtualKeyCode::B
pub enum variant public_api_tests::VirtualKeyCode::C
pub enum variant public_api_tests::VirtualKeyCode::D
pub enum variant public_api_tests::VirtualKeyCode::Key1
pub enum variant public_api_tests::VirtualKeyCode::Key2
pub enum variant public_api_tests::VirtualKeyCode::Key3
pub enum variant public_api_tests::VirtualKeyCode::Key4
pub fn public_api_tests::VirtualKeyCode::try_from(number: u32) -> ::core::result::Result<Self, ::num_enum::TryFromPrimitiveError<Self>>
pub fn public_api_tests::VirtualKeyCode::try_from_primitive(number: <Self as >::Primitive) -> ::core::result::Result<Self, ::num_enum::TryFromPrimitiveError<Self>>
pub mod public_api_tests
pub type public_api_tests::VirtualKeyCode::Error = TryFromPrimitiveError<VirtualKeyCode>
pub type public_api_tests::VirtualKeyCode::Primitive = u32

but the output I would have wanted is:

  #[repr(u32)] #[non_exhaustive] pub enum public_api_tests::VirtualKeyCode
  pub const public_api_tests::VirtualKeyCode::NAME: &'static str
- pub enum variant public_api_tests::VirtualKeyCode::A
+ pub enum variant public_api_tests::VirtualKeyCode::A = 10u32
- pub enum variant public_api_tests::VirtualKeyCode::B
+ pub enum variant public_api_tests::VirtualKeyCode::B = 11u32
- pub enum variant public_api_tests::VirtualKeyCode::C
+ pub enum variant public_api_tests::VirtualKeyCode::C = 12u32
- pub enum variant public_api_tests::VirtualKeyCode::D
+ pub enum variant public_api_tests::VirtualKeyCode::D = 13u32
- pub enum variant public_api_tests::VirtualKeyCode::Key1
+ pub enum variant public_api_tests::VirtualKeyCode::Key1 = 1u32
- pub enum variant public_api_tests::VirtualKeyCode::Key2
+ pub enum variant public_api_tests::VirtualKeyCode::Key2 = 2u32
- pub enum variant public_api_tests::VirtualKeyCode::Key3
+ pub enum variant public_api_tests::VirtualKeyCode::Key3 = 3u32
- pub enum variant public_api_tests::VirtualKeyCode::Key4
+ pub enum variant public_api_tests::VirtualKeyCode::Key4 = 4u32
  pub fn public_api_tests::VirtualKeyCode::try_from(number: u32) -> ::core::result::Result<Self, ::num_enum::TryFromPrimitiveError<Self>>
  pub fn public_api_tests::VirtualKeyCode::try_from_primitive(number: <Self as >::Primitive) -> ::core::result::Result<Self, ::num_enum::TryFromPrimitiveError<Self>>
  pub mod public_api_tests
  pub type public_api_tests::VirtualKeyCode::Error = TryFromPrimitiveError<VirtualKeyCode>
  pub type public_api_tests::VirtualKeyCode::Primitive = u32

Looks like rustdoc does not include the enum descriminants in its output so this is likely a current upstream limitation?

Make tests run in parallel (stop using `#[serial]`)

Currently, we have plenty of #[serial] tests, because there are shared resources, such as git repositories or build directories.

This makes running cargo test quite slow. Annoyingly slow, IMHO. And the more tests we add, the worse it will become.

I have done some prototyping and have come pretty far in solving it, but since I plan to do it in several steps, I wanted to create a parent issue for that work. Which is this issue.

warn when toolchain is replaced with nightly

Some type of warning should probably be emited when the used toolchain, specified explicitly or not, is not used for rustdoc.

This due to lessen the belief that cargo +stable public-api actually works, even if it doesn't right now.

Collaboration?

I was just wondering where we stood on collaboration. In crate-ci/cargo-crate-api#18 it sounded like there was interest though it looks like development has continued here, so unsure if that was a misunderstanding.

Struct fields of enum tuple struct are not included in the output

Consider this code in src/lib.rs:

enum Foo {
  Bar(usize)
}

This code contains at least 3 public items:

  1. The enum itself
  2. The enum variant Bar which is a tuple struct variant
  3. The struct field called 0 of type usize that corresponds to the first field of the enum variant tuple struct Bar

With the new ItemIterator architecture (see Enselic/public-api#15), the struct field (i.e. item 3 in the list above) will be completely missing from the output. That is because it is not references by the enum variant.

This is not that big of a deal since the tuple type on Bar itself conveys enough information to make conclusions about if the API has changed.

This will be fixed more or less automatically when rust-lang/rust#92945 is fixed.

Show Impls instead of all functions

As part of the tree data structure I was thinking about showing the impls of a struct/enum/trait instead of the full list of functions. For local traits the functions will already be in the list (in the trait definition) and for other traits the functions can be assumed to be known or at least less part of this crates api and more for that other crate. Also this should remove clutter if only a trait is updated this should only list this change one time and not for every entity implementing it.

Implementing this change would be a nice first step for a more tree like data structure as discussed before. I have already tried some things locally but nothing is working yet.

Mock up:

#[derive(Clone, Copy, Debug)]
pub struct Plain {
    pub x: usize,
}

Output:

pub struct comprehensive_api::structs::Plain
Implements: Clone, Copy, Debug

Inspecting the standard library

I would like a way to automatically find all the types in std, but naively pointing cargo public-api at std fails because it can't find core and other dependencies.

$ cargo public-api --manifest-path $(rustc --print sysroot)/lib/rustlib/src/rust/library/std/Cargo.toml
Error: Failed to build rustdoc JSON. Stderr:     Checking compiler_builtins v0.1.78
    Checking libc v0.2.127
   Compiling unwind v0.0.0 (/home/michael/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/unwind)
error[E0433]: failed to resolve: could not find `prelude` in `core`

error[E0432]: unresolved import `core::ops`
 --> /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.78/src/float/mod.rs:1:5
  |
1 | use core::ops;
  |     ^^^^^^^^^ no `ops` in the root

error[E0432]: unresolved import `core::intrinsics`
  --> /home/michael/.cargo/registry/src/github.com-1ecc6299db9ec823/compiler_builtins-0.1.78/src/mem/mod.rs:11:11
   |
11 | use core::intrinsics::{atomic_load_unordered, atomic_store_unordered, exact_div};
   |           ^^^^^^^^^^ could not find `intrinsics` in `core`

...

Presumably rustc does something funky with the sysroot that cargo public-api doesn't).

Do you have any suggestions for how I might be able to achieve this?

Machine readable output for git diffs

It would be nice to have a machine-readable output for the diffing tool (e.g. JSON), so upstream tools can consume it. E.g. having diffing running in CI and sending chat notifications about breaking changes.

Be able to diff workspace crate against published crate version

It would be great to have an alternative to --diff-git-checkouts that instead of syncing a previous commit of the same repo (which can be a quite heavy and complex operation on a large repo) you can compare against a previously published crate version on crates.io. Have there been any thoughts of such an alternative?

So something like --diff-published-crate x.y.z which downloads the crate from crates.io (or the registry it was specified to use), unpacks it, and compares it from that.

We have a monorepo that has rust-toolchain.toml and lots of forked dependencies so syncing previous git versions and comparing that can be a bit problematic and slow. Also makes it harder if you have pending staged changes etc.

"error: no such subcommand: `+nightly-2022-09-07`" when using rustdoc-json on windows

It seems I'm running into this bug rust-lang/rustup#3036
Nested cargo invocations have issues in recent versions of rustup on windows.

I'm trying to run code like:

rustdoc_json::build(BuildOptions::default().toolchain("+nightly"))

I'm on Windows 11

I can work around the issue by making cargo_rustdoc_command call rustup run nightly-2022-09-07 cargo ... instead of cargo +nightly-2022-09-07 ...

What is the correct way to run nested a cargo with a different toolchain?

Toml parsing fails if it uses workspace keys

This:

[package]
version.workspace = true

Causes the following crash

thread 'api' panicked at 'called `Result::unwrap()` on an `Err` value: CargoTomlError(Parse(Error { inner: ErrorInner { kind: Custom, line: Some(2), col: 20, at: Some(50), message: "invalid type: map, expected a string", key: ["package", "version"] } }))', fuc_engine/tests/api.rs:10:82

Not using *.workspace = true fixes the issue.

Support for `.cargo/config.toml`

On some of our internal crates that I've been testing cargo-public-api on they have successfully built with rustdoc (manually and through cargo public-api) but then failed on:

    Finished dev [unoptimized + debuginfo] target(s) in 7.05s
Error: Failed to read rustdoc JSON at "/home/repi/git/test-module/target/doc/module.json"

Caused by:
    No such file or directory (os error 2)

And indeed there is no rustdoc JSON filed output there. So feels like a rustdoc failure somehow even though it doesn't log out anything about it?

Privately renamed items can be visible in the public API listing

Ran into multiple problems regarding use statements on types (not not pub use) where the public API listing will be referring internal naming of the type within the module rather than the public type it is actually referring to.

This input:

use macaw as internal_name_for_a_crate;
use macaw::Conformal3;
use macaw::Conformal3 as WeirdName;

pub fn test1(_transform: Conformal3) {}
pub fn test2(_transform: WeirdName) {}
pub fn test3(_transform: macaw::Conformal3) {}
pub fn test4(_transform: internal_name_for_a_crate::Conformal3) {}

pub enum Test {
    V1(Conformal3),
    V2(WeirdName),
    V3(macaw::Conformal3),
    V4(internal_name_for_a_crate::Conformal3),
}

Generates this output:

pub enum a2::Test
pub enum variant a2::Test::V1(Conformal3)
pub enum variant a2::Test::V2(WeirdName)
pub enum variant a2::Test::V3(macaw::Conformal3)
pub enum variant a2::Test::V4(internal_name_for_a_crate::Conformal3)
pub fn a2::test1(_transform: Conformal3)
pub fn a2::test2(_transform: WeirdName)
pub fn a2::test3(_transform: macaw::Conformal3)
pub fn a2::test4(_transform: internal_name_for_a_crate::Conformal3)
pub mod a2

Which I believe needs to be this to reflect what the public API actually is and not "leak" any internal naming within the crate module.

pub enum a2::Test
pub enum variant a2::Test::V1(macaw::Conformal3)
pub enum variant a2::Test::V2(macaw::Conformal3)
pub enum variant a2::Test::V3(macaw::Conformal3)
pub enum variant a2::Test::V4(macaw::Conformal3)
pub fn a2::test1(_transform: macaw::Conformal3)
pub fn a2::test2(_transform: macaw::Conformal3)
pub fn a2::test3(_transform: macaw::Conformal3)
pub fn a2::test4(_transform: macaw::Conformal3)
pub mod a2

Rustdoc HTML handles the the function output here correctly referring to all of them as Conformal3 but all linking to the macaw::Conformal3 docs page. I think in our case we would want it to be directly fully qualified names of macaw::Conformal3 everywhere where used.

In addition, even in the case of a single use crate::type can be problematic because one module could do that and use that type in a public API, and another module in the same crate could do use crate2::type and export another public API. So believe all imported used types need to be listed as fully qualified as crate::<potential-path>::name in the listing.

Stack overflow in parsing rustdoc JSON

When running cargo-public-api on one of our crates we get a 100% stack overflow on it, debugging it one can see that it is in from public_api_from_rustdoc_json_str which get recursively stuck in public_api::item_iterator::ItemIterator::try_add_item_to_visit and then crashes on a stack overflow.

So must have gotten stuck in some recursive loop of references in this specific crate rustdoc JSON output?

Have attached the specific rustdoc .json output that one hopefully can reproduce this with: crate.json

Here is a detailed call stack:

<usize as core::slice::index::SliceIndex<[T]>>::get_unchecked (@<usize as core::slice::index::SliceIndex<[T]>>::get_unchecked:4)
core::slice::<impl [T]>::get_unchecked (@core::slice::<impl [T]>::get_unchecked:12)
core::hash::sip::u8to64_le (@core::hash::sip::u8to64_le:105)
<core::hash::sip::Hasher<S> as core::hash::Hasher>::write (@<core::hash::sip::Hasher<S> as core::hash::Hasher>::write:82)
<core::hash::sip::Hasher<S> as core::hash::Hasher>::write_str (@<core::hash::sip::Hasher<S> as core::hash::Hasher>::write_str:20)
<core::hash::sip::SipHasher13 as core::hash::Hasher>::write_str (@<core::hash::sip::SipHasher13 as core::hash::Hasher>::write_str:8)
<std::collections::hash::map::DefaultHasher as core::hash::Hasher>::write_str (@<std::collections::hash::map::DefaultHasher as core::hash::Hasher>::write_str:8)
core::hash::impls::<impl core::hash::Hash for str>::hash (@core::hash::impls::<impl core::hash::Hash for str>::hash:12)
<alloc::string::String as core::hash::Hash>::hash (@<alloc::string::String as core::hash::Hash>::hash:14)
<rustdoc_types::Id as core::hash::Hash>::hash (/home/repi/.cargo/registry/src/github.com-1ecc6299db9ec823/rustdoc-types-0.14.0/src/lib.rs:189)
core::hash::impls::<impl core::hash::Hash for &T>::hash (@core::hash::impls::<impl core::hash::Hash for &T>::hash:8)
core::hash::BuildHasher::hash_one (@core::hash::BuildHasher::hash_one:21)
hashbrown::map::make_hash (@hashbrown::map::make_hash:7)
hashbrown::map::HashMap<K,V,S,A>::get_inner (@hashbrown::map::HashMap<K,V,S,A>::get_inner:18)
hashbrown::map::HashMap<K,V,S,A>::get (@hashbrown::map::HashMap<K,V,S,A>::get:7)
std::collections::hash::map::HashMap<K,V,S>::get (@std::collections::hash::map::HashMap<K,V,S>::get:7)
public_api::item_iterator::ItemIterator::add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:141)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:115)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:115)

<removed 37000 similar calls here>

public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::try_add_item_to_visit (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:107)
public_api::item_iterator::ItemIterator::add_children_for_item (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:80)
<public_api::item_iterator::ItemIterator as core::iter::traits::iterator::Iterator>::next (/home/repi/git/rust/cargo-public-api/public-api/src/item_iterator.rs:169)
<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next (@<core::iter::adapters::map::Map<I,F> as core::iter::traits::iterator::Iterator>::next:11)
alloc::vec::Vec<T,A>::extend_desugared (@alloc::vec::Vec<T,A>::extend_desugared:11)
<alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<T,I>>::spec_extend (@<alloc::vec::Vec<T,A> as alloc::vec::spec_extend::SpecExtend<T,I>>::spec_extend:12)
<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter (@<alloc::vec::Vec<T> as alloc::vec::spec_from_iter_nested::SpecFromIterNested<T,I>>::from_iter:129)
<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter (@<alloc::vec::Vec<T> as alloc::vec::spec_from_iter::SpecFromIter<T,I>>::from_iter:12)
<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter (@<alloc::vec::Vec<T> as core::iter::traits::collect::FromIterator<T>>::from_iter:15)
core::iter::traits::iterator::Iterator::collect (@core::iter::traits::iterator::Iterator::collect:12)
public_api::public_api_from_rustdoc_json_str (/home/repi/git/rust/cargo-public-api/public-api/src/lib.rs:132)
cargo_public_api::public_api_from_rustdoc_json_path (/home/repi/git/rust/cargo-public-api/cargo-public-api/src/main.rs:322)
cargo_public_api::collect_public_items_from_commit (/home/repi/git/rust/cargo-public-api/cargo-public-api/src/main.rs:310)
cargo_public_api::print_public_items_of_current_commit (/home/repi/git/rust/cargo-public-api/cargo-public-api/src/main.rs:181)
cargo_public_api::main_ (/home/repi/git/rust/cargo-public-api/cargo-public-api/src/main.rs:142)
cargo_public_api::main (/home/repi/git/rust/cargo-public-api/cargo-public-api/src/main.rs:355)
core::ops::function::FnOnce::call_once (@core::ops::function::FnOnce::call_once:6)
std::sys_common::backtrace::__rust_begin_short_backtrace (@std::sys_common::backtrace::__rust_begin_short_backtrace:6)
std::rt::lang_start::{{closure}} (@std::rt::lang_start::{{closure}}:7)
core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once (@std::rt::lang_start_internal:218)
std::panicking::try::do_call (@std::rt::lang_start_internal:216)
std::panicking::try (@std::rt::lang_start_internal:216)
std::panic::catch_unwind (@std::rt::lang_start_internal:216)
std::rt::lang_start_internal::{{closure}} (@std::rt::lang_start_internal:216)
std::panicking::try::do_call (@std::rt::lang_start_internal:216)
std::panicking::try (@std::rt::lang_start_internal:216)
std::panic::catch_unwind (@std::rt::lang_start_internal:216)
std::rt::lang_start_internal (@std::rt::lang_start_internal:216)
std::rt::lang_start (@std::rt::lang_start:13)
main (@main:10)
___lldb_unnamed_symbol3139 (@___lldb_unnamed_symbol3139:29)
__libc_start_main (@__libc_start_main:43)
_start (@_start:15)

error: the option `Z` is only accepted on the nightly compiler

This night CI failed. Sure enough, I can reproduce it locally by doing:

% cargo run -- --manifest-path cargo-public-api/Cargo.toml
Error: Failed to build rustdoc JSON. Stderr:     Checking public-api v0.12.2 (/Users/martin/src/cargo-public-api/public-api)
    Checking rustdoc-json v0.2.1 (/Users/martin/src/cargo-public-api/rustdoc-json)
 Documenting cargo-public-api v0.12.2 (/Users/martin/src/cargo-public-api/cargo-public-api)
error: the option `Z` is only accepted on the nightly compiler

error: could not document `cargo-public-api`

Caused by:
  process didn't exit successfully: `/Users/martin/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustdoc --edition=2021 --crate-type lib --crate-name cargo_public_api cargo-public-api/src/lib.rs -o /Users/martin/src/cargo-public-api/target/doc --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat -Z unstable-options --output-format json --cap-lints warn -C metadata=a8187698374ba899 -L dependency=/Users/martin/src/cargo-public-api/target/debug/deps --extern ansi_term=/Users/martin/src/cargo-public-api/target/debug/deps/libansi_term-2dcfebadd4a11f02.rmeta --extern anyhow=/Users/martin/src/cargo-public-api/target/debug/deps/libanyhow-ff31ead167d75e4a.rmeta --extern atty=/Users/martin/src/cargo-public-api/target/debug/deps/libatty-03508689ddba4741.rmeta --extern clap=/Users/martin/src/cargo-public-api/target/debug/deps/libclap-85bbfd8e37db05d7.rmeta --extern diff=/Users/martin/src/cargo-public-api/target/debug/deps/libdiff-2132f39c67c267ab.rmeta --extern public_api=/Users/martin/src/cargo-public-api/target/debug/deps/libpublic_api-ea8caa28a08ae247.rmeta --extern rustdoc_json=/Users/martin/src/cargo-public-api/target/debug/deps/librustdoc_json-149a0e783af514d2.rmeta --crate-version 0.12.2` (exit status: 1)

For some reason, the stable rustdoc (/Users/martin/.rustup/toolchains/stable-aarch64-apple-darwin/bin/rustdoc) is used even though we pass +nightly to cargo.

Maybe related to the recently released rustup 1.25.0?

Add `--deny` flag for diffs in CI usage situations

Hi there! Cool project 😄

I'd like to use this as part of a CI pipeline but it doesn't look like there's any way to
programmatically check if something in the public API changed.

RustFmt has a --check flag which exits with 0 if the input would be formatted successfully
and 1 if it wouldn't be.

I think having a similar flag as part of this project would allow it to be used in the context
of CI.

Present associated items as part of `impl`s

If a struct Foo implements both e.g. TryFrom and TryInto, the output will contain

pub type some_crate::Foo::Error
pub type some_crate::Foo::Error

This is because both TryFrom and TryInto has an associated type called Error.

The output should be more specific about where the Error comes from in each case, to make it clear it is not a matter of duplication.

Incorrect handling of wildcard re-exports (`pub use foo::*`)

If one have one module importing types from another module (in the same crate or another crate) it looks like the output from cargo-public-api incorrectly appends the name of the module one was useing - which is not how the type is imported.

Here is an example:

pub mod v0 {
    pub fn hej() {
        println!("hej!")
    }
}

pub mod v1 {
    // this API is additive to v0, so let's include the contents of v0
    pub use super::v0::*;

    pub fn hej2() {
        hej();
    }
}

This gives the cargo-public-api output:

pub fn api_test::test()
pub fn api_test::v0::hej()
pub fn api_test::v1::hej2()
pub fn api_test::v1::v0::hej()
pub mod api_test
pub mod api_test::v0
pub mod api_test::v1
pub mod api_test::v1::v0

But I believe it really should be:

  pub fn api_test::test()
  pub fn api_test::v0::hej()
  pub fn api_test::v1::hej2()
- pub fn api_test::v1::v0::hej()
+ pub fn api_test::v1::hej()
  pub mod api_test
  pub mod api_test::v0
  pub mod api_test::v1
- pub mod api_test::v1::v0

Because there is no v1::v0 in the usable public API of the crate, we imported all the types from v0 into the v1 module as well.

We do this type of imports a lot in one of our crates, and sometimes with 4-5 nested versions which with this became a bit of a recursive mess right now in the public API listings

Allow using `-p` to select package in workspace

If you stand in the root of this git repo, you can run this command to build the HTML docs of say the rustdoc-json crate:

cargo doc -p rustdoc-json

It would be convenient to be able to use the same flag for cargo public-api, like this:

cargo public-api -p rustdoc-json

because currently you have to use the much longer:

cargo public-api  --manifest-path rustdoc-json/Cargo.toml

which means you can barely re-use the cargo doc command from your shell history. It is worth noting that cargo doc also support the longer form that we currently use:

cargo doc --manifest-path rustdoc-json/Cargo.toml

Type cargo help doc and read the Package Selection section for more info on how package selection works with cargo doc.

Nightly 2022-09-06 fails, needs `rustdoc-types` v0.16.0 upgrade

Otherwise fails in one of our crates on:

Error: Failed to parse rustdoc JSON
Caused by:
    invalid type: string "0:211:1559", expected adjacently tagged enum Type at line 1 column 253901

looks like a pretty small upgrade of the types.

stabilization of rustdoc json output can't come soon enough! :)

Automatically finding semver-breaks for crates-io crates

Just heads up that I'm really liking this project! I'm interested in integrating public_items into https://lib.rs, e.g. list of versions like this https://lib.rs/crates/cc/versions to show which releases were significant, and automatically generate API changelog for crates.

For this I think it would be better to diff an internal simplified representation of types, rather than textual output (of cargo-public-items), so for example if someone adds a struct, I can show the diff as a new struct, not X new fields. But while implementing that I've run into the problem of recursive types — it's unfortunately not possible to "flatten" rustdoc's types to remove the index indirection.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.