gitfetch_rs/utils/
git.rs

1use anyhow::Result;
2use chrono::{DateTime, Datelike, Duration, NaiveDate, Utc};
3use git2::Repository;
4use serde_json::{Value, json};
5use std::collections::HashMap;
6
7pub fn get_repo_path() -> Result<String> {
8  let repo = Repository::discover(".")?;
9  let path = repo
10    .path()
11    .parent()
12    .ok_or_else(|| anyhow::anyhow!("Could not get repo path"))?;
13  Ok(path.to_string_lossy().to_string())
14}
15
16pub fn analyze_local_repo() -> Result<Value> {
17  let repo = Repository::discover(".")?;
18
19  // Get current user from git config
20  let config = repo.config()?;
21  let user_name = config
22    .get_string("user.name")
23    .unwrap_or_else(|_| "Unknown".to_string());
24  let user_email = config
25    .get_string("user.email")
26    .unwrap_or_else(|_| "".to_string());
27
28  // Collect commits from last 52 weeks
29  let mut revwalk = repo.revwalk()?;
30  revwalk.push_head()?;
31
32  let now = Utc::now();
33  let one_year_ago = now - Duration::weeks(52);
34
35  let mut commits_by_date: HashMap<NaiveDate, u32> = HashMap::new();
36  let mut total_commits = 0;
37
38  for oid in revwalk {
39    let oid = oid?;
40    let commit = repo.find_commit(oid)?;
41
42    let commit_time = commit.time();
43    let timestamp = commit_time.seconds();
44    let datetime =
45      DateTime::from_timestamp(timestamp, 0).ok_or_else(|| anyhow::anyhow!("Invalid timestamp"))?;
46
47    // Only count commits from last 52 weeks
48    if datetime < one_year_ago {
49      continue;
50    }
51
52    let date = datetime.date_naive();
53    *commits_by_date.entry(date).or_insert(0) += 1;
54    total_commits += 1;
55  }
56
57  // Generate weeks data (52 weeks, 7 days each)
58  let mut weeks = Vec::new();
59  let mut current_date = one_year_ago.date_naive();
60
61  // Start from Sunday
62  while current_date.weekday().num_days_from_sunday() != 0 {
63    current_date = current_date
64      .pred_opt()
65      .ok_or_else(|| anyhow::anyhow!("Date calculation error"))?;
66  }
67
68  for _ in 0..52 {
69    let mut week_days = Vec::new();
70
71    for _ in 0..7 {
72      let count = commits_by_date.get(&current_date).copied().unwrap_or(0);
73      week_days.push(json!({
74        "contributionCount": count,
75        "date": current_date.format("%Y-%m-%d").to_string(),
76      }));
77
78      current_date = current_date
79        .succ_opt()
80        .ok_or_else(|| anyhow::anyhow!("Date calculation error"))?;
81    }
82
83    weeks.push(json!({
84      "contributionDays": week_days
85    }));
86  }
87
88  Ok(json!({
89    "name": user_name,
90    "email": user_email,
91    "bio": format!("Local repository: {}", get_repo_path()?),
92    "company": "",
93    "website": "",
94    "total_repos": 1,
95    "total_stars": 0,
96    "total_forks": 0,
97    "languages": {},
98    "contribution_graph": weeks,
99    "current_streak": 0,
100    "longest_streak": 0,
101    "total_contributions": total_commits,
102    "pull_requests": {
103      "open": 0,
104      "awaiting_review": 0,
105      "mentions": 0
106    },
107    "issues": {
108      "assigned": 0,
109      "created": 0,
110      "mentions": 0
111    },
112  }))
113}