diff --git a/app/routes/crate/version.js b/app/routes/crate/version.js index b78f3e2138b..9239b13e27f 100644 --- a/app/routes/crate/version.js +++ b/app/routes/crate/version.js @@ -19,29 +19,6 @@ export default Route.extend({ const crate = this.modelFor('crate'); const controller = this.controllerFor(this.routeName); const maxVersion = crate.get('max_version'); - - const isUnstableVersion = version => { - const versionLen = version.length; - let majorMinorPatchChars = 0; - let result = false; - - for (let i = 0; i < versionLen; i++) { - const char = version.charAt(i); - - if (!isNaN(parseInt(char)) || char === '.') { - majorMinorPatchChars++; - } else { - break; - } - } - - if (versionLen !== majorMinorPatchChars) { - result = true; - } - - return result; - }; - const fetchCrateDocumentation = () => { if (!crate.get('documentation') || crate.get('documentation').substr(0, 16) === 'https://docs.rs/') { let crateName = crate.get('name'); @@ -54,34 +31,10 @@ export default Route.extend({ } }; - // Fallback to the crate's last stable version - // If `max_version` is `0.0.0` then all versions have been yanked if (!requestedVersion && maxVersion !== '0.0.0') { - if (isUnstableVersion(maxVersion)) { - crate - .get('versions') - .then(versions => { - const latestStableVersion = versions.find(version => { - if (!isUnstableVersion(version.get('num'))) { - return version; - } - }); - - if (latestStableVersion == null) { - // If no stable version exists, fallback to `maxVersion` - params.version_num = maxVersion; - } else { - params.version_num = latestStableVersion.get('num'); - } - }) - .then(fetchCrateDocumentation); - } else { - params.version_num = maxVersion; - fetchCrateDocumentation(); - } - } else { - fetchCrateDocumentation(); + params.version_num = maxVersion; } + fetchCrateDocumentation(); controller.set('crate', crate); controller.set('requestedVersion', requestedVersion); diff --git a/src/controllers/krate/search.rs b/src/controllers/krate/search.rs index 111315c413a..b518fe6d6a3 100644 --- a/src/controllers/krate/search.rs +++ b/src/controllers/krate/search.rs @@ -160,6 +160,7 @@ pub fn search(req: &mut dyn Request) -> CargoResult { let crates = data.into_iter().map(|((c, _, _), _)| c).collect::>(); let versions = Version::belonging_to(&crates) + .filter(versions::yanked.eq(false)) .load::(&*conn)? .grouped_by(&crates) .into_iter() diff --git a/src/models/version.rs b/src/models/version.rs index 8bf7313e4f5..e2c683c3fe8 100644 --- a/src/models/version.rs +++ b/src/models/version.rs @@ -1,3 +1,4 @@ +use std::cmp::Ordering; use std::collections::HashMap; use chrono::NaiveDateTime; @@ -87,13 +88,23 @@ impl Version { { versions .into_iter() - .max() - .unwrap_or_else(|| semver::Version { - major: 0, - minor: 0, - patch: 0, - pre: vec![], - build: vec![], + .max_by(|x, y| { + if !x.is_prerelease() && y.is_prerelease() { + Ordering::Greater + } else if x.is_prerelease() && !y.is_prerelease() { + Ordering::Less + } else { + x.cmp(y) + } + }) + .unwrap_or_else(|| { + semver::Version { + major: 0, + minor: 0, + patch: 0, + pre: vec![], + build: vec![], + } }) } @@ -216,3 +227,51 @@ impl Queryable for Version { } } } + +#[cfg(test)] +mod test { + use semver; + use super::Version; + + fn create_version(version: &str) -> semver::Version { + semver::Version::parse(version).unwrap() + } + + #[test] + fn max_version_returns_max_stable_when_only_stable() { + let versions = vec![ + create_version("0.0.1"), + create_version("1.0.0"), + create_version("0.1.0"), + ]; + assert_eq!(create_version("1.0.0"), Version::max(versions)) + } + + #[test] + fn max_version_returns_max_prerelease_when_only_prerelease() { + let versions = vec![ + create_version("0.0.1-pre.1"), + create_version("0.0.1-pre.3"), + create_version("0.0.1-pre.2"), + ]; + assert_eq!(create_version("0.0.1-pre.3"), Version::max(versions)) + } + + #[test] + fn max_version_returns_zero_when_no_versions() { + let versions = vec![]; + assert_eq!(create_version("0.0.0"), Version::max(versions)) + } + + #[test] + fn max_version_returns_latest_stable_when_prerelease_and_stable_mixed() { + let versions = vec![ + create_version("1.0.1-pre.1"), + create_version("1.0.1-pre.3"), + create_version("1.0.0"), + create_version("0.9.0"), + create_version("1.0.1-pre.2"), + ]; + assert_eq!(create_version("1.0.0"), Version::max(versions)) + } +} diff --git a/tests/acceptance/crate-test.js b/tests/acceptance/crate-test.js index 7aa04710215..e9c5ba8f473 100644 --- a/tests/acceptance/crate-test.js +++ b/tests/acceptance/crate-test.js @@ -178,7 +178,7 @@ module('Acceptance | crate page', function(hooks) { this.server.loadFixtures(); await visit('/crates/nanomsg'); - assert.dom('[data-test-license]').hasText('Apache-2.0'); + assert.dom('[data-test-license]').hasText('MIT'); await click('[data-test-version-link="0.5.0"]'); assert.dom('[data-test-license]').hasText('MIT/Apache-2.0');