fix(#1060): dynamic meta commit message from staged files; skip commit on no-op
This commit is contained in:
parent
4ee7967e2a
commit
3a1cfa26ec
1 changed files with 65 additions and 4 deletions
|
|
@ -90,7 +90,7 @@ pub async fn sync_agents(
|
|||
// only fills in missing entries. Idempotent; when nothing changed
|
||||
// the file isn't touched.
|
||||
let agent_names: Vec<String> = agents.iter().map(|a| a.name.clone()).collect();
|
||||
let topology_changed = crate::topology::reconcile(&agent_names)
|
||||
crate::topology::reconcile(&agent_names)
|
||||
.with_context(|| format!("reconcile {}", crate::topology::topology_path().display()))?;
|
||||
|
||||
// Refresh /var/lib/hyperhive/agent-ports.json so the hive-gateway
|
||||
|
|
@ -168,12 +168,35 @@ pub async fn sync_agents(
|
|||
if std::path::Path::new(&dir).join("flake.lock").exists() {
|
||||
git(&dir, &["add", "flake.lock"]).await?;
|
||||
}
|
||||
// Build the commit message from what's actually staged so it
|
||||
// reflects reality — and skip the commit entirely when nothing
|
||||
// changed (avoids "nothing to commit" errors on redundant syncs).
|
||||
let staged = git_staged_names(&dir).await?;
|
||||
if staged.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let msg = if initial {
|
||||
format!("seed meta from {} agent(s)", agents.len())
|
||||
} else if topology_changed {
|
||||
"regenerate meta flake + topology".to_owned()
|
||||
} else {
|
||||
"regenerate meta flake".to_owned()
|
||||
// Compose a message that names every file that actually changed,
|
||||
// mapping the on-disk filename to a short human label.
|
||||
let labels: Vec<&str> = staged
|
||||
.iter()
|
||||
.filter_map(|f| match f.as_str() {
|
||||
"flake.nix" => Some("flake"),
|
||||
"flake.lock" => Some("lock"),
|
||||
"topology.json" => Some("topology"),
|
||||
"capabilities.json" => Some("capabilities"),
|
||||
"tool-groups.json" => Some("tool-groups"),
|
||||
"roles.json" => Some("roles"),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
if labels.is_empty() {
|
||||
"meta: update".to_owned()
|
||||
} else {
|
||||
format!("meta: update {}", labels.join(", "))
|
||||
}
|
||||
};
|
||||
git_commit(&dir, &msg).await?;
|
||||
Ok(())
|
||||
|
|
@ -625,6 +648,44 @@ async fn git_is_clean(dir: &Path) -> Result<bool> {
|
|||
Ok(out.stdout.iter().all(u8::is_ascii_whitespace))
|
||||
}
|
||||
|
||||
/// Return the list of file names that are currently staged (index differs
|
||||
/// from HEAD). On the initial commit (`HEAD` doesn't exist yet) falls back
|
||||
/// to `git diff --cached --name-only HEAD` failing gracefully by using
|
||||
/// `git status --porcelain` and collecting the `A ` / `M ` prefix lines.
|
||||
async fn git_staged_names(dir: &Path) -> Result<Vec<String>> {
|
||||
// `--diff-filter=ACM` skips deleted entries — we only care about
|
||||
// additions and modifications for message-building purposes.
|
||||
let out = lifecycle::git_command()
|
||||
.current_dir(dir)
|
||||
.args(["diff", "--cached", "--name-only", "--diff-filter=ACM"])
|
||||
.output()
|
||||
.await
|
||||
.with_context(|| format!("git diff --cached in {}", dir.display()))?;
|
||||
if out.status.success() {
|
||||
let names = String::from_utf8_lossy(&out.stdout)
|
||||
.lines()
|
||||
.map(str::trim)
|
||||
.filter(|l| !l.is_empty())
|
||||
.map(ToOwned::to_owned)
|
||||
.collect();
|
||||
return Ok(names);
|
||||
}
|
||||
// Fallback for initial commit (no HEAD yet): parse `git status --porcelain`.
|
||||
let st = lifecycle::git_command()
|
||||
.current_dir(dir)
|
||||
.args(["status", "--porcelain"])
|
||||
.output()
|
||||
.await
|
||||
.with_context(|| format!("git status in {}", dir.display()))?;
|
||||
let names = String::from_utf8_lossy(&st.stdout)
|
||||
.lines()
|
||||
.filter(|l| l.starts_with("A ") || l.starts_with("M "))
|
||||
.filter_map(|l| l.get(3..))
|
||||
.map(ToOwned::to_owned)
|
||||
.collect();
|
||||
Ok(names)
|
||||
}
|
||||
|
||||
async fn git(dir: &Path, args: &[&str]) -> Result<()> {
|
||||
let out = lifecycle::git_command()
|
||||
.current_dir(dir)
|
||||
|
|
|
|||
Loading…
Reference in a new issue