upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-07-18 11:56:15 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2025-07-18 11:56:15 +0100
commit3eb2354edb8e76428625d5645e110c30aa1ccc2a (patch)
tree59798e071817e2a8b155b15230a367005181ac56 /src/lib
parent757c2f888b2be2b37ea01e02a6c020c5f8c7aa9c (diff)
feat(pr): list PR and PR updates
remote will list the refs under `pr/*` namespace. `ngit list` will display in the list of open / draft proposals. it won't yet fetch the related oids to enable fetching or checking out the branch.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/client.rs37
-rw-r--r--src/lib/git_events.rs50
2 files changed, 63 insertions, 24 deletions
diff --git a/src/lib/client.rs b/src/lib/client.rs
index ae3b414..1f3b08c 100644
--- a/src/lib/client.rs
+++ b/src/lib/client.rs
@@ -1811,7 +1811,7 @@ pub async fn get_proposals_and_revisions_from_cache(
1811 git_repo_path, 1811 git_repo_path,
1812 vec![ 1812 vec![
1813 nostr::Filter::default() 1813 nostr::Filter::default()
1814 .kind(nostr::Kind::GitPatch) 1814 .kinds([nostr::Kind::GitPatch, KIND_PULL_REQUEST])
1815 .custom_tags( 1815 .custom_tags(
1816 nostr::SingleLetterTag::lowercase(nostr_sdk::Alphabet::A), 1816 nostr::SingleLetterTag::lowercase(nostr_sdk::Alphabet::A),
1817 repo_coordinates 1817 repo_coordinates
@@ -1823,7 +1823,7 @@ pub async fn get_proposals_and_revisions_from_cache(
1823 ) 1823 )
1824 .await? 1824 .await?
1825 .iter() 1825 .iter()
1826 .filter(|e| event_is_patch_set_root(e)) 1826 .filter(|e| event_is_patch_set_root(e) || e.kind.eq(&KIND_PULL_REQUEST))
1827 .cloned() 1827 .cloned()
1828 .collect::<Vec<nostr::Event>>(); 1828 .collect::<Vec<nostr::Event>>();
1829 proposals.sort_by_key(|e| e.created_at); 1829 proposals.sort_by_key(|e| e.created_at);
@@ -1831,7 +1831,7 @@ pub async fn get_proposals_and_revisions_from_cache(
1831 Ok(proposals) 1831 Ok(proposals)
1832} 1832}
1833 1833
1834pub async fn get_all_proposal_patch_events_from_cache( 1834pub async fn get_all_proposal_patch_pr_pr_update_events_from_cache(
1835 git_repo_path: &Path, 1835 git_repo_path: &Path,
1836 repo_ref: &RepoRef, 1836 repo_ref: &RepoRef,
1837 proposal_id: &nostr::EventId, 1837 proposal_id: &nostr::EventId,
@@ -1840,10 +1840,21 @@ pub async fn get_all_proposal_patch_events_from_cache(
1840 git_repo_path, 1840 git_repo_path,
1841 vec![ 1841 vec![
1842 nostr::Filter::default() 1842 nostr::Filter::default()
1843 .kind(nostr::Kind::GitPatch) 1843 .kinds([
1844 nostr::Kind::GitPatch,
1845 KIND_PULL_REQUEST,
1846 KIND_PULL_REQUEST_UPDATE,
1847 ])
1844 .event(*proposal_id), 1848 .event(*proposal_id),
1845 nostr::Filter::default() 1849 nostr::Filter::default()
1846 .kind(nostr::Kind::GitPatch) 1850 .kinds([
1851 nostr::Kind::GitPatch,
1852 KIND_PULL_REQUEST,
1853 KIND_PULL_REQUEST_UPDATE,
1854 ])
1855 .custom_tag(SingleLetterTag::uppercase(Alphabet::E), *proposal_id),
1856 nostr::Filter::default()
1857 .kinds([nostr::Kind::GitPatch, KIND_PULL_REQUEST])
1847 .id(*proposal_id), 1858 .id(*proposal_id),
1848 ], 1859 ],
1849 ) 1860 )
@@ -1876,8 +1887,20 @@ pub async fn get_all_proposal_patch_events_from_cache(
1876 git_repo_path, 1887 git_repo_path,
1877 vec![ 1888 vec![
1878 nostr::Filter::default() 1889 nostr::Filter::default()
1879 .kind(nostr::Kind::GitPatch) 1890 .kinds([
1880 .events(revision_roots) 1891 nostr::Kind::GitPatch,
1892 KIND_PULL_REQUEST,
1893 KIND_PULL_REQUEST_UPDATE,
1894 ])
1895 .events(revision_roots.clone())
1896 .authors(permissioned_users.clone()),
1897 nostr::Filter::default()
1898 .kinds([
1899 nostr::Kind::GitPatch,
1900 KIND_PULL_REQUEST,
1901 KIND_PULL_REQUEST_UPDATE,
1902 ])
1903 .custom_tags(SingleLetterTag::uppercase(Alphabet::E), revision_roots)
1881 .authors(permissioned_users.clone()), 1904 .authors(permissioned_users.clone()),
1882 ], 1905 ],
1883 ) 1906 )
diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs
index 80793bd..7b25daf 100644
--- a/src/lib/git_events.rs
+++ b/src/lib/git_events.rs
@@ -70,11 +70,16 @@ pub fn event_is_patch_set_root(event: &Event) -> bool {
70} 70}
71 71
72pub fn event_is_revision_root(event: &Event) -> bool { 72pub fn event_is_revision_root(event: &Event) -> bool {
73 event.kind.eq(&Kind::GitPatch) 73 (event.kind.eq(&Kind::GitPatch)
74 && event 74 && event
75 .tags 75 .tags
76 .iter() 76 .iter()
77 .any(|t| t.as_slice().len() > 1 && t.as_slice()[1].eq("revision-root")) 77 .any(|t| t.as_slice().len() > 1 && t.as_slice()[1].eq("revision-root")))
78 || (event.kind.eq(&KIND_PULL_REQUEST)
79 && event
80 .tags
81 .iter()
82 .any(|t| t.as_slice().len() > 1 && t.as_slice()[0].eq("e")))
78} 83}
79 84
80pub fn patch_supports_commit_ids(event: &Event) -> bool { 85pub fn patch_supports_commit_ids(event: &Event) -> bool {
@@ -534,13 +539,22 @@ pub fn commit_msg_from_patch_oneliner(patch: &nostr::Event) -> Result<String> {
534} 539}
535 540
536pub fn event_to_cover_letter(event: &nostr::Event) -> Result<CoverLetter> { 541pub fn event_to_cover_letter(event: &nostr::Event) -> Result<CoverLetter> {
537 if !event_is_patch_set_root(event) { 542 if !event.kind.eq(&KIND_PULL_REQUEST) && !event_is_patch_set_root(event) {
538 bail!("event is not a patch set root event (root patch or cover letter)") 543 bail!("event is not a patch set root event (root patch or cover letter)")
539 } 544 }
540 545
541 let title = commit_msg_from_patch_oneliner(event)?; 546 let title = if event.kind.eq(&KIND_PULL_REQUEST) {
542 let full = commit_msg_from_patch(event)?; 547 tag_value(event, "subject").unwrap_or("untitled".to_owned())
543 let description = full[title.len()..].trim().to_string(); 548 } else {
549 commit_msg_from_patch_oneliner(event)?
550 };
551 let description = if event.kind.eq(&KIND_PULL_REQUEST) {
552 event.content.clone()
553 } else {
554 commit_msg_from_patch(event)?[title.len()..]
555 .trim()
556 .to_string()
557 };
544 558
545 Ok(CoverLetter { 559 Ok(CoverLetter {
546 title: title.clone(), 560 title: title.clone(),
@@ -572,25 +586,25 @@ fn safe_branch_name_for_pr(s: &str) -> String {
572 .collect() 586 .collect()
573} 587}
574 588
575pub fn get_most_recent_patch_with_ancestors( 589pub fn get_pr_tip_event_or_most_recent_patch_with_ancestors(
576 mut patches: Vec<nostr::Event>, 590 mut proposal_events: Vec<nostr::Event>,
577) -> Result<Vec<nostr::Event>> { 591) -> Result<Vec<nostr::Event>> {
578 patches.sort_by_key(|e| e.created_at); 592 proposal_events.sort_by_key(|e| e.created_at);
579 593
580 let youngest_patch = patches.last().context("no patches found")?; 594 let youngest = proposal_events.last().context("no proposal events found")?;
581 595
582 let patches_with_youngest_created_at: Vec<&nostr::Event> = patches 596 let events_with_youngest_created_at: Vec<&nostr::Event> = proposal_events
583 .iter() 597 .iter()
584 .filter(|p| p.created_at.eq(&youngest_patch.created_at)) 598 .filter(|p| p.created_at.eq(&youngest.created_at))
585 .collect(); 599 .collect();
586 600
587 let mut res = vec![]; 601 let mut res = vec![];
588 602
589 let mut event_id_to_search = patches_with_youngest_created_at 603 let mut event_id_to_search = events_with_youngest_created_at
590 .clone() 604 .clone()
591 .iter() 605 .iter()
592 .find(|p| { 606 .find(|p| {
593 !patches_with_youngest_created_at.iter().any(|p2| { 607 !events_with_youngest_created_at.iter().any(|p2| {
594 if let Ok(reply_to) = get_event_parent_id(p2) { 608 if let Ok(reply_to) = get_event_parent_id(p2) {
595 reply_to.eq(&p.id.to_string()) 609 reply_to.eq(&p.id.to_string())
596 } else { 610 } else {
@@ -598,16 +612,18 @@ pub fn get_most_recent_patch_with_ancestors(
598 } 612 }
599 }) 613 })
600 }) 614 })
601 .context("failed to find patches_with_youngest_created_at")? 615 .context("failed to find events_with_youngest_created_at")?
602 .id 616 .id
603 .to_string(); 617 .to_string();
604 618
605 while let Some(event) = patches 619 while let Some(event) = proposal_events
606 .iter() 620 .iter()
607 .find(|e| e.id.to_string().eq(&event_id_to_search)) 621 .find(|e| e.id.to_string().eq(&event_id_to_search))
608 { 622 {
609 res.push(event.clone()); 623 res.push(event.clone());
610 if event_is_patch_set_root(event) { 624 if [KIND_PULL_REQUEST, KIND_PULL_REQUEST_UPDATE].contains(&event.kind)
625 || event_is_patch_set_root(event)
626 {
611 break; 627 break;
612 } 628 }
613 event_id_to_search = get_event_parent_id(event).unwrap_or_default(); 629 event_id_to_search = get_event_parent_id(event).unwrap_or_default();