From 5a5c16465a7d489b125a5c0ad8864c2151bc9978 Mon Sep 17 00:00:00 2001 From: Tarek Date: Sat, 29 Jul 2023 07:57:03 +0300 Subject: [PATCH 1/3] feat(core): implement the search command Signed-off-by: Tarek --- coffee_cmd/src/cmd.rs | 4 ++++ coffee_cmd/src/main.rs | 8 ++++++++ coffee_core/src/coffee.rs | 13 +++++++++++++ coffee_core/src/lib.rs | 2 ++ coffee_lib/src/plugin_manager.rs | 3 +++ coffee_lib/src/types/mod.rs | 6 ++++++ docs/docs-book/src/using-coffee.md | 8 ++++++++ 7 files changed, 44 insertions(+) diff --git a/coffee_cmd/src/cmd.rs b/coffee_cmd/src/cmd.rs index 77f4699f..0025d671 100644 --- a/coffee_cmd/src/cmd.rs +++ b/coffee_cmd/src/cmd.rs @@ -50,6 +50,9 @@ pub enum CoffeeCommand { /// show the README file of the plugin #[clap(arg_required_else_help = true)] Show { plugin: String }, + /// search the remote repositories for a plugin + #[clap(arg_required_else_help = true)] + Search { plugin: String }, /// clean up remote repositories storage information #[clap(arg_required_else_help = false)] Nurse {}, @@ -76,6 +79,7 @@ impl From<&CoffeeCommand> for coffee_core::CoffeeOperation { CoffeeCommand::Remote { action } => Self::Remote(action.into()), CoffeeCommand::Remove { plugin } => Self::Remove(plugin.to_owned()), CoffeeCommand::Show { plugin } => Self::Show(plugin.to_owned()), + CoffeeCommand::Search { plugin } => Self::Search(plugin.to_owned()), CoffeeCommand::Nurse {} => Self::Nurse, } } diff --git a/coffee_cmd/src/main.rs b/coffee_cmd/src/main.rs index f3b773a0..7355076b 100644 --- a/coffee_cmd/src/main.rs +++ b/coffee_cmd/src/main.rs @@ -115,6 +115,14 @@ async fn main() -> Result<(), CoffeeError> { } Err(err) => Err(err), }, + CoffeeCommand::Search { plugin } => match coffee.search(&plugin).await { + Ok(val) => { + let repository_url = val.repository_url.as_str(); + term::success!("found plugin {plugin} in remote repository {repository_url}"); + Ok(()) + } + Err(err) => Err(err), + }, CoffeeCommand::Nurse {} => { term::info!("Nurse command is not implemented"); Ok(()) diff --git a/coffee_core/src/coffee.rs b/coffee_core/src/coffee.rs index 1eccc522..79e98229 100644 --- a/coffee_core/src/coffee.rs +++ b/coffee_core/src/coffee.rs @@ -379,6 +379,19 @@ impl PluginManager for CoffeeManager { Err(err) } + async fn search(&mut self, plugin: &str) -> Result { + for repo in self.repos.values() { + if let Some(plugin) = repo.get_plugin_by_name(plugin) { + return Ok(CoffeeSearch { + repository_url: repo.url().url_string, + plugin, + }); + } + } + let err = CoffeeError::new(404, &format!("unable to locate plugin `{plugin}`")); + Err(err) + } + async fn nurse(&mut self) -> Result<(), CoffeeError> { unimplemented!("nurse command is not implemented") } diff --git a/coffee_core/src/lib.rs b/coffee_core/src/lib.rs index 7fe6203b..5968bb4d 100644 --- a/coffee_core/src/lib.rs +++ b/coffee_core/src/lib.rs @@ -17,6 +17,8 @@ pub enum CoffeeOperation { /// Setup(core lightning root path) Setup(String), Show(String), + /// Search(plugin name) + Search(String), Nurse, } diff --git a/coffee_lib/src/plugin_manager.rs b/coffee_lib/src/plugin_manager.rs index 48583461..6028e610 100644 --- a/coffee_lib/src/plugin_manager.rs +++ b/coffee_lib/src/plugin_manager.rs @@ -43,6 +43,9 @@ pub trait PluginManager { /// show the README file of the plugin async fn show(&mut self, plugin: &str) -> Result; + /// search remote repositories for a plugin by name + async fn search(&mut self, plugin: &str) -> Result; + /// clean up storage information about the remote repositories of the plugin manager. async fn nurse(&mut self) -> Result<(), CoffeeError>; } diff --git a/coffee_lib/src/types/mod.rs b/coffee_lib/src/types/mod.rs index bfec37e7..d6b20d38 100644 --- a/coffee_lib/src/types/mod.rs +++ b/coffee_lib/src/types/mod.rs @@ -118,4 +118,10 @@ pub mod response { pub struct CoffeeShow { pub readme: String, } + + #[derive(Clone, Debug, Serialize, Deserialize)] + pub struct CoffeeSearch { + pub repository_url: String, + pub plugin: Plugin, + } } diff --git a/docs/docs-book/src/using-coffee.md b/docs/docs-book/src/using-coffee.md index 3742d06d..3bc27d7f 100644 --- a/docs/docs-book/src/using-coffee.md +++ b/docs/docs-book/src/using-coffee.md @@ -130,6 +130,14 @@ coffee list ```bash coffee show ``` + +## Searching for a plugin in remote repositories + +> ✅ Implemented + +```bash +coffee search +``` _________ ## Running coffee as a server From 6f8a742cf197a0af983881d9ed0eadbe0c0244c6 Mon Sep 17 00:00:00 2001 From: Tarek Date: Sat, 29 Jul 2023 19:48:24 +0300 Subject: [PATCH 2/3] feat(httpd): implement the search endpoint Signed-off-by: Tarek --- coffee_httpd/src/httpd/server.rs | 15 +++++++++++++++ coffee_lib/src/types/mod.rs | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/coffee_httpd/src/httpd/server.rs b/coffee_httpd/src/httpd/server.rs index f40c600f..743f89eb 100644 --- a/coffee_httpd/src/httpd/server.rs +++ b/coffee_httpd/src/httpd/server.rs @@ -60,6 +60,7 @@ pub async fn run_httpd( .service(coffee_remote_rm) .service(coffee_remote_list) .service(coffee_show) + .service(coffee_search) .with_json_spec_at("/api/v1") .build() }) @@ -168,6 +169,20 @@ async fn coffee_show(data: web::Data, body: Json) -> Result, + body: Json, +) -> Result, Error> { + let plugin = &body.plugin; + + let mut coffee = data.coffee.lock().await; + let result = coffee.search(plugin).await; + + handle_httpd_response!(result) +} + // this is just a hack to support swagger UI with https://paperclip-rs.github.io/paperclip/ // and the raw html is taken from https://github.com/swagger-api/swagger-ui/blob/master/docs/usage/installation.md#unpkg #[get("/")] diff --git a/coffee_lib/src/types/mod.rs b/coffee_lib/src/types/mod.rs index d6b20d38..5cb4469f 100644 --- a/coffee_lib/src/types/mod.rs +++ b/coffee_lib/src/types/mod.rs @@ -68,6 +68,11 @@ pub mod request { pub struct Show { pub plugin: String, } + + #[derive(Debug, Deserialize, Apiv2Schema, Serialize)] + pub struct Search { + pub plugin: String, + } } // Definition of the response types. From de52027f7e402c6509c159e2dd81ceeefa70fd4c Mon Sep 17 00:00:00 2001 From: Tarek Date: Sat, 29 Jul 2023 19:48:40 +0300 Subject: [PATCH 3/3] feat(test): add assertions for search command and httpd endpoint Signed-off-by: Tarek --- tests/src/coffee_httpd_integration_tests.rs | 35 +++++++++++++++++++++ tests/src/coffee_integration_tests.rs | 13 +++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/tests/src/coffee_httpd_integration_tests.rs b/tests/src/coffee_httpd_integration_tests.rs index ed749534..8a4ecc4b 100644 --- a/tests/src/coffee_httpd_integration_tests.rs +++ b/tests/src/coffee_httpd_integration_tests.rs @@ -134,6 +134,41 @@ pub async fn httpd_add_remove_plugins() { // Assert that the `readme` starts with the expected content assert!(readme.starts_with("# Helpme plugin"), "{:?}", readme); + // Define the request body to be sent to the /search endpoint + let search_request = Search { + plugin: "summary".to_string(), + }; + + let response = client + .get(format!("{}/search", url)) + .json(&search_request) + .send() + .await; + assert!(response.is_ok(), "{:?}", response); + let response = response.unwrap(); + + // Check the response status code, log the body. + assert!(response.status().is_success()); + let body = response.text().await.unwrap(); + log::info!("/search response: {}", body); + + // Parse the response body + let response_json = serde_json::from_str(&body); + assert!(response_json.is_ok(), "{:?}", response_json); + let response_json: serde_json::Value = response_json.unwrap(); + + // Extract the `repository_url` field from the response JSON + let repository_url = response_json["repository_url"].as_str(); + assert!(repository_url.is_some(), "{:?}", repository_url); + let repository_url = repository_url.unwrap(); + + // Assert that repository_url is the expected value + assert_eq!( + repository_url, "https://github.com/lightningd/plugins", + "{:?}", + repository_url + ); + // Define the request body to be sent to the /install endpoint let install_request = Install { plugin: "summary".to_string(), diff --git a/tests/src/coffee_integration_tests.rs b/tests/src/coffee_integration_tests.rs index eb1ffb28..d9faee89 100644 --- a/tests/src/coffee_integration_tests.rs +++ b/tests/src/coffee_integration_tests.rs @@ -84,7 +84,7 @@ pub async fn init_coffee_test_with_cln() -> anyhow::Result<()> { } #[tokio::test] -//#[ntest::timeout(120000)] +#[ntest::timeout(560000)] pub async fn init_coffee_test_add_remote() { init(); let mut cln = Node::tmp("regtest").await.unwrap(); @@ -240,6 +240,17 @@ pub async fn test_errors_and_show() { .await .unwrap(); + // Search for summary plugin + let result = manager.coffee().search("summary").await; + assert!(result.is_ok(), "{:?}", result); + let result = result.unwrap(); + let repo_url = result.repository_url.as_str(); + assert_eq!( + repo_url, "https://github.com/lightningd/plugins", + "{:?}", + repo_url + ); + // Install summary plugin let result = manager.coffee().install("summary", true, false).await; assert!(result.is_ok(), "{:?}", result);