Skip to main content

git_stk/
cli.rs

1use clap::{ArgAction, Parser, Subcommand};
2use clap_complete::engine::ArgValueCompleter;
3
4use crate::completions;
5
6#[derive(Debug, Parser)]
7#[command(name = "git-stk")]
8#[command(version)]
9#[command(about = "Git-native stacked branch workflow helper, with GitHub and GitLab integration")]
10pub struct Cli {
11    #[command(subcommand)]
12    pub command: Command,
13}
14
15#[derive(Debug, Subcommand)]
16pub enum Command {
17    /// Create a new child branch from the current branch.
18    New { branch: String },
19    /// Print a branch's stack parent.
20    Parent {
21        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
22        branch: Option<String>,
23    },
24    /// Print a branch's stack children.
25    Children {
26        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
27        branch: Option<String>,
28    },
29    /// Move up the stack: check out a child of the current branch.
30    Up {
31        #[arg(add = ArgValueCompleter::new(completions::child_branch_candidates))]
32        branch: Option<String>,
33    },
34    /// Move down the stack: check out the current branch's parent.
35    Down,
36    /// Print the current stack.
37    List {
38        /// Print a shareable markdown summary with PR links and states.
39        #[arg(long, action = ArgAction::SetTrue)]
40        markdown: bool,
41    },
42    /// Print local and remote stack status for a branch.
43    Status {
44        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
45        branch: Option<String>,
46    },
47    /// Attach an existing branch to a parent.
48    Adopt {
49        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
50        branch: String,
51        #[arg(long, add = ArgValueCompleter::new(completions::branch_candidates))]
52        parent: String,
53    },
54    /// Remove stack parent metadata from a branch.
55    Detach {
56        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
57        branch: Option<String>,
58    },
59    /// Rebase the current branch and descendants onto their stack parents.
60    Restack {
61        /// Pass --update-refs to git rebase.
62        #[arg(long, action = ArgAction::SetTrue, conflicts_with = "no_update_refs")]
63        update_refs: bool,
64        /// Do not pass --update-refs to git rebase.
65        #[arg(long, action = ArgAction::SetTrue)]
66        no_update_refs: bool,
67        /// Force-push (with lease) every rebased branch afterwards.
68        #[arg(long, action = ArgAction::SetTrue, conflicts_with = "no_push")]
69        push: bool,
70        /// Do not push rebased branches, overriding stk.pushOnRestack.
71        #[arg(long, action = ArgAction::SetTrue)]
72        no_push: bool,
73    },
74    /// Continue an interrupted restack after resolving conflicts.
75    Continue,
76    /// Abort an interrupted restack.
77    Abort,
78    /// Print detected review provider.
79    Provider,
80    /// Print the review request for a branch.
81    Review {
82        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
83        branch: Option<String>,
84    },
85    /// Sync local stack metadata from remote review requests.
86    Sync {
87        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
88        branch: Option<String>,
89        /// Print what would change without updating local metadata.
90        #[arg(long, action = ArgAction::SetTrue)]
91        dry_run: bool,
92    },
93    /// Rebuild or verify local stack metadata from reviews and ancestry.
94    Repair {
95        /// Print what would change without updating local metadata.
96        #[arg(long, action = ArgAction::SetTrue)]
97        dry_run: bool,
98    },
99    /// Create or update a remote review request for a branch.
100    Submit {
101        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
102        branch: Option<String>,
103        /// Print what would change without creating or updating reviews.
104        #[arg(long, action = ArgAction::SetTrue)]
105        dry_run: bool,
106        /// Submit the branch and its descendants parent-first.
107        #[arg(long, conflicts_with = "branch")]
108        stack: bool,
109        /// Push branches (-u --force-with-lease) before submitting.
110        #[arg(long, action = ArgAction::SetTrue, conflicts_with = "no_push")]
111        push: bool,
112        /// Do not push branches, overriding stk.pushOnSubmit.
113        #[arg(long, action = ArgAction::SetTrue)]
114        no_push: bool,
115    },
116    /// Print all stk git config settings and branch metadata.
117    Config,
118    /// Print shell completions.
119    Completions {
120        /// Shell to print completions for.
121        #[arg(value_enum)]
122        shell: clap_complete::Shell,
123    },
124    /// Install the man page and wire up shell completions.
125    Setup {
126        /// Skip confirmation prompts.
127        #[arg(long, short = 'y', action = ArgAction::SetTrue)]
128        yes: bool,
129        /// Only re-render generated assets (man page); never touch shell rc files.
130        #[arg(long, action = ArgAction::SetTrue, conflicts_with = "yes")]
131        refresh: bool,
132    },
133    /// Upgrade git-stk to the latest release.
134    Upgrade {
135        /// Build and install the latest unreleased commit instead.
136        #[arg(long, action = ArgAction::SetTrue, conflicts_with = "force")]
137        head: bool,
138        /// Reinstall the latest release even when already up to date.
139        #[arg(long, action = ArgAction::SetTrue)]
140        force: bool,
141        /// Skip the --head confirmation prompt.
142        #[arg(long, short = 'y', action = ArgAction::SetTrue, requires = "head")]
143        yes: bool,
144    },
145    /// Clean up local metadata for merged review requests.
146    Cleanup {
147        #[arg(add = ArgValueCompleter::new(completions::branch_candidates))]
148        branch: Option<String>,
149        /// Print what would change without updating local metadata.
150        #[arg(long, action = ArgAction::SetTrue)]
151        dry_run: bool,
152        /// Delete cleaned merged branches after updating stack metadata.
153        #[arg(long, action = ArgAction::SetTrue)]
154        delete_branch: bool,
155    },
156}
157
158#[derive(Debug, Clone, Copy, Eq, PartialEq)]
159pub enum UpdateRefsMode {
160    Config,
161    Enabled,
162    Disabled,
163}
164
165impl UpdateRefsMode {
166    pub fn from_flags(update_refs: bool, no_update_refs: bool) -> Self {
167        match (update_refs, no_update_refs) {
168            (true, false) => Self::Enabled,
169            (false, true) => Self::Disabled,
170            _ => Self::Config,
171        }
172    }
173}
174
175#[derive(Debug, Clone, Copy, Eq, PartialEq)]
176pub enum PushMode {
177    Config,
178    Enabled,
179    Disabled,
180}
181
182impl PushMode {
183    pub fn from_flags(push: bool, no_push: bool) -> Self {
184        match (push, no_push) {
185            (true, false) => Self::Enabled,
186            (false, true) => Self::Disabled,
187            _ => Self::Config,
188        }
189    }
190}