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