use crate::services::GitService;
use crate::app::rebase::{RebaseSession, RebasePhase};
use std::path::Path;
#[derive(Debug, thiserror::Error)]
pub enum RebaseValidationError {
#[error("Repository has uncommitted changes")]
UncommittedChanges,
#[error("Repository is already in a rebase state")]
RebaseInProgress,
#[error("Invalid repository state: {0}")]
InvalidRepositoryState(String),
#[error("No commits to rebase")]
NoCommitsToRebase,
#[error("Invalid base commit: {0}")]
InvalidBaseCommit(String),
#[error("Session is in invalid state: {0}")]
InvalidSessionState(String),
}
pub struct RebaseValidator;
impl RebaseValidator {
pub fn validate_repository_state(
git_service: &GitService,
repo_path: &str,
) -> Result<(), RebaseValidationError> {
let status = git_service
.status_porcelain(repo_path)
.map_err(|_| RebaseValidationError::InvalidRepositoryState("Cannot read status".to_string()))?;
if !status.trim().is_empty() {
return Err(RebaseValidationError::UncommittedChanges);
}
let git_dir = Path::new(repo_path).join(".git");
if git_dir.join("rebase-merge").exists() || git_dir.join("rebase-apply").exists() {
return Err(RebaseValidationError::RebaseInProgress);
}
Ok(())
}
pub fn validate_session_state(
session: &RebaseSession,
operation: &str,
) -> Result<(), RebaseValidationError> {
match operation {
"start_planning" => {
Ok(())
}
"execute_rebase" => {
if session.entries.is_empty() {
return Err(RebaseValidationError::NoCommitsToRebase);
}
if session.base_commit.is_none() && !session.use_root {
return Err(RebaseValidationError::InvalidBaseCommit("No base commit specified".to_string()));
}
if session.phase != RebasePhase::Planning {
return Err(RebaseValidationError::InvalidSessionState(
format!("Cannot execute from phase {:?}", session.phase)
));
}
Ok(())
}
"continue_rebase" => {
if session.phase != RebasePhase::Active && session.phase != RebasePhase::Conflict {
return Err(RebaseValidationError::InvalidSessionState(
format!("Cannot continue from phase {:?}", session.phase)
));
}
Ok(())
}
"abort_rebase" => {
if session.phase == RebasePhase::Planning {
return Err(RebaseValidationError::InvalidSessionState(
"Cannot abort planning phase".to_string()
));
}
Ok(())
}
_ => Ok(()),
}
}
pub fn validate_session_entries(session: &RebaseSession) -> Result<(), RebaseValidationError> {
for entry in &session.entries {
if entry.hash.is_empty() {
return Err(RebaseValidationError::InvalidSessionState("Entry has empty hash".to_string()));
}
if entry.hash.len() < 4 {
return Err(RebaseValidationError::InvalidSessionState("Entry hash too short".to_string()));
}
}
Ok(())
}
pub fn validate_before_execution(
git_service: &GitService,
repo_path: &str,
session: &RebaseSession,
) -> Result<(), RebaseValidationError> {
Self::validate_repository_state(git_service, repo_path)?;
Self::validate_session_state(session, "execute_rebase")?;
Self::validate_session_entries(session)?;
Ok(())
}
}