use crate::{git, ui};
use anyhow::{anyhow, Result};
fn looks_like_release_commit(s: &str) -> bool {
let ls = s.to_ascii_lowercase();
ls.contains("bump")
|| ls.contains("release")
|| ls.starts_with("docs(changelog):")
}
pub async fn run(_owner_repo: &str, remote: bool) -> Result<()> {
ui::section("rollback");
let tags_at_head = git::tags_pointing_at_head();
if tags_at_head.is_empty() {
ui::info("no tag at head");
} else {
for t in &tags_at_head {
ui::info(&format!("tag at head: {}", t));
}
}
let last = git::last_commit_subject().unwrap_or_default();
ui::info(&format!("last commit: {}", last));
if remote {
for t in &tags_at_head {
let _ = git::delete_remote_tag(t);
}
if !tags_at_head.is_empty() {
ui::ok("remote tags removed if they existed");
}
}
for t in &tags_at_head {
let _ = git::delete_local_tag(t);
ui::ok(&format!("deleted local tag {}", t));
}
let mut popped = 0usize;
if looks_like_release_commit(&last) {
git::reset_hard("HEAD^")?;
popped += 1;
ui::ok("reverted last release commit");
let second = git::last_commit_subject().unwrap_or_default();
if looks_like_release_commit(&second) {
git::reset_hard("HEAD^")?;
popped += 1;
ui::ok("reverted secondary release commit");
}
} else {
ui::warn(
"last commit does not look like a release commit; no reset done",
);
}
if remote && popped > 0 {
if let Some(_br) = git::current_branch() {
git::push_force_with_lease()?;
ui::ok("forced branch update to remote");
} else {
return Err(anyhow!(
"failed to detect current branch for remote push"
));
}
}
ui::ok("rollback completed");
Ok(())
}