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:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/push.rs64
1 files changed, 50 insertions, 14 deletions
diff --git a/src/lib/push.rs b/src/lib/push.rs
index 2aafc1d..a5a29a2 100644
--- a/src/lib/push.rs
+++ b/src/lib/push.rs
@@ -4,7 +4,7 @@ use std::{
4 time::Instant, 4 time::Instant,
5}; 5};
6 6
7use anyhow::{Result, anyhow}; 7use anyhow::{Context, Result, anyhow};
8use auth_git2::GitAuthenticator; 8use auth_git2::GitAuthenticator;
9use console::Term; 9use console::Term;
10use nostr::{ 10use nostr::{
@@ -19,19 +19,20 @@ use crate::{
19 cli_interactor::count_lines_per_msg_vec, 19 cli_interactor::count_lines_per_msg_vec,
20 client::{sign_draft_event, sign_event}, 20 client::{sign_draft_event, sign_event},
21 git::{ 21 git::{
22 Repo, 22 Repo, RepoActions,
23 nostr_url::{CloneUrl, NostrUrlDecoded}, 23 nostr_url::{CloneUrl, NostrUrlDecoded},
24 oid_to_shorthand_string, 24 oid_to_shorthand_string,
25 }, 25 },
26 git_events::generate_unsigned_pr_or_update_event, 26 git_events::generate_unsigned_pr_or_update_event,
27 login::user::UserRef, 27 login::user::UserRef,
28 repo_ref::{RepoRef, normalize_grasp_server_url}, 28 repo_ref::{RepoRef, is_grasp_server_clone_url, normalize_grasp_server_url},
29 utils::{ 29 utils::{
30 Direction, get_short_git_server_name, get_write_protocols_to_try, join_with_and, 30 Direction, get_short_git_server_name, get_write_protocols_to_try, join_with_and,
31 set_protocol_preference, 31 set_protocol_preference,
32 }, 32 },
33}; 33};
34 34
35// returns failed refs as a HashMaps of failed refspec and their error
35pub fn push_to_remote( 36pub fn push_to_remote(
36 git_repo: &Repo, 37 git_repo: &Repo,
37 git_server_url: &str, 38 git_server_url: &str,
@@ -39,13 +40,14 @@ pub fn push_to_remote(
39 remote_refspecs: &[String], 40 remote_refspecs: &[String],
40 term: &Term, 41 term: &Term,
41 is_grasp_server: bool, 42 is_grasp_server: bool,
42) -> Result<()> { 43) -> Result<HashMap<String, String>> {
43 let server_url = git_server_url.parse::<CloneUrl>()?; 44 let server_url = git_server_url.parse::<CloneUrl>()?;
44 let protocols_to_attempt = 45 let protocols_to_attempt =
45 get_write_protocols_to_try(git_repo, &server_url, decoded_nostr_url, is_grasp_server); 46 get_write_protocols_to_try(git_repo, &server_url, decoded_nostr_url, is_grasp_server);
46 47
47 let mut failed_protocols = vec![]; 48 let mut failed_protocols = vec![];
48 let mut success = false; 49 let mut success = false;
50 let mut failed_refs = HashMap::new();
49 51
50 for protocol in &protocols_to_attempt { 52 for protocol in &protocols_to_attempt {
51 term.write_line(format!("push: {} over {protocol}...", server_url.short_name(),).as_str())?; 53 term.write_line(format!("push: {} over {protocol}...", server_url.short_name(),).as_str())?;
@@ -59,14 +61,9 @@ pub fn push_to_remote(
59 )?; 61 )?;
60 failed_protocols.push(protocol); 62 failed_protocols.push(protocol);
61 } 63 }
62 Ok(failed_refs) => { 64 Ok(failed_refs_on_protocol) => {
63 if let Some((_, error)) = failed_refs.iter().next() { 65 success = true;
64 term.write_line( 66 if failed_refs_on_protocol.is_empty() {
65 format!("push: {formatted_url} failed over {protocol}: {error}").as_str(),
66 )?;
67 failed_protocols.push(protocol);
68 } else {
69 success = true;
70 if !failed_protocols.is_empty() { 67 if !failed_protocols.is_empty() {
71 term.write_line(format!("push: succeeded over {protocol}").as_str())?; 68 term.write_line(format!("push: succeeded over {protocol}").as_str())?;
72 let _ = set_protocol_preference( 69 let _ = set_protocol_preference(
@@ -77,12 +74,25 @@ pub fn push_to_remote(
77 ); 74 );
78 } 75 }
79 break; 76 break;
77 } else {
78 term.write_line(
79 format!(
80 "push: {formatted_url} with {protocol} complete but {}ref{} not accepted:",
81 if remote_refspecs.len() != failed_protocols.len() { "some " } else {""},
82 if remote_refspecs.len() == 1 { "s"} else {""},
83 ).as_str(),
84 )?;
85 for (git_ref, error) in &failed_refs_on_protocol {
86 term.write_line(format!("push: - {git_ref}: {error}").as_str())?;
87 }
88 failed_refs = failed_refs_on_protocol;
80 } 89 }
90 break;
81 } 91 }
82 } 92 }
83 } 93 }
84 if success { 94 if success {
85 Ok(()) 95 Ok(failed_refs)
86 } else { 96 } else {
87 let error = anyhow!( 97 let error = anyhow!(
88 "{} failed over {}{}", 98 "{} failed over {}{}",
@@ -382,7 +392,33 @@ pub async fn push_refs_and_generate_pr_or_pr_update_event(
382 392
383 let refspec = format!("{tip}:{git_ref_used}"); 393 let refspec = format!("{tip}:{git_ref_used}");
384 394
385 match push_to_remote_url(git_repo, clone_url, &[refspec], term) { 395 let res = if is_grasp_server_clone_url(clone_url) {
396 push_to_remote_url(git_repo, clone_url, &[refspec], term)
397 } else {
398 // anticipated only when pushing to user's own repo or a personal-fork with
399 // non-grasp git servers. this is used to extract prefered protocols / ssh
400 // details from nostr url
401 let decoded_nostr_url = {
402 if let Ok(Some((_, decoded_nostr_url))) = git_repo
403 .get_first_nostr_remote_when_in_ngit_binary()
404 .await.context("failed to list git remotes")
405 .context("no `nostr://` remote detected. `ngit sync` must be run from a repo with a nostr remote") {
406 decoded_nostr_url
407 } else {
408 repo_ref.to_nostr_git_url(&Some(git_repo))
409 }
410 };
411 push_to_remote(
412 git_repo,
413 clone_url,
414 &decoded_nostr_url,
415 &[refspec],
416 term,
417 false,
418 )
419 };
420
421 match res {
386 Err(error) => { 422 Err(error) => {
387 let normalized_url = normalize_grasp_server_url(clone_url)?; 423 let normalized_url = normalize_grasp_server_url(clone_url)?;
388 term.write_line(&format!( 424 term.write_line(&format!(