2026-04-26 21:15:06 +00:00
|
|
|
//! Merge operations — rebases agent work onto master and runs post-merge validation.
|
|
|
|
|
|
2026-04-28 10:19:43 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2026-04-26 21:15:06 +00:00
|
|
|
|
|
|
|
|
mod squash;
|
|
|
|
|
|
2026-04-27 01:32:08 +00:00
|
|
|
pub(crate) use squash::run_squash_merge;
|
2026-04-26 21:15:06 +00:00
|
|
|
|
|
|
|
|
/// Status of an async merge job.
|
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
|
|
|
pub enum MergeJobStatus {
|
|
|
|
|
Running,
|
|
|
|
|
Completed(MergeReport),
|
|
|
|
|
Failed(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Tracks a background merge job started by `merge_agent_work`.
|
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
|
|
|
pub struct MergeJob {
|
|
|
|
|
pub story_id: String,
|
|
|
|
|
pub status: MergeJobStatus,
|
2026-04-28 20:41:32 +00:00
|
|
|
/// Server start-time (Unix seconds) of the server instance that started
|
|
|
|
|
/// this job.
|
2026-04-27 17:41:39 +00:00
|
|
|
///
|
|
|
|
|
/// Used by stale-lock recovery: on a new merge attempt the system checks
|
2026-04-28 20:41:32 +00:00
|
|
|
/// every Running entry and removes any whose recorded start-time is older
|
|
|
|
|
/// than the current server's boot time. This survives `rebuild_and_restart`
|
|
|
|
|
/// (which re-execs and keeps the same PID).
|
|
|
|
|
pub server_start_time: f64,
|
2026-04-26 21:15:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Result of a mergemaster merge operation.
|
2026-04-28 10:19:43 +00:00
|
|
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
2026-04-26 21:15:06 +00:00
|
|
|
pub struct MergeReport {
|
|
|
|
|
pub story_id: String,
|
|
|
|
|
pub success: bool,
|
|
|
|
|
pub had_conflicts: bool,
|
|
|
|
|
/// `true` when conflicts were detected but automatically resolved.
|
|
|
|
|
pub conflicts_resolved: bool,
|
|
|
|
|
pub conflict_details: Option<String>,
|
|
|
|
|
pub gates_passed: bool,
|
2026-05-13 15:57:24 +00:00
|
|
|
/// Human-readable output from quality gates (display and retry-prompt injection only).
|
2026-04-26 21:15:06 +00:00
|
|
|
pub gate_output: String,
|
2026-05-13 15:57:24 +00:00
|
|
|
/// Typed classification of the gate failure, produced at the gate boundary.
|
|
|
|
|
/// `None` when `gates_passed` is `true` or when there were no gate results.
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub gate_failure_kind: Option<crate::agents::gates::GateFailureKind>,
|
|
|
|
|
/// `true` when the feature branch had zero commits ahead of the base branch.
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub no_commits: bool,
|
2026-04-26 21:15:06 +00:00
|
|
|
pub worktree_cleaned_up: bool,
|
|
|
|
|
pub story_archived: bool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Result of a squash-merge operation.
|
|
|
|
|
pub(crate) struct SquashMergeResult {
|
|
|
|
|
pub(crate) success: bool,
|
|
|
|
|
pub(crate) had_conflicts: bool,
|
|
|
|
|
/// `true` when conflicts were detected but automatically resolved.
|
|
|
|
|
pub(crate) conflicts_resolved: bool,
|
|
|
|
|
pub(crate) conflict_details: Option<String>,
|
|
|
|
|
pub(crate) output: String,
|
|
|
|
|
/// Whether quality gates ran and passed. `false` when `success` is `false`
|
|
|
|
|
/// due to a gate failure; callers can use this to distinguish gate failures
|
|
|
|
|
/// from merge/commit/FF failures in the `MergeReport`.
|
|
|
|
|
pub(crate) gates_passed: bool,
|
2026-05-13 15:57:24 +00:00
|
|
|
/// Typed gate failure kind produced at the gate boundary. `None` when
|
|
|
|
|
/// `gates_passed` is `true` or when failure was not from the gate step.
|
|
|
|
|
pub(crate) gate_failure_kind: Option<crate::agents::gates::GateFailureKind>,
|
|
|
|
|
/// `true` when the feature branch had zero commits ahead of the base branch.
|
|
|
|
|
pub(crate) no_commits: bool,
|
2026-04-26 21:15:06 +00:00
|
|
|
}
|