diff options
Diffstat (limited to 'src/bin/ngit/sub_commands')
| -rw-r--r-- | src/bin/ngit/sub_commands/send.rs | 137 |
1 files changed, 90 insertions, 47 deletions
diff --git a/src/bin/ngit/sub_commands/send.rs b/src/bin/ngit/sub_commands/send.rs index 9f1857f..0aefb03 100644 --- a/src/bin/ngit/sub_commands/send.rs +++ b/src/bin/ngit/sub_commands/send.rs | |||
| @@ -4,9 +4,11 @@ use anyhow::{Context, Result, bail}; | |||
| 4 | use console::Style; | 4 | use console::Style; |
| 5 | use ngit::{ | 5 | use ngit::{ |
| 6 | client::{Params, send_events}, | 6 | client::{Params, send_events}, |
| 7 | git_events::{EventRefType, generate_cover_letter_and_patch_events}, | 7 | git_events::{EventRefType, KIND_PULL_REQUEST, generate_cover_letter_and_patch_events}, |
| 8 | push::push_refs_and_generate_pr_or_pr_update_event, | ||
| 9 | utils::proposal_tip_is_pr_or_pr_update, | ||
| 8 | }; | 10 | }; |
| 9 | use nostr::{ToBech32, nips::nip19::Nip19Event}; | 11 | use nostr::{ToBech32, event::Event, nips::nip19::Nip19Event}; |
| 10 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; | 12 | use nostr_sdk::hashes::sha1::Hash as Sha1Hash; |
| 11 | 13 | ||
| 12 | use crate::{ | 14 | use crate::{ |
| @@ -60,12 +62,14 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re | |||
| 60 | fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; | 62 | fetching_with_report(git_repo_path, &client, &repo_coordinates).await?; |
| 61 | } | 63 | } |
| 62 | 64 | ||
| 63 | let (root_proposal_id, mention_tags) = | 65 | let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; |
| 64 | get_root_proposal_id_and_mentions_from_in_reply_to(git_repo.get_path()?, &args.in_reply_to) | 66 | |
| 67 | let (root_proposal, mention_tags) = | ||
| 68 | get_root_proposal_and_mentions_from_in_reply_to(git_repo.get_path()?, &args.in_reply_to) | ||
| 65 | .await?; | 69 | .await?; |
| 66 | 70 | ||
| 67 | if let Some(root_ref) = args.in_reply_to.first() { | 71 | if let Some(root_ref) = args.in_reply_to.first() { |
| 68 | if root_proposal_id.is_some() { | 72 | if root_proposal.is_some() { |
| 69 | println!("creating proposal revision for: {root_ref}"); | 73 | println!("creating proposal revision for: {root_ref}"); |
| 70 | } | 74 | } |
| 71 | } | 75 | } |
| @@ -112,7 +116,30 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re | |||
| 112 | &main_tip, | 116 | &main_tip, |
| 113 | )?; | 117 | )?; |
| 114 | 118 | ||
| 115 | let title = if args.no_cover_letter { | 119 | let as_pr = { |
| 120 | if let Some(root_proposal) = &root_proposal { | ||
| 121 | proposal_tip_is_pr_or_pr_update(git_repo_path, &repo_ref, &root_proposal.id).await? | ||
| 122 | } else { | ||
| 123 | false | ||
| 124 | } | ||
| 125 | } || git_repo.are_commits_too_big_for_patches(&commits); | ||
| 126 | |||
| 127 | let title = if as_pr { | ||
| 128 | match &args.title { | ||
| 129 | Some(t) => Some(t.clone()), | ||
| 130 | None => { | ||
| 131 | if root_proposal.is_none() { | ||
| 132 | Some( | ||
| 133 | Interactor::default() | ||
| 134 | .input(PromptInputParms::default().with_prompt("title"))? | ||
| 135 | .clone(), | ||
| 136 | ) | ||
| 137 | } else { | ||
| 138 | None | ||
| 139 | } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } else if args.no_cover_letter { | ||
| 116 | None | 143 | None |
| 117 | } else { | 144 | } else { |
| 118 | match &args.title { | 145 | match &args.title { |
| @@ -142,7 +169,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re | |||
| 142 | t.clone() | 169 | t.clone() |
| 143 | } else { | 170 | } else { |
| 144 | Interactor::default() | 171 | Interactor::default() |
| 145 | .input(PromptInputParms::default().with_prompt("cover letter description"))? | 172 | .input(PromptInputParms::default().with_prompt("description"))? |
| 146 | .clone() | 173 | .clone() |
| 147 | }, | 174 | }, |
| 148 | )) | 175 | )) |
| @@ -161,42 +188,58 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re | |||
| 161 | 188 | ||
| 162 | client.set_signer(signer.clone()).await; | 189 | client.set_signer(signer.clone()).await; |
| 163 | 190 | ||
| 164 | let repo_ref = get_repo_ref_from_cache(Some(git_repo_path), &repo_coordinates).await?; | ||
| 165 | |||
| 166 | // oldest first | 191 | // oldest first |
| 167 | commits.reverse(); | 192 | commits.reverse(); |
| 168 | 193 | ||
| 169 | let events = generate_cover_letter_and_patch_events( | 194 | let events = if as_pr { |
| 170 | cover_letter_title_description.clone(), | 195 | push_refs_and_generate_pr_or_pr_update_event( |
| 171 | &git_repo, | 196 | &git_repo, |
| 172 | &commits, | 197 | &repo_ref, |
| 173 | &signer, | 198 | commits.last().context("no commits")?, |
| 174 | &repo_ref, | 199 | &user_ref, |
| 175 | &root_proposal_id, | 200 | root_proposal.as_ref(), |
| 176 | &mention_tags, | 201 | &cover_letter_title_description, |
| 177 | ) | 202 | &signer, |
| 178 | .await?; | 203 | &console::Term::stdout(), |
| 204 | ) | ||
| 205 | .await? | ||
| 179 | 206 | ||
| 180 | println!( | 207 | // TODO |
| 181 | "posting {} patch{} {} a covering letter...", | 208 | // - allow specifying clone url and ref |
| 182 | if cover_letter_title_description.is_none() { | 209 | } else { |
| 183 | events.len() | 210 | let events = generate_cover_letter_and_patch_events( |
| 184 | } else { | 211 | cover_letter_title_description.clone(), |
| 185 | events.len() - 1 | 212 | &git_repo, |
| 186 | }, | 213 | &commits, |
| 187 | if cover_letter_title_description.is_none() && events.len().eq(&1) | 214 | &signer, |
| 188 | || cover_letter_title_description.is_some() && events.len().eq(&2) | 215 | &repo_ref, |
| 189 | { | 216 | &root_proposal.as_ref().map(|e| e.id.to_string()), |
| 190 | "" | 217 | &mention_tags, |
| 191 | } else { | 218 | ) |
| 192 | "es" | 219 | .await?; |
| 193 | }, | 220 | |
| 194 | if cover_letter_title_description.is_none() { | 221 | println!( |
| 195 | "without" | 222 | "posting {} patch{} {} a covering letter...", |
| 196 | } else { | 223 | if cover_letter_title_description.is_none() { |
| 197 | "with" | 224 | events.len() |
| 198 | } | 225 | } else { |
| 199 | ); | 226 | events.len() - 1 |
| 227 | }, | ||
| 228 | if cover_letter_title_description.is_none() && events.len().eq(&1) | ||
| 229 | || cover_letter_title_description.is_some() && events.len().eq(&2) | ||
| 230 | { | ||
| 231 | "" | ||
| 232 | } else { | ||
| 233 | "es" | ||
| 234 | }, | ||
| 235 | if cover_letter_title_description.is_none() { | ||
| 236 | "without" | ||
| 237 | } else { | ||
| 238 | "with" | ||
| 239 | } | ||
| 240 | ); | ||
| 241 | events | ||
| 242 | }; | ||
| 200 | 243 | ||
| 201 | send_events( | 244 | send_events( |
| 202 | &client, | 245 | &client, |
| @@ -209,7 +252,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs, no_fetch: bool) -> Re | |||
| 209 | ) | 252 | ) |
| 210 | .await?; | 253 | .await?; |
| 211 | 254 | ||
| 212 | if root_proposal_id.is_none() { | 255 | if root_proposal.is_none() { |
| 213 | if let Some(event) = events.first() { | 256 | if let Some(event) = events.first() { |
| 214 | let event_bech32 = if let Some(relay) = repo_ref.relays.first() { | 257 | let event_bech32 = if let Some(relay) = repo_ref.relays.first() { |
| 215 | Nip19Event { | 258 | Nip19Event { |
| @@ -376,11 +419,11 @@ fn summarise_commit_for_selection(git_repo: &Repo, commit: &Sha1Hash) -> Result< | |||
| 376 | )) | 419 | )) |
| 377 | } | 420 | } |
| 378 | 421 | ||
| 379 | async fn get_root_proposal_id_and_mentions_from_in_reply_to( | 422 | async fn get_root_proposal_and_mentions_from_in_reply_to( |
| 380 | git_repo_path: &Path, | 423 | git_repo_path: &Path, |
| 381 | in_reply_to: &[String], | 424 | in_reply_to: &[String], |
| 382 | ) -> Result<(Option<String>, Vec<nostr::Tag>)> { | 425 | ) -> Result<(Option<Event>, Vec<nostr::Tag>)> { |
| 383 | let root_proposal_id = if let Some(first) = in_reply_to.first() { | 426 | let root_proposal = if let Some(first) = in_reply_to.first() { |
| 384 | match event_tag_from_nip19_or_hex(first, "in-reply-to", EventRefType::Root, true, false)? | 427 | match event_tag_from_nip19_or_hex(first, "in-reply-to", EventRefType::Root, true, false)? |
| 385 | .as_standardized() | 428 | .as_standardized() |
| 386 | { | 429 | { |
| @@ -398,8 +441,8 @@ async fn get_root_proposal_id_and_mentions_from_in_reply_to( | |||
| 398 | .await?; | 441 | .await?; |
| 399 | 442 | ||
| 400 | if let Some(first) = events.iter().find(|e| e.id.eq(event_id)) { | 443 | if let Some(first) = events.iter().find(|e| e.id.eq(event_id)) { |
| 401 | if event_is_patch_set_root(first) { | 444 | if event_is_patch_set_root(first) || first.kind.eq(&KIND_PULL_REQUEST) { |
| 402 | Some(event_id.to_string()) | 445 | Some(first.clone()) |
| 403 | } else { | 446 | } else { |
| 404 | None | 447 | None |
| 405 | } | 448 | } |
| @@ -415,7 +458,7 @@ async fn get_root_proposal_id_and_mentions_from_in_reply_to( | |||
| 415 | 458 | ||
| 416 | let mut mention_tags = vec![]; | 459 | let mut mention_tags = vec![]; |
| 417 | for (i, reply_to) in in_reply_to.iter().enumerate() { | 460 | for (i, reply_to) in in_reply_to.iter().enumerate() { |
| 418 | if i.ne(&0) || root_proposal_id.is_none() { | 461 | if i.ne(&0) || root_proposal.is_none() { |
| 419 | mention_tags.push( | 462 | mention_tags.push( |
| 420 | event_tag_from_nip19_or_hex( | 463 | event_tag_from_nip19_or_hex( |
| 421 | reply_to, | 464 | reply_to, |
| @@ -431,7 +474,7 @@ async fn get_root_proposal_id_and_mentions_from_in_reply_to( | |||
| 431 | } | 474 | } |
| 432 | } | 475 | } |
| 433 | 476 | ||
| 434 | Ok((root_proposal_id, mention_tags)) | 477 | Ok((root_proposal, mention_tags)) |
| 435 | } | 478 | } |
| 436 | 479 | ||
| 437 | // TODO | 480 | // TODO |