summaryrefslogtreecommitdiffstats
path: root/ranking
diff options
context:
space:
mode:
authorKornel <kornel@geekhood.net>2019-04-09 01:37:18 +0100
committerKornel <kornel@geekhood.net>2019-04-09 14:37:31 +0100
commit3495372868ea4e2855caf814e13e53b1b228ec54 (patch)
tree7f3e7b20f89916b6d3cf4508e288793e3842d7c9 /ranking
parent5c387344c5fa0ed1f44b5034f366bd48e8cd08ba (diff)
Rank code
Diffstat (limited to 'ranking')
-rw-r--r--ranking/src/lib_ranking.rs37
1 files changed, 29 insertions, 8 deletions
diff --git a/ranking/src/lib_ranking.rs b/ranking/src/lib_ranking.rs
index a889a9c..b5daaf8 100644
--- a/ranking/src/lib_ranking.rs
+++ b/ranking/src/lib_ranking.rs
@@ -17,6 +17,7 @@ pub struct CrateVersionInputs<'a> {
pub readme: Option<&'a Handle>,
pub owners: &'a [CrateOwner],
pub authors: &'a [Author],
+ pub contributors: Option<u32>, // based on source history
pub edition: Edition,
pub is_app: bool,
pub has_build_rs: bool,
@@ -38,6 +39,11 @@ pub struct CrateVersionInputs<'a> {
pub maintenance: MaintenanceStatus,
pub is_nightly: bool,
+ pub total_code_lines: u32,
+ pub rust_comment_lines: u32,
+ pub rust_code_lines: u32,
+
+
// (relative) weight of dependencies?
// rust loc
@@ -113,10 +119,8 @@ fn cargo_toml_score(cr: &CrateVersionInputs) -> Score {
// it's the best practice, may help building old versions of the project
// s.has("has_lockfile", 5, cr.has_lockfile);
// assume it's CI, which helps improve quality
- s.has("has_badges", 20, cr.has_badges);
-
- // not official
- // s.has("has_changelog", 5, cr.has_changelog);
+ // TODO: detect travis, etc. without badges
+ s.has("has_badges", 15, cr.has_badges);
s.n("maintenance status", 30, match cr.maintenance {
MaintenanceStatus::ActivelyDeveloped => 30,
@@ -285,11 +289,23 @@ fn versions_score(ver: &[CrateVersion]) -> Score {
s
}
-fn authors_score(authors: &[Author], owners: &[CrateOwner]) -> Score {
+fn authors_score(authors: &[Author], owners: &[CrateOwner], contributors: Option<u32>) -> Score {
let mut s = Score::new();
- s.n("bus factor", 5, owners.len() as u32);
- s.n("more than one owner", 8, owners.len() > 1);
+ s.n("more than one owner", 3, owners.len() > 1);
+ s.n("bus factor", 4, owners.len() as u32);
s.n("authors", 5, authors.len() as u32);
+ if let Some(contributors) = contributors {
+ s.frac("contributors", 7, (contributors as f64 / 7.).min(1.));
+ }
+ s
+}
+
+fn code_score(cr: &CrateVersionInputs) -> Score {
+ let mut s = Score::new();
+ s.has("Non-trivial", 1, cr.total_code_lines > 700); // usually trivial/toy programs
+ s.has("Non-giant", 1, cr.total_code_lines < 80000); // these should be split into crates
+ s.frac("Rust LoC", 2, (cr.rust_code_lines as f64 / 5000.).min(1.)); // prefer substantial projects (and ignore vendored non-Rust code)
+ s.frac("Comments", 2, (10. * cr.rust_comment_lines as f64 / (3000. + cr.rust_code_lines as f64)).min(1.)); // it's easier to keep small project commented
s
}
@@ -298,8 +314,9 @@ pub fn crate_score_version(cr: &CrateVersionInputs) -> Score {
score.group("Cargo.toml", 2, cargo_toml_score(cr));
score.group("README", 4, readme_score(cr.readme, cr.is_app));
+ score.group("Code", 1, code_score(cr));
score.group("Versions", 4, versions_score(cr.versions));
- score.group("Authors/Owners", 3, authors_score(cr.authors, cr.owners));
+ score.group("Authors/Owners", 3, authors_score(cr.authors, cr.owners, cr.contributors));
score
}
@@ -347,6 +364,10 @@ pub fn crate_score_temporal(cr: &CrateTemporalInputs) -> Score {
score.score_f("Downloads", 6., pop);
score.score_f("Downloads (cleaned)", 18., pop_cleaned);
+ // if it's new, it doesn't have to have many downloads.
+ // if it's aging, it'd better have more users
+ score.has("Any traction", 2, (cr.downloads_per_month as f64 * freshness_score) > 1000.);
+
// Don't expect apps to have rev deps (omitting these entirely proprtionally increases importance of other factors)
if !cr.is_app || cr.number_of_direct_reverse_deps > 1 {
score.score_f("Direct rev deps", 10., (cr.number_of_direct_reverse_deps as f64).sqrt());