Skip to main content

aft/github_read/
model.rs

1use serde::{Deserialize, Serialize};
2
3use super::resource::GithubResourceKind;
4
5/// Structured GitHub data consumed by the canonical Rust renderer.
6///
7/// Fetchers normalize their provider-specific JSON into this model. Keeping the
8/// renderer independent of CLI field spelling prevents accidental parsing of
9/// human-oriented `gh` output and gives fixture tests a stable seam.
10#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
11#[serde(default, rename_all = "camelCase")]
12pub struct GithubDocument {
13    pub repository: String,
14    pub kind: GithubDocumentKind,
15    pub number: u64,
16    pub title: String,
17    pub state: String,
18    pub author: Option<String>,
19    pub created_at: Option<String>,
20    pub updated_at: Option<String>,
21    pub labels: Vec<String>,
22    pub assignees: Vec<String>,
23    pub milestone: Option<String>,
24    pub body: String,
25    pub reactions: Vec<GithubReaction>,
26    pub comments: Vec<GithubComment>,
27    /// Total issue-discussion comments before the renderer applies its cap.
28    pub comments_total_count: Option<usize>,
29    /// Server-supplied count when it includes minimized comments outside the
30    /// local page. The renderer also counts minimized comments it received.
31    pub minimized_comments_count: Option<usize>,
32    pub files: Vec<GithubPullRequestFile>,
33    pub reviews: Vec<GithubReview>,
34    pub review_comment_sections: Vec<GithubReviewCommentSection>,
35    pub base_ref_name: Option<String>,
36    pub head_ref_name: Option<String>,
37    pub review_decision: Option<String>,
38    /// Timeline events selected from GitHub's issue timeline endpoint.
39    pub timeline: Vec<GithubTimelineEvent>,
40}
41
42impl GithubDocument {
43    pub fn resource_kind(&self) -> GithubResourceKind {
44        match self.kind {
45            GithubDocumentKind::Issue => GithubResourceKind::Issue,
46            GithubDocumentKind::PullRequest => GithubResourceKind::PullRequest,
47        }
48    }
49}
50
51/// Resource-kind mirror included in structured fixtures and normalized data.
52#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
53#[serde(rename_all = "snake_case")]
54pub enum GithubDocumentKind {
55    #[default]
56    Issue,
57    PullRequest,
58}
59
60#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
61#[serde(default, rename_all = "camelCase")]
62pub struct GithubReaction {
63    pub content: String,
64    pub count: u64,
65}
66
67#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
68#[serde(default, rename_all = "camelCase")]
69pub struct GithubComment {
70    pub author: Option<String>,
71    pub body: String,
72    /// Stable browser URL used to correlate a just-created comment with its read ordinal.
73    pub url: Option<String>,
74    pub created_at: Option<String>,
75    pub updated_at: Option<String>,
76    pub minimized: bool,
77    pub path: Option<String>,
78    pub line: Option<u64>,
79}
80
81#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
82#[serde(default, rename_all = "camelCase")]
83pub struct GithubPullRequestFile {
84    pub path: String,
85    pub additions: Option<u64>,
86    pub deletions: Option<u64>,
87    pub status: Option<String>,
88}
89
90#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
91#[serde(default, rename_all = "camelCase")]
92pub struct GithubReview {
93    pub author: Option<String>,
94    pub body: String,
95    pub state: Option<String>,
96    pub submitted_at: Option<String>,
97    pub comments: Vec<GithubComment>,
98    pub comments_total_count: Option<usize>,
99}
100
101/// One review's inline-comment section. Each section is capped independently,
102/// so an active review cannot crowd comments out of a different review.
103#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
104#[serde(default, rename_all = "camelCase")]
105pub struct GithubReviewCommentSection {
106    pub author: Option<String>,
107    pub submitted_at: Option<String>,
108    pub comments: Vec<GithubComment>,
109    pub comments_total_count: Option<usize>,
110    pub minimized_comments_count: Option<usize>,
111}
112
113/// A timeline state-change event normalized from GitHub's issue timeline API.
114#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
115#[serde(default, rename_all = "camelCase")]
116pub struct GithubTimelineEvent {
117    pub actor: Option<String>,
118    pub event: String,
119    pub created_at: Option<String>,
120    pub label: Option<String>,
121    pub assignee: Option<String>,
122    pub milestone: Option<String>,
123    pub rename_from: Option<String>,
124    pub rename_to: Option<String>,
125    pub requested_reviewer: Option<String>,
126    pub commit_id: Option<String>,
127}