diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-07-22 17:14:21 +0100 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-07-22 17:14:21 +0100 |
| commit | f4e1df4c718a3755ffe50e99946996729f3504e9 (patch) | |
| tree | 9d3d83f42d4d9cf7f18c5451d524a7b995d8053b /src/lib | |
| parent | d1283a6b55826175423bd382a859928e0f92ffe7 (diff) | |
feat(pr): generate pr event > oversized patch
but only for new proposals
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/client.rs | 26 | ||||
| -rw-r--r-- | src/lib/git_events.rs | 130 |
2 files changed, 136 insertions, 20 deletions
diff --git a/src/lib/client.rs b/src/lib/client.rs index 091d68d..3fe2b57 100644 --- a/src/lib/client.rs +++ b/src/lib/client.rs | |||
| @@ -31,7 +31,7 @@ use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressState, P | |||
| 31 | use mockall::*; | 31 | use mockall::*; |
| 32 | use nostr::{ | 32 | use nostr::{ |
| 33 | Event, | 33 | Event, |
| 34 | event::{TagKind, TagStandard}, | 34 | event::{TagKind, TagStandard, UnsignedEvent}, |
| 35 | filter::Alphabet, | 35 | filter::Alphabet, |
| 36 | nips::{nip01::Coordinate, nip19::Nip19Coordinate}, | 36 | nips::{nip01::Coordinate, nip19::Nip19Coordinate}, |
| 37 | signer::SignerBackend, | 37 | signer::SignerBackend, |
| @@ -814,6 +814,30 @@ pub async fn sign_event( | |||
| 814 | } | 814 | } |
| 815 | } | 815 | } |
| 816 | 816 | ||
| 817 | pub async fn sign_draft_event( | ||
| 818 | draft_event: UnsignedEvent, | ||
| 819 | signer: &Arc<dyn NostrSigner>, | ||
| 820 | description: String, | ||
| 821 | ) -> Result<nostr::Event> { | ||
| 822 | if signer.backend() == SignerBackend::NostrConnect { | ||
| 823 | let term = console::Term::stderr(); | ||
| 824 | term.write_line(&format!( | ||
| 825 | "signing event ({description}) with remote signer..." | ||
| 826 | ))?; | ||
| 827 | let event = signer | ||
| 828 | .sign_event(draft_event) | ||
| 829 | .await | ||
| 830 | .context("failed to sign event")?; | ||
| 831 | term.clear_last_lines(1)?; | ||
| 832 | Ok(event) | ||
| 833 | } else { | ||
| 834 | signer | ||
| 835 | .sign_event(draft_event) | ||
| 836 | .await | ||
| 837 | .context("failed to sign event") | ||
| 838 | } | ||
| 839 | } | ||
| 840 | |||
| 817 | pub async fn fetch_public_key(signer: &Arc<dyn NostrSigner>) -> Result<nostr::PublicKey> { | 841 | pub async fn fetch_public_key(signer: &Arc<dyn NostrSigner>) -> Result<nostr::PublicKey> { |
| 818 | if signer.backend() == SignerBackend::NostrConnect { | 842 | if signer.backend() == SignerBackend::NostrConnect { |
| 819 | let term = console::Term::stderr(); | 843 | let term = console::Term::stderr(); |
diff --git a/src/lib/git_events.rs b/src/lib/git_events.rs index 09ec040..86b9641 100644 --- a/src/lib/git_events.rs +++ b/src/lib/git_events.rs | |||
| @@ -1,7 +1,10 @@ | |||
| 1 | use std::{str::FromStr, sync::Arc}; | 1 | use std::{str::FromStr, sync::Arc}; |
| 2 | 2 | ||
| 3 | use anyhow::{Context, Result, bail}; | 3 | use anyhow::{Context, Result, bail}; |
| 4 | use nostr::nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}; | 4 | use nostr::{ |
| 5 | event::UnsignedEvent, | ||
| 6 | nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}, | ||
| 7 | }; | ||
| 5 | use nostr_sdk::{ | 8 | use nostr_sdk::{ |
| 6 | Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, Tag, TagKind, | 9 | Event, EventBuilder, EventId, FromBech32, Kind, NostrSigner, PublicKey, Tag, TagKind, |
| 7 | TagStandard, hashes::sha1::Hash as Sha1Hash, | 10 | TagStandard, hashes::sha1::Hash as Sha1Hash, |
| @@ -347,6 +350,111 @@ pub fn event_tag_from_nip19_or_hex( | |||
| 347 | } | 350 | } |
| 348 | } | 351 | } |
| 349 | 352 | ||
| 353 | pub fn generate_unsigned_pr_event( | ||
| 354 | git_repo: &Repo, | ||
| 355 | repo_ref: &RepoRef, | ||
| 356 | signing_public_key: &PublicKey, | ||
| 357 | commit: &Sha1Hash, | ||
| 358 | clone_url_hint: &[&str], | ||
| 359 | mentions: &[nostr::Tag], | ||
| 360 | ) -> Result<UnsignedEvent> { | ||
| 361 | let title = git_repo.get_commit_message_summary(commit)?; | ||
| 362 | |||
| 363 | let description = { | ||
| 364 | let mut description = git_repo.get_commit_message(commit)?.trim().to_string(); | ||
| 365 | if let Some(remaining_description) = description.strip_prefix(&title) { | ||
| 366 | description = remaining_description.trim().to_string(); | ||
| 367 | } | ||
| 368 | description | ||
| 369 | }; | ||
| 370 | |||
| 371 | let root_commit = git_repo | ||
| 372 | .get_root_commit() | ||
| 373 | .context("failed to get root commit of the repository")?; | ||
| 374 | |||
| 375 | Ok(EventBuilder::new(KIND_PULL_REQUEST, description) | ||
| 376 | .tags( | ||
| 377 | [ | ||
| 378 | repo_ref | ||
| 379 | .maintainers | ||
| 380 | .iter() | ||
| 381 | .map(|m| { | ||
| 382 | Tag::from_standardized(TagStandard::Coordinate { | ||
| 383 | coordinate: Coordinate { | ||
| 384 | kind: nostr::Kind::GitRepoAnnouncement, | ||
| 385 | public_key: *m, | ||
| 386 | identifier: repo_ref.identifier.to_string(), | ||
| 387 | }, | ||
| 388 | relay_url: repo_ref.relays.first().cloned(), | ||
| 389 | uppercase: false, | ||
| 390 | }) | ||
| 391 | }) | ||
| 392 | .collect::<Vec<Tag>>(), | ||
| 393 | mentions.to_vec(), | ||
| 394 | vec![ | ||
| 395 | Tag::from_standardized(TagStandard::Subject(title.clone())), | ||
| 396 | Tag::from_standardized(TagStandard::Reference(format!("{root_commit}"))), | ||
| 397 | Tag::custom( | ||
| 398 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("c")), | ||
| 399 | vec![format!("{commit}")], | ||
| 400 | ), | ||
| 401 | Tag::custom( | ||
| 402 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("clone")), | ||
| 403 | clone_url_hint | ||
| 404 | .iter() | ||
| 405 | .map(|s| s.to_string()) | ||
| 406 | .collect::<Vec<String>>(), | ||
| 407 | ), | ||
| 408 | Tag::custom( | ||
| 409 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")), | ||
| 410 | vec![format!("git Pull Request: {}", title.clone())], | ||
| 411 | ), | ||
| 412 | ], | ||
| 413 | if let Some(branch_name_tag) = make_branch_name_tag_from_check_out_branch(git_repo) | ||
| 414 | { | ||
| 415 | vec![branch_name_tag] | ||
| 416 | } else { | ||
| 417 | vec![] | ||
| 418 | }, | ||
| 419 | repo_ref | ||
| 420 | .maintainers | ||
| 421 | .iter() | ||
| 422 | .map(|pk| Tag::public_key(*pk)) | ||
| 423 | .collect(), | ||
| 424 | ] | ||
| 425 | .concat(), | ||
| 426 | ) | ||
| 427 | .build(*signing_public_key)) | ||
| 428 | } | ||
| 429 | |||
| 430 | fn make_branch_name_tag_from_check_out_branch(git_repo: &Repo) -> Option<Tag> { | ||
| 431 | if let Ok(branch_name) = git_repo.get_checked_out_branch_name() { | ||
| 432 | if !branch_name.eq("main") | ||
| 433 | && !branch_name.eq("master") | ||
| 434 | && !branch_name.eq("origin/main") | ||
| 435 | && !branch_name.eq("origin/master") | ||
| 436 | { | ||
| 437 | Some(Tag::custom( | ||
| 438 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("branch-name")), | ||
| 439 | vec![ | ||
| 440 | if let Some(branch_name) = branch_name.strip_prefix("pr/") { | ||
| 441 | branch_name.to_string() | ||
| 442 | } else { | ||
| 443 | branch_name | ||
| 444 | } | ||
| 445 | .chars() | ||
| 446 | .take(60) | ||
| 447 | .collect::<String>(), | ||
| 448 | ], | ||
| 449 | )) | ||
| 450 | } else { | ||
| 451 | None | ||
| 452 | } | ||
| 453 | } else { | ||
| 454 | None | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 350 | #[allow(clippy::too_many_lines)] | 458 | #[allow(clippy::too_many_lines)] |
| 351 | pub async fn generate_cover_letter_and_patch_events( | 459 | pub async fn generate_cover_letter_and_patch_events( |
| 352 | cover_letter_title_description: Option<(String, String)>, | 460 | cover_letter_title_description: Option<(String, String)>, |
| @@ -409,24 +517,8 @@ pub async fn generate_cover_letter_and_patch_events( | |||
| 409 | // eventually a prefix will be needed of the event id to stop 2 proposals with the same name colliding | 517 | // eventually a prefix will be needed of the event id to stop 2 proposals with the same name colliding |
| 410 | // a change like this, or the removal of this tag will require the actual branch name to be tracked | 518 | // a change like this, or the removal of this tag will require the actual branch name to be tracked |
| 411 | // so pulling and pushing still work | 519 | // so pulling and pushing still work |
| 412 | if let Ok(branch_name) = git_repo.get_checked_out_branch_name() { | 520 | if let Some(branch_name_tag) = make_branch_name_tag_from_check_out_branch(git_repo) { |
| 413 | if !branch_name.eq("main") | 521 | vec![branch_name_tag] |
| 414 | && !branch_name.eq("master") | ||
| 415 | && !branch_name.eq("origin/main") | ||
| 416 | && !branch_name.eq("origin/master") | ||
| 417 | { | ||
| 418 | vec![ | ||
| 419 | Tag::custom( | ||
| 420 | nostr::TagKind::Custom(std::borrow::Cow::Borrowed("branch-name")), | ||
| 421 | vec![if let Some(branch_name) = branch_name.strip_prefix("pr/") { | ||
| 422 | branch_name.to_string() | ||
| 423 | } else { | ||
| 424 | branch_name | ||
| 425 | }.chars().take(60).collect::<String>()], | ||
| 426 | ), | ||
| 427 | ] | ||
| 428 | } | ||
| 429 | else { vec![] } | ||
| 430 | } else { | 522 | } else { |
| 431 | vec![] | 523 | vec![] |
| 432 | }, | 524 | }, |