Skip to content

Commit

Permalink
Refactoring git metrics module (#1217)
Browse files Browse the repository at this point in the history
* refacot

* add break line
  • Loading branch information
o2sh authored Nov 28, 2023
1 parent 621da73 commit f1905dc
Show file tree
Hide file tree
Showing 11 changed files with 284 additions and 248 deletions.
98 changes: 94 additions & 4 deletions src/info/authors.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use super::git::metrics::GitMetrics;
use super::git::sig::Sig;
use crate::{
cli::NumberSeparator,
info::utils::{format_number, info_field::InfoField},
};
use serde::Serialize;
use std::fmt::Write;
use std::{collections::HashMap, fmt::Write};

#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -66,8 +66,20 @@ pub struct AuthorsInfo {
}

impl AuthorsInfo {
pub fn new(git_metrics: &GitMetrics) -> Self {
let authors = git_metrics.authors_to_display.clone();
pub fn new(
number_of_commits_by_signature: &HashMap<Sig, usize>,
total_number_of_commits: usize,
number_of_authors_to_display: usize,
show_email: bool,
number_separator: NumberSeparator,
) -> Self {
let authors = compute_authors(
number_of_commits_by_signature,
total_number_of_commits,
number_of_authors_to_display,
show_email,
number_separator,
);
Self { authors }
}

Expand All @@ -79,6 +91,40 @@ impl AuthorsInfo {
}
}

fn compute_authors(
number_of_commits_by_signature: &HashMap<Sig, usize>,
total_number_of_commits: usize,
number_of_authors_to_display: usize,
show_email: bool,
number_separator: NumberSeparator,
) -> Vec<Author> {
let mut signature_with_number_of_commits_sorted: Vec<(&Sig, &usize)> =
Vec::from_iter(number_of_commits_by_signature);

signature_with_number_of_commits_sorted.sort_by(|(sa, a_count), (sb, b_count)| {
b_count.cmp(a_count).then_with(|| sa.name.cmp(&sb.name))
});

let authors: Vec<Author> = signature_with_number_of_commits_sorted
.into_iter()
.map(|(author, author_nbr_of_commits)| {
Author::new(
author.name.to_string(),
if show_email {
Some(author.email.to_string())
} else {
None
},
*author_nbr_of_commits,
total_number_of_commits,
number_separator,
)
})
.take(number_of_authors_to_display)
.collect();
authors
}

fn digit_difference(num1: usize, num2: usize) -> usize {
let count_digits = |num: usize| (num.checked_ilog10().unwrap_or(0) + 1) as usize;
count_digits(num1).abs_diff(count_digits(num2))
Expand Down Expand Up @@ -285,4 +331,48 @@ mod test {
let result = digit_difference(num1, num2);
assert_eq!(result, expected);
}

#[test]
fn test_compute_authors() {
let mut number_of_commits_by_signature: HashMap<Sig, usize> = HashMap::new();
number_of_commits_by_signature.insert(
Sig {
name: "John Doe".into(),
email: "johndoe@example.com".into(),
},
30,
);
number_of_commits_by_signature.insert(
Sig {
name: "Jane Doe".into(),
email: "janedoe@example.com".into(),
},
20,
);
number_of_commits_by_signature.insert(
Sig {
name: "Ellen Smith".into(),
email: "ellensmith@example.com".into(),
},
50,
);
let total_number_of_commits = 100;
let number_of_authors_to_display = 2;
let show_email = false;
let number_separator = NumberSeparator::Comma;

let actual = compute_authors(
&number_of_commits_by_signature,
total_number_of_commits,
number_of_authors_to_display,
show_email,
number_separator,
);

let expected = vec![
Author::new(String::from("Ellen Smith"), None, 50, 100, number_separator),
Author::new(String::from("John Doe"), None, 30, 100, number_separator),
];
assert_eq!(actual, expected);
}
}
95 changes: 88 additions & 7 deletions src/info/churn.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use super::{git::metrics::GitMetrics, utils::info_field::InfoField};
use super::utils::info_field::InfoField;
use crate::{cli::NumberSeparator, info::utils::format_number};
use anyhow::Result;
use gix::bstr::BString;
use globset::{Glob, GlobSetBuilder};
use serde::Serialize;
use std::fmt::Write;
use std::{collections::HashMap, fmt::Write};

#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
Expand Down Expand Up @@ -42,15 +45,62 @@ pub struct ChurnInfo {
pub file_churns: Vec<FileChurn>,
pub churn_pool_size: usize,
}

impl ChurnInfo {
pub fn new(git_metrics: &GitMetrics) -> Self {
let file_churns = git_metrics.file_churns_to_display.clone();
Self {
pub fn new(
number_of_commits_by_file_path: &HashMap<BString, usize>,
churn_pool_size: usize,
number_of_file_churns_to_display: usize,
globs_to_exclude: &[String],
number_separator: NumberSeparator,
) -> Result<Self> {
let file_churns = compute_file_churns(
number_of_commits_by_file_path,
number_of_file_churns_to_display,
globs_to_exclude,
number_separator,
)?;

Ok(Self {
file_churns,
churn_pool_size: git_metrics.churn_pool_size,
}
churn_pool_size,
})
}
}

fn compute_file_churns(
number_of_commits_by_file_path: &HashMap<BString, usize>,
number_of_file_churns_to_display: usize,
globs_to_exclude: &[String],
number_separator: NumberSeparator,
) -> Result<Vec<FileChurn>> {
let mut builder = GlobSetBuilder::new();
for glob in globs_to_exclude {
builder.add(Glob::new(glob)?);
}
let glob_set = builder.build()?;
let mut number_of_commits_by_file_path_sorted = Vec::from_iter(number_of_commits_by_file_path);

number_of_commits_by_file_path_sorted
.sort_by(|(_, a_count), (_, b_count)| b_count.cmp(a_count));

Ok(number_of_commits_by_file_path_sorted
.into_iter()
.filter_map(|(file_path, nbr_of_commits)| {
if !glob_set.is_match(file_path.to_string()) {
Some(FileChurn::new(
file_path.to_string(),
*nbr_of_commits,
number_separator,
))
} else {
None
}
})
.take(number_of_file_churns_to_display)
.collect())
}

impl std::fmt::Display for ChurnInfo {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let mut churn_info = String::new();
Expand Down Expand Up @@ -139,4 +189,35 @@ mod tests {
);
assert_eq!(shorten_file_path("file.txt", 0), "file.txt");
}

#[test]
fn test_compute_file_churns() -> Result<()> {
let mut number_of_commits_by_file_path = HashMap::new();
number_of_commits_by_file_path.insert("path/to/file1.txt".into(), 2);
number_of_commits_by_file_path.insert("path/to/file2.txt".into(), 5);
number_of_commits_by_file_path.insert("path/to/file3.txt".into(), 3);
number_of_commits_by_file_path.insert("path/to/file4.txt".into(), 7);
number_of_commits_by_file_path.insert("foo/x/y/file.txt".into(), 70);
number_of_commits_by_file_path.insert("foo/x/file.txt".into(), 10);

let number_of_file_churns_to_display = 3;
let number_separator = NumberSeparator::Comma;
let globs_to_exclude = vec![
"foo/**/file.txt".to_string(),
"path/to/file2.txt".to_string(),
];
let actual = compute_file_churns(
&number_of_commits_by_file_path,
number_of_file_churns_to_display,
&globs_to_exclude,
number_separator,
)?;
let expected = vec![
FileChurn::new(String::from("path/to/file4.txt"), 7, number_separator),
FileChurn::new(String::from("path/to/file3.txt"), 3, number_separator),
FileChurn::new(String::from("path/to/file1.txt"), 2, number_separator),
];
assert_eq!(actual, expected);
Ok(())
}
}
20 changes: 4 additions & 16 deletions src/info/contributors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::{git::metrics::GitMetrics, utils::format_number};
use super::utils::format_number;
use crate::{cli::NumberSeparator, info::utils::info_field::InfoField};
use serde::Serialize;

Expand All @@ -14,12 +14,12 @@ pub struct ContributorsInfo {

impl ContributorsInfo {
pub fn new(
git_metrics: &GitMetrics,
total_number_of_authors: usize,
number_of_authors_to_display: usize,
number_separator: NumberSeparator,
) -> Self {
Self {
total_number_of_authors: git_metrics.total_number_of_authors,
total_number_of_authors,
number_of_authors_to_display,
number_separator,
}
Expand All @@ -44,22 +44,10 @@ impl InfoField for ContributorsInfo {
#[cfg(test)]
mod test {
use super::*;
use gix::date::Time;

#[test]
fn test_display_contributors_info() {
let timestamp = Time::now_utc();
let git_metrics = GitMetrics {
authors_to_display: vec![],
file_churns_to_display: vec![],
total_number_of_authors: 12,
total_number_of_commits: 2,
churn_pool_size: 0,
time_of_most_recent_commit: timestamp,
time_of_first_commit: timestamp,
};

let contributors_info = ContributorsInfo::new(&git_metrics, 2, NumberSeparator::Plain);
let contributors_info = ContributorsInfo::new(12, 2, NumberSeparator::Plain);
assert_eq!(contributors_info.value(), "12".to_string());
assert_eq!(contributors_info.title(), "Contributors".to_string());
}
Expand Down
Loading

0 comments on commit f1905dc

Please sign in to comment.