feat: phase 2 — playbooks (am history --save + am playbook, rejeu pas à pas) (closes #51)
This commit is contained in:
@@ -42,6 +42,37 @@ fn rerun_entry(app: &App, n: usize) -> Result<i32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter history entries; returns them most recent first.
|
||||
/// Parse "12..25" (inclusive bounds, 1-based) or a single "12".
|
||||
fn parse_range(r: &str) -> Result<(usize, usize)> {
|
||||
let r = r.trim();
|
||||
if r.is_empty() {
|
||||
anyhow::bail!("empty range — usage: am history <from>..<to> --save <file>");
|
||||
}
|
||||
if let Some((a, b)) = r.split_once("..") {
|
||||
let from = a
|
||||
.trim()
|
||||
.parse::<usize>()
|
||||
.map_err(|_| anyhow!("invalid range '{r}' — expected <from>..<to>"))?;
|
||||
let to = b
|
||||
.trim()
|
||||
.parse::<usize>()
|
||||
.map_err(|_| anyhow!("invalid range '{r}' — expected <from>..<to>"))?;
|
||||
if from == 0 || to == 0 {
|
||||
anyhow::bail!("history entries start at 1");
|
||||
}
|
||||
Ok((from, to))
|
||||
} else {
|
||||
let n = r
|
||||
.parse::<usize>()
|
||||
.map_err(|_| anyhow!("invalid range '{r}' — expected <from>..<to>"))?;
|
||||
if n == 0 {
|
||||
anyhow::bail!("history entries start at 1");
|
||||
}
|
||||
Ok((n, n))
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter history entries; returns them most recent first.
|
||||
pub fn filter(
|
||||
app: &App,
|
||||
@@ -96,11 +127,25 @@ pub fn run(
|
||||
session: Option<&str>,
|
||||
limit: usize,
|
||||
rerun: Option<usize>,
|
||||
range: Option<&str>,
|
||||
save: Option<&Path>,
|
||||
) -> Result<i32> {
|
||||
history::migrate(app)?;
|
||||
if let Some(n) = rerun {
|
||||
return rerun_entry(app, n);
|
||||
}
|
||||
// Issue #51: 'am history 12..25 --save <file>' exports a playbook.
|
||||
if let Some(r) = range {
|
||||
let file = save.ok_or_else(|| anyhow!("--save <file> is required with a range"))?;
|
||||
let (from, to) = parse_range(r)?;
|
||||
let (n, path) = crate::playbook::export_range(app, from, to, file)?;
|
||||
app.log
|
||||
.success(&format!("playbook saved: {} ({n} step(s))", path.display()));
|
||||
return Ok(0);
|
||||
}
|
||||
if save.is_some() {
|
||||
anyhow::bail!("usage: am history <from>..<to> --save <file>");
|
||||
}
|
||||
let rows = filter(app, kind, cwd, search, failed, session, limit);
|
||||
if app.json() {
|
||||
let payload: Vec<serde_json::Value> = rows
|
||||
|
||||
Reference in New Issue
Block a user