upleb.uk

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

summaryrefslogtreecommitdiff
path: root/src/bin/git_remote_nostr
diff options
context:
space:
mode:
Diffstat (limited to 'src/bin/git_remote_nostr')
-rw-r--r--src/bin/git_remote_nostr/push.rs126
1 files changed, 111 insertions, 15 deletions
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
12use console::Term; 12use console::Term;
13use git::{RepoActions, sha1_to_oid}; 13use git::{RepoActions, sha1_to_oid};
14use git_events::{ 14use git_events::{
15 generate_cover_letter_and_patch_events, generate_patch_event, get_commit_id_from_patch, 15 generate_cover_letter_and_patch_events, generate_patch_event, generate_unsigned_pr_event,
16 get_commit_id_from_patch,
16}; 17};
17use git2::{Oid, Repository}; 18use git2::{Oid, Repository};
18use ngit::{ 19use ngit::{
19 cli_interactor::count_lines_per_msg_vec, 20 cli_interactor::count_lines_per_msg_vec,
20 client::{self, get_event_from_cache_by_id}, 21 client::{self, get_event_from_cache_by_id, sign_draft_event},
21 git::{ 22 git::{
22 self, 23 self,
23 nostr_url::{CloneUrl, NostrUrlDecoded}, 24 nostr_url::{CloneUrl, NostrUrlDecoded},
@@ -25,10 +26,10 @@ use ngit::{
25 }, 26 },
26 git_events::{self, event_to_cover_letter, get_event_root}, 27 git_events::{self, event_to_cover_letter, get_event_root},
27 login::{self, user::UserRef}, 28 login::{self, user::UserRef},
28 repo_ref::{self, get_repo_config_from_yaml, is_grasp_server}, 29 repo_ref::{self, get_repo_config_from_yaml, is_grasp_server, normalize_grasp_server_url},
29 repo_state, 30 repo_state,
30}; 31};
31use nostr::nips::nip10::Marker; 32use nostr::{event::UnsignedEvent, nips::nip10::Marker};
32use nostr_sdk::{ 33use nostr_sdk::{
33 Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard, 34 Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard,
34 hashes::sha1::Hash as Sha1Hash, 35 hashes::sha1::Hash as Sha1Hash,
@@ -404,18 +405,11 @@ async fn process_proposal_refspecs(
404 let (mut ahead, _) = 405 let (mut ahead, _) =
405 git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?; 406 git_repo.get_commits_ahead_behind(&main_tip, &tip_of_pushed_branch)?;
406 ahead.reverse(); 407 ahead.reverse();
407 for patch in generate_cover_letter_and_patch_events( 408 for event in
408 None, 409 generate_patches_or_pr_event(git_repo, repo_ref, &ahead, user_ref, signer, term)
409 git_repo, 410 .await?
410 &ahead,
411 signer,
412 repo_ref,
413 &None,
414 &[],
415 )
416 .await?
417 { 411 {
418 events.push(patch); 412 events.push(event);
419 } 413 }
420 } 414 }
421 } 415 }
@@ -423,6 +417,108 @@ async fn process_proposal_refspecs(
423 Ok((events, rejected_proposal_refspecs)) 417 Ok((events, rejected_proposal_refspecs))
424} 418}
425 419
420async fn generate_patches_or_pr_event(
421 git_repo: &Repo,
422 repo_ref: &RepoRef,
423 ahead: &[Sha1Hash],
424 user_ref: &UserRef,
425 signer: &Arc<dyn NostrSigner>,
426 term: &Term,
427) -> Result<Vec<Event>> {
428 let mut events: Vec<Event> = vec![];
429 let use_pr = ahead.iter().any(|commit| {
430 if let Ok(patch) = git_repo.make_patch_from_commit(commit, &None) {
431 patch.len()
432 > ((65 // max recomended patch event size specified in nip34 in kb
433 // allownace for nostr event wrapper (id, pubkey, tags, sig)
434 - 1) * 1024)
435 } else {
436 true
437 }
438 });
439
440 if use_pr {
441 let repo_grasps = repo_ref.grasp_servers();
442 let repo_grasp_clone_urls = repo_ref
443 .git_server
444 .iter()
445 .filter(|s| is_grasp_server(s, &repo_grasps));
446
447 let mut unsigned_pr_event: Option<UnsignedEvent> = None;
448 let mut failed_clone_urls = vec![];
449 for clone_url in repo_grasp_clone_urls {
450 let mut draft_pr_event = if let Some(ref unsigned_pr_event) = unsigned_pr_event {
451 unsigned_pr_event.clone()
452 } else {
453 generate_unsigned_pr_event(
454 git_repo,
455 repo_ref,
456 &user_ref.public_key,
457 ahead.first().context("no commits to push")?,
458 &[clone_url],
459 &[],
460 )?
461 };
462
463 let refspec = format!(
464 "{}:refs/nostr/{}",
465 ahead.first().unwrap(),
466 draft_pr_event.id()
467 );
468
469 if let Err(error) = push_to_remote_url(git_repo, clone_url, &[refspec], term) {
470 failed_clone_urls.push(clone_url);
471 term.write_line(
472 format!(
473 "push: error sending commit data to {}: {error}",
474 normalize_grasp_server_url(clone_url)?
475 )
476 .as_str(),
477 )?;
478 } else {
479 term.write_line(
480 format!(
481 "push: commit data sent to {}",
482 normalize_grasp_server_url(clone_url)?
483 )
484 .as_str(),
485 )?;
486 unsigned_pr_event = Some(draft_pr_event);
487 }
488 }
489 if unsigned_pr_event.is_none() {
490 // TODO get fallback grasp servers that aren't in repo_grasps cycle
491 // through until one succeeds TODO create personal-fork
492 // announcement with grasp servers and push, after a few seconds
493 // push ref/nostr/eventid. if one success break out of
494 // for loop and continue
495 }
496 if let Some(unsigned_pr_event) = unsigned_pr_event {
497 let pr_event =
498 sign_draft_event(unsigned_pr_event, signer, "Pull Request".to_string()).await?;
499 events.push(pr_event);
500 } else {
501 bail!("could not find a grasp server that accepts the Pull Request refs");
502 }
503 } else {
504 for patch in generate_cover_letter_and_patch_events(
505 None,
506 git_repo,
507 ahead,
508 signer,
509 repo_ref,
510 &None,
511 &[],
512 )
513 .await?
514 {
515 events.push(patch);
516 }
517 }
518
519 Ok(events)
520}
521
426fn push_to_remote( 522fn push_to_remote(
427 git_repo: &Repo, 523 git_repo: &Repo,
428 git_server_url: &str, 524 git_server_url: &str,