ralph_workflow/git_helpers/rebase/operations/
continuation.rs1#[cfg(any(test, feature = "test-utils"))]
23pub fn verify_rebase_completed(upstream_branch: &str) -> io::Result<bool> {
24 let repo = git2::Repository::discover(".").map_err(|e| git2_to_io_error(&e))?;
25
26 let state = repo.state();
28 if state == git2::RepositoryState::Rebase
29 || state == git2::RepositoryState::RebaseMerge
30 || state == git2::RepositoryState::RebaseInteractive
31 {
32 return Ok(false);
33 }
34
35 let index = repo.index().map_err(|e| git2_to_io_error(&e))?;
37 if index.has_conflicts() {
38 return Ok(false);
39 }
40
41 let head = repo.head().map_err(|e| {
43 io::Error::new(
44 io::ErrorKind::InvalidData,
45 format!("Repository HEAD is invalid: {e}"),
46 )
47 })?;
48
49 if let Ok(head_commit) = head.peel_to_commit() {
51 if let Ok(upstream_object) = repo.revparse_single(upstream_branch) {
52 if let Ok(upstream_commit) = upstream_object.peel_to_commit() {
53 match repo.graph_descendant_of(head_commit.id(), upstream_commit.id()) {
54 Ok(is_descendant) => {
55 if is_descendant {
56 return Ok(true);
57 }
58 return Ok(false);
59 }
60 Err(e) => {
61 let _ = e;
62 }
63 }
64 }
65 }
66 }
67
68 Ok(!index.has_conflicts())
69}
70
71pub fn continue_rebase(executor: &dyn crate::executor::ProcessExecutor) -> io::Result<()> {
75 let repo = git2::Repository::discover(".").map_err(|e| git2_to_io_error(&e))?;
76 continue_rebase_impl(&repo, executor)
77}
78
79fn continue_rebase_impl(
81 repo: &git2::Repository,
82 executor: &dyn crate::executor::ProcessExecutor,
83) -> io::Result<()> {
84 let state = repo.state();
86 if state != git2::RepositoryState::Rebase
87 && state != git2::RepositoryState::RebaseMerge
88 && state != git2::RepositoryState::RebaseInteractive
89 {
90 return Err(io::Error::new(
91 io::ErrorKind::InvalidInput,
92 "No rebase in progress",
93 ));
94 }
95
96 let conflicted = get_conflicted_files()?;
98 if !conflicted.is_empty() {
99 return Err(io::Error::new(
100 io::ErrorKind::InvalidInput,
101 format!(
102 "Cannot continue rebase: {} file(s) still have conflicts",
103 conflicted.len()
104 ),
105 ));
106 }
107
108 let output = executor.execute("git", &["rebase", "--continue"], &[], None)?;
110
111 if output.status.success() {
112 Ok(())
113 } else {
114 Err(io::Error::other(format!(
115 "Failed to continue rebase: {}",
116 output.stderr
117 )))
118 }
119}
120
121pub fn rebase_in_progress() -> io::Result<bool> {
123 let repo = git2::Repository::discover(".").map_err(|e| git2_to_io_error(&e))?;
124 rebase_in_progress_impl(&repo)
125}
126
127fn rebase_in_progress_impl(repo: &git2::Repository) -> io::Result<bool> {
129 let state = repo.state();
130 Ok(state == git2::RepositoryState::Rebase
131 || state == git2::RepositoryState::RebaseMerge
132 || state == git2::RepositoryState::RebaseInteractive)
133}