Skip to content

Commit fc2777c

Browse files
committed
feat: sort recipes by updated_at
1 parent 36f314c commit fc2777c

File tree

1 file changed

+85
-6
lines changed

1 file changed

+85
-6
lines changed

enwiro-cookbook-github/src/main.rs

Lines changed: 85 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub struct GithubItem {
3737
pub title: String,
3838
pub repo: String,
3939
pub kind: GithubItemKind,
40+
pub updated_at: String,
4041
}
4142

4243
#[derive(Parser)]
@@ -200,6 +201,8 @@ struct GraphQlNode {
200201
title: String,
201202
#[serde(rename = "headRefName", default)]
202203
head_ref_name: Option<String>,
204+
#[serde(rename = "updatedAt", default)]
205+
updated_at: Option<String>,
203206
repository: GraphQlRepo,
204207
}
205208

@@ -235,6 +238,7 @@ fn parse_search_response(json: &str) -> anyhow::Result<Vec<GithubItem>> {
235238
title: node.title,
236239
repo,
237240
kind,
241+
updated_at: node.updated_at.unwrap_or_default(),
238242
}
239243
})
240244
.collect())
@@ -304,6 +308,10 @@ fn search_github(repos: &[String], type_filter: &str) -> anyhow::Result<Vec<Gith
304308
Ok(items)
305309
}
306310

311+
fn sort_items_by_date(items: &mut [GithubItem]) {
312+
items.sort_by(|a, b| b.updated_at.cmp(&a.updated_at));
313+
}
314+
307315
fn list_recipes() -> anyhow::Result<()> {
308316
let repos = discover_github_repos()?;
309317
let repo_names: Vec<String> = repos.iter().map(|r| r.repo.clone()).collect();
@@ -312,13 +320,17 @@ fn list_recipes() -> anyhow::Result<()> {
312320
// Issues are scoped to `assignee:@me` so only actionable work appears,
313321
// unlike PRs which show all open PRs on configured repos.
314322
let issues = search_github(&repo_names, "is:issue is:open assignee:@me")?;
315-
for item in prs {
316-
let safe_title = item.title.replace(['\t', '\n', '\0', '\x1f'], " ");
317-
println!("{}#{}\t[PR] {}", item.repo, item.number, safe_title);
318-
}
319-
for item in issues {
323+
324+
let mut items: Vec<GithubItem> = prs.into_iter().chain(issues).collect();
325+
sort_items_by_date(&mut items);
326+
327+
for item in items {
320328
let safe_title = item.title.replace(['\t', '\n', '\0', '\x1f'], " ");
321-
println!("{}#{}\t[issue] {}", item.repo, item.number, safe_title);
329+
let prefix = match &item.kind {
330+
GithubItemKind::PullRequest { .. } => "[PR]",
331+
GithubItemKind::Issue => "[issue]",
332+
};
333+
println!("{}#{}\t{} {}", item.repo, item.number, prefix, safe_title);
322334
}
323335
Ok(())
324336
}
@@ -1027,6 +1039,73 @@ mod tests {
10271039
assert_eq!(branch, "master");
10281040
}
10291041

1042+
#[test]
1043+
fn test_parse_search_response_captures_updated_at() {
1044+
let json = r#"{
1045+
"data": {
1046+
"search": {
1047+
"nodes": [
1048+
{
1049+
"number": 42,
1050+
"title": "Fix the thing",
1051+
"headRefName": "fix-thing",
1052+
"updatedAt": "2026-02-14T13:10:29Z",
1053+
"repository": { "nameWithOwner": "kantord/enwiro" }
1054+
},
1055+
{
1056+
"number": 225,
1057+
"title": "Bug report",
1058+
"updatedAt": "2026-02-12T09:00:00Z",
1059+
"repository": { "nameWithOwner": "kantord/enwiro" }
1060+
}
1061+
]
1062+
}
1063+
}
1064+
}"#;
1065+
let items = parse_search_response(json).unwrap();
1066+
assert_eq!(items[0].updated_at, "2026-02-14T13:10:29Z");
1067+
assert_eq!(items[1].updated_at, "2026-02-12T09:00:00Z");
1068+
}
1069+
1070+
#[test]
1071+
fn test_list_recipes_sorts_combined_items_by_date() {
1072+
// When PRs and issues are combined, they should be sorted by
1073+
// updated_at descending (newest first), not grouped by type.
1074+
let mut items = vec![
1075+
GithubItem {
1076+
number: 10,
1077+
title: "Old PR".to_string(),
1078+
repo: "enwiro".to_string(),
1079+
kind: GithubItemKind::PullRequest {
1080+
head_ref_name: "old-pr".to_string(),
1081+
},
1082+
updated_at: "2026-02-01T00:00:00Z".to_string(),
1083+
},
1084+
GithubItem {
1085+
number: 20,
1086+
title: "Recent issue".to_string(),
1087+
repo: "enwiro".to_string(),
1088+
kind: GithubItemKind::Issue,
1089+
updated_at: "2026-02-15T00:00:00Z".to_string(),
1090+
},
1091+
GithubItem {
1092+
number: 30,
1093+
title: "Newest PR".to_string(),
1094+
repo: "enwiro".to_string(),
1095+
kind: GithubItemKind::PullRequest {
1096+
head_ref_name: "newest-pr".to_string(),
1097+
},
1098+
updated_at: "2026-02-18T00:00:00Z".to_string(),
1099+
},
1100+
];
1101+
1102+
sort_items_by_date(&mut items);
1103+
1104+
assert_eq!(items[0].number, 30, "Newest PR should be first");
1105+
assert_eq!(items[1].number, 20, "Recent issue should be second");
1106+
assert_eq!(items[2].number, 10, "Old PR should be last");
1107+
}
1108+
10301109
#[test]
10311110
fn test_get_default_branch_errors_when_no_candidates() {
10321111
let tmp = tempfile::TempDir::new().unwrap();

0 commit comments

Comments
 (0)