diff options
Diffstat (limited to 'src/bin/git_remote_nostr/push.rs')
| -rw-r--r-- | src/bin/git_remote_nostr/push.rs | 126 |
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 | |||
| 12 | use console::Term; | 12 | use console::Term; |
| 13 | use git::{RepoActions, sha1_to_oid}; | 13 | use git::{RepoActions, sha1_to_oid}; |
| 14 | use git_events::{ | 14 | use 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 | }; |
| 17 | use git2::{Oid, Repository}; | 18 | use git2::{Oid, Repository}; |
| 18 | use ngit::{ | 19 | use 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 | }; |
| 31 | use nostr::nips::nip10::Marker; | 32 | use nostr::{event::UnsignedEvent, nips::nip10::Marker}; |
| 32 | use nostr_sdk::{ | 33 | use 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 | ||
| 420 | async 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 | |||
| 426 | fn push_to_remote( | 522 | fn push_to_remote( |
| 427 | git_repo: &Repo, | 523 | git_repo: &Repo, |
| 428 | git_server_url: &str, | 524 | git_server_url: &str, |