1use crate::doctor::{CheckStatus, DoctorReport};
19use crate::error::Result;
20use crate::worktree::{self, BranchStatus, WorktreeInfo};
21use serde::{Deserialize, Serialize};
22
23#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct JsonStatus {
27 pub is_dirty: bool,
28 pub has_upstream: bool,
29 pub ahead: usize,
30 pub behind: usize,
31 pub unknown: bool,
33}
34
35impl From<&BranchStatus> for JsonStatus {
36 fn from(s: &BranchStatus) -> Self {
37 Self {
38 is_dirty: s.is_dirty,
39 has_upstream: s.has_upstream,
40 ahead: s.ahead,
41 behind: s.behind,
42 unknown: s.unknown,
43 }
44 }
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
51pub struct JsonWorktree {
52 pub name: String,
54 pub id: String,
57 pub path: String,
59 pub branch: Option<String>,
60 pub head: Option<String>,
64 pub is_main: bool,
65 pub is_locked: bool,
66 pub is_prunable: bool,
67 pub status: JsonStatus,
68 pub age_seconds: Option<u64>,
71 pub issue: Option<u64>,
73 pub pr: Option<u64>,
75}
76
77impl From<&WorktreeInfo> for JsonWorktree {
78 fn from(w: &WorktreeInfo) -> Self {
79 Self {
80 name: w.name.clone(),
81 id: w.id.clone(),
82 path: w.path.to_string_lossy().into_owned(),
83 branch: w.branch.clone(),
84 head: w.head.clone(),
85 is_main: w.is_main,
86 is_locked: w.is_locked,
87 is_prunable: w.is_prunable,
88 status: JsonStatus::from(&w.status),
89 age_seconds: w.age.map(|d| d.as_secs()),
90 issue: w.link.issue,
91 pr: w.link.pr,
92 }
93 }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
98pub struct JsonPath {
99 pub name: String,
100 pub path: String,
101 pub branch: Option<String>,
102}
103
104impl From<&WorktreeInfo> for JsonPath {
105 fn from(w: &WorktreeInfo) -> Self {
106 Self {
107 name: w.name.clone(),
108 path: w.path.to_string_lossy().into_owned(),
109 branch: w.branch.clone(),
110 }
111 }
112}
113
114pub fn check_status_str(status: &CheckStatus) -> &'static str {
117 match status {
118 CheckStatus::Ok => "ok",
119 CheckStatus::Warning => "warning",
120 CheckStatus::Failed => "failed",
121 }
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
126pub struct JsonCheck {
127 pub name: String,
128 pub status: String,
130 pub detail: String,
131 pub fix_hint: Option<String>,
132}
133
134#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
138pub struct JsonDoctorReport {
139 pub checks: Vec<JsonCheck>,
140 pub severity: String,
142 pub exit_code: i32,
143}
144
145impl From<&DoctorReport> for JsonDoctorReport {
146 fn from(r: &DoctorReport) -> Self {
147 Self {
148 checks: r
149 .checks
150 .iter()
151 .map(|c| JsonCheck {
152 name: c.name.clone(),
153 status: check_status_str(&c.status).to_string(),
154 detail: c.detail.clone(),
155 fix_hint: c.fix_hint.clone(),
156 })
157 .collect(),
158 severity: check_status_str(&r.severity()).to_string(),
159 exit_code: r.exit_code(),
160 }
161 }
162}
163
164pub fn worktrees(repo: &git2::Repository) -> Result<Vec<JsonWorktree>> {
168 Ok(worktree::list(repo)?.iter().map(JsonWorktree::from).collect())
169}