upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-02-23 13:57:23 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2024-02-23 13:57:23 +0000
commitd5284b758661c491e6a206570763f2982424b70a (patch)
treecc7d8cee7b535999dc99e466a17127b1a94aee97
parenta9e4c6772a378fd28edbca9b9267d2e7d08bee2c (diff)
feat(init): add customisation and defaults
- allow more cli input options - allow customisation of more fields in interface - change default identifer from shorthand root commit to short name - defaults to existing repo event (users or other) or maintainers.yaml
-rw-r--r--src/repo_ref.rs4
-rw-r--r--src/sub_commands/init.rs256
-rw-r--r--src/sub_commands/list.rs1
-rw-r--r--src/sub_commands/pull.rs1
-rw-r--r--src/sub_commands/push.rs1
-rw-r--r--src/sub_commands/send.rs1
-rw-r--r--tests/init.rs260
7 files changed, 266 insertions, 258 deletions
diff --git a/src/repo_ref.rs b/src/repo_ref.rs
index 8e944d7..c7b42fa 100644
--- a/src/repo_ref.rs
+++ b/src/repo_ref.rs
@@ -152,6 +152,7 @@ pub async fn fetch(
152 #[cfg(not(test))] client: &Client, 152 #[cfg(not(test))] client: &Client,
153 // TODO: more rubust way of finding repo events 153 // TODO: more rubust way of finding repo events
154 fallback_relays: Vec<String>, 154 fallback_relays: Vec<String>,
155 prompt_for_nevent_if_cant_event: bool,
155) -> Result<RepoRef> { 156) -> Result<RepoRef> {
156 let repo_config = get_repo_config_from_yaml(git_repo); 157 let repo_config = get_repo_config_from_yaml(git_repo);
157 158
@@ -187,6 +188,9 @@ pub async fn fetch(
187 { 188 {
188 break event.clone(); 189 break event.clone();
189 } 190 }
191 if !prompt_for_nevent_if_cant_event {
192 bail!("cannot find repo event");
193 }
190 println!("cannot find repo event"); 194 println!("cannot find repo event");
191 loop { 195 loop {
192 let bech32 = Interactor::default() 196 let bech32 = Interactor::default()
diff --git a/src/sub_commands/init.rs b/src/sub_commands/init.rs
index 3a0ff55..54b6156 100644
--- a/src/sub_commands/init.rs
+++ b/src/sub_commands/init.rs
@@ -1,4 +1,5 @@
1use anyhow::{Context, Result}; 1use anyhow::{Context, Result};
2use nostr::{secp256k1::XOnlyPublicKey, FromBech32, ToBech32};
2 3
3use super::send::send_events; 4use super::send::send_events;
4#[cfg(not(test))] 5#[cfg(not(test))]
@@ -10,7 +11,7 @@ use crate::{
10 client::Connect, 11 client::Connect,
11 git::{Repo, RepoActions}, 12 git::{Repo, RepoActions},
12 login, 13 login,
13 repo_ref::{extract_pks, get_repo_config_from_yaml, save_repo_config_to_yaml, RepoRef}, 14 repo_ref::{self, extract_pks, get_repo_config_from_yaml, save_repo_config_to_yaml, RepoRef},
14 Cli, 15 Cli,
15}; 16};
16 17
@@ -22,14 +23,27 @@ pub struct SubCommandArgs {
22 #[clap(short, long)] 23 #[clap(short, long)]
23 /// optional description 24 /// optional description
24 description: Option<String>, 25 description: Option<String>,
26 #[clap(long)]
27 /// git server url users can clone from
28 clone_url: Option<String>,
25 #[clap(short, long, value_parser, num_args = 1..)] 29 #[clap(short, long, value_parser, num_args = 1..)]
26 /// homepage 30 /// homepage
27 web: Vec<String>, 31 web: Vec<String>,
28 #[clap(short, long, value_parser, num_args = 1..)] 32 #[clap(short, long, value_parser, num_args = 1..)]
29 /// relays contributors push patches and comments to 33 /// relays contributors push patches and comments to
30 relays: Vec<String>, 34 relays: Vec<String>,
35 #[clap(short, long, value_parser, num_args = 1..)]
36 /// npubs of other maintainers
37 other_maintainers: Vec<String>,
38 #[clap(long)]
39 /// usually root commit but will be more recent commit for forks
40 earliest_unique_commit: Option<String>,
41 #[clap(short, long)]
42 /// shortname with no spaces or special characters
43 identifier: Option<String>,
31} 44}
32 45
46#[allow(clippy::too_many_lines)]
33pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> { 47pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
34 let git_repo = Repo::discover().context("cannot find a git repository")?; 48 let git_repo = Repo::discover().context("cannot find a git repository")?;
35 49
@@ -40,29 +54,95 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
40 // TODO: check for empty repo 54 // TODO: check for empty repo
41 // TODO: check for existing maintaiers file 55 // TODO: check for existing maintaiers file
42 56
57 #[cfg(not(test))]
58 let mut client = Client::default();
59 #[cfg(test)]
60 let mut client = <MockConnect as std::default::Default>::default();
61
62 let (keys, user_ref) = login::launch(&cli_args.nsec, &cli_args.password, Some(&client)).await?;
63
64 client.set_keys(&keys).await;
65
66 let repo_ref = if let Ok(rep_ref) = repo_ref::fetch(
67 &git_repo,
68 root_commit.to_string(),
69 &client,
70 user_ref.relays.write(),
71 false,
72 )
73 .await
74 {
75 Some(rep_ref)
76 } else {
77 None
78 };
79
43 let repo_config_result = get_repo_config_from_yaml(&git_repo); 80 let repo_config_result = get_repo_config_from_yaml(&git_repo);
44 // TODO: check for other claims 81 // TODO: check for other claims
45 82
46 let identifier = root_commit.to_string()[..7].to_string();
47
48 let name = match &args.title { 83 let name = match &args.title {
49 Some(t) => t.clone(), 84 Some(t) => t.clone(),
50 None => Interactor::default().input(PromptInputParms::default().with_prompt("name"))?, 85 None => Interactor::default().input(
86 PromptInputParms::default()
87 .with_prompt("name")
88 .with_default(if let Some(repo_ref) = &repo_ref {
89 repo_ref.name.clone()
90 } else {
91 String::new()
92 }),
93 )?,
94 };
95
96 let identifier = match &args.identifier {
97 Some(t) => t.clone(),
98 None => Interactor::default().input(
99 PromptInputParms::default()
100 .with_prompt("identifier")
101 .with_default(if let Some(repo_ref) = &repo_ref {
102 repo_ref.identifier.clone()
103 } else {
104 name.clone()
105 .replace(' ', "-")
106 .chars()
107 .map(|c| {
108 if c.is_ascii_alphanumeric() || c.eq(&'/') {
109 c
110 } else {
111 '-'
112 }
113 })
114 .collect()
115 }),
116 )?,
51 }; 117 };
52 118
53 let description = match &args.description { 119 let description = match &args.description {
54 Some(t) => t.clone(), 120 Some(t) => t.clone(),
55 None => { 121 None => Interactor::default().input(
56 Interactor::default().input(PromptInputParms::default().with_prompt("description"))? 122 PromptInputParms::default()
57 } 123 .with_prompt("description")
124 .with_default(if let Some(repo_ref) = &repo_ref {
125 repo_ref.description.clone()
126 } else {
127 String::new()
128 }),
129 )?,
58 }; 130 };
59 131
60 let git_server = git_repo 132 let git_server = match &args.clone_url {
61 .get_origin_url() 133 Some(t) => t.clone(),
62 .context( 134 None => Interactor::default().input(
63 "to claim the repository it must be available on a publically accessable git server", 135 PromptInputParms::default()
64 ) 136 .with_prompt("clone url")
65 .context("no git remote origin configured")?; 137 .with_default(if let Some(repo_ref) = &repo_ref {
138 repo_ref.git_server.clone()
139 } else if let Ok(git_repo) = git_repo.get_origin_url() {
140 git_repo
141 } else {
142 String::new()
143 }),
144 )?,
145 };
66 146
67 let web: Vec<String> = if args.web.is_empty() { 147 let web: Vec<String> = if args.web.is_empty() {
68 Interactor::default() 148 Interactor::default()
@@ -70,7 +150,11 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
70 PromptInputParms::default() 150 PromptInputParms::default()
71 .with_prompt("web") 151 .with_prompt("web")
72 .optional() 152 .optional()
73 .with_default(format!("https://gitworkshop.dev/repo/{}", &identifier)), 153 .with_default(if let Some(repo_ref) = &repo_ref {
154 repo_ref.web.clone().join(" ")
155 } else {
156 format!("https://gitworkshop.dev/repo/{}", &identifier)
157 }),
74 )? 158 )?
75 .split(' ') 159 .split(' ')
76 .map(std::string::ToString::to_string) 160 .map(std::string::ToString::to_string)
@@ -78,41 +162,132 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
78 } else { 162 } else {
79 args.web.clone() 163 args.web.clone()
80 }; 164 };
81 #[cfg(not(test))]
82 let mut client = Client::default();
83 #[cfg(test)]
84 let mut client = <MockConnect as std::default::Default>::default();
85 165
86 let (keys, user_ref) = login::launch(&cli_args.nsec, &cli_args.password, Some(&client)).await?; 166 let maintainers: Vec<XOnlyPublicKey> = {
87 167 let mut dont_ask = !args.other_maintainers.is_empty();
88 client.set_keys(&keys).await; 168 let mut maintainers_string = if !args.other_maintainers.is_empty() {
89 169 [args.other_maintainers.clone()].concat().join(" ")
90 let mut maintainers = vec![keys.public_key()]; 170 } else if repo_ref.is_none() && repo_config_result.is_err() {
171 keys.public_key().to_bech32()?
172 } else {
173 let maintainers = if let Ok(config) = &repo_config_result {
174 config.maintainers.clone()
175 } else if let Some(repo_ref) = &repo_ref {
176 repo_ref
177 .maintainers
178 .clone()
179 .iter()
180 .map(|k| k.to_bech32().unwrap())
181 .collect()
182 } else {
183 //unreachable
184 vec![keys.public_key().to_bech32()?]
185 };
186 // add current user if not present
187 if maintainers.iter().any(|m| {
188 if let Ok(m_pubkey) = XOnlyPublicKey::from_bech32(m) {
189 user_ref.public_key.eq(&m_pubkey)
190 } else {
191 false
192 }
193 }) {
194 maintainers.join(" ")
195 } else {
196 [maintainers, vec![keys.public_key().to_bech32()?]]
197 .concat()
198 .join(" ")
199 }
200 };
201 'outer: loop {
202 if !dont_ask {
203 maintainers_string = Interactor::default()
204 .input(
205 PromptInputParms::default()
206 .with_prompt("maintainers")
207 .with_default(maintainers_string),
208 )?
209 .split(' ')
210 .map(std::string::ToString::to_string)
211 .collect();
212 }
213 let mut maintainers: Vec<XOnlyPublicKey> = vec![];
214 for m in maintainers_string.split(' ') {
215 if let Ok(m_pubkey) = XOnlyPublicKey::from_bech32(m) {
216 maintainers.push(m_pubkey);
217 } else {
218 println!("not a valid set of npubs seperated by a space");
219 dont_ask = false;
220 continue 'outer;
221 }
222 }
223 // add current user incase removed
224 if !maintainers.iter().any(|m| user_ref.public_key.eq(m)) {
225 maintainers.push(keys.public_key());
226 }
227 break maintainers;
228 }
229 };
91 230
92 let repo_relays: Vec<String> = if !args.relays.is_empty() { 231 // TODO: check if relays are free to post to so contributors can submit patches
93 args.relays.clone() 232 // TODO: recommend some reliable free ones
94 } else if let Ok(config) = &repo_config_result { 233 let relays: Vec<String> = if args.relays.is_empty() {
95 config.relays.clone() 234 Interactor::default()
235 .input(
236 PromptInputParms::default()
237 .with_prompt("relays")
238 .with_default(if let Ok(config) = &repo_config_result {
239 config.relays.clone().join(" ")
240 } else if let Some(repo_ref) = &repo_ref {
241 repo_ref.relays.clone().join(" ")
242 } else {
243 user_ref.relays.write().join(" ")
244 }),
245 )?
246 .split(' ')
247 .map(std::string::ToString::to_string)
248 .collect()
96 } else { 249 } else {
97 // TODO: choice input defaulting to user relay list filtered by non paid relays 250 args.relays.clone()
98 // TODO: allow manual input for more relays
99 // TODO: reccommend some free relays
100 user_ref.relays.write()
101 }; 251 };
102 252
103 if let Ok(config) = &repo_config_result { 253 let earliest_unique_commit = match &args.earliest_unique_commit {
104 maintainers = extract_pks(config.maintainers.clone())?; 254 Some(t) => t.clone(),
105 } 255 None => {
256 let mut earliest_unique_commit = if let Some(repo_ref) = &repo_ref {
257 repo_ref.root_commit.clone()
258 } else {
259 root_commit.to_string()
260 };
261 loop {
262 earliest_unique_commit = Interactor::default().input(
263 PromptInputParms::default()
264 .with_prompt("earliest unique commit")
265 .with_default(earliest_unique_commit.clone()),
266 )?;
267 if let Ok(exists) = git_repo.does_commit_exist(&earliest_unique_commit) {
268 if exists {
269 break earliest_unique_commit;
270 }
271 println!("commit does not exist on current repository");
272 } else {
273 println!("commit id not formatted correctly");
274 }
275 if earliest_unique_commit.len().ne(&40) {
276 println!("commit id must be 40 characters long");
277 }
278 }
279 }
280 };
106 281
107 // if yaml file doesnt exist or needs updating 282 // if yaml file doesnt exist or needs updating
108 if match &repo_config_result { 283 if match &repo_config_result {
109 Ok(config) => { 284 Ok(config) => {
110 !(extract_pks(config.maintainers.clone())?.eq(&maintainers) 285 !(extract_pks(config.maintainers.clone())?.eq(&maintainers)
111 && config.relays.eq(&repo_relays)) 286 && config.relays.eq(&relays))
112 } 287 }
113 Err(_) => true, 288 Err(_) => true,
114 } { 289 } {
115 save_repo_config_to_yaml(&git_repo, maintainers.clone(), repo_relays.clone())?; 290 save_repo_config_to_yaml(&git_repo, maintainers.clone(), relays.clone())?;
116 println!( 291 println!(
117 "maintainers.yaml {}. commit and push.", 292 "maintainers.yaml {}. commit and push.",
118 if repo_config_result.is_err() { 293 if repo_config_result.is_err() {
@@ -121,6 +296,9 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
121 "updated" 296 "updated"
122 } 297 }
123 ); 298 );
299 println!(
300 "this enables existing contributors to automatically fetch your repo event (instead of one from a pubkey pretending to be the maintainer)"
301 );
124 } 302 }
125 303
126 println!("publishing repostory reference..."); 304 println!("publishing repostory reference...");
@@ -129,10 +307,10 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
129 identifier, 307 identifier,
130 name, 308 name,
131 description, 309 description,
132 root_commit: root_commit.to_string(), 310 root_commit: earliest_unique_commit,
133 git_server, 311 git_server,
134 web, 312 web,
135 relays: repo_relays.clone(), 313 relays: relays.clone(),
136 maintainers, 314 maintainers,
137 } 315 }
138 .to_event(&keys)?; 316 .to_event(&keys)?;
@@ -141,7 +319,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
141 &client, 319 &client,
142 vec![repo_event], 320 vec![repo_event],
143 user_ref.relays.write(), 321 user_ref.relays.write(),
144 repo_relays, 322 relays,
145 !cli_args.disable_cli_spinners, 323 !cli_args.disable_cli_spinners,
146 ) 324 )
147 .await?; 325 .await?;
diff --git a/src/sub_commands/list.rs b/src/sub_commands/list.rs
index 666c4bf..f7397f1 100644
--- a/src/sub_commands/list.rs
+++ b/src/sub_commands/list.rs
@@ -48,6 +48,7 @@ pub async fn launch(_cli_args: &Cli, _args: &SubCommandArgs) -> Result<()> {
48 root_commit.to_string(), 48 root_commit.to_string(),
49 &client, 49 &client,
50 client.get_fallback_relays().clone(), 50 client.get_fallback_relays().clone(),
51 true,
51 ) 52 )
52 .await?; 53 .await?;
53 54
diff --git a/src/sub_commands/pull.rs b/src/sub_commands/pull.rs
index 9b74719..daae37f 100644
--- a/src/sub_commands/pull.rs
+++ b/src/sub_commands/pull.rs
@@ -44,6 +44,7 @@ pub async fn launch() -> Result<()> {
44 root_commit.to_string(), 44 root_commit.to_string(),
45 &client, 45 &client,
46 client.get_fallback_relays().clone(), 46 client.get_fallback_relays().clone(),
47 true,
47 ) 48 )
48 .await?; 49 .await?;
49 50
diff --git a/src/sub_commands/push.rs b/src/sub_commands/push.rs
index 06c3e50..bcac178 100644
--- a/src/sub_commands/push.rs
+++ b/src/sub_commands/push.rs
@@ -60,6 +60,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
60 root_commit.to_string(), 60 root_commit.to_string(),
61 &client, 61 &client,
62 client.get_fallback_relays().clone(), 62 client.get_fallback_relays().clone(),
63 true,
63 ) 64 )
64 .await?; 65 .await?;
65 66
diff --git a/src/sub_commands/send.rs b/src/sub_commands/send.rs
index b5ab78f..857bc60 100644
--- a/src/sub_commands/send.rs
+++ b/src/sub_commands/send.rs
@@ -151,6 +151,7 @@ pub async fn launch(cli_args: &Cli, args: &SubCommandArgs) -> Result<()> {
151 .to_string(), 151 .to_string(),
152 &client, 152 &client,
153 user_ref.relays.write(), 153 user_ref.relays.write(),
154 true,
154 ) 155 )
155 .await?; 156 .await?;
156 157
diff --git a/tests/init.rs b/tests/init.rs
index 1ad3810..d733643 100644
--- a/tests/init.rs
+++ b/tests/init.rs
@@ -8,10 +8,40 @@ fn expect_msgs_first(p: &mut CliTester) -> Result<()> {
8 p.expect("logged in as fred\r\n")?; 8 p.expect("logged in as fred\r\n")?;
9 // // p.expect("searching for existing claims on repository...\r\n")?; 9 // // p.expect("searching for existing claims on repository...\r\n")?;
10 p.expect("maintainers.yaml created. commit and push.\r\n")?; 10 p.expect("maintainers.yaml created. commit and push.\r\n")?;
11 p.expect("this enables existing contributors to automatically fetch your repo event (instead of one from a pubkey pretending to be the maintainer) publishing repostory reference...\r\n")?;
11 p.expect("publishing repostory reference...\r\n")?; 12 p.expect("publishing repostory reference...\r\n")?;
12 Ok(()) 13 Ok(())
13} 14}
14 15
16fn get_cli_args() -> Vec<&'static str> {
17 vec![
18 "--nsec",
19 TEST_KEY_1_NSEC,
20 "--password",
21 TEST_PASSWORD,
22 "--disable-cli-spinners",
23 "init",
24 "--title",
25 "example-name",
26 "--identifier",
27 "example-identifier",
28 "--description",
29 "example-description",
30 "--web",
31 "https://exampleproject.xyz",
32 "https://gitworkshop.dev/123",
33 "--relays",
34 "ws://localhost:8055",
35 "ws://localhost:8056",
36 "--clone-url",
37 "https://git.myhosting.com/my-repo.git",
38 "--earliest-unique-commit",
39 "9ee507fc4357d7ee16a5d8901bedcd103f23c17d",
40 "--other-maintainers",
41 TEST_KEY_1_NPUB,
42 ]
43}
44
15mod when_repo_not_previously_claimed { 45mod when_repo_not_previously_claimed {
16 use super::*; 46 use super::*;
17 47
@@ -29,27 +59,7 @@ mod when_repo_not_previously_claimed {
29 } 59 }
30 60
31 fn cli_tester_init(git_repo: &GitTestRepo) -> CliTester { 61 fn cli_tester_init(git_repo: &GitTestRepo) -> CliTester {
32 CliTester::new_from_dir( 62 CliTester::new_from_dir(&git_repo.dir, get_cli_args())
33 &git_repo.dir,
34 [
35 "--nsec",
36 TEST_KEY_1_NSEC,
37 "--password",
38 TEST_PASSWORD,
39 "--disable-cli-spinners",
40 "init",
41 "--title",
42 "example-name",
43 "--description",
44 "example-description",
45 "--web",
46 "https://exampleproject.xyz",
47 "https://gitworkshop.dev/123",
48 "--relays",
49 "ws://localhost:8055",
50 "ws://localhost:8056",
51 ],
52 )
53 } 63 }
54 64
55 async fn prep_run_init() -> Result<( 65 async fn prep_run_init() -> Result<(
@@ -259,13 +269,12 @@ mod when_repo_not_previously_claimed {
259 } 269 }
260 } 270 }
261 271
262 mod tags { 272 mod tags_as_specified_in_args {
263 use super::*; 273 use super::*;
264 274
265 #[tokio::test] 275 #[tokio::test]
266 #[serial] 276 #[serial]
267 async fn d_replaceable_event_identifier_defaults_to_root_commit_id_shorthand() 277 async fn d_replaceable_event_identifier() -> Result<()> {
268 -> Result<()> {
269 let (_, _, r53, r55, r56, r57) = prep_run_init().await?; 278 let (_, _, r53, r55, r56, r57) = prep_run_init().await?;
270 for relay in [&r53, &r55, &r56, &r57] { 279 for relay in [&r53, &r55, &r56, &r57] {
271 let event: &nostr::Event = relay 280 let event: &nostr::Event = relay
@@ -275,10 +284,9 @@ mod when_repo_not_previously_claimed {
275 .unwrap(); 284 .unwrap();
276 285
277 assert!( 286 assert!(
278 event 287 event.tags.iter().any(
279 .tags 288 |t| t.as_vec()[0].eq("d") && t.as_vec()[1].eq("example-identifier")
280 .iter() 289 )
281 .any(|t| t.as_vec()[0].eq("d") && t.as_vec()[1].eq("9ee507f"))
282 ); 290 );
283 } 291 }
284 Ok(()) 292 Ok(())
@@ -286,7 +294,7 @@ mod when_repo_not_previously_claimed {
286 294
287 #[tokio::test] 295 #[tokio::test]
288 #[serial] 296 #[serial]
289 async fn root_commit_as_reference() -> Result<()> { 297 async fn earliest_unique_commit_as_reference() -> Result<()> {
290 let (_, _, r53, r55, r56, r57) = prep_run_init().await?; 298 let (_, _, r53, r55, r56, r57) = prep_run_init().await?;
291 for relay in [&r53, &r55, &r56, &r57] { 299 for relay in [&r53, &r55, &r56, &r57] {
292 let event: &nostr::Event = relay 300 let event: &nostr::Event = relay
@@ -352,7 +360,7 @@ mod when_repo_not_previously_claimed {
352 360
353 assert!( 361 assert!(
354 event.tags.iter().any(|t| t.as_vec()[0].eq("clone") 362 event.tags.iter().any(|t| t.as_vec()[0].eq("clone")
355 && t.as_vec()[1].eq("https://localhost:1000")) 363 && t.as_vec()[1].eq("https://git.myhosting.com/my-repo.git")) /* todo check it defaults to origin */
356 ); 364 );
357 } 365 }
358 Ok(()) 366 Ok(())
@@ -404,7 +412,7 @@ mod when_repo_not_previously_claimed {
404 412
405 #[tokio::test] 413 #[tokio::test]
406 #[serial] 414 #[serial]
407 async fn current_user_in_maintainers() -> Result<()> { 415 async fn maintainers() -> Result<()> {
408 let (_, _, r53, r55, r56, r57) = prep_run_init().await?; 416 let (_, _, r53, r55, r56, r57) = prep_run_init().await?;
409 for relay in [&r53, &r55, &r56, &r57] { 417 for relay in [&r53, &r55, &r56, &r57] {
410 let event: &nostr::Event = relay 418 let event: &nostr::Event = relay
@@ -498,192 +506,6 @@ mod when_repo_not_previously_claimed {
498 } 506 }
499 } 507 }
500 } 508 }
501 509 // TODO: cli caputuring input
502 mod when_repo_relays_not_specified {
503 use futures::join;
504 use test_utils::relay::Relay;
505
506 use super::*;
507
508 fn prep_git_repo() -> Result<GitTestRepo> {
509 let test_repo = GitTestRepo::default();
510 test_repo.populate()?;
511 test_repo.add_remote("origin", "https://localhost:1000")?;
512 Ok(test_repo)
513 }
514
515 fn cli_tester_init(git_repo: &GitTestRepo) -> CliTester {
516 CliTester::new_from_dir(
517 &git_repo.dir,
518 [
519 "--nsec",
520 TEST_KEY_1_NSEC,
521 "--password",
522 TEST_PASSWORD,
523 "--disable-cli-spinners",
524 "init",
525 "--title",
526 "example-name",
527 "--description",
528 "example-description",
529 "--web",
530 "https://exampleproject.xyz",
531 "https://gitworkshop.dev/123",
532 ],
533 )
534 }
535
536 async fn prep_run_init() -> Result<(
537 Relay<'static>,
538 Relay<'static>,
539 Relay<'static>,
540 Relay<'static>,
541 Relay<'static>,
542 Relay<'static>,
543 )> {
544 let git_repo = prep_git_repo()?;
545 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
546 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
547 Relay::new(
548 8051,
549 None,
550 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
551 relay.respond_events(
552 client_id,
553 &subscription_id,
554 &vec![
555 generate_test_key_1_metadata_event("fred"),
556 generate_test_key_1_relay_list_event(),
557 ],
558 )?;
559 Ok(())
560 }),
561 ),
562 Relay::new(8052, None, None),
563 Relay::new(8053, None, None),
564 Relay::new(8055, None, None),
565 Relay::new(8056, None, None),
566 Relay::new(8057, None, None),
567 );
568
569 // // check relay had the right number of events
570 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
571 let mut p = cli_tester_init(&git_repo);
572 p.expect_end_eventually()?;
573 for p in [51, 52, 53, 55, 56, 57] {
574 relay::shutdown_relay(8000 + p)?;
575 }
576 Ok(())
577 });
578
579 // launch relay
580 let _ = join!(
581 r51.listen_until_close(),
582 r52.listen_until_close(),
583 r53.listen_until_close(),
584 r55.listen_until_close(),
585 r56.listen_until_close(),
586 r57.listen_until_close(),
587 );
588 cli_tester_handle.join().unwrap()?;
589 Ok((r51, r52, r53, r55, r56, r57))
590 }
591
592 mod tags {
593 use super::*;
594
595 #[tokio::test]
596 #[serial]
597 async fn relays_match_user_write_relays() -> Result<()> {
598 let (_, _, r53, r55, _, _) = prep_run_init().await?;
599 for relay in [&r53, &r55] {
600 let event: &nostr::Event = relay
601 .events
602 .iter()
603 .find(|e| e.kind.as_u64().eq(&REPOSITORY_KIND))
604 .unwrap();
605
606 assert!(event.tags.iter().any(|t| t.as_vec()[0].eq("relays")
607 && t.as_vec()[1].eq("ws://localhost:8053")
608 && t.as_vec()[2].eq("ws://localhost:8055")));
609 }
610 Ok(())
611 }
612 }
613
614 mod cli_ouput {
615 use super::*;
616
617 async fn run_test_async() -> Result<()> {
618 let git_repo = prep_git_repo()?;
619
620 // fallback (51,52) user write (53, 55) repo (55, 56) blaster (57)
621 let (mut r51, mut r52, mut r53, mut r55, mut r56, mut r57) = (
622 Relay::new(
623 8051,
624 None,
625 Some(&|relay, client_id, subscription_id, _| -> Result<()> {
626 relay.respond_events(
627 client_id,
628 &subscription_id,
629 &vec![
630 generate_test_key_1_metadata_event("fred"),
631 generate_test_key_1_relay_list_event(),
632 ],
633 )?;
634 Ok(())
635 }),
636 ),
637 Relay::new(8052, None, None),
638 Relay::new(8053, None, None),
639 Relay::new(8055, None, None),
640 Relay::new(8056, None, None),
641 Relay::new(8057, None, None),
642 );
643
644 // // check relay had the right number of events
645 let cli_tester_handle = std::thread::spawn(move || -> Result<()> {
646 let mut p = cli_tester_init(&git_repo);
647 expect_msgs_first(&mut p)?;
648 relay::expect_send_with_progress(
649 &mut p,
650 vec![
651 (" [my-relay] [repo-relay] ws://localhost:8053", true, ""),
652 (" [my-relay] [repo-relay] ws://localhost:8055", true, ""),
653 (" [default] ws://localhost:8051", true, ""),
654 (" [default] ws://localhost:8052", true, ""),
655 (" [default] ws://localhost:8057", true, ""),
656 ],
657 1,
658 )?;
659 p.expect_end_with_whitespace()?;
660 for p in [51, 52, 53, 55, 56, 57] {
661 relay::shutdown_relay(8000 + p)?;
662 }
663 Ok(())
664 });
665
666 // launch relay
667 let _ = join!(
668 r51.listen_until_close(),
669 r52.listen_until_close(),
670 r53.listen_until_close(),
671 r55.listen_until_close(),
672 r56.listen_until_close(),
673 r57.listen_until_close(),
674 );
675 cli_tester_handle.join().unwrap()?;
676 Ok(())
677 }
678
679 #[tokio::test]
680 #[serial]
681 async fn check_cli_output() -> Result<()> {
682 run_test_async().await?;
683 Ok(())
684 }
685 }
686 }
687} 510}
688 511// TODO: when_updating_existing_repoistory correct defaults are used
689// TODO: when_updating_existing_repoistory