From f4e1df4c718a3755ffe50e99946996729f3504e9 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Tue, 22 Jul 2025 17:14:21 +0100 Subject: feat(pr): generate pr event > oversized patch but only for new proposals --- src/bin/git_remote_nostr/push.rs | 126 ++++++++++++++++++++++++++++++++++----- 1 file changed, 111 insertions(+), 15 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 9ff8af0..b9e8571 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -12,12 +12,13 @@ use client::{get_events_from_local_cache, get_state_from_cache, send_events, sig use console::Term; use git::{RepoActions, sha1_to_oid}; use git_events::{ - generate_cover_letter_and_patch_events, generate_patch_event, get_commit_id_from_patch, + generate_cover_letter_and_patch_events, generate_patch_event, generate_unsigned_pr_event, + get_commit_id_from_patch, }; use git2::{Oid, Repository}; use ngit::{ cli_interactor::count_lines_per_msg_vec, - client::{self, get_event_from_cache_by_id}, + client::{self, get_event_from_cache_by_id, sign_draft_event}, git::{ self, nostr_url::{CloneUrl, NostrUrlDecoded}, @@ -25,10 +26,10 @@ use ngit::{ }, git_events::{self, event_to_cover_letter, get_event_root}, login::{self, user::UserRef}, - repo_ref::{self, get_repo_config_from_yaml, is_grasp_server}, + repo_ref::{self, get_repo_config_from_yaml, is_grasp_server, normalize_grasp_server_url}, repo_state, }; -use nostr::nips::nip10::Marker; +use nostr::{event::UnsignedEvent, nips::nip10::Marker}; use nostr_sdk::{ Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard, hashes::sha1::Hash as Sha1Hash, @@ -404,18 +405,11 @@ async fn process_proposal_refspecs( let (mut ahead, _) = git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; ahead.reverse(); - for patch in generate_cover_letter_and_patch_events( - None, - git_repo, - &ahead, - signer, - repo_ref, - &None, - &[], - ) - .await? + for event in + generate_patches_or_pr_event(git_repo, repo_ref, &ahead, user_ref, signer, term) + .await? { - events.push(patch); + events.push(event); } } } @@ -423,6 +417,108 @@ async fn process_proposal_refspecs( Ok((events, rejected_proposal_refspecs)) } +async fn generate_patches_or_pr_event( + git_repo: &Repo, + repo_ref: &RepoRef, + ahead: &[Sha1Hash], + user_ref: &UserRef, + signer: &Arc, + term: &Term, +) -> Result> { + let mut events: Vec = vec![]; + let use_pr = ahead.iter().any(|commit| { + if let Ok(patch) = git_repo.make_patch_from_commit(commit, &None) { + patch.len() + > ((65 // max recomended patch event size specified in nip34 in kb + // allownace for nostr event wrapper (id, pubkey, tags, sig) + - 1) * 1024) + } else { + true + } + }); + + if use_pr { + let repo_grasps = repo_ref.grasp_servers(); + let repo_grasp_clone_urls = repo_ref + .git_server + .iter() + .filter(|s| is_grasp_server(s, &repo_grasps)); + + let mut unsigned_pr_event: Option = None; + let mut failed_clone_urls = vec![]; + for clone_url in repo_grasp_clone_urls { + let mut draft_pr_event = if let Some(ref unsigned_pr_event) = unsigned_pr_event { + unsigned_pr_event.clone() + } else { + generate_unsigned_pr_event( + git_repo, + repo_ref, + &user_ref.public_key, + ahead.first().context("no commits to push")?, + &[clone_url], + &[], + )? + }; + + let refspec = format!( + "{}:refs/nostr/{}", + ahead.first().unwrap(), + draft_pr_event.id() + ); + + if let Err(error) = push_to_remote_url(git_repo, clone_url, &[refspec], term) { + failed_clone_urls.push(clone_url); + term.write_line( + format!( + "push: error sending commit data to {}: {error}", + normalize_grasp_server_url(clone_url)? + ) + .as_str(), + )?; + } else { + term.write_line( + format!( + "push: commit data sent to {}", + normalize_grasp_server_url(clone_url)? + ) + .as_str(), + )?; + unsigned_pr_event = Some(draft_pr_event); + } + } + if unsigned_pr_event.is_none() { + // TODO get fallback grasp servers that aren't in repo_grasps cycle + // through until one succeeds TODO create personal-fork + // announcement with grasp servers and push, after a few seconds + // push ref/nostr/eventid. if one success break out of + // for loop and continue + } + if let Some(unsigned_pr_event) = unsigned_pr_event { + let pr_event = + sign_draft_event(unsigned_pr_event, signer, "Pull Request".to_string()).await?; + events.push(pr_event); + } else { + bail!("could not find a grasp server that accepts the Pull Request refs"); + } + } else { + for patch in generate_cover_letter_and_patch_events( + None, + git_repo, + ahead, + signer, + repo_ref, + &None, + &[], + ) + .await? + { + events.push(patch); + } + } + + Ok(events) +} + fn push_to_remote( git_repo: &Repo, git_server_url: &str, -- cgit v1.2.3 From 698b05be2e48b38a4f268bfabc3562e83e0c1363 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 23 Jul 2025 05:07:03 +0100 Subject: refactor(pr): rename functions to reflect there new role of also pushing prs to git severs --- src/bin/git_remote_nostr/push.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index b9e8571..61f4f92 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -66,7 +66,7 @@ pub async fn run_push( .cloned() .collect::>(); - let mut git_server_refspecs = refspecs + let mut git_state_refspecs = refspecs .iter() .filter(|r| !r.contains("refs/heads/pr/")) .cloned() @@ -106,12 +106,12 @@ pub async fn run_push( let (rejected_refspecs, remote_refspecs) = create_rejected_refspecs_and_remotes_refspecs( &term, git_repo, - &git_server_refspecs, + &git_state_refspecs, &existing_state, &list_outputs, )?; - git_server_refspecs.retain(|refspec| { + git_state_refspecs.retain(|refspec| { if let Some(rejected) = rejected_refspecs.get(&refspec.to_string()) { let (_, to) = refspec_to_from_to(refspec).unwrap(); println!("error {to} {} out of sync with nostr", rejected.join(" ")); @@ -122,11 +122,11 @@ pub async fn run_push( }); // all refspecs aren't rejected - if !(git_server_refspecs.is_empty() && proposal_refspecs.is_empty()) { - let (rejected_proposal_refspecs, rejected) = create_and_publish_events( + if !(git_state_refspecs.is_empty() && proposal_refspecs.is_empty()) { + let (rejected_proposal_refspecs, rejected) = create_and_publish_events_and_proposals( git_repo, repo_ref, - &git_server_refspecs, + &git_state_refspecs, &proposal_refspecs, client, existing_state, @@ -135,7 +135,7 @@ pub async fn run_push( .await?; if !rejected { - for refspec in git_server_refspecs.iter().chain(proposal_refspecs.iter()) { + for refspec in git_state_refspecs.iter().chain(proposal_refspecs.iter()) { if rejected_proposal_refspecs.contains(refspec) { continue; } @@ -154,7 +154,7 @@ pub async fn run_push( for (git_server_url, remote_refspecs) in remote_refspecs { let remote_refspecs = remote_refspecs .iter() - .filter(|refspec| git_server_refspecs.contains(refspec)) + .filter(|refspec| git_state_refspecs.contains(refspec)) .cloned() .collect::>(); if !refspecs.is_empty() { @@ -175,7 +175,7 @@ pub async fn run_push( Ok(()) } -async fn create_and_publish_events( +async fn create_and_publish_events_and_proposals( git_repo: &Repo, repo_ref: &RepoRef, git_server_refspecs: &Vec, -- cgit v1.2.3 From ecfb54e1c89455590f816152b9efb722f0115bf1 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 23 Jul 2025 08:51:21 +0100 Subject: feat(pr): updates and pr as patch revision issue a pull request update if pushing or force pushing a pull request issue a pull request with an e tag for original patch and close status for the original patch when pushing or force pushing against a patch when the new commits are too big to be iussed as patches --- src/bin/git_remote_nostr/push.rs | 155 ++++++++++++++++++++++++++++++++------- src/lib/git_events.rs | 143 +++++++++++++++++++++++------------- 2 files changed, 220 insertions(+), 78 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 61f4f92..596cd68 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -12,8 +12,8 @@ use client::{get_events_from_local_cache, get_state_from_cache, send_events, sig use console::Term; use git::{RepoActions, sha1_to_oid}; use git_events::{ - generate_cover_letter_and_patch_events, generate_patch_event, generate_unsigned_pr_event, - get_commit_id_from_patch, + generate_cover_letter_and_patch_events, generate_patch_event, + generate_unsigned_pr_or_update_event, get_commit_id_from_patch, }; use git2::{Oid, Repository}; use ngit::{ @@ -24,7 +24,7 @@ use ngit::{ nostr_url::{CloneUrl, NostrUrlDecoded}, oid_to_shorthand_string, }, - git_events::{self, event_to_cover_letter, get_event_root}, + git_events::{self, KIND_PULL_REQUEST, event_to_cover_letter, get_event_root}, login::{self, user::UserRef}, repo_ref::{self, get_repo_config_from_yaml, is_grasp_server, normalize_grasp_server_url}, repo_state, @@ -325,14 +325,14 @@ async fn process_proposal_refspecs( let (mut ahead, _) = git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; ahead.reverse(); - for patch in generate_cover_letter_and_patch_events( - None, + for patch in generate_patches_or_pr_event_or_pr_updates( git_repo, + repo_ref, &ahead, + user_ref, + Some(proposal), signer, - repo_ref, - &Some(proposal.id.to_string()), - &[], + term, ) .await? { @@ -356,6 +356,23 @@ async fn process_proposal_refspecs( }; let mut parent_patch = tip_patch.clone(); ahead.reverse(); + if proposal.kind.eq(&KIND_PULL_REQUEST) + || are_commits_too_big_for_patches(git_repo, &ahead) + { + for event in generate_patches_or_pr_event_or_pr_updates( + git_repo, + repo_ref, + &ahead, + user_ref, + Some(proposal), + signer, + term, + ) + .await? + { + events.push(event); + } + } for (i, commit) in ahead.iter().enumerate() { let new_patch = generate_patch_event( git_repo, @@ -405,9 +422,10 @@ async fn process_proposal_refspecs( let (mut ahead, _) = git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; ahead.reverse(); - for event in - generate_patches_or_pr_event(git_repo, repo_ref, &ahead, user_ref, signer, term) - .await? + for event in generate_patches_or_pr_event_or_pr_updates( + git_repo, repo_ref, &ahead, user_ref, None, signer, term, + ) + .await? { events.push(event); } @@ -417,25 +435,32 @@ async fn process_proposal_refspecs( Ok((events, rejected_proposal_refspecs)) } -async fn generate_patches_or_pr_event( +fn are_commits_too_big_for_patches(git_repo: &Repo, commits: &[Sha1Hash]) -> bool { + commits.iter().any(|commit| { + if let Ok(patch) = git_repo.make_patch_from_commit(commit, &None) { + patch.len() + > ((65 // max recomended patch event size specified in nip34 in kb + // allownace for nostr event wrapper (id, pubkey, tags, sig) + - 1) * 1024) + } else { + true + } + }) +} + +#[allow(clippy::too_many_lines)] +async fn generate_patches_or_pr_event_or_pr_updates( git_repo: &Repo, repo_ref: &RepoRef, ahead: &[Sha1Hash], user_ref: &UserRef, + root_proposal: Option<&Event>, signer: &Arc, term: &Term, ) -> Result> { let mut events: Vec = vec![]; - let use_pr = ahead.iter().any(|commit| { - if let Ok(patch) = git_repo.make_patch_from_commit(commit, &None) { - patch.len() - > ((65 // max recomended patch event size specified in nip34 in kb - // allownace for nostr event wrapper (id, pubkey, tags, sig) - - 1) * 1024) - } else { - true - } - }); + let use_pr = root_proposal.is_some_and(|proposal| proposal.kind.eq(&KIND_PULL_REQUEST)) + || are_commits_too_big_for_patches(git_repo, ahead); if use_pr { let repo_grasps = repo_ref.grasp_servers(); @@ -450,10 +475,11 @@ async fn generate_patches_or_pr_event( let mut draft_pr_event = if let Some(ref unsigned_pr_event) = unsigned_pr_event { unsigned_pr_event.clone() } else { - generate_unsigned_pr_event( + generate_unsigned_pr_or_update_event( git_repo, repo_ref, &user_ref.public_key, + root_proposal, ahead.first().context("no commits to push")?, &[clone_url], &[], @@ -494,9 +520,30 @@ async fn generate_patches_or_pr_event( // for loop and continue } if let Some(unsigned_pr_event) = unsigned_pr_event { - let pr_event = - sign_draft_event(unsigned_pr_event, signer, "Pull Request".to_string()).await?; + let pr_event = sign_draft_event( + unsigned_pr_event, + signer, + if root_proposal.is_some_and(|proposal| proposal.kind.eq(&Kind::GitPatch)) { + "Pull Request Replacing Original Patch" + } else if root_proposal.is_some() { + "Pull Request Update" + } else { + "Pull Request" + } + .to_string(), + ) + .await?; events.push(pr_event); + if root_proposal.is_some_and(|proposal| proposal.kind.eq(&Kind::GitPatch)) { + events.push( + create_close_status_for_original_patch( + signer, + repo_ref, + root_proposal.unwrap(), + ) + .await?, + ); + } } else { bail!("could not find a grasp server that accepts the Pull Request refs"); } @@ -507,7 +554,7 @@ async fn generate_patches_or_pr_event( ahead, signer, repo_ref, - &None, + &root_proposal.map(|proposal| proposal.id.to_string()), &[], ) .await? @@ -1487,6 +1534,62 @@ async fn create_merge_status( .await } +async fn create_close_status_for_original_patch( + signer: &Arc, + repo_ref: &RepoRef, + proposal: &Event, +) -> Result { + let mut public_keys = repo_ref + .maintainers + .iter() + .copied() + .collect::>(); + public_keys.insert(proposal.pubkey); + + sign_event( + EventBuilder::new(nostr::event::Kind::GitStatusClosed, String::new()).tags( + [ + vec![ + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")), + vec![ + "Git patch closed as forthcoming update is too large. Replacing with Pull Request" + .to_string(), + ], + ), + Tag::from_standardized(nostr::TagStandard::Event { + event_id: proposal.id, + relay_url: repo_ref.relays.first().cloned(), + marker: Some(Marker::Root), + public_key: None, + uppercase: false, + }), + ], + public_keys.iter().map(|pk| Tag::public_key(*pk)).collect(), + repo_ref + .coordinates() + .iter() + .map(|c| { + Tag::from_standardized(TagStandard::Coordinate { + coordinate: c.coordinate.clone(), + relay_url: c.relays.first().cloned(), + uppercase: false, + }) + }) + .collect::>(), + vec![ + Tag::from_standardized(nostr::TagStandard::Reference( + repo_ref.root_commit.to_string(), + )), + ], + ] + .concat(), + ), + signer, + "close status for original patch".to_string(), + ) + .await +} async fn get_proposal_and_revision_root_from_patch( git_repo: &Repo, patch: &Event, diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs index 86b9641..7bca63b 100644 --- a/src/lib/git_events.rs +++ b/src/lib/git_events.rs @@ -350,10 +350,11 @@ pub fn event_tag_from_nip19_or_hex( } } -pub fn generate_unsigned_pr_event( +pub fn generate_unsigned_pr_or_update_event( git_repo: &Repo, repo_ref: &RepoRef, signing_public_key: &PublicKey, + root_proposal: Option<&Event>, commit: &Sha1Hash, clone_url_hint: &[&str], mentions: &[nostr::Tag], @@ -372,59 +373,97 @@ pub fn generate_unsigned_pr_event( .get_root_commit() .context("failed to get root commit of the repository")?; - Ok(EventBuilder::new(KIND_PULL_REQUEST, description) - .tags( - [ - repo_ref - .maintainers - .iter() - .map(|m| { - Tag::from_standardized(TagStandard::Coordinate { - coordinate: Coordinate { - kind: nostr::Kind::GitRepoAnnouncement, - public_key: *m, - identifier: repo_ref.identifier.to_string(), - }, - relay_url: repo_ref.relays.first().cloned(), - uppercase: false, - }) + Ok(if root_proposal.is_some() { + EventBuilder::new(KIND_PULL_REQUEST_UPDATE, "") + } else { + EventBuilder::new(KIND_PULL_REQUEST, description) + } + .tags( + [ + repo_ref + .maintainers + .iter() + .map(|m| { + Tag::from_standardized(TagStandard::Coordinate { + coordinate: Coordinate { + kind: nostr::Kind::GitRepoAnnouncement, + public_key: *m, + identifier: repo_ref.identifier.to_string(), + }, + relay_url: repo_ref.relays.first().cloned(), + uppercase: false, }) - .collect::>(), - mentions.to_vec(), - vec![ - Tag::from_standardized(TagStandard::Subject(title.clone())), - Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))), - Tag::custom( - nostr::TagKind::Custom(std::borrow::Cow::Borrowed("c")), - vec![format!("{commit}")], - ), - Tag::custom( - nostr::TagKind::Custom(std::borrow::Cow::Borrowed("clone")), - clone_url_hint - .iter() - .map(|s| s.to_string()) - .collect::>(), - ), - Tag::custom( + }) + .collect::>(), + mentions.to_vec(), + if let Some(root_proposal) = root_proposal { + [ + vec![Tag::custom( nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")), - vec![format!("git Pull Request: {}", title.clone())], - ), - ], - if let Some(branch_name_tag) = make_branch_name_tag_from_check_out_branch(git_repo) - { - vec![branch_name_tag] - } else { - vec![] - }, - repo_ref - .maintainers - .iter() - .map(|pk| Tag::public_key(*pk)) - .collect(), - ] - .concat(), - ) - .build(*signing_public_key)) + vec![format!("git Pull Request Update")], + )], + if root_proposal.kind.eq(&KIND_PULL_REQUEST) { + vec![ + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("E")), + vec![root_proposal.id], + ), + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("P")), + vec![root_proposal.pubkey], + ), + ] + } else { + // root proposal is a Patch - so use e tag per nip34 spec + vec![Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("e")), + vec![root_proposal.id], + )] + }, + ] + .concat() + } else { + [ + vec![ + Tag::from_standardized(TagStandard::Subject(title.clone())), + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")), + vec![format!("git Pull Request: {}", title.clone())], + ), + ], + if let Some(branch_name_tag) = + make_branch_name_tag_from_check_out_branch(git_repo) + { + vec![branch_name_tag] + } else { + vec![] + }, + ] + .concat() + }, + vec![ + Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))), + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("c")), + vec![format!("{commit}")], + ), + Tag::custom( + nostr::TagKind::Custom(std::borrow::Cow::Borrowed("clone")), + clone_url_hint + .iter() + .map(|s| s.to_string()) + .collect::>(), + ), + ], + repo_ref + .maintainers + .iter() + .map(|pk| Tag::public_key(*pk)) + .collect(), + ] + .concat(), + ) + .build(*signing_public_key)) } fn make_branch_name_tag_from_check_out_branch(git_repo: &Repo) -> Option { -- cgit v1.2.3 From bbdd2093506b31359ab1ff61b709e40de043c879 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 23 Jul 2025 16:25:49 +0100 Subject: fix(remote): error if pushed proposal is empty erorr if the pushed ref would produce a proposal with no patches, or if the ref is in origin/ --- src/bin/git_remote_nostr/push.rs | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 596cd68..b997ea7 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -321,10 +321,15 @@ async fn process_proposal_refspecs( { if refspec.starts_with('+') { // force push - let (_, main_tip) = git_repo.get_main_or_master_branch()?; + let (main_branch_name, main_tip) = git_repo.get_main_or_master_branch()?; let (mut ahead, _) = git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; ahead.reverse(); + if ahead.is_empty() { + bail!( + "cannot push '{from}' as proposal as branch isn't ahead of '{main_branch_name}'" + ); + } for patch in generate_patches_or_pr_event_or_pr_updates( git_repo, repo_ref, @@ -356,6 +361,11 @@ async fn process_proposal_refspecs( }; let mut parent_patch = tip_patch.clone(); ahead.reverse(); + if ahead.is_empty() { + bail!( + "cannot push '{from}' as proposal as branch isn't ahead of proposal on nostr" + ); + } if proposal.kind.eq(&KIND_PULL_REQUEST) || are_commits_too_big_for_patches(git_repo, &ahead) { @@ -418,10 +428,15 @@ async fn process_proposal_refspecs( } } else { // TODO new proposal / couldn't find exisiting proposal - let (_, main_tip) = git_repo.get_main_or_master_branch()?; + let (main_branch_name, main_tip) = git_repo.get_main_or_master_branch()?; let (mut ahead, _) = git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; ahead.reverse(); + if ahead.is_empty() { + bail!( + "cannot push '{from}' as proposal as branch isn't ahead of '{main_branch_name}'" + ); + } for event in generate_patches_or_pr_event_or_pr_updates( git_repo, repo_ref, &ahead, user_ref, None, signer, term, ) @@ -513,11 +528,11 @@ async fn generate_patches_or_pr_event_or_pr_updates( } } if unsigned_pr_event.is_none() { - // TODO get fallback grasp servers that aren't in repo_grasps cycle - // through until one succeeds TODO create personal-fork - // announcement with grasp servers and push, after a few seconds - // push ref/nostr/eventid. if one success break out of - // for loop and continue + // TODO get grasp_default_set servers that aren't in repo_grasps + // cycle through until one succeeds TODO create + // personal-fork announcement with grasp servers and + // push, after a few seconds push ref/nostr/eventid. if + // one success break out of for loop and continue } if let Some(unsigned_pr_event) = unsigned_pr_event { let pr_event = sign_draft_event( -- cgit v1.2.3 From 3a3f8c877d060f7510b79f32233e2bd2574de4c1 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 23 Jul 2025 16:27:50 +0100 Subject: fix(remote): dont send pr and patches on upgrade when an upgrade to a pr is needed, dont also try and send patches --- src/bin/git_remote_nostr/push.rs | 45 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index b997ea7..e694e18 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -382,28 +382,29 @@ async fn process_proposal_refspecs( { events.push(event); } - } - for (i, commit) in ahead.iter().enumerate() { - let new_patch = generate_patch_event( - git_repo, - &git_repo.get_root_commit()?, - commit, - Some(thread_id), - signer, - repo_ref, - Some(parent_patch.id), - Some(( - (patches.len() + i + 1).try_into().unwrap(), - (patches.len() + ahead.len()).try_into().unwrap(), - )), - None, - &None, - &[], - ) - .await - .context("failed to make patch event from commit")?; - events.push(new_patch.clone()); - parent_patch = new_patch; + } else { + for (i, commit) in ahead.iter().enumerate() { + let new_patch = generate_patch_event( + git_repo, + &git_repo.get_root_commit()?, + commit, + Some(thread_id), + signer, + repo_ref, + Some(parent_patch.id), + Some(( + (patches.len() + i + 1).try_into().unwrap(), + (patches.len() + ahead.len()).try_into().unwrap(), + )), + None, + &None, + &[], + ) + .await + .context("failed to make patch event from commit")?; + events.push(new_patch.clone()); + parent_patch = new_patch; + } } } else { // we shouldn't get here -- cgit v1.2.3 From 802b115ca648011fd311a22ef3650aaa5a1a0acf Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 23 Jul 2025 17:16:18 +0100 Subject: fix(remote): improve pr error messages as a temporary measure --- src/bin/git_remote_nostr/push.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index e694e18..353ad77 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -529,6 +529,10 @@ async fn generate_patches_or_pr_event_or_pr_updates( } } if unsigned_pr_event.is_none() { + bail!( + "a commit in your proposal is too big for a nostr patch. The repository doesnt list a grasp server which would otherwise be used to submit your proposal as nostr Pull Request. Soon ngit will support pushing your changes to a different git / grasp git server." + ); + // TODO get grasp_default_set servers that aren't in repo_grasps // cycle through until one succeeds TODO create // personal-fork announcement with grasp servers and @@ -561,7 +565,11 @@ async fn generate_patches_or_pr_event_or_pr_updates( ); } } else { - bail!("could not find a grasp server that accepts the Pull Request refs"); + bail!( + "a commit in your proposal is too big for a nostr patch. tried to use submit as a nostr Pull Request but could not find a grasp server that would accept your changes" + ); + // TODO suggest `ngit send` where user could specify their own clone + // url to push to once that feature is added } } else { for patch in generate_cover_letter_and_patch_events( -- cgit v1.2.3 From 4fc659074ec5ced3cc0727cf1f3e6af082a189cc Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Fri, 25 Jul 2025 12:23:23 +0100 Subject: feat(pr): add pr and pr update merge support as these events use `c` instead of `commit` --- src/bin/git_remote_nostr/push.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/bin/git_remote_nostr/push.rs') diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 353ad77..909a0ab 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -1246,7 +1246,7 @@ type MergedProposalsInfo = async fn get_merged_proposals_info( git_repo: &Repo, ahead: &Vec, - available_patches: &[Event], + available_patches_pr_pr_update: &[Event], ) -> Result { let mut proposals: MergedProposalsInfo = HashMap::new(); @@ -1256,19 +1256,19 @@ async fn get_merged_proposals_info( // are in ahead if commit.parent_count() > 1 { for parent in commit.parents() { - for patch_event in available_patches + for event in available_patches_pr_pr_update .iter() .filter(|e| { e.tags.iter().any(|t| { t.as_slice().len() > 1 - && t.as_slice()[0].eq("commit") + && (t.as_slice()[0].eq("commit") || t.as_slice()[0].eq("c")) && t.as_slice()[1].eq(&parent.id().to_string()) }) }) .collect::>() { if let Ok((proposal_id, revision_id)) = - get_proposal_and_revision_root_from_patch(git_repo, patch_event).await + get_proposal_and_revision_root_from_patch(git_repo, event).await { let (entry_revision_id, merged_patches) = proposals.entry(proposal_id).or_default(); @@ -1281,12 +1281,12 @@ async fn get_merged_proposals_info( } else { // three way merge or fast forward merge commits // note: ahead included commits of three-way merged branches - let mut matching_patches = available_patches + let mut matching_patches = available_patches_pr_pr_update .iter() .filter(|e| { e.tags.iter().any(|t| { t.as_slice().len() > 1 - && t.as_slice()[0].eq("commit") + && (t.as_slice()[0].eq("commit") || t.as_slice()[0].eq("c")) && t.as_slice()[1].eq(&commit_hash.to_string()) }) }) @@ -1311,7 +1311,7 @@ async fn get_merged_proposals_info( // applied commits - this is done after so that merged revisions take priority if matching_patches.is_empty() { let author = git_repo.get_commit_author(commit_hash)?; - matching_patches = available_patches + matching_patches = available_patches_pr_pr_update .iter() .filter(|e| { if let Ok(patch_author) = get_patch_author(e) { -- cgit v1.2.3