git_stk/commands/
status.rs1use anyhow::Result;
2use clap_complete::engine::ArgValueCompleter;
3
4use crate::commands::Run;
5use crate::completions;
6use crate::providers::{CheckStatus, ReviewState, detect_review_provider};
7use crate::style;
8use crate::{git, stack};
9
10#[derive(Debug, clap::Args)]
12pub struct Status {
13 #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
15 branch: Option<String>,
16}
17
18impl Run for Status {
19 fn run(self) -> Result<()> {
20 print_status(self.branch.as_deref())
21 }
22}
23
24pub fn print_status(branch: Option<&str>) -> Result<()> {
25 let branch = branch
26 .map(str::to_owned)
27 .map_or_else(git::current_branch, Ok)?;
28 let parent = stack::parent_of(&branch)?;
29 let children = stack::children_of(&branch)?;
30
31 anstream::println!("branch: {}", style::paint(style::CURRENT, &branch));
32 if let Some(path) = git::worktree_holding(&branch).ok().flatten() {
35 anstream::println!("worktree: {}", git::display_path(&path));
36 }
37 match parent.as_deref() {
38 Some(parent) => anstream::println!("parent: {}", style::paint(style::BRANCH, parent)),
39 None => anstream::println!("parent: none"),
40 }
41 if children.is_empty() {
42 anstream::println!("children: none");
43 } else {
44 let children: Vec<String> = children
45 .iter()
46 .map(|child| style::paint(style::BRANCH, child))
47 .collect();
48 anstream::println!("children: {}", children.join(", "));
49 }
50
51 let detected = detect_review_provider().ok();
54 let review = match &detected {
55 Some((provider, review_provider)) => {
56 anstream::println!("provider: {} ({})", provider.kind, provider.source);
57 let review = review_provider.review_for_branch_including_closed(&branch)?;
60 match &review {
61 Some(review) => {
62 let queued = review_provider
67 .enqueued_branches(std::slice::from_ref(&review.branch))
68 .map(|set| set.contains(&review.branch))
69 .unwrap_or(false);
70 let marker = if queued {
71 crate::providers::QUEUED_MARK
72 } else {
73 review_provider
74 .check_status(review)
75 .unwrap_or(CheckStatus::None)
76 .dot()
77 };
78 anstream::println!(
79 "review: {marker}{} {} {} -> {}",
80 review.id,
81 style::state(&review.state),
82 style::paint(style::BRANCH, &review.branch),
83 style::paint(style::BRANCH, &review.base)
84 );
85 anstream::println!("url: {}", style::paint(style::DIM, &review.url));
86
87 if let Some(parent) = parent.as_deref()
88 && parent != review.base
89 {
90 anstream::println!(
91 "{} review base is {}, local parent is {parent} - run `git stk submit`",
92 style::paint(style::WARN, "warning:"),
93 review.base
94 );
95 }
96 }
97 None => anstream::println!("review: none"),
98 }
99 review
100 }
101 None => {
102 anstream::println!("{}", style::dim("provider: not detected (no review info)"));
103 None
104 }
105 };
106
107 let mut hints = Vec::new();
110 match &review {
111 Some(review) if review.state == ReviewState::Merged => {
112 hints.push(format!(
113 "review {} is merged - run `git stk sync`",
114 review.id
115 ));
116 }
117 Some(review) if review.state == ReviewState::Closed => {
118 hints.push(format!(
119 "review {} was closed without merging - `git stk submit` opens a new review",
120 review.id
121 ));
122 }
123 _ => {}
124 }
125 if let Some(parent) = parent.as_deref() {
126 if let Some((_, review_provider)) = &detected {
127 match review_provider.review_for_branch_including_closed(parent) {
128 Ok(Some(parent_review)) if parent_review.branch == parent => {
129 match parent_review.state {
130 ReviewState::Merged => hints.push(format!(
131 "parent review {} is merged - run `git stk sync`",
132 parent_review.id
133 )),
134 ReviewState::Closed => hints.push(format!(
135 "parent review {} was closed without merging - \
136 retarget {branch} with `git stk adopt`",
137 parent_review.id
138 )),
139 _ => {}
140 }
141 }
142 _ => {}
143 }
144 }
145
146 if hints.is_empty()
147 && let Some(hint) = stack::behind_parent_hint(&branch, parent)
148 {
149 hints.push(hint);
150 }
151 }
152 for hint in hints {
153 anstream::println!("{} {hint}", style::paint(style::HINT, "hint:"));
154 }
155
156 Ok(())
157}