use crate::commands::{Command, CommandResult};
use crate::services::GitService;
use crate::app::{AppState, Action, reducer};
use crate::app::rebase::{RebaseOperations, operations::{RebaseResult, RebaseRecovery}};
use crate::errors::CommandError;
use tracing::instrument;
#[cfg(test)]
mod tests {
use super::*;
use crate::app::AppState;
use crate::services::GitService;
use crate::commands::CommandResult;
use std::sync::Arc;
fn create_test_state() -> AppState {
let mut state = AppState::new();
state.repo_path = ".".to_string();
state
}
fn create_mock_git_service() -> Arc<GitService> {
Arc::new(GitService::new())
}
#[test]
fn test_rebase_save_and_run_command_creation() {
let command = RebaseSaveAndRunCommand;
assert!(true); }
#[test]
fn test_rebase_continue_command_creation() {
let command = RebaseContinueCommand;
assert!(true); }
#[test]
fn test_rebase_skip_command_creation() {
let command = RebaseSkipCommand;
assert!(true); }
#[test]
fn test_rebase_abort_command_creation() {
let command = RebaseAbortCommand;
assert!(true); }
#[test]
fn test_rebase_resolve_conflicts_command_creation() {
let command = RebaseResolveConflictsCommand;
assert!(true); }
#[test]
fn test_rebase_abort_from_conflict_command_creation() {
let command = RebaseAbortFromConflictCommand;
assert!(true); }
#[test]
fn test_rebase_continue_interrupted_command_creation() {
let command = RebaseContinueInterruptedCommand;
assert!(true); }
#[test]
fn test_rebase_abort_interrupted_command_creation() {
let command = RebaseAbortInterruptedCommand;
assert!(true); }
}
pub struct RebaseSaveAndRunCommand;
pub struct RebaseContinueCommand;
pub struct RebaseSkipCommand;
pub struct RebaseAbortCommand;
pub struct RebaseResolveConflictsCommand;
pub struct RebaseAbortFromConflictCommand;
pub struct RebaseContinueInterruptedCommand;
pub struct RebaseAbortInterruptedCommand;
impl Command for RebaseSaveAndRunCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseOperations::execute_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Success => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase started successfully".to_string())));
new_state.rebase_editor_open = false;
}
RebaseResult::Conflicts { .. } => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase started but conflicts detected".to_string())));
new_state.rebase_editor_open = false;
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to start rebase: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseContinueCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseOperations::continue_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Success => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase continued successfully".to_string())));
}
RebaseResult::Completed => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase completed successfully".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
}
RebaseResult::Conflicts { .. } => {
new_state = reducer(new_state, Action::SetFeedback(Some("Conflicts detected during continue".to_string())));
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result during continue".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to continue rebase: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseSkipCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseOperations::skip_rebase_step(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Success => {
new_state = reducer(new_state, Action::SetFeedback(Some("Skipped current commit, rebase continued".to_string())));
}
RebaseResult::Completed => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase completed successfully".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
}
RebaseResult::Conflicts { .. } => {
new_state = reducer(new_state, Action::SetFeedback(Some("Conflicts detected after skipping".to_string())));
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result during skip".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to skip rebase step: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseAbortCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseOperations::abort_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Aborted => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase aborted successfully".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result during abort".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to abort rebase: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseResolveConflictsCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match git.status_porcelain(&state.repo_path) {
Ok(status) => {
if status.contains("U ") || status.contains("AA ") || status.contains("DD ") {
new_state = reducer(new_state, Action::SetStatusError(Some("Conflicts still exist. Please resolve all conflicts before continuing.".to_string())));
return Ok(CommandResult::StateUpdate(new_state));
}
if !status.lines().any(|line| line.starts_with("M ") || line.starts_with("A ") || line.starts_with("D ")) {
new_state = reducer(new_state, Action::SetStatusError(Some("No staged changes found. Please stage your conflict resolutions.".to_string())));
return Ok(CommandResult::StateUpdate(new_state));
}
match RebaseOperations::continue_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Success => {
new_state = reducer(new_state, Action::SetFeedback(Some("Conflicts resolved, rebase continued".to_string())));
}
RebaseResult::Completed => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase completed successfully after conflict resolution".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
}
RebaseResult::Conflicts { .. } => {
new_state = reducer(new_state, Action::SetFeedback(Some("Additional conflicts detected".to_string())));
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result after conflict resolution".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to continue rebase after conflict resolution: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
Err(e) => {
let error_msg = format!("Failed to check repository status: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseAbortFromConflictCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseOperations::abort_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Aborted => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase aborted from conflict state".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result during abort from conflict".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to abort rebase from conflict state: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseContinueInterruptedCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseRecovery::continue_interrupted_rebase(git, &state.repo_path, &mut new_state.rebase_session) {
Ok(result) => {
match result {
RebaseResult::Success => {
new_state = reducer(new_state, Action::SetFeedback(Some("Continued interrupted rebase".to_string())));
new_state.rebase_recovery_open = false;
}
RebaseResult::Completed => {
new_state = reducer(new_state, Action::SetFeedback(Some("Rebase completed successfully".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
new_state.rebase_recovery_open = false;
}
RebaseResult::Conflicts { .. } => {
new_state = reducer(new_state, Action::SetFeedback(Some("Conflicts detected in interrupted rebase".to_string())));
new_state.rebase_recovery_open = false;
}
_ => {
new_state = reducer(new_state, Action::SetStatusError(Some("Unexpected rebase result during recovery".to_string())));
}
}
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to continue interrupted rebase: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}
impl Command for RebaseAbortInterruptedCommand {
#[instrument(skip(self, git, state))]
fn execute(
&self,
git: &GitService,
state: &AppState,
) -> Result<CommandResult, CommandError> {
let mut new_state = state.clone();
match RebaseRecovery::abort_interrupted_rebase(git, &state.repo_path) {
Ok(()) => {
new_state = reducer(new_state, Action::SetFeedback(Some("Aborted interrupted rebase".to_string())));
new_state.rebase_session = crate::app::rebase::RebaseSession::default();
new_state.rebase_recovery_open = false;
Ok(CommandResult::StateUpdate(new_state))
}
Err(e) => {
let error_msg = format!("Failed to abort interrupted rebase: {}", e);
new_state = reducer(new_state, Action::SetStatusError(Some(error_msg.clone())));
Err(CommandError::GitError(crate::errors::GitError::OperationError(anyhow::anyhow!(error_msg))))
}
}
}
}