Skip to content

Commit 13fdc94

Browse files
committed
Auto merge of #3163 - Turbo87:top-versions, r=jtgeibel
EncodableCrate: Add `max_stable_version` field This PR resolves the API part of #654 by adding a `max_stable_version` field for the `krate` resource. Since naming is hard, it is called `highest_stable` internally on the `TopVersions` struct. Contrary to `newest_version` and `max_version` this field will be `null` (not `"0.0.0"`) if all available versions have been yanked. r? `@jtgeibel`
2 parents beb6b13 + 9bad2a6 commit 13fdc94

File tree

4 files changed

+58
-3
lines changed

4 files changed

+58
-3
lines changed

src/models/krate.rs

+3
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,8 @@ impl Crate {
357357
.map(|v| v.to_string())
358358
.unwrap_or_else(|| "0.0.0".to_string());
359359

360+
let max_stable_version = top_versions.highest_stable.as_ref().map(|v| v.to_string());
361+
360362
EncodableCrate {
361363
id: name.clone(),
362364
name: name.clone(),
@@ -370,6 +372,7 @@ impl Crate {
370372
badges,
371373
max_version,
372374
newest_version,
375+
max_stable_version,
373376
documentation,
374377
homepage,
375378
exact_match,

src/models/version.rs

+32-3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ pub struct NewVersion {
4343
pub struct TopVersions {
4444
/// The "highest" version in terms of semver
4545
pub highest: Option<semver::Version>,
46+
/// The "highest" non-prerelease version
47+
pub highest_stable: Option<semver::Version>,
4648
/// The "newest" version in terms of publishing date
4749
pub newest: Option<semver::Version>,
4850
}
@@ -61,9 +63,19 @@ impl TopVersions {
6163
T: Clone + IntoIterator<Item = (NaiveDateTime, semver::Version)>,
6264
{
6365
let newest = pairs.clone().into_iter().max().map(|(_, v)| v);
64-
let highest = pairs.into_iter().map(|(_, v)| v).max();
66+
let highest = pairs.clone().into_iter().map(|(_, v)| v).max();
6567

66-
Self { newest, highest }
68+
let highest_stable = pairs
69+
.into_iter()
70+
.map(|(_, v)| v)
71+
.filter(|v| !v.is_prerelease())
72+
.max();
73+
74+
Self {
75+
newest,
76+
highest,
77+
highest_stable,
78+
}
6779
}
6880
}
6981

@@ -262,6 +274,7 @@ mod tests {
262274
TopVersions::from_date_version_pairs(versions),
263275
TopVersions {
264276
highest: None,
277+
highest_stable: None,
265278
newest: None,
266279
}
267280
);
@@ -274,23 +287,39 @@ mod tests {
274287
TopVersions::from_date_version_pairs(versions),
275288
TopVersions {
276289
highest: Some(version("1.0.0")),
290+
highest_stable: Some(version("1.0.0")),
277291
newest: Some(version("1.0.0")),
278292
}
279293
);
280294
}
281295

296+
#[test]
297+
fn top_versions_prerelease() {
298+
let versions = vec![(date("2020-12-03T12:34:56"), version("1.0.0-beta.5"))];
299+
assert_eq!(
300+
TopVersions::from_date_version_pairs(versions),
301+
TopVersions {
302+
highest: Some(version("1.0.0-beta.5")),
303+
highest_stable: None,
304+
newest: Some(version("1.0.0-beta.5")),
305+
}
306+
);
307+
}
308+
282309
#[test]
283310
fn top_versions_multiple() {
284311
let versions = vec![
285312
(date("2018-12-03T12:34:56"), version("1.0.0")),
286313
(date("2019-12-03T12:34:56"), version("2.0.0-alpha.1")),
287314
(date("2020-12-03T12:34:56"), version("1.1.0")),
315+
(date("2020-12-31T12:34:56"), version("1.0.4")),
288316
];
289317
assert_eq!(
290318
TopVersions::from_date_version_pairs(versions),
291319
TopVersions {
292320
highest: Some(version("2.0.0-alpha.1")),
293-
newest: Some(version("1.1.0")),
321+
highest_stable: Some(version("1.1.0")),
322+
newest: Some(version("1.0.4")),
294323
}
295324
);
296325
}

src/tests/krate/search.rs

+21
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,27 @@ fn yanked_versions_are_not_considered_for_max_version() {
508508
assert_eq!(json.crates[0].max_version, "1.0.0");
509509
}
510510

511+
#[test]
512+
fn max_stable_version() {
513+
let (app, anon, user) = TestApp::init().with_user();
514+
let user = user.as_model();
515+
516+
app.db(|conn| {
517+
CrateBuilder::new("foo", user.id)
518+
.description("foo")
519+
.version("0.3.0")
520+
.version("1.0.0")
521+
.version(VersionBuilder::new("1.1.0").yanked(true))
522+
.version("2.0.0-beta.1")
523+
.version("0.3.1")
524+
.expect_build(conn);
525+
});
526+
527+
let json = anon.search("q=foo");
528+
assert_eq!(json.meta.total, 1);
529+
assert_eq!(json.crates[0].max_stable_version, Some("1.0.0".to_string()));
530+
}
531+
511532
/* Given two crates, one with downloads less than 90 days ago, the
512533
other with all downloads greater than 90 days ago, check that
513534
the order returned is by recent downloads, descending. Check

src/views.rs

+2
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ pub struct EncodableCrate {
156156
// NOTE: Used by shields.io, altering `max_version` requires a PR with shields.io
157157
pub max_version: String,
158158
pub newest_version: String, // Most recently updated version, which may not be max
159+
pub max_stable_version: Option<String>,
159160
pub description: Option<String>,
160161
pub homepage: Option<String>,
161162
pub documentation: Option<String>,
@@ -510,6 +511,7 @@ mod tests {
510511
recent_downloads: None,
511512
max_version: "".to_string(),
512513
newest_version: "".to_string(),
514+
max_stable_version: None,
513515
description: None,
514516
homepage: None,
515517
documentation: None,

0 commit comments

Comments
 (0)