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/client.rs15
-rw-r--r--src/git.rs176
-rw-r--r--src/login.rs12
-rw-r--r--src/repo_ref.rs257
-rw-r--r--src/sub_commands/init.rs17
-rw-r--r--src/sub_commands/push.rs9
-rw-r--r--src/sub_commands/send.rs32
-rw-r--r--test_utils/src/lib.rs9
8 files changed, 283 insertions, 244 deletions
diff --git a/src/client.rs b/src/client.rs
index 56f0e16..9dba528 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -34,7 +34,7 @@ pub struct Client {
34pub trait Connect { 34pub trait Connect {
35 fn default() -> Self; 35 fn default() -> Self;
36 fn new(opts: Params) -> Self; 36 fn new(opts: Params) -> Self;
37 async fn set_keys(&mut self, keys: &nostr::Keys); 37 async fn set_signer(&mut self, signer: NostrSigner);
38 async fn disconnect(&self) -> Result<()>; 38 async fn disconnect(&self) -> Result<()>;
39 fn get_fallback_relays(&self) -> &Vec<String>; 39 fn get_fallback_relays(&self) -> &Vec<String>;
40 fn get_more_fallback_relays(&self) -> &Vec<String>; 40 fn get_more_fallback_relays(&self) -> &Vec<String>;
@@ -91,17 +91,20 @@ impl Connect for Client {
91 } 91 }
92 fn new(opts: Params) -> Self { 92 fn new(opts: Params) -> Self {
93 Client { 93 Client {
94 client: nostr_sdk::Client::new(&opts.keys.unwrap_or(nostr::Keys::generate())), 94 client: nostr_sdk::ClientBuilder::new()
95 .signer(&opts.keys.unwrap_or(nostr::Keys::generate()))
96 // .database(
97 // SQLiteDatabase::open(get_dirs()?.config_dir().join("cache.sqlite")).await?,
98 // )
99 .build(),
95 fallback_relays: opts.fallback_relays, 100 fallback_relays: opts.fallback_relays,
96 more_fallback_relays: opts.more_fallback_relays, 101 more_fallback_relays: opts.more_fallback_relays,
97 blaster_relays: opts.blaster_relays, 102 blaster_relays: opts.blaster_relays,
98 } 103 }
99 } 104 }
100 105
101 async fn set_keys(&mut self, keys: &nostr::Keys) { 106 async fn set_signer(&mut self, signer: NostrSigner) {
102 self.client 107 self.client.set_signer(Some(signer)).await;
103 .set_signer(Some(NostrSigner::Keys(keys.clone())))
104 .await;
105 } 108 }
106 109
107 async fn disconnect(&self) -> Result<()> { 110 async fn disconnect(&self) -> Result<()> {
diff --git a/src/git.rs b/src/git.rs
index 7f44861..46687ae 100644
--- a/src/git.rs
+++ b/src/git.rs
@@ -828,7 +828,7 @@ fn extract_sig_from_patch_tags<'a>(
828mod tests { 828mod tests {
829 use std::fs; 829 use std::fs;
830 830
831 use test_utils::{generate_repo_ref_event, git::GitTestRepo, TEST_KEY_1_KEYS}; 831 use test_utils::{generate_repo_ref_event, git::GitTestRepo};
832 832
833 use super::*; 833 use super::*;
834 834
@@ -1591,10 +1591,12 @@ mod tests {
1591 1591
1592 mod apply_patch { 1592 mod apply_patch {
1593 1593
1594 use test_utils::TEST_KEY_1_SIGNER;
1595
1594 use super::*; 1596 use super::*;
1595 use crate::{repo_ref::RepoRef, sub_commands::send::generate_patch_event}; 1597 use crate::{repo_ref::RepoRef, sub_commands::send::generate_patch_event};
1596 1598
1597 fn generate_patch_from_head_commit(test_repo: &GitTestRepo) -> Result<nostr::Event> { 1599 async fn generate_patch_from_head_commit(test_repo: &GitTestRepo) -> Result<nostr::Event> {
1598 let original_oid = test_repo.git_repo.head()?.peel_to_commit()?.id(); 1600 let original_oid = test_repo.git_repo.head()?.peel_to_commit()?.id();
1599 let git_repo = Repo::from_path(&test_repo.dir)?; 1601 let git_repo = Repo::from_path(&test_repo.dir)?;
1600 generate_patch_event( 1602 generate_patch_event(
@@ -1602,7 +1604,7 @@ mod tests {
1602 &git_repo.get_root_commit()?, 1604 &git_repo.get_root_commit()?,
1603 &oid_to_sha1(&original_oid), 1605 &oid_to_sha1(&original_oid),
1604 Some(nostr::EventId::all_zeros()), 1606 Some(nostr::EventId::all_zeros()),
1605 &TEST_KEY_1_KEYS, 1607 &TEST_KEY_1_SIGNER,
1606 &RepoRef::try_from(generate_repo_ref_event()).unwrap(), 1608 &RepoRef::try_from(generate_repo_ref_event()).unwrap(),
1607 None, 1609 None,
1608 None, 1610 None,
@@ -1610,6 +1612,7 @@ mod tests {
1610 &None, 1612 &None,
1611 &[], 1613 &[],
1612 ) 1614 )
1615 .await
1613 } 1616 }
1614 fn test_patch_applies_to_repository(patch_event: nostr::Event) -> Result<()> { 1617 fn test_patch_applies_to_repository(patch_event: nostr::Event) -> Result<()> {
1615 let test_repo = GitTestRepo::default(); 1618 let test_repo = GitTestRepo::default();
@@ -1649,19 +1652,21 @@ mod tests {
1649 1652
1650 use super::*; 1653 use super::*;
1651 1654
1652 #[test] 1655 #[tokio::test]
1653 fn simple_signature_author_committer_same_as_git_user_0_unixtime_no_pgp_signature() 1656 async fn simple_signature_author_committer_same_as_git_user_0_unixtime_no_pgp_signature()
1654 -> Result<()> { 1657 -> Result<()> {
1655 let source_repo = GitTestRepo::default(); 1658 let source_repo = GitTestRepo::default();
1656 source_repo.populate()?; 1659 source_repo.populate()?;
1657 fs::write(source_repo.dir.join("x1.md"), "some content")?; 1660 fs::write(source_repo.dir.join("x1.md"), "some content")?;
1658 source_repo.stage_and_commit("add x1.md")?; 1661 source_repo.stage_and_commit("add x1.md")?;
1659 1662
1660 test_patch_applies_to_repository(generate_patch_from_head_commit(&source_repo)?) 1663 test_patch_applies_to_repository(
1664 generate_patch_from_head_commit(&source_repo).await?,
1665 )
1661 } 1666 }
1662 1667
1663 #[test] 1668 #[tokio::test]
1664 fn signature_with_specific_author_time() -> Result<()> { 1669 async fn signature_with_specific_author_time() -> Result<()> {
1665 let source_repo = GitTestRepo::default(); 1670 let source_repo = GitTestRepo::default();
1666 source_repo.populate()?; 1671 source_repo.populate()?;
1667 fs::write(source_repo.dir.join("x1.md"), "some content")?; 1672 fs::write(source_repo.dir.join("x1.md"), "some content")?;
@@ -1675,11 +1680,13 @@ mod tests {
1675 None, 1680 None,
1676 )?; 1681 )?;
1677 1682
1678 test_patch_applies_to_repository(generate_patch_from_head_commit(&source_repo)?) 1683 test_patch_applies_to_repository(
1684 generate_patch_from_head_commit(&source_repo).await?,
1685 )
1679 } 1686 }
1680 1687
1681 #[test] 1688 #[tokio::test]
1682 fn author_name_and_email_not_current_git_user() -> Result<()> { 1689 async fn author_name_and_email_not_current_git_user() -> Result<()> {
1683 let source_repo = GitTestRepo::default(); 1690 let source_repo = GitTestRepo::default();
1684 source_repo.populate()?; 1691 source_repo.populate()?;
1685 fs::write(source_repo.dir.join("x1.md"), "some content")?; 1692 fs::write(source_repo.dir.join("x1.md"), "some content")?;
@@ -1693,11 +1700,13 @@ mod tests {
1693 None, 1700 None,
1694 )?; 1701 )?;
1695 1702
1696 test_patch_applies_to_repository(generate_patch_from_head_commit(&source_repo)?) 1703 test_patch_applies_to_repository(
1704 generate_patch_from_head_commit(&source_repo).await?,
1705 )
1697 } 1706 }
1698 1707
1699 #[test] 1708 #[tokio::test]
1700 fn comiiter_name_and_email_not_current_git_user_or_author() -> Result<()> { 1709 async fn comiiter_name_and_email_not_current_git_user_or_author() -> Result<()> {
1701 let source_repo = GitTestRepo::default(); 1710 let source_repo = GitTestRepo::default();
1702 source_repo.populate()?; 1711 source_repo.populate()?;
1703 fs::write(source_repo.dir.join("x1.md"), "some content")?; 1712 fs::write(source_repo.dir.join("x1.md"), "some content")?;
@@ -1715,13 +1724,15 @@ mod tests {
1715 )?), 1724 )?),
1716 )?; 1725 )?;
1717 1726
1718 test_patch_applies_to_repository(generate_patch_from_head_commit(&source_repo)?) 1727 test_patch_applies_to_repository(
1728 generate_patch_from_head_commit(&source_repo).await?,
1729 )
1719 } 1730 }
1720 1731
1721 // TODO: pgp signature 1732 // TODO: pgp signature
1722 1733
1723 #[test] 1734 #[tokio::test]
1724 fn unique_author_and_commiter_details() -> Result<()> { 1735 async fn unique_author_and_commiter_details() -> Result<()> {
1725 let source_repo = GitTestRepo::default(); 1736 let source_repo = GitTestRepo::default();
1726 source_repo.populate()?; 1737 source_repo.populate()?;
1727 fs::write(source_repo.dir.join("x1.md"), "some content")?; 1738 fs::write(source_repo.dir.join("x1.md"), "some content")?;
@@ -1739,13 +1750,15 @@ mod tests {
1739 )?), 1750 )?),
1740 )?; 1751 )?;
1741 1752
1742 test_patch_applies_to_repository(generate_patch_from_head_commit(&source_repo)?) 1753 test_patch_applies_to_repository(
1754 generate_patch_from_head_commit(&source_repo).await?,
1755 )
1743 } 1756 }
1744 } 1757 }
1745 } 1758 }
1746 1759
1747 mod apply_patch_chain { 1760 mod apply_patch_chain {
1748 use test_utils::TEST_KEY_1_KEYS; 1761 use test_utils::TEST_KEY_1_SIGNER;
1749 1762
1750 use super::*; 1763 use super::*;
1751 use crate::{ 1764 use crate::{
@@ -1754,8 +1767,8 @@ mod tests {
1754 1767
1755 static BRANCH_NAME: &str = "add-example-feature"; 1768 static BRANCH_NAME: &str = "add-example-feature";
1756 // returns original_repo, cover_letter_event, patch_events 1769 // returns original_repo, cover_letter_event, patch_events
1757 fn generate_test_repo_and_events() -> Result<(GitTestRepo, nostr::Event, Vec<nostr::Event>)> 1770 async fn generate_test_repo_and_events()
1758 { 1771 -> Result<(GitTestRepo, nostr::Event, Vec<nostr::Event>)> {
1759 let original_repo = GitTestRepo::default(); 1772 let original_repo = GitTestRepo::default();
1760 let oid3 = original_repo.populate_with_test_branch()?; 1773 let oid3 = original_repo.populate_with_test_branch()?;
1761 let oid2 = original_repo.git_repo.find_commit(oid3)?.parent_id(0)?; 1774 let oid2 = original_repo.git_repo.find_commit(oid3)?.parent_id(0)?;
@@ -1767,11 +1780,12 @@ mod tests {
1767 Some(("test".to_string(), "test".to_string())), 1780 Some(("test".to_string(), "test".to_string())),
1768 &git_repo, 1781 &git_repo,
1769 &[oid_to_sha1(&oid1), oid_to_sha1(&oid2), oid_to_sha1(&oid3)], 1782 &[oid_to_sha1(&oid1), oid_to_sha1(&oid2), oid_to_sha1(&oid3)],
1770 &TEST_KEY_1_KEYS, 1783 &TEST_KEY_1_SIGNER,
1771 &RepoRef::try_from(generate_repo_ref_event()).unwrap(), 1784 &RepoRef::try_from(generate_repo_ref_event()).unwrap(),
1772 &None, 1785 &None,
1773 &[], 1786 &[],
1774 )?; 1787 )
1788 .await?;
1775 1789
1776 events.reverse(); 1790 events.reverse();
1777 1791
@@ -1784,9 +1798,9 @@ mod tests {
1784 mod when_branch_root_is_tip_of_main { 1798 mod when_branch_root_is_tip_of_main {
1785 use super::*; 1799 use super::*;
1786 1800
1787 #[test] 1801 #[tokio::test]
1788 fn branch_gets_created_with_name_specified_in_proposal() -> Result<()> { 1802 async fn branch_gets_created_with_name_specified_in_proposal() -> Result<()> {
1789 let (_, _, patch_events) = generate_test_repo_and_events()?; 1803 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1790 let test_repo = GitTestRepo::default(); 1804 let test_repo = GitTestRepo::default();
1791 test_repo.populate()?; 1805 test_repo.populate()?;
1792 let git_repo = Repo::from_path(&test_repo.dir)?; 1806 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1799,9 +1813,9 @@ mod tests {
1799 Ok(()) 1813 Ok(())
1800 } 1814 }
1801 1815
1802 #[test] 1816 #[tokio::test]
1803 fn branch_checked_out() -> Result<()> { 1817 async fn branch_checked_out() -> Result<()> {
1804 let (_, _, patch_events) = generate_test_repo_and_events()?; 1818 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1805 let test_repo = GitTestRepo::default(); 1819 let test_repo = GitTestRepo::default();
1806 test_repo.populate()?; 1820 test_repo.populate()?;
1807 let git_repo = Repo::from_path(&test_repo.dir)?; 1821 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1813,9 +1827,9 @@ mod tests {
1813 Ok(()) 1827 Ok(())
1814 } 1828 }
1815 1829
1816 #[test] 1830 #[tokio::test]
1817 fn patches_get_created_as_commits() -> Result<()> { 1831 async fn patches_get_created_as_commits() -> Result<()> {
1818 let (original_repo, _, patch_events) = generate_test_repo_and_events()?; 1832 let (original_repo, _, patch_events) = generate_test_repo_and_events().await?;
1819 let test_repo = GitTestRepo::default(); 1833 let test_repo = GitTestRepo::default();
1820 test_repo.populate()?; 1834 test_repo.populate()?;
1821 let git_repo = Repo::from_path(&test_repo.dir)?; 1835 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1827,9 +1841,9 @@ mod tests {
1827 Ok(()) 1841 Ok(())
1828 } 1842 }
1829 1843
1830 #[test] 1844 #[tokio::test]
1831 fn branch_tip_is_most_recent_patch() -> Result<()> { 1845 async fn branch_tip_is_most_recent_patch() -> Result<()> {
1832 let (original_repo, _, patch_events) = generate_test_repo_and_events()?; 1846 let (original_repo, _, patch_events) = generate_test_repo_and_events().await?;
1833 let test_repo = GitTestRepo::default(); 1847 let test_repo = GitTestRepo::default();
1834 test_repo.populate()?; 1848 test_repo.populate()?;
1835 let git_repo = Repo::from_path(&test_repo.dir)?; 1849 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1841,9 +1855,9 @@ mod tests {
1841 Ok(()) 1855 Ok(())
1842 } 1856 }
1843 1857
1844 #[test] 1858 #[tokio::test]
1845 fn previously_checked_out_branch_tip_does_not_change() -> Result<()> { 1859 async fn previously_checked_out_branch_tip_does_not_change() -> Result<()> {
1846 let (_, _, patch_events) = generate_test_repo_and_events()?; 1860 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1847 let test_repo = GitTestRepo::default(); 1861 let test_repo = GitTestRepo::default();
1848 test_repo.populate()?; 1862 test_repo.populate()?;
1849 let existing_branch = test_repo.get_checked_out_branch_name()?; 1863 let existing_branch = test_repo.get_checked_out_branch_name()?;
@@ -1858,9 +1872,9 @@ mod tests {
1858 Ok(()) 1872 Ok(())
1859 } 1873 }
1860 1874
1861 #[test] 1875 #[tokio::test]
1862 fn returns_all_patches_applied() -> Result<()> { 1876 async fn returns_all_patches_applied() -> Result<()> {
1863 let (_, _, patch_events) = generate_test_repo_and_events()?; 1877 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1864 let test_repo = GitTestRepo::default(); 1878 let test_repo = GitTestRepo::default();
1865 test_repo.populate()?; 1879 test_repo.populate()?;
1866 let git_repo = Repo::from_path(&test_repo.dir)?; 1880 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1873,9 +1887,9 @@ mod tests {
1873 mod when_branch_root_is_tip_behind_main { 1887 mod when_branch_root_is_tip_behind_main {
1874 use super::*; 1888 use super::*;
1875 1889
1876 #[test] 1890 #[tokio::test]
1877 fn branch_gets_created_with_name_specified_in_proposal() -> Result<()> { 1891 async fn branch_gets_created_with_name_specified_in_proposal() -> Result<()> {
1878 let (_, _, patch_events) = generate_test_repo_and_events()?; 1892 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1879 let test_repo = GitTestRepo::default(); 1893 let test_repo = GitTestRepo::default();
1880 test_repo.populate()?; 1894 test_repo.populate()?;
1881 std::fs::write(test_repo.dir.join("m3.md"), "some content")?; 1895 std::fs::write(test_repo.dir.join("m3.md"), "some content")?;
@@ -1890,9 +1904,9 @@ mod tests {
1890 Ok(()) 1904 Ok(())
1891 } 1905 }
1892 1906
1893 #[test] 1907 #[tokio::test]
1894 fn branch_checked_out() -> Result<()> { 1908 async fn branch_checked_out() -> Result<()> {
1895 let (_, _, patch_events) = generate_test_repo_and_events()?; 1909 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1896 let test_repo = GitTestRepo::default(); 1910 let test_repo = GitTestRepo::default();
1897 test_repo.populate()?; 1911 test_repo.populate()?;
1898 std::fs::write(test_repo.dir.join("m3.md"), "some content")?; 1912 std::fs::write(test_repo.dir.join("m3.md"), "some content")?;
@@ -1906,9 +1920,9 @@ mod tests {
1906 Ok(()) 1920 Ok(())
1907 } 1921 }
1908 1922
1909 #[test] 1923 #[tokio::test]
1910 fn branch_tip_is_most_recent_patch() -> Result<()> { 1924 async fn branch_tip_is_most_recent_patch() -> Result<()> {
1911 let (original_repo, _, patch_events) = generate_test_repo_and_events()?; 1925 let (original_repo, _, patch_events) = generate_test_repo_and_events().await?;
1912 let test_repo = GitTestRepo::default(); 1926 let test_repo = GitTestRepo::default();
1913 test_repo.populate()?; 1927 test_repo.populate()?;
1914 std::fs::write(test_repo.dir.join("m3.md"), "some content")?; 1928 std::fs::write(test_repo.dir.join("m3.md"), "some content")?;
@@ -1922,9 +1936,9 @@ mod tests {
1922 Ok(()) 1936 Ok(())
1923 } 1937 }
1924 1938
1925 #[test] 1939 #[tokio::test]
1926 fn previously_checked_out_branch_tip_does_not_change() -> Result<()> { 1940 async fn previously_checked_out_branch_tip_does_not_change() -> Result<()> {
1927 let (_, _, patch_events) = generate_test_repo_and_events()?; 1941 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1928 let test_repo = GitTestRepo::default(); 1942 let test_repo = GitTestRepo::default();
1929 test_repo.populate()?; 1943 test_repo.populate()?;
1930 std::fs::write(test_repo.dir.join("m3.md"), "some content")?; 1944 std::fs::write(test_repo.dir.join("m3.md"), "some content")?;
@@ -1941,9 +1955,9 @@ mod tests {
1941 Ok(()) 1955 Ok(())
1942 } 1956 }
1943 1957
1944 #[test] 1958 #[tokio::test]
1945 fn returns_all_patches_applied() -> Result<()> { 1959 async fn returns_all_patches_applied() -> Result<()> {
1946 let (_, _, patch_events) = generate_test_repo_and_events()?; 1960 let (_, _, patch_events) = generate_test_repo_and_events().await?;
1947 let test_repo = GitTestRepo::default(); 1961 let test_repo = GitTestRepo::default();
1948 test_repo.populate()?; 1962 test_repo.populate()?;
1949 let git_repo = Repo::from_path(&test_repo.dir)?; 1963 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1962,9 +1976,10 @@ mod tests {
1962 mod when_branch_already_checked_out { 1976 mod when_branch_already_checked_out {
1963 use super::*; 1977 use super::*;
1964 1978
1965 #[test] 1979 #[tokio::test]
1966 fn branch_tip_is_most_recent_patch() -> Result<()> { 1980 async fn branch_tip_is_most_recent_patch() -> Result<()> {
1967 let (original_repo, _, mut patch_events) = generate_test_repo_and_events()?; 1981 let (original_repo, _, mut patch_events) =
1982 generate_test_repo_and_events().await?;
1968 let test_repo = GitTestRepo::default(); 1983 let test_repo = GitTestRepo::default();
1969 test_repo.populate()?; 1984 test_repo.populate()?;
1970 let git_repo = Repo::from_path(&test_repo.dir)?; 1985 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1978,9 +1993,9 @@ mod tests {
1978 Ok(()) 1993 Ok(())
1979 } 1994 }
1980 1995
1981 #[test] 1996 #[tokio::test]
1982 fn returns_all_patches_applied() -> Result<()> { 1997 async fn returns_all_patches_applied() -> Result<()> {
1983 let (_, _, mut patch_events) = generate_test_repo_and_events()?; 1998 let (_, _, mut patch_events) = generate_test_repo_and_events().await?;
1984 let test_repo = GitTestRepo::default(); 1999 let test_repo = GitTestRepo::default();
1985 test_repo.populate()?; 2000 test_repo.populate()?;
1986 let git_repo = Repo::from_path(&test_repo.dir)?; 2001 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -1993,9 +2008,10 @@ mod tests {
1993 mod when_branch_not_checked_out { 2008 mod when_branch_not_checked_out {
1994 use super::*; 2009 use super::*;
1995 2010
1996 #[test] 2011 #[tokio::test]
1997 fn branch_tip_is_most_recent_patch() -> Result<()> { 2012 async fn branch_tip_is_most_recent_patch() -> Result<()> {
1998 let (original_repo, _, mut patch_events) = generate_test_repo_and_events()?; 2013 let (original_repo, _, mut patch_events) =
2014 generate_test_repo_and_events().await?;
1999 let test_repo = GitTestRepo::default(); 2015 let test_repo = GitTestRepo::default();
2000 test_repo.populate()?; 2016 test_repo.populate()?;
2001 let git_repo = Repo::from_path(&test_repo.dir)?; 2017 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -2010,9 +2026,9 @@ mod tests {
2010 Ok(()) 2026 Ok(())
2011 } 2027 }
2012 2028
2013 #[test] 2029 #[tokio::test]
2014 fn branch_checked_out() -> Result<()> { 2030 async fn branch_checked_out() -> Result<()> {
2015 let (_, _, mut patch_events) = generate_test_repo_and_events()?; 2031 let (_, _, mut patch_events) = generate_test_repo_and_events().await?;
2016 let test_repo = GitTestRepo::default(); 2032 let test_repo = GitTestRepo::default();
2017 test_repo.populate()?; 2033 test_repo.populate()?;
2018 let git_repo = Repo::from_path(&test_repo.dir)?; 2034 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -2027,9 +2043,9 @@ mod tests {
2027 Ok(()) 2043 Ok(())
2028 } 2044 }
2029 2045
2030 #[test] 2046 #[tokio::test]
2031 fn returns_all_patches_applied() -> Result<()> { 2047 async fn returns_all_patches_applied() -> Result<()> {
2032 let (_, _, mut patch_events) = generate_test_repo_and_events()?; 2048 let (_, _, mut patch_events) = generate_test_repo_and_events().await?;
2033 let test_repo = GitTestRepo::default(); 2049 let test_repo = GitTestRepo::default();
2034 test_repo.populate()?; 2050 test_repo.populate()?;
2035 let git_repo = Repo::from_path(&test_repo.dir)?; 2051 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -2048,9 +2064,9 @@ mod tests {
2048 mod when_branch_already_checked_out { 2064 mod when_branch_already_checked_out {
2049 use super::*; 2065 use super::*;
2050 2066
2051 #[test] 2067 #[tokio::test]
2052 fn returns_all_patches_applied_0() -> Result<()> { 2068 async fn returns_all_patches_applied_0() -> Result<()> {
2053 let (_, _, patch_events) = generate_test_repo_and_events()?; 2069 let (_, _, patch_events) = generate_test_repo_and_events().await?;
2054 let test_repo = GitTestRepo::default(); 2070 let test_repo = GitTestRepo::default();
2055 test_repo.populate()?; 2071 test_repo.populate()?;
2056 let git_repo = Repo::from_path(&test_repo.dir)?; 2072 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -2063,9 +2079,9 @@ mod tests {
2063 mod when_branch_not_checked_out { 2079 mod when_branch_not_checked_out {
2064 use super::*; 2080 use super::*;
2065 2081
2066 #[test] 2082 #[tokio::test]
2067 fn branch_checked_out() -> Result<()> { 2083 async fn branch_checked_out() -> Result<()> {
2068 let (_, _, patch_events) = generate_test_repo_and_events()?; 2084 let (_, _, patch_events) = generate_test_repo_and_events().await?;
2069 let test_repo = GitTestRepo::default(); 2085 let test_repo = GitTestRepo::default();
2070 test_repo.populate()?; 2086 test_repo.populate()?;
2071 let git_repo = Repo::from_path(&test_repo.dir)?; 2087 let git_repo = Repo::from_path(&test_repo.dir)?;
@@ -2080,9 +2096,9 @@ mod tests {
2080 Ok(()) 2096 Ok(())
2081 } 2097 }
2082 2098
2083 #[test] 2099 #[tokio::test]
2084 fn returns_all_patches_applied_0() -> Result<()> { 2100 async fn returns_all_patches_applied_0() -> Result<()> {
2085 let (_, _, patch_events) = generate_test_repo_and_events()?; 2101 let (_, _, patch_events) = generate_test_repo_and_events().await?;
2086 let test_repo = GitTestRepo::default(); 2102 let test_repo = GitTestRepo::default();
2087 test_repo.populate()?; 2103 test_repo.populate()?;
2088 let git_repo = Repo::from_path(&test_repo.dir)?; 2104 let git_repo = Repo::from_path(&test_repo.dir)?;
diff --git a/src/login.rs b/src/login.rs
index ad9902d..e1669c1 100644
--- a/src/login.rs
+++ b/src/login.rs
@@ -3,7 +3,9 @@ use std::str::FromStr;
3use anyhow::{bail, Context, Result}; 3use anyhow::{bail, Context, Result};
4use nostr::PublicKey; 4use nostr::PublicKey;
5use nostr_database::Order; 5use nostr_database::Order;
6use nostr_sdk::{Alphabet, FromBech32, JsonUtil, Kind, NostrDatabase, SingleLetterTag, ToBech32}; 6use nostr_sdk::{
7 Alphabet, FromBech32, JsonUtil, Kind, NostrDatabase, NostrSigner, SingleLetterTag, ToBech32,
8};
7use nostr_sqlite::SQLiteDatabase; 9use nostr_sqlite::SQLiteDatabase;
8 10
9#[cfg(not(test))] 11#[cfg(not(test))]
@@ -28,7 +30,7 @@ pub async fn launch(
28 #[cfg(test)] client: Option<&MockConnect>, 30 #[cfg(test)] client: Option<&MockConnect>,
29 #[cfg(not(test))] client: Option<&Client>, 31 #[cfg(not(test))] client: Option<&Client>,
30 change_user: bool, 32 change_user: bool,
31) -> Result<(nostr::Keys, UserRef)> { 33) -> Result<(NostrSigner, UserRef)> {
32 if let Ok(keys) = match get_keys_without_prompts(git_repo, nsec, password, change_user) { 34 if let Ok(keys) = match get_keys_without_prompts(git_repo, nsec, password, change_user) {
33 Ok(keys) => Ok(keys), 35 Ok(keys) => Ok(keys),
34 Err(error) => { 36 Err(error) => {
@@ -73,7 +75,7 @@ pub async fn launch(
73 // get user ref 75 // get user ref
74 let user_ref = get_user_details(&keys.public_key(), client, git_repo).await?; 76 let user_ref = get_user_details(&keys.public_key(), client, git_repo).await?;
75 print_logged_in_as(&user_ref, client.is_none())?; 77 print_logged_in_as(&user_ref, client.is_none())?;
76 Ok((keys, user_ref)) 78 Ok((NostrSigner::Keys(keys), user_ref))
77 } else { 79 } else {
78 fresh_login(git_repo, client, change_user).await 80 fresh_login(git_repo, client, change_user).await
79 } 81 }
@@ -172,7 +174,7 @@ async fn fresh_login(
172 #[cfg(test)] client: Option<&MockConnect>, 174 #[cfg(test)] client: Option<&MockConnect>,
173 #[cfg(not(test))] client: Option<&Client>, 175 #[cfg(not(test))] client: Option<&Client>,
174 always_save: bool, 176 always_save: bool,
175) -> Result<(nostr::Keys, UserRef)> { 177) -> Result<(NostrSigner, UserRef)> {
176 // prompt for nsec 178 // prompt for nsec
177 let mut prompt = "login with nsec"; 179 let mut prompt = "login with nsec";
178 let keys = loop { 180 let keys = loop {
@@ -196,7 +198,7 @@ async fn fresh_login(
196 } 198 }
197 let user_ref = get_user_details(&keys.public_key(), client, git_repo).await?; 199 let user_ref = get_user_details(&keys.public_key(), client, git_repo).await?;
198 print_logged_in_as(&user_ref, client.is_none())?; 200 print_logged_in_as(&user_ref, client.is_none())?;
199 Ok((keys, user_ref)) 201 Ok((NostrSigner::Keys(keys), user_ref))
200} 202}
201 203
202fn save_keys(git_repo: &Repo, keys: &nostr::Keys, always_save: bool) -> Result<()> { 204fn save_keys(git_repo: &Repo, keys: &nostr::Keys, always_save: bool) -> Result<()> {
diff --git a/src/repo_ref.rs b/src/repo_ref.rs
index 7016257..2b0d024 100644
--- a/src/repo_ref.rs
+++ b/src/repo_ref.rs
@@ -2,6 +2,7 @@ use std::{fs::File, io::BufReader, str::FromStr};
2 2
3use anyhow::{bail, Context, Result}; 3use anyhow::{bail, Context, Result};
4use nostr::{nips::nip19::Nip19, FromBech32, PublicKey, Tag, TagStandard, ToBech32}; 4use nostr::{nips::nip19::Nip19, FromBech32, PublicKey, Tag, TagStandard, ToBech32};
5use nostr_sdk::NostrSigner;
5use serde::{Deserialize, Serialize}; 6use serde::{Deserialize, Serialize};
6 7
7#[cfg(not(test))] 8#[cfg(not(test))]
@@ -93,66 +94,67 @@ impl TryFrom<nostr::Event> for RepoRef {
93pub static REPO_REF_KIND: u16 = 30_617; 94pub static REPO_REF_KIND: u16 = 30_617;
94 95
95impl RepoRef { 96impl RepoRef {
96 pub fn to_event(&self, keys: &nostr::Keys) -> Result<nostr::Event> { 97 pub async fn to_event(&self, signer: &NostrSigner) -> Result<nostr::Event> {
97 nostr_sdk::EventBuilder::new( 98 signer
98 nostr::event::Kind::Custom(REPO_REF_KIND), 99 .sign_event_builder(nostr_sdk::EventBuilder::new(
99 "", 100 nostr::event::Kind::Custom(REPO_REF_KIND),
100 [ 101 "",
101 vec![ 102 [
102 Tag::identifier(if self.identifier.to_string().is_empty() { 103 vec![
103 // fiatjaf thought a random string. its not in the draft nip. 104 Tag::identifier(if self.identifier.to_string().is_empty() {
104 // thread_rng() 105 // fiatjaf thought a random string. its not in the draft nip.
105 // .sample_iter(&Alphanumeric) 106 // thread_rng()
106 // .take(15) 107 // .sample_iter(&Alphanumeric)
107 // .map(char::from) 108 // .take(15)
108 // .collect() 109 // .map(char::from)
109 110 // .collect()
110 // an identifier based on first commit is better so that users dont 111
111 // accidentally create two seperate identifiers for the same repo 112 // an identifier based on first commit is better so that users dont
112 // there is a hesitancy to use the commit id 113 // accidentally create two seperate identifiers for the same repo
113 // in another conversaion with fiatjaf he suggested the first 6 character of 114 // there is a hesitancy to use the commit id
114 // the commit id 115 // in another conversaion with fiatjaf he suggested the first 6
115 // here we are using 7 which is the standard for shorthand commit id 116 // character of the commit id
116 self.root_commit.to_string()[..7].to_string() 117 // here we are using 7 which is the standard for shorthand commit id
117 } else { 118 self.root_commit.to_string()[..7].to_string()
118 self.identifier.to_string() 119 } else {
119 }), 120 self.identifier.to_string()
120 Tag::custom( 121 }),
121 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("r")), 122 Tag::custom(
122 vec![self.root_commit.to_string(), "euc".to_string()], 123 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("r")),
123 ), 124 vec![self.root_commit.to_string(), "euc".to_string()],
124 Tag::from_standardized(TagStandard::Name(self.name.clone())), 125 ),
125 Tag::from_standardized(TagStandard::Description(self.description.clone())), 126 Tag::from_standardized(TagStandard::Name(self.name.clone())),
126 Tag::custom( 127 Tag::from_standardized(TagStandard::Description(self.description.clone())),
127 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("clone")), 128 Tag::custom(
128 self.git_server.clone(), 129 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("clone")),
129 ), 130 self.git_server.clone(),
130 Tag::custom( 131 ),
131 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("web")), 132 Tag::custom(
132 self.web.clone(), 133 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("web")),
133 ), 134 self.web.clone(),
134 Tag::custom( 135 ),
135 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("relays")), 136 Tag::custom(
136 self.relays.clone(), 137 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("relays")),
137 ), 138 self.relays.clone(),
138 Tag::custom( 139 ),
139 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("maintainers")), 140 Tag::custom(
140 self.maintainers 141 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("maintainers")),
141 .iter() 142 self.maintainers
142 .map(std::string::ToString::to_string) 143 .iter()
143 .collect::<Vec<String>>(), 144 .map(std::string::ToString::to_string)
144 ), 145 .collect::<Vec<String>>(),
145 Tag::custom( 146 ),
146 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")), 147 Tag::custom(
147 vec![format!("git repository: {}", self.name.clone())], 148 nostr::TagKind::Custom(std::borrow::Cow::Borrowed("alt")),
148 ), 149 vec![format!("git repository: {}", self.name.clone())],
149 ], 150 ),
150 // code languages and hashtags 151 ],
151 ] 152 // code languages and hashtags
152 .concat(), 153 ]
153 ) 154 .concat(),
154 .to_event(keys) 155 ))
155 .context("failed to create repository reference event") 156 .await
157 .context("failed to create repository reference event")
156 } 158 }
157} 159}
158 160
@@ -308,7 +310,7 @@ mod tests {
308 310
309 use super::*; 311 use super::*;
310 312
311 fn create() -> nostr::Event { 313 async fn create() -> nostr::Event {
312 RepoRef { 314 RepoRef {
313 identifier: "123412341".to_string(), 315 identifier: "123412341".to_string(),
314 name: "test name".to_string(), 316 name: "test name".to_string(),
@@ -322,34 +324,38 @@ mod tests {
322 relays: vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 324 relays: vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()],
323 maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], 325 maintainers: vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()],
324 } 326 }
325 .to_event(&TEST_KEY_1_KEYS) 327 .to_event(&TEST_KEY_1_SIGNER)
328 .await
326 .unwrap() 329 .unwrap()
327 } 330 }
328 mod try_from { 331 mod try_from {
329 use super::*; 332 use super::*;
330 333
331 #[test] 334 #[tokio::test]
332 fn identifier() { 335 async fn identifier() {
333 assert_eq!(RepoRef::try_from(create()).unwrap().identifier, "123412341",) 336 assert_eq!(
337 RepoRef::try_from(create().await).unwrap().identifier,
338 "123412341",
339 )
334 } 340 }
335 341
336 #[test] 342 #[tokio::test]
337 fn name() { 343 async fn name() {
338 assert_eq!(RepoRef::try_from(create()).unwrap().name, "test name",) 344 assert_eq!(RepoRef::try_from(create().await).unwrap().name, "test name",)
339 } 345 }
340 346
341 #[test] 347 #[tokio::test]
342 fn description() { 348 async fn description() {
343 assert_eq!( 349 assert_eq!(
344 RepoRef::try_from(create()).unwrap().description, 350 RepoRef::try_from(create().await).unwrap().description,
345 "test description", 351 "test description",
346 ) 352 )
347 } 353 }
348 354
349 #[test] 355 #[tokio::test]
350 fn root_commit_is_r_tag() { 356 async fn root_commit_is_r_tag() {
351 assert_eq!( 357 assert_eq!(
352 RepoRef::try_from(create()).unwrap().root_commit, 358 RepoRef::try_from(create().await).unwrap().root_commit,
353 "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2", 359 "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2",
354 ) 360 )
355 } 361 }
@@ -358,42 +364,43 @@ mod tests {
358 use nostr::JsonUtil; 364 use nostr::JsonUtil;
359 365
360 use super::*; 366 use super::*;
361 fn create_with_incorrect_first_commit_ref(s: &str) -> nostr::Event { 367 async fn create_with_incorrect_first_commit_ref(s: &str) -> nostr::Event {
362 nostr::Event::from_json( 368 nostr::Event::from_json(
363 create() 369 create()
370 .await
364 .as_json() 371 .as_json()
365 .replace("5e664e5a7845cd1373c79f580ca4fe29ab5b34d2", s), 372 .replace("5e664e5a7845cd1373c79f580ca4fe29ab5b34d2", s),
366 ) 373 )
367 .unwrap() 374 .unwrap()
368 } 375 }
369 376
370 #[test] 377 #[tokio::test]
371 fn less_than_40_characters() { 378 async fn less_than_40_characters() {
372 let s = "5e664e5a7845cd1373"; 379 let s = "5e664e5a7845cd1373";
373 assert_eq!( 380 assert_eq!(
374 RepoRef::try_from(create_with_incorrect_first_commit_ref(s)) 381 RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await)
375 .unwrap() 382 .unwrap()
376 .root_commit, 383 .root_commit,
377 "", 384 "",
378 ) 385 )
379 } 386 }
380 387
381 #[test] 388 #[tokio::test]
382 fn more_than_40_characters() { 389 async fn more_than_40_characters() {
383 let s = "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2111111111"; 390 let s = "5e664e5a7845cd1373c79f580ca4fe29ab5b34d2111111111";
384 assert_eq!( 391 assert_eq!(
385 RepoRef::try_from(create_with_incorrect_first_commit_ref(s)) 392 RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await)
386 .unwrap() 393 .unwrap()
387 .root_commit, 394 .root_commit,
388 "", 395 "",
389 ) 396 )
390 } 397 }
391 398
392 #[test] 399 #[tokio::test]
393 fn not_hex_characters() { 400 async fn not_hex_characters() {
394 let s = "xxx64e5a7845cd1373c79f580ca4fe29ab5b34d2"; 401 let s = "xxx64e5a7845cd1373c79f580ca4fe29ab5b34d2";
395 assert_eq!( 402 assert_eq!(
396 RepoRef::try_from(create_with_incorrect_first_commit_ref(s)) 403 RepoRef::try_from(create_with_incorrect_first_commit_ref(s).await)
397 .unwrap() 404 .unwrap()
398 .root_commit, 405 .root_commit,
399 "", 406 "",
@@ -401,18 +408,18 @@ mod tests {
401 } 408 }
402 } 409 }
403 410
404 #[test] 411 #[tokio::test]
405 fn git_server() { 412 async fn git_server() {
406 assert_eq!( 413 assert_eq!(
407 RepoRef::try_from(create()).unwrap().git_server, 414 RepoRef::try_from(create().await).unwrap().git_server,
408 vec!["https://localhost:1000"], 415 vec!["https://localhost:1000"],
409 ) 416 )
410 } 417 }
411 418
412 #[test] 419 #[tokio::test]
413 fn web() { 420 async fn web() {
414 assert_eq!( 421 assert_eq!(
415 RepoRef::try_from(create()).unwrap().web, 422 RepoRef::try_from(create().await).unwrap().web,
416 vec![ 423 vec![
417 "https://exampleproject.xyz".to_string(), 424 "https://exampleproject.xyz".to_string(),
418 "https://gitworkshop.dev/123".to_string() 425 "https://gitworkshop.dev/123".to_string()
@@ -420,18 +427,18 @@ mod tests {
420 ) 427 )
421 } 428 }
422 429
423 #[test] 430 #[tokio::test]
424 fn relays() { 431 async fn relays() {
425 assert_eq!( 432 assert_eq!(
426 RepoRef::try_from(create()).unwrap().relays, 433 RepoRef::try_from(create().await).unwrap().relays,
427 vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()], 434 vec!["ws://relay1.io".to_string(), "ws://relay2.io".to_string()],
428 ) 435 )
429 } 436 }
430 437
431 #[test] 438 #[tokio::test]
432 fn maintainers() { 439 async fn maintainers() {
433 assert_eq!( 440 assert_eq!(
434 RepoRef::try_from(create()).unwrap().maintainers, 441 RepoRef::try_from(create().await).unwrap().maintainers,
435 vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()], 442 vec![TEST_KEY_1_KEYS.public_key(), TEST_KEY_2_KEYS.public_key()],
436 ) 443 )
437 } 444 }
@@ -442,57 +449,59 @@ mod tests {
442 mod tags { 449 mod tags {
443 use super::*; 450 use super::*;
444 451
445 #[test] 452 #[tokio::test]
446 fn identifier() { 453 async fn identifier() {
447 assert!( 454 assert!(
448 create() 455 create()
456 .await
449 .tags 457 .tags
450 .iter() 458 .iter()
451 .any(|t| t.as_vec()[0].eq("d") && t.as_vec()[1].eq("123412341")) 459 .any(|t| t.as_vec()[0].eq("d") && t.as_vec()[1].eq("123412341"))
452 ) 460 )
453 } 461 }
454 462
455 #[test] 463 #[tokio::test]
456 fn name() { 464 async fn name() {
457 assert!( 465 assert!(
458 create() 466 create()
467 .await
459 .tags 468 .tags
460 .iter() 469 .iter()
461 .any(|t| t.as_vec()[0].eq("name") && t.as_vec()[1].eq("test name")) 470 .any(|t| t.as_vec()[0].eq("name") && t.as_vec()[1].eq("test name"))
462 ) 471 )
463 } 472 }
464 473
465 #[test] 474 #[tokio::test]
466 fn alt() { 475 async fn alt() {
467 assert!( 476 assert!(
468 create().tags.iter().any(|t| t.as_vec()[0].eq("alt") 477 create().await.tags.iter().any(|t| t.as_vec()[0].eq("alt")
469 && t.as_vec()[1].eq("git repository: test name")) 478 && t.as_vec()[1].eq("git repository: test name"))
470 ) 479 )
471 } 480 }
472 481
473 #[test] 482 #[tokio::test]
474 fn description() { 483 async fn description() {
475 assert!(create().tags.iter().any( 484 assert!(create().await.tags.iter().any(
476 |t| t.as_vec()[0].eq("description") && t.as_vec()[1].eq("test description") 485 |t| t.as_vec()[0].eq("description") && t.as_vec()[1].eq("test description")
477 )) 486 ))
478 } 487 }
479 488
480 #[test] 489 #[tokio::test]
481 fn root_commit_as_reference() { 490 async fn root_commit_as_reference() {
482 assert!(create().tags.iter().any(|t| t.as_vec()[0].eq("r") 491 assert!(create().await.tags.iter().any(|t| t.as_vec()[0].eq("r")
483 && t.as_vec()[1].eq("5e664e5a7845cd1373c79f580ca4fe29ab5b34d2"))) 492 && t.as_vec()[1].eq("5e664e5a7845cd1373c79f580ca4fe29ab5b34d2")))
484 } 493 }
485 494
486 #[test] 495 #[tokio::test]
487 fn git_server() { 496 async fn git_server() {
488 assert!(create().tags.iter().any( 497 assert!(create().await.tags.iter().any(
489 |t| t.as_vec()[0].eq("clone") && t.as_vec()[1].eq("https://localhost:1000") 498 |t| t.as_vec()[0].eq("clone") && t.as_vec()[1].eq("https://localhost:1000")
490 )) 499 ))
491 } 500 }
492 501
493 #[test] 502 #[tokio::test]
494 fn relays() { 503 async fn relays() {
495 let event = create(); 504 let event = create().await;
496 let relays_tag: &nostr::Tag = event 505 let relays_tag: &nostr::Tag = event
497 .tags 506 .tags
498 .iter() 507 .iter()
@@ -503,9 +512,9 @@ mod tests {
503 assert_eq!(relays_tag.as_vec()[2], "ws://relay2.io"); 512 assert_eq!(relays_tag.as_vec()[2], "ws://relay2.io");
504 } 513 }
505 514
506 #[test] 515 #[tokio::test]
507 fn web() { 516 async fn web() {
508 let event = create(); 517 let event = create().await;
509 let web_tag: &nostr::Tag = 518 let web_tag: &nostr::Tag =
510 event.tags.iter().find(|t| t.as_vec()[0].eq("web")).unwrap(); 519 event.tags.iter().find(|t| t.as_vec()[0].eq("web")).unwrap();
511 assert_eq!(web_tag.as_vec().len(), 3); 520 assert_eq!(web_tag.as_vec().len(), 3);
@@ -513,9 +522,9 @@ mod tests {
513 assert_eq!(web_tag.as_vec()[2], "https://gitworkshop.dev/123"); 522 assert_eq!(web_tag.as_vec()[2], "https://gitworkshop.dev/123");
514 } 523 }
515 524
516 #[test] 525 #[tokio::test]
517 fn maintainers() { 526 async fn maintainers() {
518 let event = create(); 527 let event = create().await;
519 let maintainers_tag: &nostr::Tag = event 528 let maintainers_tag: &nostr::Tag = event
520 .tags 529 .tags
521 .iter() 530 .iter()
@@ -532,9 +541,9 @@ mod tests {
532 ); 541 );
533 } 542 }
534 543
535 #[test] 544 #[tokio::test]
536 fn no_other_tags() { 545 async fn no_other_tags() {
537 assert_eq!(create().tags.len(), 9) 546 assert_eq!(create().await.tags.len(), 9)
538 } 547 }
539 } 548 }
540 } 549 }
diff --git a/src/sub_commands/init.rs b/src/sub_commands/init.rs
index 4d1bdfb..4afe83c 100644
--- a/src/sub_commands/init.rs
+++ b/src/sub_commands/init.rs
@@ -59,7 +59,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
59 #[cfg(test)] 59 #[cfg(test)]
60 let mut client = <MockConnect as std::default::Default>::default(); 60 let mut client = <MockConnect as std::default::Default>::default();
61 61
62 let (keys, user_ref) = login::launch( 62 let (signer, user_ref) = login::launch(
63 &git_repo, 63 &git_repo,
64 &cli_args.nsec, 64 &cli_args.nsec,
65 &cli_args.password, 65 &cli_args.password,
@@ -68,8 +68,6 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
68 ) 68 )
69 .await?; 69 .await?;
70 70
71 client.set_keys(&keys).await;
72
73 let repo_ref = if let Ok(rep_ref) = repo_ref::fetch( 71 let repo_ref = if let Ok(rep_ref) = repo_ref::fetch(
74 &git_repo, 72 &git_repo,
75 root_commit.to_string(), 73 root_commit.to_string(),
@@ -180,7 +178,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
180 let mut maintainers_string = if !args.other_maintainers.is_empty() { 178 let mut maintainers_string = if !args.other_maintainers.is_empty() {
181 [args.other_maintainers.clone()].concat().join(" ") 179 [args.other_maintainers.clone()].concat().join(" ")
182 } else if repo_ref.is_none() && repo_config_result.is_err() { 180 } else if repo_ref.is_none() && repo_config_result.is_err() {
183 keys.public_key().to_bech32()? 181 signer.public_key().await?.to_bech32()?
184 } else { 182 } else {
185 let maintainers = if let Ok(config) = &repo_config_result { 183 let maintainers = if let Ok(config) = &repo_config_result {
186 config.maintainers.clone() 184 config.maintainers.clone()
@@ -193,7 +191,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
193 .collect() 191 .collect()
194 } else { 192 } else {
195 //unreachable 193 //unreachable
196 vec![keys.public_key().to_bech32()?] 194 vec![signer.public_key().await?.to_bech32()?]
197 }; 195 };
198 // add current user if not present 196 // add current user if not present
199 if maintainers.iter().any(|m| { 197 if maintainers.iter().any(|m| {
@@ -205,7 +203,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
205 }) { 203 }) {
206 maintainers.join(" ") 204 maintainers.join(" ")
207 } else { 205 } else {
208 [maintainers, vec![keys.public_key().to_bech32()?]] 206 [maintainers, vec![signer.public_key().await?.to_bech32()?]]
209 .concat() 207 .concat()
210 .join(" ") 208 .join(" ")
211 } 209 }
@@ -231,7 +229,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
231 } 229 }
232 // add current user incase removed 230 // add current user incase removed
233 if !maintainers.iter().any(|m| user_ref.public_key.eq(m)) { 231 if !maintainers.iter().any(|m| user_ref.public_key.eq(m)) {
234 maintainers.push(keys.public_key()); 232 maintainers.push(signer.public_key().await?);
235 } 233 }
236 break maintainers; 234 break maintainers;
237 } 235 }
@@ -300,7 +298,10 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
300 relays: relays.clone(), 298 relays: relays.clone(),
301 maintainers: maintainers.clone(), 299 maintainers: maintainers.clone(),
302 } 300 }
303 .to_event(&keys)?; 301 .to_event(&signer)
302 .await?;
303
304 client.set_signer(signer).await;
304 305
305 send_events( 306 send_events(
306 &client, 307 &client,
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index ade2ff8..92c1c18 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -148,7 +148,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
148 ahead.len() 148 ahead.len()
149 ); 149 );
150 150
151 let (keys, user_ref) = login::launch( 151 let (signer, user_ref) = login::launch(
152 &git_repo, 152 &git_repo,
153 &cli_args.nsec, 153 &cli_args.nsec,
154 &cli_args.password, 154 &cli_args.password,
@@ -157,8 +157,6 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
157 ) 157 )
158 .await?; 158 .await?;
159 159
160 client.set_keys(&keys).await;
161
162 let mut patch_events: Vec<nostr::Event> = vec![]; 160 let mut patch_events: Vec<nostr::Event> = vec![];
163 for commit in &ahead { 161 for commit in &ahead {
164 patch_events.push( 162 patch_events.push(
@@ -167,7 +165,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
167 &root_commit, 165 &root_commit,
168 commit, 166 commit,
169 Some(proposal_root_event.id), 167 Some(proposal_root_event.id),
170 &keys, 168 &signer,
171 &repo_ref, 169 &repo_ref,
172 patch_events.last().map(nostr::Event::id), 170 patch_events.last().map(nostr::Event::id),
173 None, 171 None,
@@ -175,11 +173,14 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
175 &None, 173 &None,
176 &[], 174 &[],
177 ) 175 )
176 .await
178 .context("cannot make patch event from commit")?, 177 .context("cannot make patch event from commit")?,
179 ); 178 );
180 } 179 }
181 println!("pushing {} commits", ahead.len()); 180 println!("pushing {} commits", ahead.len());
182 181
182 client.set_signer(signer).await;
183
183 send_events( 184 send_events(
184 &client, 185 &client,
185 patch_events, 186 patch_events,
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs
index 8971d8b..1d20e90 100644
--- a/src/sub_commands/send.rs
+++ b/src/sub_commands/send.rs
@@ -8,7 +8,7 @@ use nostr::{
8 nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19}, 8 nips::{nip01::Coordinate, nip10::Marker, nip19::Nip19},
9 EventBuilder, FromBech32, Tag, TagKind, ToBech32, UncheckedUrl, 9 EventBuilder, FromBech32, Tag, TagKind, ToBech32, UncheckedUrl,
10}; 10};
11use nostr_sdk::{hashes::sha1::Hash as Sha1Hash, TagStandard}; 11use nostr_sdk::{hashes::sha1::Hash as Sha1Hash, NostrSigner, TagStandard};
12 12
13use super::list::tag_value; 13use super::list::tag_value;
14#[cfg(not(test))] 14#[cfg(not(test))]
@@ -178,7 +178,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
178 } else { 178 } else {
179 None 179 None
180 }; 180 };
181 let (keys, user_ref) = login::launch( 181 let (signer, user_ref) = login::launch(
182 &git_repo, 182 &git_repo,
183 &cli_args.nsec, 183 &cli_args.nsec,
184 &cli_args.password, 184 &cli_args.password,
@@ -187,7 +187,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
187 ) 187 )
188 .await?; 188 .await?;
189 189
190 client.set_keys(&keys).await; 190 client.set_signer(signer.clone()).await;
191 191
192 let repo_ref = repo_ref::fetch( 192 let repo_ref = repo_ref::fetch(
193 &git_repo, 193 &git_repo,
@@ -208,11 +208,12 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
208 cover_letter_title_description.clone(), 208 cover_letter_title_description.clone(),
209 &git_repo, 209 &git_repo,
210 &commits, 210 &commits,
211 &keys, 211 &signer,
212 &repo_ref, 212 &repo_ref,
213 &root_proposal_id, 213 &root_proposal_id,
214 &mention_tags, 214 &mention_tags,
215 )?; 215 )
216 .await?;
216 217
217 println!( 218 println!(
218 "posting {} patch{} {} a covering letter...", 219 "posting {} patch{} {} a covering letter...",
@@ -576,11 +577,11 @@ async fn get_root_proposal_id_and_mentions_from_in_reply_to(
576pub static PATCH_KIND: u16 = 1617; 577pub static PATCH_KIND: u16 = 1617;
577 578
578#[allow(clippy::too_many_lines)] 579#[allow(clippy::too_many_lines)]
579pub fn generate_cover_letter_and_patch_events( 580pub async fn generate_cover_letter_and_patch_events(
580 cover_letter_title_description: Option<(String, String)>, 581 cover_letter_title_description: Option<(String, String)>,
581 git_repo: &Repo, 582 git_repo: &Repo,
582 commits: &[Sha1Hash], 583 commits: &[Sha1Hash],
583 keys: &nostr::Keys, 584 signer: &NostrSigner,
584 repo_ref: &RepoRef, 585 repo_ref: &RepoRef,
585 root_proposal_id: &Option<String>, 586 root_proposal_id: &Option<String>,
586 mentions: &[nostr::Tag], 587 mentions: &[nostr::Tag],
@@ -592,7 +593,7 @@ pub fn generate_cover_letter_and_patch_events(
592 let mut events = vec![]; 593 let mut events = vec![];
593 594
594 if let Some((title, description)) = cover_letter_title_description { 595 if let Some((title, description)) = cover_letter_title_description {
595 events.push(EventBuilder::new( 596 events.push(signer.sign_event_builder(EventBuilder::new(
596 nostr::event::Kind::Custom(PATCH_KIND), 597 nostr::event::Kind::Custom(PATCH_KIND),
597 format!( 598 format!(
598 "From {} Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/{}] {title}\n\n{description}", 599 "From {} Mon Sep 17 00:00:00 2001\nSubject: [PATCH 0/{}] {title}\n\n{description}",
@@ -655,8 +656,7 @@ pub fn generate_cover_letter_and_patch_events(
655 .map(|pk| Tag::public_key(*pk)) 656 .map(|pk| Tag::public_key(*pk))
656 .collect(), 657 .collect(),
657 ].concat(), 658 ].concat(),
658 ) 659 )).await
659 .to_event(keys)
660 .context("failed to create cover-letter event")?); 660 .context("failed to create cover-letter event")?);
661 } 661 }
662 662
@@ -667,7 +667,7 @@ pub fn generate_cover_letter_and_patch_events(
667 &root_commit, 667 &root_commit,
668 commit, 668 commit,
669 events.first().map(|event| event.id), 669 events.first().map(|event| event.id),
670 keys, 670 signer,
671 repo_ref, 671 repo_ref,
672 events.last().map(nostr::Event::id), 672 events.last().map(nostr::Event::id),
673 if events.is_empty() { 673 if events.is_empty() {
@@ -695,6 +695,7 @@ pub fn generate_cover_letter_and_patch_events(
695 root_proposal_id, 695 root_proposal_id,
696 if events.is_empty() { mentions } else { &[] }, 696 if events.is_empty() { mentions } else { &[] },
697 ) 697 )
698 .await
698 .context("failed to generate patch event")?, 699 .context("failed to generate patch event")?,
699 ); 700 );
700 } 701 }
@@ -864,12 +865,12 @@ pub fn patch_supports_commit_ids(event: &nostr::Event) -> bool {
864 865
865#[allow(clippy::too_many_arguments)] 866#[allow(clippy::too_many_arguments)]
866#[allow(clippy::too_many_lines)] 867#[allow(clippy::too_many_lines)]
867pub fn generate_patch_event( 868pub async fn generate_patch_event(
868 git_repo: &Repo, 869 git_repo: &Repo,
869 root_commit: &Sha1Hash, 870 root_commit: &Sha1Hash,
870 commit: &Sha1Hash, 871 commit: &Sha1Hash,
871 thread_event_id: Option<nostr::EventId>, 872 thread_event_id: Option<nostr::EventId>,
872 keys: &nostr::Keys, 873 signer: &nostr_sdk::NostrSigner,
873 repo_ref: &RepoRef, 874 repo_ref: &RepoRef,
874 parent_patch_event_id: Option<nostr::EventId>, 875 parent_patch_event_id: Option<nostr::EventId>,
875 series_count: Option<(u64, u64)>, 876 series_count: Option<(u64, u64)>,
@@ -882,7 +883,7 @@ pub fn generate_patch_event(
882 .context("failed to get parent commit")?; 883 .context("failed to get parent commit")?;
883 let relay_hint = repo_ref.relays.first().map(nostr::UncheckedUrl::from); 884 let relay_hint = repo_ref.relays.first().map(nostr::UncheckedUrl::from);
884 885
885 EventBuilder::new( 886 signer.sign_event_builder(EventBuilder::new(
886 nostr::event::Kind::Custom(PATCH_KIND), 887 nostr::event::Kind::Custom(PATCH_KIND),
887 git_repo 888 git_repo
888 .make_patch_from_commit(commit,&series_count) 889 .make_patch_from_commit(commit,&series_count)
@@ -999,8 +1000,7 @@ pub fn generate_patch_event(
999 ], 1000 ],
1000 ] 1001 ]
1001 .concat(), 1002 .concat(),
1002 ) 1003 )).await
1003 .to_event(keys)
1004 .context("failed to sign event") 1004 .context("failed to sign event")
1005} 1005}
1006// TODO 1006// TODO
diff --git a/test_utils/src/lib.rs b/test_utils/src/lib.rs
index bf6c37b..ade60fc 100644
--- a/test_utils/src/lib.rs
+++ b/test_utils/src/lib.rs
@@ -4,7 +4,7 @@ use anyhow::{bail, ensure, Context, Result};
4use dialoguer::theme::{ColorfulTheme, Theme}; 4use dialoguer::theme::{ColorfulTheme, Theme};
5use directories::ProjectDirs; 5use directories::ProjectDirs;
6use nostr::{self, nips::nip65::RelayMetadata, Kind, Tag}; 6use nostr::{self, nips::nip65::RelayMetadata, Kind, Tag};
7use nostr_sdk::{serde_json, TagStandard}; 7use nostr_sdk::{serde_json, NostrSigner, TagStandard};
8use once_cell::sync::Lazy; 8use once_cell::sync::Lazy;
9use rexpect::session::{Options, PtySession}; 9use rexpect::session::{Options, PtySession};
10use strip_ansi_escapes::strip_str; 10use strip_ansi_escapes::strip_str;
@@ -29,6 +29,13 @@ pub static TEST_KEY_1_ENCRYPTED_WEAK: &str = "ncryptsec1qg835almhlrmyxqtqeva44d5
29pub static TEST_KEY_1_KEYS: Lazy<nostr::Keys> = 29pub static TEST_KEY_1_KEYS: Lazy<nostr::Keys> =
30 Lazy::new(|| nostr::Keys::from_str(TEST_KEY_1_NSEC).unwrap()); 30 Lazy::new(|| nostr::Keys::from_str(TEST_KEY_1_NSEC).unwrap());
31 31
32pub static TEST_KEY_1_SIGNER: Lazy<NostrSigner> =
33 Lazy::new(|| NostrSigner::Keys(nostr::Keys::from_str(TEST_KEY_1_NSEC).unwrap()));
34
35pub fn generate_test_key_1_signer() -> NostrSigner {
36 NostrSigner::Keys(nostr::Keys::from_str(TEST_KEY_1_NSEC).unwrap())
37}
38
32pub fn generate_test_key_1_metadata_event(name: &str) -> nostr::Event { 39pub fn generate_test_key_1_metadata_event(name: &str) -> nostr::Event {
33 nostr::event::EventBuilder::metadata(&nostr::Metadata::new().name(name)) 40 nostr::event::EventBuilder::metadata(&nostr::Metadata::new().name(name))
34 .to_event(&TEST_KEY_1_KEYS) 41 .to_event(&TEST_KEY_1_KEYS)