upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib/push.rs61
1 files changed, 40 insertions, 21 deletions
diff --git a/src/lib/push.rs b/src/lib/push.rs
index a5a29a2..0ee66cf 100644
--- a/src/lib/push.rs
+++ b/src/lib/push.rs
@@ -32,7 +32,7 @@ use crate::{
32 }, 32 },
33}; 33};
34 34
35// returns failed refs as a HashMaps of failed refspec and their error 35// returns a HashMap of refs responded to and any related cancellation reasons
36pub fn push_to_remote( 36pub fn push_to_remote(
37 git_repo: &Repo, 37 git_repo: &Repo,
38 git_server_url: &str, 38 git_server_url: &str,
@@ -40,14 +40,14 @@ pub fn push_to_remote(
40 remote_refspecs: &[String], 40 remote_refspecs: &[String],
41 term: &Term, 41 term: &Term,
42 is_grasp_server: bool, 42 is_grasp_server: bool,
43) -> Result<HashMap<String, String>> { 43) -> Result<HashMap<String, Option<String>>> {
44 let server_url = git_server_url.parse::<CloneUrl>()?; 44 let server_url = git_server_url.parse::<CloneUrl>()?;
45 let protocols_to_attempt = 45 let protocols_to_attempt =
46 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);
47 47
48 let mut failed_protocols = vec![]; 48 let mut failed_protocols = vec![];
49 let mut success = false; 49 let mut success = false;
50 let mut failed_refs = HashMap::new(); 50 let mut ref_updates = HashMap::new();
51 51
52 for protocol in &protocols_to_attempt { 52 for protocol in &protocols_to_attempt {
53 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())?;
@@ -61,9 +61,13 @@ pub fn push_to_remote(
61 )?; 61 )?;
62 failed_protocols.push(protocol); 62 failed_protocols.push(protocol);
63 } 63 }
64 Ok(failed_refs_on_protocol) => { 64 Ok(ref_updates_on_protocol) => {
65 success = true; 65 success = true;
66 if failed_refs_on_protocol.is_empty() { 66 if remote_refspecs.len() == ref_updates_on_protocol.len()
67 && ref_updates_on_protocol
68 .values()
69 .all(|error| error.is_none())
70 {
67 if !failed_protocols.is_empty() { 71 if !failed_protocols.is_empty() {
68 term.write_line(format!("push: succeeded over {protocol}").as_str())?; 72 term.write_line(format!("push: succeeded over {protocol}").as_str())?;
69 let _ = set_protocol_preference( 73 let _ = set_protocol_preference(
@@ -80,19 +84,22 @@ pub fn push_to_remote(
80 "push: {formatted_url} with {protocol} complete but {}ref{} not accepted:", 84 "push: {formatted_url} with {protocol} complete but {}ref{} not accepted:",
81 if remote_refspecs.len() != failed_protocols.len() { "some " } else {""}, 85 if remote_refspecs.len() != failed_protocols.len() { "some " } else {""},
82 if remote_refspecs.len() == 1 { "s"} else {""}, 86 if remote_refspecs.len() == 1 { "s"} else {""},
83 ).as_str(), 87 ).as_str(),
84 )?; 88 )?;
85 for (git_ref, error) in &failed_refs_on_protocol { 89 for (git_ref, error) in &ref_updates_on_protocol {
86 term.write_line(format!("push: - {git_ref}: {error}").as_str())?; 90 if let Some(error) = error {
91 term.write_line(format!("push: - {git_ref}: {error}").as_str())?;
92 }
87 } 93 }
88 failed_refs = failed_refs_on_protocol; 94 // TODO do we want to report on the refs that weren't responded to?
95 ref_updates = ref_updates_on_protocol;
89 } 96 }
90 break; 97 break;
91 } 98 }
92 } 99 }
93 } 100 }
94 if success { 101 if success {
95 Ok(failed_refs) 102 Ok(ref_updates)
96 } else { 103 } else {
97 let error = anyhow!( 104 let error = anyhow!(
98 "{} failed over {}{}", 105 "{} failed over {}{}",
@@ -109,13 +116,13 @@ pub fn push_to_remote(
109 } 116 }
110} 117}
111 118
112// returns failed refs as a HashMaps of failed refspec and their error 119// returns HashMaps of refspecs responded to and any failure message
113pub fn push_to_remote_url( 120pub fn push_to_remote_url(
114 git_repo: &Repo, 121 git_repo: &Repo,
115 git_server_url: &str, 122 git_server_url: &str,
116 remote_refspecs: &[String], 123 remote_refspecs: &[String],
117 term: &Term, 124 term: &Term,
118) -> Result<HashMap<String, String>> { 125) -> Result<HashMap<String, Option<String>>> {
119 let git_config = git_repo.git_repo.config()?; 126 let git_config = git_repo.git_repo.config()?;
120 let mut git_server_remote = git_repo.git_repo.remote_anonymous(git_server_url)?; 127 let mut git_server_remote = git_repo.git_repo.remote_anonymous(git_server_url)?;
121 let auth = GitAuthenticator::default(); 128 let auth = GitAuthenticator::default();
@@ -129,11 +136,11 @@ pub fn push_to_remote_url(
129 let push_reporter = Arc::clone(&push_reporter); 136 let push_reporter = Arc::clone(&push_reporter);
130 move |name, error| { 137 move |name, error| {
131 let mut reporter = push_reporter.lock().unwrap(); 138 let mut reporter = push_reporter.lock().unwrap();
139 reporter
140 .ref_updates
141 .insert(name.to_string(), error.map(|s| s.to_string()));
132 if let Some(error) = error { 142 if let Some(error) = error {
133 let existing_lines = reporter.count_all_existing_lines(); 143 let existing_lines = reporter.count_all_existing_lines();
134 reporter
135 .failed_refs
136 .insert(name.to_string(), error.to_string());
137 reporter.update_reference_errors.push(format!( 144 reporter.update_reference_errors.push(format!(
138 "WARNING: {} failed to push {name} error: {error}", 145 "WARNING: {} failed to push {name} error: {error}",
139 get_short_git_server_name(git_repo, git_server_url), 146 get_short_git_server_name(git_repo, git_server_url),
@@ -156,7 +163,11 @@ pub fn push_to_remote_url(
156 .unwrap_or("") 163 .unwrap_or("")
157 .replace("refs/heads/", "") 164 .replace("refs/heads/", "")
158 .replace("refs/tags/", "tags/"); 165 .replace("refs/tags/", "tags/");
159 let msg = if update.dst().is_zero() { 166 let msg = if let Some(Some(_)) =
167 reporter.ref_updates.get(update.dst_refname().unwrap_or(""))
168 {
169 format!("push: - [failed] {dst_refname}")
170 } else if update.dst().is_zero() {
160 format!("push: - [delete] {dst_refname}") 171 format!("push: - [delete] {dst_refname}")
161 } else if update.src().is_zero() { 172 } else if update.src().is_zero() {
162 if update.dst_refname().unwrap_or("").contains("refs/tags") { 173 if update.dst_refname().unwrap_or("").contains("refs/tags") {
@@ -216,7 +227,7 @@ pub fn push_to_remote_url(
216 git_server_remote.push(remote_refspecs, Some(&mut push_options))?; 227 git_server_remote.push(remote_refspecs, Some(&mut push_options))?;
217 let _ = git_server_remote.disconnect(); 228 let _ = git_server_remote.disconnect();
218 let reporter = push_reporter.lock().unwrap(); 229 let reporter = push_reporter.lock().unwrap();
219 Ok(reporter.failed_refs.clone()) 230 Ok(reporter.ref_updates.clone())
220} 231}
221 232
222#[allow(clippy::cast_precision_loss)] 233#[allow(clippy::cast_precision_loss)]
@@ -265,7 +276,7 @@ pub struct PushReporter<'a> {
265 negotiation: Vec<String>, 276 negotiation: Vec<String>,
266 transfer_progress_msgs: Vec<String>, 277 transfer_progress_msgs: Vec<String>,
267 update_reference_errors: Vec<String>, 278 update_reference_errors: Vec<String>,
268 failed_refs: HashMap<String, String>, 279 ref_updates: HashMap<String, Option<String>>,
269 term: &'a console::Term, 280 term: &'a console::Term,
270 start_time: Option<Instant>, 281 start_time: Option<Instant>,
271 end_time: Option<Instant>, 282 end_time: Option<Instant>,
@@ -277,7 +288,7 @@ impl<'a> PushReporter<'a> {
277 negotiation: vec![], 288 negotiation: vec![],
278 transfer_progress_msgs: vec![], 289 transfer_progress_msgs: vec![],
279 update_reference_errors: vec![], 290 update_reference_errors: vec![],
280 failed_refs: HashMap::new(), 291 ref_updates: HashMap::new(),
281 term, 292 term,
282 start_time: None, 293 start_time: None,
283 end_time: None, 294 end_time: None,
@@ -426,13 +437,21 @@ pub async fn push_refs_and_generate_pr_or_pr_update_event(
426 ))?; 437 ))?;
427 responses.push((clone_url.clone(), Err(anyhow!(error)))); 438 responses.push((clone_url.clone(), Err(anyhow!(error))));
428 } 439 }
429 Ok(failed_refs) => { 440 Ok(ref_updates) => {
430 let normalized_url = normalize_grasp_server_url(clone_url)?; 441 let normalized_url = normalize_grasp_server_url(clone_url)?;
431 if let Some((_, error)) = failed_refs.iter().next() { 442 if let Some((_, Some(error))) = ref_updates.iter().next() {
432 term.write_line(&format!( 443 term.write_line(&format!(
433 "push: error sending commit data to {normalized_url}: {error}" 444 "push: error sending commit data to {normalized_url}: {error}"
434 ))?; 445 ))?;
435 responses.push((clone_url.clone(), Err(anyhow!(error.clone())))); 446 responses.push((clone_url.clone(), Err(anyhow!(error.clone()))));
447 } else if ref_updates.is_empty() {
448 term.write_line(&format!(
449 "push: error sending commit data to {normalized_url}: server didn't confirm acceptance"
450 ))?;
451 responses.push((
452 clone_url.clone(),
453 Err(anyhow!("server didn't confirm acceptance")),
454 ));
436 } else { 455 } else {
437 responses.push((clone_url.clone(), Ok(()))); 456 responses.push((clone_url.clone(), Ok(())));
438 term.write_line(&format!("push: commit data sent to {normalized_url}"))?; 457 term.write_line(&format!("push: commit data sent to {normalized_url}"))?;