github_fetch/
types.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct GitHubIssue {
6    pub id: u64,
7    pub number: u64,
8    pub title: String,
9    pub body: Option<String>,
10    pub state: String,
11    pub labels: Vec<GitHubLabel>,
12    pub user: GitHubUser,
13    pub assignees: Vec<GitHubUser>,
14    pub created_at: DateTime<Utc>,
15    pub updated_at: DateTime<Utc>,
16    pub closed_at: Option<DateTime<Utc>>,
17    pub merged_at: Option<DateTime<Utc>>,
18    pub html_url: String,
19    pub is_pull_request: bool,
20    pub comments: u32,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct GitHubLabel {
25    pub id: u64,
26    pub name: String,
27    pub color: String,
28    pub description: Option<String>,
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct GitHubUser {
33    pub id: u64,
34    pub login: String,
35    pub avatar_url: String,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39pub struct GitHubComment {
40    pub id: u64,
41    pub user: GitHubUser,
42    pub body: String,
43    pub created_at: DateTime<Utc>,
44    pub updated_at: DateTime<Utc>,
45    pub html_url: String,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct Repository {
50    pub owner: String,
51    pub name: String,
52    pub full_name: String,
53}
54
55impl Repository {
56    pub fn new(owner: impl Into<String>, name: impl Into<String>) -> Self {
57        let owner = owner.into();
58        let name = name.into();
59        let full_name = format!("{}/{}", owner, name);
60        Self {
61            owner,
62            name,
63            full_name,
64        }
65    }
66
67    pub fn from_url(url: &str) -> anyhow::Result<Self> {
68        let parts: Vec<&str> = url.trim_end_matches('/').split('/').collect();
69
70        if parts.len() < 2 {
71            return Err(anyhow::anyhow!("Invalid repository URL: {}", url));
72        }
73
74        let owner = parts[parts.len() - 2].to_string();
75        let name = parts[parts.len() - 1].to_string();
76
77        Ok(Self::new(owner, name))
78    }
79
80    pub fn from_full_name(full_name: &str) -> anyhow::Result<Self> {
81        let parts: Vec<&str> = full_name.split('/').collect();
82        if parts.len() != 2 {
83            return Err(anyhow::anyhow!(
84                "Invalid repository full name format. Expected 'owner/name', got: {}",
85                full_name
86            ));
87        }
88        Ok(Self::new(parts[0], parts[1]))
89    }
90}
91
92#[derive(Debug, Clone, Serialize, Deserialize)]
93pub struct Discussion {
94    pub number: u64,
95    pub title: String,
96    pub body: String,
97    pub url: String,
98    pub author: GitHubUser,
99    pub created_at: DateTime<Utc>,
100    pub updated_at: DateTime<Utc>,
101    pub comments: Vec<DiscussionComment>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct DiscussionComment {
106    pub id: String,
107    pub body: String,
108    pub author: GitHubUser,
109    pub created_at: DateTime<Utc>,
110    pub updated_at: DateTime<Utc>,
111}
112
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct PrFile {
115    pub filename: String,
116    pub status: String,
117    pub additions: u32,
118    pub deletions: u32,
119    pub changes: u32,
120    pub patch: Option<String>,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct CollectionResult {
125    pub repository: Repository,
126    pub issues: Vec<GitHubIssue>,
127    pub total_collected: usize,
128    pub collection_time: DateTime<Utc>,
129    pub filters_applied: Vec<String>,
130}
131
132/// PR Review information
133#[derive(Debug, Clone, Serialize, Deserialize)]
134pub struct PrReview {
135    pub id: u64,
136    pub user: GitHubUser,
137    pub body: Option<String>,
138    /// Review state: APPROVED, CHANGES_REQUESTED, COMMENTED, DISMISSED, PENDING
139    pub state: String,
140    pub submitted_at: Option<DateTime<Utc>>,
141    pub html_url: String,
142    pub commit_id: Option<String>,
143}
144
145/// PR Review comment (inline comment on diff)
146#[derive(Debug, Clone, Serialize, Deserialize)]
147pub struct PrReviewComment {
148    pub id: u64,
149    pub review_id: Option<u64>,
150    pub user: GitHubUser,
151    pub body: String,
152    /// File path the comment is on
153    pub path: String,
154    /// Line number in the diff
155    pub line: Option<u32>,
156    /// Original line number (for multi-line comments)
157    pub original_line: Option<u32>,
158    /// Diff hunk context
159    pub diff_hunk: String,
160    /// Side of the diff: LEFT or RIGHT
161    pub side: Option<String>,
162    pub commit_id: Option<String>,
163    pub created_at: DateTime<Utc>,
164    pub updated_at: DateTime<Utc>,
165    pub html_url: String,
166    /// Position in the diff (deprecated, use line instead)
167    pub position: Option<u32>,
168    /// In reply to another comment
169    pub in_reply_to_id: Option<u64>,
170}