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 tag = git::tag_pointing_at_head();
if let Some(t) = &tag {
ui::info(&format!("tag at head: {}", t));
} else {
ui::info("no tag at head");
}
let last = git::last_commit_subject().unwrap_or_default();
ui::info(&format!("last commit: {}", last));
if remote {
if let Some(t) = &tag {
let _ = git::delete_github_release(t, owner_repo);
let _ = git::delete_remote_tag(t);
ui::ok("remote release and tag removed if they existed");
}
}
if let Some(t) = &tag {
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(())
}