diff --git a/src/test/fakes.rs b/src/test/fakes.rs index 2dd7e8504..ac3ed6925 100644 --- a/src/test/fakes.rs +++ b/src/test/fakes.rs @@ -76,6 +76,11 @@ impl<'db> FakeRelease<'db> { self } + pub(crate) fn cratesio_data_yanked(mut self, new: bool) -> Self { + self.cratesio_data.yanked = new; + self + } + pub(crate) fn create(self) -> Result { let tempdir = tempdir::TempDir::new("docs.rs-fake")?; diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 1d91820e4..e691b5254 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -94,8 +94,9 @@ impl ToJson for CrateDetails { #[derive(Debug, Eq, PartialEq)] struct Release { - pub version: String, - pub build_status: bool, + version: String, + build_status: bool, + yanked: bool, } @@ -235,21 +236,11 @@ impl CrateDetails { crate_details.owners.push((row.get(0), row.get(1))); } - // retrieve last successful build if build failed if !crate_details.build_status { - let rows = conn.query( - "SELECT version - FROM releases - INNER JOIN crates ON releases.crate_id = crates.id - WHERE build_status = true AND yanked = false AND crates.name = $1 - ORDER BY release_time desc - LIMIT 1;", - &[&name], - ).unwrap(); - - if rows.len() >= 1 { - crate_details.last_successful_build = Some(rows.get(0).get(0)); - } + crate_details.last_successful_build = crate_details.releases.iter() + .filter(|release| release.build_status && !release.yanked) + .map(|release| release.version.to_owned()) + .next(); } Some(crate_details) @@ -264,19 +255,19 @@ impl CrateDetails { fn map_to_release(conn: &Connection, crate_id: i32, version: String) -> Release { let rows = conn.query( - "SELECT build_status + "SELECT build_status, yanked FROM releases WHERE releases.crate_id = $1 and releases.version = $2;", &[&crate_id, &version], ).unwrap(); - let build_status = if !rows.is_empty() { - rows.get(0).get(0) + let (build_status, yanked) = if !rows.is_empty() { + (rows.get(0).get(0), rows.get(0).get(1)) } else { - false + Default::default() }; - Release { version, build_status } + Release { version, build_status, yanked } } @@ -313,20 +304,14 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult { } } + + #[cfg(test)] mod tests { use super::*; use crate::test::TestDatabase; use failure::Error; - fn create_release(db: &TestDatabase, package: &str, version: &str, successful: bool) -> Result { - db.fake_release() - .name(package) - .version(version) - .build_result_successful(successful) - .create() - } - fn assert_last_successful_build_equals( db: &TestDatabase, package: &str, @@ -345,47 +330,55 @@ mod tests { } #[test] - fn test_last_successful_build_when_last_release_failed() { + fn test_last_successful_build_when_last_releases_failed_or_yanked() { crate::test::wrapper(|env| { let db = env.db(); - create_release(&db, "foo", "0.0.1", true)?; - create_release(&db, "foo", "0.0.2", true)?; - create_release(&db, "foo", "0.0.3", false)?; + db.fake_release().name("foo").version("0.0.1").create()?; + db.fake_release().name("foo").version("0.0.2").create()?; + db.fake_release().name("foo").version("0.0.3").build_result_successful(false).create()?; + db.fake_release().name("foo").version("0.0.4").cratesio_data_yanked(true).create()?; + db.fake_release().name("foo").version("0.0.5").build_result_successful(false).cratesio_data_yanked(true).create()?; assert_last_successful_build_equals(&db, "foo", "0.0.1", None)?; assert_last_successful_build_equals(&db, "foo", "0.0.2", None)?; assert_last_successful_build_equals(&db, "foo", "0.0.3", Some("0.0.2"))?; + assert_last_successful_build_equals(&db, "foo", "0.0.4", None)?; + assert_last_successful_build_equals(&db, "foo", "0.0.5", Some("0.0.2"))?; Ok(()) }); } #[test] - fn test_last_successful_build_when_all_releases_failed() { + fn test_last_successful_build_when_all_releases_failed_or_yanked() { crate::test::wrapper(|env| { let db = env.db(); - create_release(&db, "foo", "0.0.1", false)?; - create_release(&db, "foo", "0.0.2", false)?; + db.fake_release().name("foo").version("0.0.1").build_result_successful(false).create()?; + db.fake_release().name("foo").version("0.0.2").build_result_successful(false).create()?; + db.fake_release().name("foo").version("0.0.3").cratesio_data_yanked(true).create()?; assert_last_successful_build_equals(&db, "foo", "0.0.1", None)?; assert_last_successful_build_equals(&db, "foo", "0.0.2", None)?; + assert_last_successful_build_equals(&db, "foo", "0.0.3", None)?; Ok(()) }); } #[test] - fn test_last_successful_build_when_an_intermittent_release_failed() { + fn test_last_successful_build_with_intermittent_releases_failed_or_yanked() { crate::test::wrapper(|env| { let db = env.db(); - create_release(&db, "foo", "0.0.1", true)?; - create_release(&db, "foo", "0.0.2", false)?; - create_release(&db, "foo", "0.0.3", true)?; + db.fake_release().name("foo").version("0.0.1").create()?; + db.fake_release().name("foo").version("0.0.2").build_result_successful(false).create()?; + db.fake_release().name("foo").version("0.0.3").cratesio_data_yanked(true).create()?; + db.fake_release().name("foo").version("0.0.4").create()?; assert_last_successful_build_equals(&db, "foo", "0.0.1", None)?; - assert_last_successful_build_equals(&db, "foo", "0.0.2", Some("0.0.3"))?; + assert_last_successful_build_equals(&db, "foo", "0.0.2", Some("0.0.4"))?; assert_last_successful_build_equals(&db, "foo", "0.0.3", None)?; + assert_last_successful_build_equals(&db, "foo", "0.0.4", None)?; Ok(()) }); } @@ -396,23 +389,23 @@ mod tests { let db = env.db(); // Add new releases of 'foo' out-of-order since CrateDetails should sort them descending - create_release(&db, "foo", "0.1.0", true)?; - create_release(&db, "foo", "0.1.1", true)?; - create_release(&db, "foo", "0.3.0", false)?; - create_release(&db, "foo", "1.0.0", true)?; - create_release(&db, "foo", "0.12.0", true)?; - create_release(&db, "foo", "0.2.0", true)?; - create_release(&db, "foo", "0.2.0-alpha", true)?; + db.fake_release().name("foo").version("0.1.0").create()?; + db.fake_release().name("foo").version("0.1.1").create()?; + db.fake_release().name("foo").version("0.3.0").build_result_successful(false).create()?; + db.fake_release().name("foo").version("1.0.0").create()?; + db.fake_release().name("foo").version("0.12.0").create()?; + db.fake_release().name("foo").version("0.2.0").cratesio_data_yanked(true).create()?; + db.fake_release().name("foo").version("0.2.0-alpha").create()?; let details = CrateDetails::new(&db.conn(), "foo", "0.2.0").unwrap(); assert_eq!(details.releases, vec![ - Release { version: "1.0.0".to_string(), build_status: true }, - Release { version: "0.12.0".to_string(), build_status: true }, - Release { version: "0.3.0".to_string(), build_status: false }, - Release { version: "0.2.0".to_string(), build_status: true }, - Release { version: "0.2.0-alpha".to_string(), build_status: true }, - Release { version: "0.1.1".to_string(), build_status: true }, - Release { version: "0.1.0".to_string(), build_status: true }, + Release { version: "1.0.0".to_string(), build_status: true, yanked: false }, + Release { version: "0.12.0".to_string(), build_status: true, yanked: false }, + Release { version: "0.3.0".to_string(), build_status: false, yanked: false }, + Release { version: "0.2.0".to_string(), build_status: true, yanked: true }, + Release { version: "0.2.0-alpha".to_string(), build_status: true, yanked: false }, + Release { version: "0.1.1".to_string(), build_status: true, yanked: false }, + Release { version: "0.1.0".to_string(), build_status: true, yanked: false }, ]); Ok(())