upleb.uk

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

summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-17 12:11:33 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-17 14:04:32 +0000
commit5cc8ae28cb462d2cb0b7f74dfa5238e62d17eb70 (patch)
tree7e1f81c8204c3f50b30fa69b410f60ffa872bec7 /tests
parent06ebbf7c73b64225ae083bb3134f7c7c630c5565 (diff)
feat: support multiline descriptions in push-options via \n escape
Git push-options are line-based so literal newlines cannot be sent. Users can now write the two-character sequence \n which is decoded into real newlines before publishing. Use \\n for a literal backslash-n. Includes unit tests, integration test, help text, and changelog entry.
Diffstat (limited to 'tests')
-rw-r--r--tests/git_remote_nostr/push.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/tests/git_remote_nostr/push.rs b/tests/git_remote_nostr/push.rs
index 38b1f8c..8498958 100644
--- a/tests/git_remote_nostr/push.rs
+++ b/tests/git_remote_nostr/push.rs
@@ -1895,6 +1895,114 @@ async fn push_new_pr_branch_with_title_description_options_creates_pr_with_custo
1895 Ok(()) 1895 Ok(())
1896} 1896}
1897 1897
1898#[tokio::test]
1899#[serial]
1900async fn push_with_escaped_newlines_in_description_creates_pr_with_multiline_description()
1901-> Result<()> {
1902 let (events, source_git_repo) = prep_source_repo_and_events_including_proposals().await?;
1903 let _source_path = source_git_repo.dir.to_str().unwrap().to_string();
1904
1905 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
1906 Relay::new(8051, None, None),
1907 Relay::new(8052, None, None),
1908 Relay::new(8053, None, None),
1909 Relay::new(8055, None, None),
1910 Relay::new(8056, None, None),
1911 Relay::new(8057, None, None),
1912 );
1913 r51.events = events.clone();
1914 r55.events = events.clone();
1915
1916 #[allow(clippy::mutable_key_type)]
1917 let before = r55.events.iter().cloned().collect::<HashSet<Event>>();
1918 let branch_name = "pr/my-pr-multiline";
1919
1920 let cli_tester_handle = std::thread::spawn(move || -> Result<String> {
1921 let mut git_repo = clone_git_repo_with_nostr_url()?;
1922 git_repo.delete_dir_on_drop = false;
1923 git_repo.create_branch(branch_name)?;
1924 git_repo.checkout(branch_name)?;
1925
1926 let large_content = "x".repeat(70 * 1024);
1927 std::fs::write(git_repo.dir.join("large_file.txt"), large_content)?;
1928 git_repo.stage_and_commit("large_file.txt")?;
1929
1930 // Use \\n in the push-option value — the two-character escape sequence
1931 let mut p = CliTester::new_git_with_remote_helper_from_dir(
1932 &git_repo.dir,
1933 [
1934 "push",
1935 "--push-option=title=Multiline PR",
1936 r"--push-option=description=First line\n\nSecond paragraph\nThird line",
1937 "-u",
1938 "origin",
1939 branch_name,
1940 ],
1941 );
1942 cli_expect_nostr_fetch(&mut p)?;
1943 p.expect("git servers: listing refs...\r\n")?;
1944 p.expect_eventually_and_print(format!("To {}\r\n", get_nostr_remote_url()?).as_str())?;
1945 let output = p.expect_end_eventually()?;
1946
1947 for p in [51, 52, 53, 55, 56, 57] {
1948 relay::shutdown_relay(8000 + p)?;
1949 }
1950
1951 Ok(output)
1952 });
1953 let _ = join!(
1954 r51.listen_until_close(),
1955 r52.listen_until_close(),
1956 r53.listen_until_close(),
1957 r55.listen_until_close(),
1958 r56.listen_until_close(),
1959 r57.listen_until_close(),
1960 );
1961
1962 let output = cli_tester_handle.join().unwrap()?;
1963
1964 assert_eq!(
1965 output,
1966 format!(" * [new branch] {branch_name} -> {branch_name}\r\nbranch '{branch_name}' set up to track 'origin/{branch_name}'.\r\n").as_str(),
1967 );
1968
1969 let new_events = r55
1970 .events
1971 .iter()
1972 .cloned()
1973 .collect::<HashSet<Event>>()
1974 .difference(&before)
1975 .cloned()
1976 .collect::<Vec<Event>>();
1977 assert_eq!(new_events.len(), 1, "should create exactly 1 PR event");
1978
1979 let pr_event = new_events.first().unwrap();
1980
1981 assert!(
1982 pr_event.kind.eq(&KIND_PULL_REQUEST),
1983 "event should be a PR event"
1984 );
1985
1986 let title_tag = pr_event.tags.iter().find(|t| t.as_slice()[0].eq("subject"));
1987 assert!(
1988 title_tag.is_some(),
1989 "PR event should have a subject tag for title"
1990 );
1991 assert_eq!(
1992 title_tag.unwrap().as_slice()[1],
1993 "Multiline PR",
1994 "title should match push-option"
1995 );
1996
1997 // The \\n sequences should have been decoded into real newlines
1998 assert_eq!(
1999 pr_event.content, "First line\n\nSecond paragraph\nThird line",
2000 "description should contain real newlines from escaped \\n sequences"
2001 );
2002
2003 Ok(())
2004}
2005
1898mod push_from_another_maintainer { 2006mod push_from_another_maintainer {
1899 2007
1900 // TODO that has issued announcement 2008 // TODO that has issued announcement