From 8521fda04c2b2e9901311c8016a4093ab3eb7960 Mon Sep 17 00:00:00 2001 From: korvyashka Date: Mon, 6 May 2024 19:26:22 +0400 Subject: [PATCH] Adds: deleting missing settings. --- src/cli.rs | 10 ++- src/commands/edge_app.rs | 116 +++++++++++++++++++++++++++++++-- src/commands/edge_app_utils.rs | 16 ++++- src/commands/mod.rs | 2 + 4 files changed, 136 insertions(+), 8 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index aad4665..31a5b01 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -343,6 +343,9 @@ pub enum EdgeAppCommands { /// Edge App id. If not specified CLI will use the id from the manifest. #[arg(short, long)] app_id: Option, + + #[arg(short, long)] + delete_missing_settings: Option, }, /// Deletes an Edge App. This cannot be undone. Delete { @@ -923,10 +926,15 @@ pub fn handle_cli_edge_app_command(command: &EdgeAppCommands) { EdgeAppCommands::List { json } => { handle_command_execution_result(edge_app_command.list(), json); } - EdgeAppCommands::Upload { path, app_id } => { + EdgeAppCommands::Upload { + path, + app_id, + delete_missing_settings, + } => { match edge_app_command.upload( transform_edge_app_path_to_manifest(path).as_path(), app_id.clone(), + *delete_missing_settings, ) { Ok(revision) => { println!( diff --git a/src/commands/edge_app.rs b/src/commands/edge_app.rs index 1488c8b..ea359f9 100644 --- a/src/commands/edge_app.rs +++ b/src/commands/edge_app.rs @@ -6,7 +6,7 @@ use crate::commands::{CommandError, EdgeAppSecrets, EdgeAppSettings, EdgeAppVers use indicatif::ProgressBar; use log::debug; use std::collections::HashMap; -use std::{str, thread}; +use std::{io, str, thread}; use reqwest::header::HeaderMap; use reqwest::StatusCode; @@ -388,7 +388,12 @@ impl EdgeAppCommand { Ok(()) } - pub fn upload(self, path: &Path, app_id: Option) -> Result { + pub fn upload( + self, + path: &Path, + app_id: Option, + delete_missing_settings: Option, + ) -> Result { EdgeAppManifest::ensure_manifest_is_valid(path)?; let mut manifest = EdgeAppManifest::new(path)?; @@ -432,6 +437,25 @@ impl EdgeAppCommand { let changed_settings = detect_changed_settings(&manifest, &remote_settings)?; self.upload_changed_settings(actual_app_id.clone(), &changed_settings)?; + match { delete_missing_settings } { + Some(delete) => { + if delete { + self.delete_deleted_settings( + actual_app_id.clone(), + &changed_settings.deleted, + false, + )?; + } + } + None => { + self.delete_deleted_settings( + actual_app_id.clone(), + &changed_settings.deleted, + true, + )?; + } + } + let file_tree = generate_file_tree(&local_files, edge_app_dir); let old_file_tree = self.get_file_tree(actual_app_id, revision); @@ -833,6 +857,18 @@ impl EdgeAppCommand { Ok(()) } + fn delete_deleted_settings( + &self, + app_id: String, + deleted: &Vec, + prompt_user: bool, + ) -> Result<(), CommandError> { + for setting in deleted { + self.try_delete_setting(app_id.clone(), setting, prompt_user)?; + } + Ok(()) + } + fn upload_changed_files( &self, edge_app_dir: &Path, @@ -916,6 +952,56 @@ impl EdgeAppCommand { Ok(()) } + fn delete_setting(&self, app_id: String, setting: &Setting) -> Result<(), CommandError> { + let response = commands::delete( + &self.authentication, + &format!( + "v4.1/edge-apps/settings?app_id=eq.{id}&name=eq.{name}", + id = app_id, + name = setting.name + ), + ); + + if let Err(error) = response { + debug!("Failed to delete setting: {}", setting.name); + return Err(error); + } + + Ok(()) + } + + fn try_delete_setting( + &self, + app_id: String, + setting: &Setting, + prompt_user: bool, + ) -> Result<(), CommandError> { + debug!("Deleting setting: {:?}", &setting.name); + + let mut input_name = String::new(); + + if !prompt_user { + return self.delete_setting(app_id, setting); + } + + let prompt = format!("It seems like the setting \"{}\" is absent in the YAML file, but it exists on the server. If you wish to skip deletion, you can leave the input blank. Warning, deleting the setting will drop all the associated values. To proceed with deletion, please confirm the setting name by writing it down: ", setting.name); + println!("{}", prompt); + io::stdin() + .read_line(&mut input_name) + .expect("Failed to read input"); + + if input_name.trim() == "" { + return Ok(()); + } + + if input_name.trim() != setting.name { + // Should we ask for confirmation again if user input is wrong? + return Err(CommandError::WrongSettingName(setting.name.to_string())); + } + + self.delete_setting(app_id, setting) + } + fn copy_edge_app_assets( &self, app_id: &str, @@ -2289,6 +2375,19 @@ mod tests { }])); }); + let settings_mock_delete = mock_server.mock(|when, then| { + when.method(DELETE) + .path("/v4.1/edge-apps/settings") + .header("Authorization", "Token token") + .header( + "user-agent", + format!("screenly-cli {}", env!("CARGO_PKG_VERSION")), + ) + .query_param("app_id", "eq.01H2QZ6Z8WXWNDC0KQ198XCZEW") + .query_param("name", "eq.isetting"); + then.status(204).json_body(json!({})); + }); + let copy_assets_mock = mock_server.mock(|when, then| { when.method(POST) .path("/v4/edge-apps/copy-assets") @@ -2383,7 +2482,11 @@ mod tests { let config = Config::new(mock_server.base_url()); let authentication = Authentication::new_with_config(config, "token"); let command = EdgeAppCommand::new(authentication); - let result = command.upload(temp_dir.path().join("screenly.yml").as_path(), None); + let result = command.upload( + temp_dir.path().join("screenly.yml").as_path(), + None, + Some(true), + ); last_versions_mock.assert_hits(2); assets_mock.assert(); @@ -2392,6 +2495,7 @@ mod tests { create_version_mock.assert(); settings_mock_create.assert(); settings_mock_patch.assert(); + settings_mock_delete.assert(); upload_assets_mock.assert(); finished_processing_mock.assert(); publish_mock.assert(); @@ -3275,7 +3379,11 @@ settings: let config = Config::new(mock_server.base_url()); let authentication = Authentication::new_with_config(config, "token"); let command = EdgeAppCommand::new(authentication); - let result = command.upload(temp_dir.path().join("screenly.yml").as_path(), None); + let result = command.upload( + temp_dir.path().join("screenly.yml").as_path(), + None, + Some(true), + ); assert!(result.is_err()); assert_eq!( diff --git a/src/commands/edge_app_utils.rs b/src/commands/edge_app_utils.rs index ad2e9e6..e47b2b7 100644 --- a/src/commands/edge_app_utils.rs +++ b/src/commands/edge_app_utils.rs @@ -21,6 +21,7 @@ pub struct EdgeAppFile { pub struct SettingChanges { pub creates: Vec, pub updates: Vec, + pub deleted: Vec, } #[derive(Debug)] @@ -124,6 +125,7 @@ pub fn detect_changed_settings( manifest: &EdgeAppManifest, remote_settings: &[Setting], ) -> Result { + // Remote and local settings MUST be sorted. // This function compares remote and local settings // And returns if there are any new local settings missing from the remote // And changed settings to update @@ -131,6 +133,7 @@ pub fn detect_changed_settings( let mut creates = Vec::new(); let mut updates = Vec::new(); + let mut deleted: Vec = Vec::new(); let mut remote_iter = remote_settings.iter().peekable(); let mut new_iter = new_settings.iter().peekable(); @@ -145,6 +148,7 @@ pub fn detect_changed_settings( new_iter.next(); } std::cmp::Ordering::Less => { + deleted.push(remote_setting.clone()); remote_iter.next(); } std::cmp::Ordering::Greater => { @@ -155,8 +159,13 @@ pub fn detect_changed_settings( } creates.extend(new_iter.cloned()); + deleted.extend(remote_iter.cloned()); - Ok(SettingChanges { creates, updates }) + Ok(SettingChanges { + creates, + updates, + deleted, + }) } pub fn generate_file_tree(files: &[EdgeAppFile], root_path: &Path) -> HashMap { @@ -248,7 +257,7 @@ mod tests { } #[test] - fn test_detect_changes_settings_when_setting_removed_should_not_detect_changes() { + fn test_detect_changes_settings_when_setting_removed_should_detect_deleted_changes() { // Arrange let manifest = create_manifest(); @@ -288,7 +297,8 @@ mod tests { // Assert assert!(result.is_ok()); let changes = result.unwrap(); - assert_eq!(changes.creates.len(), 0); + assert_eq!(changes.deleted.len(), 1); + assert_eq!(changes.deleted[0].name, "new_setting"); } #[test] diff --git a/src/commands/mod.rs b/src/commands/mod.rs index cdc3d9e..cdac3f3 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -124,6 +124,8 @@ pub enum CommandError { MisingManifest(String), #[error("Setting does not exist: {0}.")] SettingDoesNotExist(String), + #[error("Wrong setting name: {0}.")] + WrongSettingName(String), } pub fn get(