use async_trait::async_trait;
use super::classify::MergeRepositoryState;
use super::spine::SpineCommit;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct UpstreamPortError {
pub operation: String,
pub message: String,
}
impl UpstreamPortError {
pub fn new(operation: impl Into<String>, message: impl Into<String>) -> Self {
Self {
operation: operation.into(),
message: message.into(),
}
}
}
impl std::fmt::Display for UpstreamPortError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} failed: {}", self.operation, self.message)
}
}
impl std::error::Error for UpstreamPortError {}
pub type PortResult<T> = std::result::Result<T, UpstreamPortError>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MergeCommandResult {
pub exit_success: bool,
pub state: MergeRepositoryState,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RecoveryCommit {
pub sha: String,
pub message: String,
pub parents: Vec<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PushCommandResult {
pub exit_success: bool,
pub porcelain_stdout: String,
}
#[async_trait]
pub trait UpstreamGit: Send + Sync {
async fn remote_configured(&self, remote: &str) -> PortResult<bool>;
async fn current_branch(&self) -> PortResult<Option<String>>;
async fn fetch(&self, remote: &str, branch: &str) -> PortResult<()>;
async fn fetched_sha(&self, remote: &str, branch: &str) -> PortResult<Option<String>>;
async fn head_sha(&self) -> PortResult<String>;
async fn is_ancestor(&self, ancestor: &str, descendant: &str) -> PortResult<bool>;
async fn merge_base(&self, a: &str, b: &str) -> PortResult<String>;
async fn merge_no_ff(&self, sha: &str, message: &str) -> PortResult<MergeCommandResult>;
async fn commit_empty(&self, message: &str) -> PortResult<String>;
async fn merge_repository_state(&self) -> PortResult<MergeRepositoryState>;
async fn is_working_tree_clean(&self) -> PortResult<bool>;
async fn status_porcelain_v2(&self) -> PortResult<String>;
async fn commit_message(&self, sha: &str) -> PortResult<String>;
async fn commit_parents(&self, sha: &str) -> PortResult<Vec<String>>;
async fn first_parent_recovery_metadata(
&self,
to: &str,
limit: Option<usize>,
) -> PortResult<Vec<RecoveryCommit>>;
async fn first_parent_commits(
&self,
from_exclusive: Option<&str>,
to: &str,
limit: Option<usize>,
) -> PortResult<Vec<SpineCommit>>;
async fn local_ref_sha(&self, reference: &str) -> PortResult<Option<String>>;
async fn push_porcelain(&self, remote: &str, branch: &str) -> PortResult<PushCommandResult>;
async fn ls_remote_sha(&self, remote: &str, branch: &str) -> PortResult<Option<String>>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VerificationOutcome {
pub success: bool,
pub output_tail: String,
}
impl VerificationOutcome {
pub fn passed() -> Self {
Self {
success: true,
output_tail: String::new(),
}
}
pub fn failed(output_tail: impl Into<String>) -> Self {
Self {
success: false,
output_tail: output_tail.into(),
}
}
}
#[async_trait]
pub trait UpstreamVerifier: Send + Sync {
async fn verify(&self) -> PortResult<VerificationOutcome>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RepairCause {
TextualConflict,
SemanticVerification,
PushRepository,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RepairRequest {
pub cause: RepairCause,
pub remote: String,
pub branch: String,
pub local_revision_before: String,
pub fetched_sha: String,
pub conflict_files: Vec<String>,
pub status: String,
pub verify_command: String,
pub verify_output_tail: String,
pub push_diagnostics: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RepairAttemptResult {
pub command_success: bool,
}
#[async_trait]
pub trait UpstreamRepairAgent: Send + Sync {
fn max_attempts(&self) -> u32;
async fn repair(&self, request: &RepairRequest) -> PortResult<RepairAttemptResult>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum UpstreamEvent {
CheckpointStarted {
remote: String,
branch: String,
trigger: String,
},
CheckpointDeferred {
reason: String,
},
FetchCompleted {
remote: String,
branch: String,
fetched_sha: String,
local_sha: String,
},
NoOp {
fetched_sha: String,
},
IntegrationStarted {
fetched_sha: String,
},
IntegrationCompleted {
merge_sha: String,
},
Resolving {
cause: String,
attempt: u32,
},
Reverifying {
command: String,
},
VerificationFailed {
output_tail: String,
},
Pushing {
remote: String,
branch: String,
head: String,
},
PushFailed {
classification: String,
},
PushConfirmed {
remote: String,
branch: String,
head: String,
},
Stalled {
reason: String,
},
Completed,
}
#[async_trait]
pub trait UpstreamObserver: Send + Sync {
async fn observe(&self, event: UpstreamEvent);
}
pub struct NoopUpstreamObserver;
#[async_trait]
impl UpstreamObserver for NoopUpstreamObserver {
async fn observe(&self, _event: UpstreamEvent) {}
}