From ad7f729ee8bcbc38f2742b8794ab5ab8e7c43362 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 3 Dec 2020 14:41:06 +0100 Subject: [PATCH 1/3] models/version: Implement `highest_stable` field --- src/models/version.rs | 37 ++++++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/src/models/version.rs b/src/models/version.rs index c9c906a9829..ba7b7813783 100644 --- a/src/models/version.rs +++ b/src/models/version.rs @@ -43,6 +43,9 @@ pub struct NewVersion { pub struct TopVersions { /// The "highest" version in terms of semver pub highest: Option, + /// The "highest" non-prerelease version, or, if only + /// prereleases exist, the "highest" version + pub highest_stable: Option, /// The "newest" version in terms of publishing date pub newest: Option, } @@ -61,9 +64,20 @@ impl TopVersions { T: Clone + IntoIterator, { let newest = pairs.clone().into_iter().max().map(|(_, v)| v); - let highest = pairs.into_iter().map(|(_, v)| v).max(); + let highest = pairs.clone().into_iter().map(|(_, v)| v).max(); - Self { newest, highest } + let highest_stable = pairs + .into_iter() + .map(|(_, v)| v) + .filter(|v| !v.is_prerelease()) + .max() + .or_else(|| highest.clone()); + + Self { + newest, + highest, + highest_stable, + } } } @@ -262,6 +276,7 @@ mod tests { TopVersions::from_date_version_pairs(versions), TopVersions { highest: None, + highest_stable: None, newest: None, } ); @@ -274,23 +289,39 @@ mod tests { TopVersions::from_date_version_pairs(versions), TopVersions { highest: Some(version("1.0.0")), + highest_stable: Some(version("1.0.0")), newest: Some(version("1.0.0")), } ); } + #[test] + fn top_versions_prerelease() { + let versions = vec![(date("2020-12-03T12:34:56"), version("1.0.0-beta.5"))]; + assert_eq!( + TopVersions::from_date_version_pairs(versions), + TopVersions { + highest: Some(version("1.0.0-beta.5")), + highest_stable: Some(version("1.0.0-beta.5")), + newest: Some(version("1.0.0-beta.5")), + } + ); + } + #[test] fn top_versions_multiple() { let versions = vec![ (date("2018-12-03T12:34:56"), version("1.0.0")), (date("2019-12-03T12:34:56"), version("2.0.0-alpha.1")), (date("2020-12-03T12:34:56"), version("1.1.0")), + (date("2020-12-31T12:34:56"), version("1.0.4")), ]; assert_eq!( TopVersions::from_date_version_pairs(versions), TopVersions { highest: Some(version("2.0.0-alpha.1")), - newest: Some(version("1.1.0")), + highest_stable: Some(version("1.1.0")), + newest: Some(version("1.0.4")), } ); } From 2ca8eccf758b454d84c2b78ee2de5ee80e923866 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Thu, 3 Dec 2020 15:10:27 +0100 Subject: [PATCH 2/3] Expose `TopVersions::highest_stable` as `max_stable_version` --- src/models/krate.rs | 3 +++ src/tests/krate/search.rs | 21 +++++++++++++++++++++ src/views.rs | 2 ++ 3 files changed, 26 insertions(+) diff --git a/src/models/krate.rs b/src/models/krate.rs index 5e5c975529b..e457251fa7b 100644 --- a/src/models/krate.rs +++ b/src/models/krate.rs @@ -357,6 +357,8 @@ impl Crate { .map(|v| v.to_string()) .unwrap_or_else(|| "0.0.0".to_string()); + let max_stable_version = top_versions.highest_stable.as_ref().map(|v| v.to_string()); + EncodableCrate { id: name.clone(), name: name.clone(), @@ -370,6 +372,7 @@ impl Crate { badges, max_version, newest_version, + max_stable_version, documentation, homepage, exact_match, diff --git a/src/tests/krate/search.rs b/src/tests/krate/search.rs index ec7e36ce208..7564ebc56d7 100644 --- a/src/tests/krate/search.rs +++ b/src/tests/krate/search.rs @@ -508,6 +508,27 @@ fn yanked_versions_are_not_considered_for_max_version() { assert_eq!(json.crates[0].max_version, "1.0.0"); } +#[test] +fn max_stable_version() { + let (app, anon, user) = TestApp::init().with_user(); + let user = user.as_model(); + + app.db(|conn| { + CrateBuilder::new("foo", user.id) + .description("foo") + .version("0.3.0") + .version("1.0.0") + .version(VersionBuilder::new("1.1.0").yanked(true)) + .version("2.0.0-beta.1") + .version("0.3.1") + .expect_build(conn); + }); + + let json = anon.search("q=foo"); + assert_eq!(json.meta.total, 1); + assert_eq!(json.crates[0].max_stable_version, Some("1.0.0".to_string())); +} + /* Given two crates, one with downloads less than 90 days ago, the other with all downloads greater than 90 days ago, check that the order returned is by recent downloads, descending. Check diff --git a/src/views.rs b/src/views.rs index 636e0a96095..6a80dd27ee7 100644 --- a/src/views.rs +++ b/src/views.rs @@ -156,6 +156,7 @@ pub struct EncodableCrate { // NOTE: Used by shields.io, altering `max_version` requires a PR with shields.io pub max_version: String, pub newest_version: String, // Most recently updated version, which may not be max + pub max_stable_version: Option, pub description: Option, pub homepage: Option, pub documentation: Option, @@ -510,6 +511,7 @@ mod tests { recent_downloads: None, max_version: "".to_string(), newest_version: "".to_string(), + max_stable_version: None, description: None, homepage: None, documentation: None, From 9bad2a6d9ad4eb18e97e4315d78fd4c434dc1a8d Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 6 Jan 2021 10:07:38 +0100 Subject: [PATCH 3/3] models/TopVersions: Remove `highest` fallback from `highest_stable` --- src/models/version.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/models/version.rs b/src/models/version.rs index ba7b7813783..39d3c2fe425 100644 --- a/src/models/version.rs +++ b/src/models/version.rs @@ -43,8 +43,7 @@ pub struct NewVersion { pub struct TopVersions { /// The "highest" version in terms of semver pub highest: Option, - /// The "highest" non-prerelease version, or, if only - /// prereleases exist, the "highest" version + /// The "highest" non-prerelease version pub highest_stable: Option, /// The "newest" version in terms of publishing date pub newest: Option, @@ -70,8 +69,7 @@ impl TopVersions { .into_iter() .map(|(_, v)| v) .filter(|v| !v.is_prerelease()) - .max() - .or_else(|| highest.clone()); + .max(); Self { newest, @@ -302,7 +300,7 @@ mod tests { TopVersions::from_date_version_pairs(versions), TopVersions { highest: Some(version("1.0.0-beta.5")), - highest_stable: Some(version("1.0.0-beta.5")), + highest_stable: None, newest: Some(version("1.0.0-beta.5")), } );