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.rs164
1 files changed, 5 insertions, 159 deletions
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs
index 3478608..e588a5a 100644
--- a/src/bin/git_remote_nostr/push.rs
+++ b/src/bin/git_remote_nostr/push.rs
@@ -10,25 +10,24 @@ use client::{get_events_from_local_cache, get_state_from_cache, send_events, sig
10use console::Term; 10use console::Term;
11use git::{RepoActions, sha1_to_oid}; 11use git::{RepoActions, sha1_to_oid};
12use git_events::{ 12use git_events::{
13 generate_cover_letter_and_patch_events, generate_patch_event, 13 generate_cover_letter_and_patch_events, generate_patch_event, get_commit_id_from_patch,
14 generate_unsigned_pr_or_update_event, get_commit_id_from_patch,
15}; 14};
16use git2::{Oid, Repository}; 15use git2::{Oid, Repository};
17use ngit::{ 16use ngit::{
18 client::{self, get_event_from_cache_by_id, sign_draft_event}, 17 client::{self, get_event_from_cache_by_id},
19 git::{self, nostr_url::NostrUrlDecoded}, 18 git::{self, nostr_url::NostrUrlDecoded},
20 git_events::{self, KIND_PULL_REQUEST, event_to_cover_letter, get_event_root}, 19 git_events::{self, KIND_PULL_REQUEST, event_to_cover_letter, get_event_root},
21 list::list_from_remotes, 20 list::list_from_remotes,
22 login::{self, user::UserRef}, 21 login::{self, user::UserRef},
23 push::{push_to_remote, push_to_remote_url}, 22 push::{push_refs_and_generate_pr_or_pr_update_event, push_to_remote},
24 repo_ref::{self, get_repo_config_from_yaml, is_grasp_server, normalize_grasp_server_url}, 23 repo_ref::{self, get_repo_config_from_yaml, is_grasp_server},
25 repo_state, 24 repo_state,
26 utils::{ 25 utils::{
27 find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url, 26 find_proposal_and_patches_by_branch_name, get_all_proposals, get_remote_name_by_url,
28 get_short_git_server_name, read_line, 27 get_short_git_server_name, read_line,
29 }, 28 },
30}; 29};
31use nostr::{event::UnsignedEvent, nips::nip10::Marker}; 30use nostr::nips::nip10::Marker;
32use nostr_sdk::{ 31use nostr_sdk::{
33 Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard, 32 Event, EventBuilder, EventId, Kind, NostrSigner, PublicKey, RelayUrl, Tag, TagStandard,
34 hashes::sha1::Hash as Sha1Hash, 33 hashes::sha1::Hash as Sha1Hash,
@@ -494,103 +493,6 @@ async fn generate_patches_or_pr_event_or_pr_updates(
494 Ok(events) 493 Ok(events)
495} 494}
496 495
497async fn push_refs_and_generate_pr_or_pr_update_event(
498 git_repo: &Repo,
499 repo_ref: &RepoRef,
500 tip: &Sha1Hash,
501 user_ref: &UserRef,
502 root_proposal: Option<&Event>,
503 signer: &Arc<dyn NostrSigner>,
504 term: &Term,
505) -> Result<Vec<Event>> {
506 let mut events: Vec<Event> = vec![];
507 let repo_grasps = repo_ref.grasp_servers();
508 let repo_grasp_clone_urls = repo_ref
509 .git_server
510 .iter()
511 .filter(|s| is_grasp_server(s, &repo_grasps));
512
513 let mut unsigned_pr_event: Option<UnsignedEvent> = None;
514 let mut failed_clone_urls = vec![];
515 for clone_url in repo_grasp_clone_urls {
516 let mut draft_pr_event = if let Some(ref unsigned_pr_event) = unsigned_pr_event {
517 unsigned_pr_event.clone()
518 } else {
519 generate_unsigned_pr_or_update_event(
520 git_repo,
521 repo_ref,
522 &user_ref.public_key,
523 root_proposal,
524 tip,
525 &[clone_url],
526 &[],
527 )?
528 };
529
530 let refspec = format!("{}:refs/nostr/{}", tip, draft_pr_event.id());
531
532 if let Err(error) = push_to_remote_url(git_repo, clone_url, &[refspec], term) {
533 failed_clone_urls.push(clone_url);
534 term.write_line(
535 format!(
536 "push: error sending commit data to {}: {error}",
537 normalize_grasp_server_url(clone_url)?
538 )
539 .as_str(),
540 )?;
541 } else {
542 term.write_line(
543 format!(
544 "push: commit data sent to {}",
545 normalize_grasp_server_url(clone_url)?
546 )
547 .as_str(),
548 )?;
549 unsigned_pr_event = Some(draft_pr_event);
550 }
551 }
552 if unsigned_pr_event.is_none() {
553 bail!(
554 "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."
555 );
556
557 // TODO get grasp_default_set servers that aren't in repo_grasps
558 // cycle through until one succeeds TODO create
559 // personal-fork announcement with grasp servers and
560 // push, after a few seconds push ref/nostr/eventid. if
561 // one success break out of for loop and continue
562 }
563 if let Some(unsigned_pr_event) = unsigned_pr_event {
564 let pr_event = sign_draft_event(
565 unsigned_pr_event,
566 signer,
567 if root_proposal.is_some_and(|proposal| proposal.kind.eq(&Kind::GitPatch)) {
568 "Pull Request Replacing Original Patch"
569 } else if root_proposal.is_some() {
570 "Pull Request Update"
571 } else {
572 "Pull Request"
573 }
574 .to_string(),
575 )
576 .await?;
577 events.push(pr_event);
578 if root_proposal.is_some_and(|proposal| proposal.kind.eq(&Kind::GitPatch)) {
579 events.push(
580 create_close_status_for_original_patch(signer, repo_ref, root_proposal.unwrap())
581 .await?,
582 );
583 }
584 } else {
585 bail!(
586 "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"
587 );
588 // TODO suggest `ngit send` where user could specify their own clone
589 // url to push to once that feature is added
590 }
591 Ok(events)
592}
593
594type HashMapUrlRefspecs = HashMap<String, Vec<String>>; 496type HashMapUrlRefspecs = HashMap<String, Vec<String>>;
595 497
596#[allow(clippy::too_many_lines)] 498#[allow(clippy::too_many_lines)]
@@ -1283,62 +1185,6 @@ async fn create_merge_status(
1283 .await 1185 .await
1284} 1186}
1285 1187
1286async fn create_close_status_for_original_patch(
1287 signer: &Arc<dyn NostrSigner>,
1288 repo_ref: &RepoRef,
1289 proposal: &Event,
1290) -> Result<Event> {
1291 let mut public_keys = repo_ref
1292 .maintainers
1293 .iter()
1294 .copied()
1295 .collect::<HashSet<PublicKey>>();
1296 public_keys.insert(proposal.pubkey);
1297
1298 sign_event(
1299 EventBuilder::new(nostr::event::Kind::GitStatusClosed, String::new()).tags(
1300 [
1301 vec![
1302 Tag::custom(
1303 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")),
1304 vec![
1305 "Git patch closed as forthcoming update is too large. Replacing with Pull Request"
1306 .to_string(),
1307 ],
1308 ),
1309 Tag::from_standardized(nostr::TagStandard::Event {
1310 event_id: proposal.id,
1311 relay_url: repo_ref.relays.first().cloned(),
1312 marker: Some(Marker::Root),
1313 public_key: None,
1314 uppercase: false,
1315 }),
1316 ],
1317 public_keys.iter().map(|pk| Tag::public_key(*pk)).collect(),
1318 repo_ref
1319 .coordinates()
1320 .iter()
1321 .map(|c| {
1322 Tag::from_standardized(TagStandard::Coordinate {
1323 coordinate: c.coordinate.clone(),
1324 relay_url: c.relays.first().cloned(),
1325 uppercase: false,
1326 })
1327 })
1328 .collect::<Vec<Tag>>(),
1329 vec![
1330 Tag::from_standardized(nostr::TagStandard::Reference(
1331 repo_ref.root_commit.to_string(),
1332 )),
1333 ],
1334 ]
1335 .concat(),
1336 ),
1337 signer,
1338 "close status for original patch".to_string(),
1339 )
1340 .await
1341}
1342async fn get_proposal_and_revision_root_from_patch( 1188async fn get_proposal_and_revision_root_from_patch(
1343 git_repo: &Repo, 1189 git_repo: &Repo,
1344 patch: &Event, 1190 patch: &Event,