Skip to main content

omni_dev/cli/
git.rs

1//! Git-related CLI commands.
2
3mod amend;
4mod check;
5mod create_pr;
6mod info;
7mod twiddle;
8mod view;
9
10pub use amend::AmendCommand;
11pub use check::CheckCommand;
12pub use create_pr::{CreatePrCommand, PrContent};
13pub use info::InfoCommand;
14pub use twiddle::TwiddleCommand;
15pub use view::ViewCommand;
16
17use anyhow::{Context, Result};
18use clap::{Parser, Subcommand};
19
20/// Parses a `--beta-header key:value` string into a `(key, value)` tuple.
21pub(crate) fn parse_beta_header(s: &str) -> Result<(String, String)> {
22    let (k, v) = s.split_once(':').ok_or_else(|| {
23        anyhow::anyhow!("Invalid --beta-header format '{}'. Expected key:value", s)
24    })?;
25    Ok((k.to_string(), v.to_string()))
26}
27
28/// Git operations.
29#[derive(Parser)]
30pub struct GitCommand {
31    /// Git subcommand to execute.
32    #[command(subcommand)]
33    pub command: GitSubcommands,
34}
35
36/// Git subcommands.
37#[derive(Subcommand)]
38pub enum GitSubcommands {
39    /// Commit-related operations.
40    Commit(CommitCommand),
41    /// Branch-related operations.
42    Branch(BranchCommand),
43}
44
45/// Commit operations.
46#[derive(Parser)]
47pub struct CommitCommand {
48    /// Commit subcommand to execute.
49    #[command(subcommand)]
50    pub command: CommitSubcommands,
51}
52
53/// Commit subcommands.
54#[derive(Subcommand)]
55pub enum CommitSubcommands {
56    /// Commit message operations.
57    Message(MessageCommand),
58}
59
60/// Message operations.
61#[derive(Parser)]
62pub struct MessageCommand {
63    /// Message subcommand to execute.
64    #[command(subcommand)]
65    pub command: MessageSubcommands,
66}
67
68/// Message subcommands.
69#[derive(Subcommand)]
70pub enum MessageSubcommands {
71    /// Analyzes commits and outputs repository information in YAML format.
72    View(ViewCommand),
73    /// Amends commit messages based on a YAML configuration file.
74    Amend(AmendCommand),
75    /// AI-powered commit message improvement using Claude.
76    Twiddle(TwiddleCommand),
77    /// Checks commit messages against guidelines without modifying them.
78    Check(CheckCommand),
79}
80
81/// Branch operations.
82#[derive(Parser)]
83pub struct BranchCommand {
84    /// Branch subcommand to execute.
85    #[command(subcommand)]
86    pub command: BranchSubcommands,
87}
88
89/// Branch subcommands.
90#[derive(Subcommand)]
91pub enum BranchSubcommands {
92    /// Analyzes branch commits and outputs repository information in YAML format.
93    Info(InfoCommand),
94    /// Create operations.
95    Create(CreateCommand),
96}
97
98/// Create operations.
99#[derive(Parser)]
100pub struct CreateCommand {
101    /// Create subcommand to execute.
102    #[command(subcommand)]
103    pub command: CreateSubcommands,
104}
105
106/// Create subcommands.
107#[derive(Subcommand)]
108pub enum CreateSubcommands {
109    /// Creates a pull request with AI-generated description.
110    Pr(CreatePrCommand),
111}
112
113impl GitCommand {
114    /// Executes the git command.
115    pub fn execute(self) -> Result<()> {
116        match self.command {
117            GitSubcommands::Commit(commit_cmd) => commit_cmd.execute(),
118            GitSubcommands::Branch(branch_cmd) => branch_cmd.execute(),
119        }
120    }
121}
122
123impl CommitCommand {
124    /// Executes the commit command.
125    pub fn execute(self) -> Result<()> {
126        match self.command {
127            CommitSubcommands::Message(message_cmd) => message_cmd.execute(),
128        }
129    }
130}
131
132impl MessageCommand {
133    /// Executes the message command.
134    pub fn execute(self) -> Result<()> {
135        match self.command {
136            MessageSubcommands::View(view_cmd) => view_cmd.execute(),
137            MessageSubcommands::Amend(amend_cmd) => amend_cmd.execute(),
138            MessageSubcommands::Twiddle(twiddle_cmd) => {
139                // Use tokio runtime for async execution
140                let rt =
141                    tokio::runtime::Runtime::new().context("Failed to create tokio runtime")?;
142                rt.block_on(twiddle_cmd.execute())
143            }
144            MessageSubcommands::Check(check_cmd) => {
145                // Use tokio runtime for async execution
146                let rt =
147                    tokio::runtime::Runtime::new().context("Failed to create tokio runtime")?;
148                rt.block_on(check_cmd.execute())
149            }
150        }
151    }
152}
153
154impl BranchCommand {
155    /// Executes the branch command.
156    pub fn execute(self) -> Result<()> {
157        match self.command {
158            BranchSubcommands::Info(info_cmd) => info_cmd.execute(),
159            BranchSubcommands::Create(create_cmd) => {
160                // Use tokio runtime for async execution
161                let rt = tokio::runtime::Runtime::new()
162                    .context("Failed to create tokio runtime for PR creation")?;
163                rt.block_on(create_cmd.execute())
164            }
165        }
166    }
167}
168
169impl CreateCommand {
170    /// Executes the create command.
171    pub async fn execute(self) -> Result<()> {
172        match self.command {
173            CreateSubcommands::Pr(pr_cmd) => pr_cmd.execute().await,
174        }
175    }
176}