Skip to main content

devcap_core/
model.rs

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}