huskies: merge 757
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
mod conflicts;
|
||||
mod squash;
|
||||
|
||||
pub(crate) use squash::run_squash_merge;
|
||||
|
||||
@@ -6,7 +6,6 @@ use std::process::Command;
|
||||
use std::sync::Mutex;
|
||||
|
||||
use super::super::gates::run_project_tests;
|
||||
use super::conflicts::try_resolve_conflicts;
|
||||
use super::{MergeReport, SquashMergeResult};
|
||||
use crate::config::ProjectConfig;
|
||||
|
||||
@@ -107,55 +106,28 @@ pub(crate) fn run_squash_merge(
|
||||
all_output.push_str(&merge_stderr);
|
||||
all_output.push('\n');
|
||||
|
||||
let mut had_conflicts = false;
|
||||
let mut conflicts_resolved = false;
|
||||
let conflicts_resolved = false;
|
||||
let mut conflict_details: Option<String> = None;
|
||||
|
||||
if !merge.status.success() {
|
||||
had_conflicts = true;
|
||||
all_output.push_str("=== Conflicts detected, attempting auto-resolution ===\n");
|
||||
|
||||
// Try to automatically resolve simple conflicts.
|
||||
match try_resolve_conflicts(&merge_wt_path) {
|
||||
Ok((resolved, resolution_log)) => {
|
||||
all_output.push_str(&resolution_log);
|
||||
if resolved {
|
||||
conflicts_resolved = true;
|
||||
all_output.push_str("=== All conflicts resolved automatically ===\n");
|
||||
} else {
|
||||
// Could not resolve — abort, clean up, and report.
|
||||
let details = format!(
|
||||
"Merge conflicts in branch '{branch}':\n{merge_stdout}{merge_stderr}\n{resolution_log}"
|
||||
);
|
||||
conflict_details = Some(details);
|
||||
all_output.push_str("=== Unresolvable conflicts, aborting merge ===\n");
|
||||
cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch);
|
||||
return Ok(SquashMergeResult {
|
||||
success: false,
|
||||
had_conflicts: true,
|
||||
conflicts_resolved: false,
|
||||
conflict_details,
|
||||
output: all_output,
|
||||
gates_passed: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
all_output.push_str(&format!("Auto-resolution error: {e}\n"));
|
||||
cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch);
|
||||
return Ok(SquashMergeResult {
|
||||
success: false,
|
||||
had_conflicts: true,
|
||||
conflicts_resolved: false,
|
||||
conflict_details: Some(format!(
|
||||
"Merge conflicts in branch '{branch}' (auto-resolution failed: {e}):\n{merge_stdout}{merge_stderr}"
|
||||
)),
|
||||
output: all_output,
|
||||
gates_passed: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
all_output.push_str(
|
||||
"=== Conflicts detected — aborting merge. Use `start_agent mergemaster` \
|
||||
to invoke LLM-driven conflict resolution. ===\n",
|
||||
);
|
||||
let details =
|
||||
format!("Merge conflicts in branch '{branch}':\n{merge_stdout}{merge_stderr}");
|
||||
conflict_details = Some(details);
|
||||
cleanup_merge_workspace(project_root, &merge_wt_path, &merge_branch);
|
||||
return Ok(SquashMergeResult {
|
||||
success: false,
|
||||
had_conflicts: true,
|
||||
conflicts_resolved,
|
||||
conflict_details,
|
||||
output: all_output,
|
||||
gates_passed: false,
|
||||
});
|
||||
}
|
||||
let had_conflicts = false;
|
||||
|
||||
// ── Commit in the temporary worktree ──────────────────────────
|
||||
all_output.push_str("=== git commit ===\n");
|
||||
|
||||
@@ -144,15 +144,15 @@ async fn squash_merge_additive_conflict_both_additions_preserved() {
|
||||
// Squash-merge the feature branch — conflicts because both appended to the same location.
|
||||
let result = run_squash_merge(repo, "feature/story-238_additive", "238_additive").unwrap();
|
||||
|
||||
// Conflict must be detected and auto-resolved.
|
||||
// Deterministic merge does NOT auto-resolve conflicts — AC3 requires failure.
|
||||
assert!(result.had_conflicts, "additive conflict should be detected");
|
||||
assert!(
|
||||
result.conflicts_resolved,
|
||||
"additive conflict must be auto-resolved; output:\n{}",
|
||||
result.output
|
||||
!result.conflicts_resolved,
|
||||
"deterministic merge must NOT auto-resolve conflicts"
|
||||
);
|
||||
assert!(!result.success, "conflict must cause merge failure");
|
||||
|
||||
// Master must contain both additions without conflict markers.
|
||||
// Master must not have been modified (merge aborted).
|
||||
let content = fs::read_to_string(repo.join("module.rs")).unwrap();
|
||||
assert!(
|
||||
!content.contains("<<<<<<<"),
|
||||
@@ -162,18 +162,6 @@ async fn squash_merge_additive_conflict_both_additions_preserved() {
|
||||
!content.contains(">>>>>>>"),
|
||||
"master must not contain conflict markers"
|
||||
);
|
||||
assert!(
|
||||
content.contains("feature_fn"),
|
||||
"feature branch addition must be preserved on master"
|
||||
);
|
||||
assert!(
|
||||
content.contains("master_fn"),
|
||||
"master branch addition must be preserved on master"
|
||||
);
|
||||
assert!(
|
||||
content.contains("existing"),
|
||||
"original function must be preserved"
|
||||
);
|
||||
|
||||
// Cleanup: no leftover merge-queue branch or workspace.
|
||||
let branches = Command::new("git")
|
||||
@@ -262,25 +250,22 @@ async fn squash_merge_conflict_resolved_but_gates_fail_reported_as_failure() {
|
||||
.output()
|
||||
.unwrap();
|
||||
|
||||
// Squash-merge: conflict detected → auto-resolved → quality gates run → fail.
|
||||
// Squash-merge: conflict detected → aborted immediately (no gate run).
|
||||
let result = run_squash_merge(repo, "feature/story-238_gates_fail", "238_gates_fail").unwrap();
|
||||
|
||||
assert!(result.had_conflicts, "conflict must be detected");
|
||||
assert!(
|
||||
result.conflicts_resolved,
|
||||
"additive conflict must be auto-resolved"
|
||||
);
|
||||
assert!(
|
||||
!result.gates_passed,
|
||||
"quality gates must fail (script/test exits 1)"
|
||||
!result.conflicts_resolved,
|
||||
"deterministic merge must NOT auto-resolve conflicts"
|
||||
);
|
||||
// Merge is aborted at conflict detection; gates are never reached.
|
||||
assert!(
|
||||
!result.success,
|
||||
"merge must be reported as failed when gates fail"
|
||||
"conflicting merge must be reported as failed"
|
||||
);
|
||||
assert!(
|
||||
!result.output.is_empty(),
|
||||
"output must contain gate failure details"
|
||||
"output must contain conflict details"
|
||||
);
|
||||
|
||||
// Master must NOT have been updated (cherry-pick was blocked by gate failure).
|
||||
|
||||
Reference in New Issue
Block a user