1use std::collections::HashSet;
2use std::fmt;
3
4use chrono::{DateTime, Local};
5use serde::Serialize;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub enum RepoOrigin {
9 #[serde(rename = "github")]
10 GitHub,
11 #[serde(rename = "gitlab")]
12 GitLab,
13 #[serde(rename = "bitbucket")]
14 Bitbucket,
15 #[serde(rename = "gitlab-self-hosted")]
16 GitLabSelfHosted,
17 #[serde(untagged)]
18 Custom(String),
19}
20
21impl fmt::Display for RepoOrigin {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 match self {
24 RepoOrigin::GitHub => write!(f, "GitHub"),
25 RepoOrigin::GitLab => write!(f, "GitLab"),
26 RepoOrigin::Bitbucket => write!(f, "Bitbucket"),
27 RepoOrigin::GitLabSelfHosted => write!(f, "GitLab Self-Hosted"),
28 RepoOrigin::Custom(host) => write!(f, "{host}"),
29 }
30 }
31}
32
33#[derive(Debug, Serialize)]
34pub struct Commit {
35 pub hash: String,
36 pub message: String,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub commit_type: Option<String>,
39 #[serde(rename = "timestamp")]
40 pub time: DateTime<Local>,
41 pub relative_time: String,
42}
43
44#[derive(Debug, Serialize)]
45pub struct BranchLog {
46 pub name: String,
47 pub commits: Vec<Commit>,
48}
49
50#[derive(Debug, Serialize)]
51pub struct ProjectLog {
52 pub project: String,
53 pub path: String,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub origin: Option<RepoOrigin>,
56 #[serde(skip_serializing_if = "Option::is_none")]
57 pub remote_url: Option<String>,
58 pub branches: Vec<BranchLog>,
59}
60
61impl BranchLog {
62 pub fn latest_activity(&self) -> Option<&str> {
63 self.commits.first().map(|c| c.relative_time.as_str())
64 }
65}
66
67impl ProjectLog {
68 pub fn total_commits(&self) -> usize {
69 let mut seen = HashSet::new();
70 self.branches
71 .iter()
72 .flat_map(|b| &b.commits)
73 .filter(|c| seen.insert(&c.hash))
74 .count()
75 }
76
77 pub fn latest_activity(&self) -> Option<&str> {
78 self.branches
79 .iter()
80 .flat_map(|b| b.commits.first())
81 .max_by_key(|c| c.time)
82 .map(|c| c.relative_time.as_str())
83 }
84}