-
Notifications
You must be signed in to change notification settings - Fork 610
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Display reported build information in a badge and on crate version pages #764
Display reported build information in a badge and on crate version pages #764
Conversation
src/version.rs
Outdated
build_info::table.primary_key(), | ||
do_update() | ||
.set((build_info::passed.eq(excluded(build_info::passed)), | ||
build_info::updated_at.eq(now_utc().to_timespec()))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated_at
is handled by database triggers everywhere else. Should we do the same here? (adding SELECT diesel_manage_updated_at('build_info');
to your migration will have Diesel set up the trigger automatically.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, good point. We should be using the db triggers here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will the triggers also handle created_at
?
src/version.rs
Outdated
ChannelVersion::Beta(date) => beta.push(date), | ||
ChannelVersion::Nightly(date) => nightly.push(date), | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this amount of code is worth it just to avoid the one allocation of an intermediate vec? What do you think about this instead?
let rust_versions = build_infos.into_iter().map(|row| row.rust_version.parse::<ChannelVersion>()).collect::<Result<Vec<_>, _>>()?;
let nightly = rust_versions.iter().filter_map(|version| match *version {
ChannelVersion::Nightly(date) => Some(date),
_ => None,
}).max();
let beta = rust_versions.iter().filter_map(|version| match *version {
ChannelVersion::Beta(date) => Some(date),
_ => None,
}).max();
let stable = rust_versions.into_iter().filter_map(|version| match version {
ChannelVersion::Stable(semver) => Some(semver),
_ => None,
}).max();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see which part of the proposed code only keeps the most recent value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you mean by "most recent"? The code simply grabs the maximum of each one, does it not?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, there's a max
call at the end of each of those. I'm not the biggest fan of that syntax for that reason. I see what you mean now though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just to avoid the one allocation of an intermediate vec
To be honest, I've never really worked on mission-critical infrastructure supporting the entire ecosystem behind a language, so I don't really know when it's appropriate. From the comment, I assume you think it's not, so I'll defer to your greater experience.
src/version.rs
Outdated
passed: bool, | ||
} | ||
|
||
pub const BUILD_INFO_FIELDS: (build_info::version_id, build_info::rust_version, build_info::target, build_info::passed) = (build_info::version_id, build_info::rust_version, build_info::target, build_info::passed); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we even need the created_at
and updated_at
fields if we aren't selecting them or using them for filtering anywhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to have them, I could see wanting to display them somewhere, but they're useful to me for auditing purposes.
src/version.rs
Outdated
} | ||
} | ||
|
||
encodable_build_info.ordering.insert( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think using the ordermap
crate instead of a hashmap could simplify this code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd still want the "stable", "beta", "nightly" keys for the JSON... or am I misunderstanding? How would ordermap instead of a hashmap simplify this code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We wouldn't need to maintain this ordering
field, since OrderMap
preserves insertion order. Even if we still need ordering
for the front-end, it'd just be .keys().collect()
to get the corresponding vec.
Though on second reading, that's not even what this code is doing. Since it's in a BTreeSet
, it's just going to be sorting the strings in ascending order. Is that the desired behavior? It seems like we could just sort them when we're ready to display them in that case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated the function with an example of the output as well as the rationale behind it. In short: no, I don't think the ordermap crate would help here.
As far as I understand it, JSON and JavaScript do not guarantee the order of objects. The ordering
field exists to avoid requiring the frontend to understand how to sort by date and/or semver.
While OrderMap
preserves insertion order, our iteration order over the returned rows is not guaranteed to be anything useful, therefore the insertion order is not valuable.
We aren't relying on the BTree
part, just the Set
part; we could just have easily used a HashSet
. I only use BTree*
stuff as a favor to @gankro, who told me that B-Trees are just all-around-cooler.
Additionally, the sets don't contain String
s — the stable one contains version numbers and the others two contain dates. We only convert to a string to serialize.
src/version.rs
Outdated
/// Handles the `POST /crates/:crate_id/:version/build_info` route. | ||
pub fn publish_build_info(req: &mut Request) -> CargoResult<Response> { | ||
let mut body = String::new(); | ||
try!(req.body().read_to_string(&mut body)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
!
src/krate.rs
Outdated
} | ||
|
||
#[cfg_attr(feature = "lint", allow(too_many_arguments))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should listen to this lint here, and start to refactor this out a bit? encodable
feels like it's becoming a bit of a dumping ground.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do think we should refactor this, I am agnostic about whether it should be done in this PR or in a separate PR
src/version.rs
Outdated
#[derive(Insertable, AsChangeset)] | ||
#[table_name="build_info"] | ||
#[primary_key(version_id, rust_version, target)] | ||
struct NewBuildInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we expect this table to be relatively stable, it might be worth just dumping this struct and adding #[derive(Insertable, AsChangeset)]
onto BuildInfo
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good.
3264a05
to
c01c6bf
Compare
I've rebased to address some conflicts and applied rustfmt to each commit. @sgrif I've added a commit that does your proposed max finding. What are your thoughts on it? I'm still going to address these comments:
I just wanted to save them from being hidden |
hints? |
5f8c398
to
f86a363
Compare
f86a363
to
956b1a9
Compare
All talking points addressed. Ready for next round of review. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have doc comments added to all new public and private types?
src/upload.rs
Outdated
@@ -55,6 +57,19 @@ pub struct CrateDependency { | |||
pub kind: Option<DependencyKind>, | |||
} | |||
|
|||
#[derive(Debug, Serialize, Deserialize)] | |||
pub struct VersionBuildInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add a doc comment here?
src/version.rs
Outdated
#[belongs_to(Version)] | ||
#[table_name = "build_info"] | ||
#[primary_key(version_id, rust_version, target)] | ||
pub struct BuildInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we have a doc comment here as well as for all structs, enums, and functions in this module?
6d29a62
to
aacad02
Compare
If the latest version builds on any stable version, show that it builds on stable. If not and it builds on any beta version, show that. If not and it builds on any nightly version, show that. Otherwise, don't show any badge.
aacad02
to
c492420
Compare
Ok, I've rebased and revived this old thing, in the start of an effort to actually get through all the open PRs. I'd love reviews from:
whenever yinz have time <3 |
@carols10cents I've finally gotten around to looking at this. In terms of MVC style, I have no issues. I'm testing this PR in a staging area with the cargo PR as well. Here are a few things I've run into:
For reference, the staging area is here. |
The NaiveDate type doesn't include any time or timezone information, so I'm explicitly formatting as year-month-day ("%Y-%m-%d").
@carols10cents I've pushed a commit that should pass your new test. I'm explicitly formatting as "%Y-%m-%d" and tweaked the test a bit to match. I'm still reviewing but will probably r+ this weekend. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rust side generally looks good to me. I'd like to take a second look at the parsing/encoding stuff when I'm less tired. I don't know enough about Ember to comment on that end.
|
||
/// `MaxBuildInfo` in JSON form. | ||
#[derive(Debug, Default, Serialize, Deserialize)] | ||
pub struct EncodableMaxVersionBuildInfo { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every field on MaxBuildVersionInfo
implements Serialize
, doesn't it? Is there a reason we need this as a separate struct?
/// The columns to select from the `build_info` table. The table also stores `created_at` and | ||
/// `updated_at` metadata for each row, but we're not displaying those anywhere so we're not | ||
/// bothering to select them. | ||
pub const BUILD_INFO_FIELDS: ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are the created_at
and updated_at
fields ever used at all? Is it worth even having them in the first place?
/// Stores information about whether this version built on the specified Rust version and target. | ||
pub struct BuildInfo { | ||
version_id: i32, | ||
pub rust_version: String, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this always a semver version? Is it worth pointing at dtolnay/semver#169 to make things easier here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sgrif currently this is storing the full version string, such as rustc 1.15.0-beta.5 (10893a9a3 2017-01-19)
. It may be better to parse this string when the build info is submitted, but I'm not sure how to best store the ParsedRustChannelVersion
enum in the database. Maybe 3 columns, rust_channel (enum), rust_version (semver), and rust_date (date) where we have a semver or a date, but not both on any given row. Seems complicated, but I'd also prefer not to store a bunch of full rustc version strings.
pub enum ParsedRustChannelVersion {
Stable(semver::Version),
Beta(NaiveDate),
Nightly(NaiveDate),
}
This should fix a regression introduced in this commit series. We should add more tests for the search route.
baadd1d
to
6c9794d
Compare
@jtgeibel @shepmaster Did we still want to merge this in? This probably needs a rework given that the codebase has been refactored since the PR was opened. |
Ugh, yeah, I'm going to close. |
(This is a replacement of #540)
This goes with rust-lang/cargo#5099. @carols10cents worked on these too :)
This PR adds a table that stores recorded crate version, rust version, target, and pass/fail as reported by crate owners using the
cargo publish-build-info
command.The purpose is to enable crate authors to automatically report to potential crate users on the Rust version and platform compatibility of each version of the crate.
There's documentation in the cargo PR for doc.crates.io about how this feature is intended to work.
The badges, as described in that documentation, will display the latest version of the most stable channel that reported any
pass
results for the max version of that crate. Here's what that will look like, including the hover text:Stable:
Beta:
Nightly:
Each crate version page will display more detail, but not all of the possible information that collection supports. It's in a new section above the download stats graph as a table showing the most recent stable, beta, and nightly with any reported results for the Tier 1 platforms using 64 bit architectures:
There's also a new page with full information for the 64-bit tier 1 platforms, showing more detailed information:
Some enhancements to the display that we've thought about but haven't implemented yet:
We also thought about, but didn't implement:
We're excited to hear what anyone thinks, and of course happy to answer questions or make modifications!