@@ -12,9 +12,9 @@
#[derive(Subcommand)]
pub enum RepoCommand {
/// List repositories in an organization
/// List every repository you can see across all your orgs
List {
/// Filter results by org slug (client-side substring match)
/// Organization slug (defaults to org from default repo)
#[arg(long)]
org: Option<String>,
/// Maximum results
@@ -65,8 +65,16 @@
visibility: Option<String>,
fork_count: Option<i64>,
inserted_at: Option<String>,
org: Option<RepoOrgRef>,
}
#[derive(Debug, Deserialize)]
#[allow(dead_code)]
struct RepoOrgRef {
slug: Option<String>,
name: Option<String>,
}
pub async fn run(args: RepoArgs) -> Result<(), Box<dyn std::error::Error>> {
match args.command {
RepoCommand::List { org, limit } => list(org.as_deref(), limit).await,
@@ -82,22 +90,11 @@
}
}
async fn list(org: Option<&str>, limit: u32) -> Result<(), Box<dyn std::error::Error>> {
async fn list(org_filter: Option<&str>, limit: u32) -> Result<(), Box<dyn std::error::Error>> {
let client = Client::from_config()?;
let org_slug = match org {
Some(o) => o.to_string(),
None => {
let (resolved_org, _) = config::resolve_repo(None)?;
resolved_org
}
};
let resp: serde_json::Value = client
.get_with_query(
&format!("/{org_slug}/repos"),
&[("per_page", &limit.to_string())],
)
.get_with_query("/repos", &[("per_page", &limit.to_string())])
.await?;
if output::is_json() {
@@ -115,22 +112,42 @@
serde_json::from_value(resp).unwrap_or_default()
};
let filtered: Vec<&Repo> = match org_filter {
Some(f) => repos
.iter()
.filter(|r| {
r.org
.as_ref()
output::header(&format!("Repositories ({org_slug})"));
.and_then(|o| o.slug.as_deref())
.map(|s| s.contains(f))
.unwrap_or(false)
})
.collect(),
None => repos.iter().collect(),
};
let rows: Vec<Vec<String>> = repos
output::header(&format!("Repositories ({} visible)", filtered.len()));
let rows: Vec<Vec<String>> = filtered
.iter()
.map(|r| {
let desc = r.description.clone().unwrap_or_default();
let desc = if desc.chars().count() > 60 {
format!("{}…", desc.chars().take(59).collect::<String>())
let desc = if desc.chars().count() > 50 {
format!("{}…", desc.chars().take(49).collect::<String>())
} else {
desc
};
let name = r
.slug
.clone()
.or_else(|| r.name.clone())
.unwrap_or_default();
let full = match r.org.as_ref().and_then(|o| o.slug.as_deref()) {
Some(org_slug) => format!("{org_slug}/{name}"),
None => name,
};
vec![
r.slug
.clone()
.or_else(|| r.name.clone())
.unwrap_or_default(),
full,
output::colorize_status(r.visibility.as_deref().unwrap_or("?")),
r.default_branch.clone().unwrap_or_default(),
desc,
@@ -138,7 +155,7 @@
})
.collect();
output::print_table(&["NAME", "VISIBILITY", "DEFAULT", "DESCRIPTION"], &rows);
output::print_table(&["REPO", "VISIBILITY", "DEFAULT", "DESCRIPTION"], &rows);
Ok(())
}