ref:082d717f60fa2f71489f6c4583a60812d282accd

feat(cli): add 'anvil commit list' command

SHA: 082d717f60fa2f71489f6c4583a60812d282accd
Author: Cole Christensen <cole.christensen@macmillan.com>
Date: 2026-03-15 22:02
Parents: 98e8653
2 files changed +113 -0
Type
src/commands/commit.rs +109 −0
@@ -1,0 +1,109 @@
use crate::client::Client;
use crate::config;
use crate::output;
use clap::{Args, Subcommand};
use serde::Deserialize;
#[derive(Args)]
pub struct CommitArgs {
#[command(subcommand)]
pub command: CommitCommand,
}
#[derive(Subcommand)]
pub enum CommitCommand {
/// List commits
List {
/// Repository (org/repo)
repo: Option<String>,
/// Branch or ref to list commits from
#[arg(long, default_value = "HEAD")]
ref_name: String,
/// Maximum results
#[arg(long, default_value = "20")]
limit: u32,
},
}
#[derive(Debug, Deserialize)]
struct Commit {
oid: Option<String>,
message: Option<String>,
author: Option<CommitAuthor>,
time: Option<String>,
}
#[derive(Debug, Deserialize)]
struct CommitAuthor {
name: Option<String>,
}
pub async fn run(args: CommitArgs) -> Result<(), Box<dyn std::error::Error>> {
match args.command {
CommitCommand::List {
repo,
ref_name,
limit,
} => list(repo.as_deref(), &ref_name, limit).await,
}
}
async fn list(
repo: Option<&str>,
ref_name: &str,
limit: u32,
) -> Result<(), Box<dyn std::error::Error>> {
let client = Client::from_config()?;
let (org, name) = config::resolve_repo(repo)?;
let resp: serde_json::Value = client
.get_with_query(
&format!("/{org}/{name}/commits"),
&[("ref", ref_name), ("per_page", &limit.to_string())],
)
.await?;
let commits: Vec<Commit> = if let Some(arr) = resp.get("commits") {
serde_json::from_value(arr.clone()).unwrap_or_default()
} else {
serde_json::from_value(resp).unwrap_or_default()
};
output::header(&format!("Commits ({org}/{name}) — {ref_name}"));
let rows: Vec<Vec<String>> = commits
.iter()
.map(|c| {
let sha = c
.oid
.as_deref()
.map(|s| if s.len() > 8 { &s[..8] } else { s })
.unwrap_or("?")
.to_string();
let msg = c
.message
.as_deref()
.unwrap_or("")
.lines()
.next()
.unwrap_or("")
.to_string();
let author = c
.author
.as_ref()
.and_then(|a| a.name.clone())
.unwrap_or_default();
let time = c
.time
.as_deref()
.map(|t| output::format_time(t))
.unwrap_or_default();
vec![sha, msg, author, time]
})
.collect();
output::print_table(&["SHA", "MESSAGE", "AUTHOR", "DATE"], &rows);
Ok(())
}
src/commands/mod.rs +4 −0
@@ -2,6 +2,7 @@
pub mod auth;
pub mod branch;
pub mod ci;
pub mod commit;
pub mod deploy;
pub mod issue;
pub mod pr;
@@ -34,6 +35,8 @@
Issue(issue::IssueArgs),
/// CI pipeline operations
Ci(ci::CiArgs),
/// Commit operations
Commit(commit::CommitArgs),
/// Branch operations
Branch(branch::BranchArgs),
/// Release operations
@@ -53,6 +56,7 @@
Command::Pr(args) => pr::run(args).await,
Command::Issue(args) => issue::run(args).await,
Command::Ci(args) => ci::run(args).await,
Command::Commit(args) => commit::run(args).await,
Command::Branch(args) => branch::run(args).await,
Command::Release(args) => release::run(args).await,
Command::Deploy(args) => deploy::run(args).await,