use std::path::Path;
use std::process::Command;
use anyhow::{anyhow, Context, Result};
pub fn publish_all(repo_root: &Path, order: &[Vec<String>], dry_run: bool) -> Result<()> {
for phase in order {
for krate in phase {
run_cargo_publish(repo_root, krate, dry_run)
.with_context(|| format!("cargo publish -p {krate}"))?;
}
}
Ok(())
}
fn run_cargo_publish(repo_root: &Path, krate: &str, dry_run: bool) -> Result<()> {
let mut cmd = Command::new("cargo");
cmd.arg("publish").arg("-p").arg(krate);
if dry_run {
cmd.arg("--dry-run");
}
cmd.current_dir(repo_root);
let status = cmd.status().context("spawn cargo publish")?;
if !status.success() {
return Err(anyhow!("cargo publish -p {krate} exited {status}"));
}
Ok(())
}
pub fn tag(repo_root: &Path, version: &str) -> Result<()> {
let tag = format!("v{version}");
let repo = gix::open(repo_root)
.with_context(|| format!("gix::open {}", repo_root.display()))?;
let head_commit = repo.head_commit().context("resolve HEAD commit")?;
let message = format!("Release {tag}\n");
let signature = repo
.author()
.ok_or_else(|| anyhow!("git author not configured (user.name / user.email)"))?
.map_err(|e| anyhow!("read git author: {e}"))?;
repo.tag(
&tag,
head_commit.id,
gix::objs::Kind::Commit,
Some(signature),
&message,
gix::refs::transaction::PreviousValue::MustNotExist,
)
.with_context(|| format!("create tag {tag}"))?;
eprintln!(
"created local tag {tag} at {}. Push with: git push origin {tag}",
head_commit.id
);
Ok(())
}