From 8edbc75bf41794ac9476025c23d120262cf66cbd Mon Sep 17 00:00:00 2001 From: Vysakh Sreenivasan Date: Sat, 20 Jul 2024 00:25:42 +0530 Subject: [PATCH] handle skip gracefully --- src/drd/cli/query/dynamic_command_handler.py | 57 +++++++------ src/drd/utils/step_executor.py | 6 +- .../cli/query/test_dynamic_command_handler.py | 80 ++++++++++++++++++- 3 files changed, 114 insertions(+), 29 deletions(-) diff --git a/src/drd/cli/query/dynamic_command_handler.py b/src/drd/cli/query/dynamic_command_handler.py index fe865ce..15cdbb5 100644 --- a/src/drd/cli/query/dynamic_command_handler.py +++ b/src/drd/cli/query/dynamic_command_handler.py @@ -19,30 +19,31 @@ def execute_commands(commands, executor, metadata_manager, is_fix=False, debug=F print_info(f"Explanation: {cmd['content']}") all_outputs.append( f"Step {i}/{total_steps}: Explanation - {cmd['content']}") - continue - - try: - if cmd['type'] == 'shell': - output = handle_shell_command(cmd, executor) - all_outputs.append( - f"Step {i}/{total_steps}: Shell command - {cmd['command']}\nOutput: {output}") - elif cmd['type'] == 'file': - output = handle_file_operation(cmd, executor, metadata_manager) - all_outputs.append( - f"Step {i}/{total_steps}: File operation - {cmd['operation']} - {cmd['filename']} - {output}") - elif cmd['type'] == 'metadata': - output = handle_metadata_operation(cmd, metadata_manager) - all_outputs.append( - f"Step {i}/{total_steps}: Metadata operation - {cmd['operation']} - {output}") - - if debug: - print_debug(f"Completed step {i}/{total_steps}") - - except Exception as e: - error_message = f"Step {i}/{total_steps}: Error executing {step_description}: {cmd}\nError details: {str(e)}" - print_error(error_message) - all_outputs.append(error_message) - return False, i, str(e), "\n".join(all_outputs) + else: + try: + if cmd['type'] == 'shell': + output = handle_shell_command(cmd, executor) + elif cmd['type'] == 'file': + output = handle_file_operation( + cmd, executor, metadata_manager) + elif cmd['type'] == 'metadata': + output = handle_metadata_operation(cmd, metadata_manager) + + if isinstance(output, str) and output.startswith("Skipping"): + print_info(f"Step {i}/{total_steps}: {output}") + all_outputs.append(f"Step {i}/{total_steps}: {output}") + else: + all_outputs.append( + f"Step {i}/{total_steps}: {cmd['type'].capitalize()} command - {cmd.get('command', '')} {cmd.get('operation', '')}\nOutput: {output}") + + except Exception as e: + error_message = f"Step {i}/{total_steps}: Error executing {step_description}: {cmd}\nError details: {str(e)}" + print_error(error_message) + all_outputs.append(error_message) + return False, i, str(e), "\n".join(all_outputs) + + if debug: + print_debug(f"Completed step {i}/{total_steps}") return True, total_steps, None, "\n".join(all_outputs) @@ -50,6 +51,9 @@ def execute_commands(commands, executor, metadata_manager, is_fix=False, debug=F def handle_shell_command(cmd, executor): print_info(f"Executing shell command: {cmd['command']}") output = executor.execute_shell_command(cmd['command']) + if isinstance(output, str) and output.startswith("Skipping"): + print_info(output) + return output if output is None: raise Exception(f"Command failed: {cmd['command']}") print_success(f"Successfully executed: {cmd['command']}") @@ -67,7 +71,10 @@ def handle_file_operation(cmd, executor, metadata_manager): cmd.get('content'), force=True ) - if operation_performed: + if isinstance(operation_performed, str) and operation_performed.startswith("Skipping"): + print_info(operation_performed) + return operation_performed + elif operation_performed: print_success( f"Successfully performed {cmd['operation']} on file: {cmd['filename']}") if cmd['operation'] in ['CREATE', 'UPDATE']: diff --git a/src/drd/utils/step_executor.py b/src/drd/utils/step_executor.py index af71074..d11b89b 100644 --- a/src/drd/utils/step_executor.py +++ b/src/drd/utils/step_executor.py @@ -78,7 +78,7 @@ def perform_file_operation(self, operation, filename, content=None, force=False) return True else: print_info("File creation cancelled by user.") - return False + return "Skipping this step" except Exception as e: print_error(f"Error creating file: {str(e)}") return False @@ -107,7 +107,7 @@ def perform_file_operation(self, operation, filename, content=None, force=False) return True else: print_info(f"File update cancelled by user.") - return False + return "Skipping this step" else: print_error( "No content or changes provided for update operation") @@ -134,7 +134,7 @@ def perform_file_operation(self, operation, filename, content=None, force=False) return False else: print_info("File deletion cancelled by user.") - return False + return "Skipping this step" else: print_error(f"Unknown file operation: {operation}") diff --git a/tests/cli/query/test_dynamic_command_handler.py b/tests/cli/query/test_dynamic_command_handler.py index 055ad5c..3707951 100644 --- a/tests/cli/query/test_dynamic_command_handler.py +++ b/tests/cli/query/test_dynamic_command_handler.py @@ -41,7 +41,7 @@ def test_execute_commands(self, mock_print_debug, mock_print_info, mock_print_st self.assertIsNone(error) self.assertIn("Explanation - Test explanation", output) self.assertIn("Shell command - echo \"Hello\"", output) - self.assertIn("File operation - CREATE - test.txt", output) + self.assertIn("File command - CREATE - test.txt", output) mock_print_debug.assert_called_with("Completed step 3/3") @patch('drd.cli.query.dynamic_command_handler.print_info') @@ -117,3 +117,81 @@ def test_handle_error_with_dravid(self, mock_echo, mock_execute_commands, mock_execute_commands.assert_called_once() mock_print_success.assert_called_with( "All fix steps successfully applied.") + + @patch('drd.cli.query.dynamic_command_handler.print_info') + @patch('drd.cli.query.dynamic_command_handler.print_success') + @patch('drd.cli.query.dynamic_command_handler.click.echo') + def test_handle_shell_command_skipped(self, mock_echo, mock_print_success, mock_print_info): + cmd = {'command': 'echo "Hello"'} + self.executor.execute_shell_command.return_value = "Skipping this step..." + + output = handle_shell_command(cmd, self.executor) + + self.assertEqual(output, "Skipping this step...") + self.executor.execute_shell_command.assert_called_once_with( + 'echo "Hello"') + mock_print_info.assert_any_call( + 'Executing shell command: echo "Hello"') + mock_print_info.assert_any_call("Skipping this step...") + mock_print_success.assert_not_called() + mock_echo.assert_not_called() + + @patch('drd.cli.query.dynamic_command_handler.print_step') + @patch('drd.cli.query.dynamic_command_handler.print_info') + @patch('drd.cli.query.dynamic_command_handler.print_debug') + def test_execute_commands(self, mock_print_debug, mock_print_info, mock_print_step): + commands = [ + {'type': 'explanation', 'content': 'Test explanation'}, + {'type': 'shell', 'command': 'echo "Hello"'}, + {'type': 'file', 'operation': 'CREATE', + 'filename': 'test.txt', 'content': 'Test content'}, + ] + + with patch('drd.cli.query.dynamic_command_handler.handle_shell_command', return_value="Shell output") as mock_shell, \ + patch('drd.cli.query.dynamic_command_handler.handle_file_operation', return_value="File operation success") as mock_file, \ + patch('drd.cli.query.dynamic_command_handler.handle_metadata_operation', return_value="Metadata operation success") as mock_metadata: + + success, steps_completed, error, output = execute_commands( + commands, self.executor, self.metadata_manager, debug=True) + + self.assertTrue(success) + self.assertEqual(steps_completed, 3) + self.assertIsNone(error) + self.assertIn("Explanation - Test explanation", output) + self.assertIn("Shell command - echo \"Hello\"", output) + self.assertIn("File command - CREATE", output) + mock_print_debug.assert_has_calls([ + call("Completed step 1/3"), + call("Completed step 2/3"), + call("Completed step 3/3") + ]) + + @patch('drd.cli.query.dynamic_command_handler.print_step') + @patch('drd.cli.query.dynamic_command_handler.print_info') + @patch('drd.cli.query.dynamic_command_handler.print_debug') + def test_execute_commands_with_skipped_steps(self, mock_print_debug, mock_print_info, mock_print_step): + commands = [ + {'type': 'explanation', 'content': 'Test explanation'}, + {'type': 'shell', 'command': 'echo "Hello"'}, + {'type': 'file', 'operation': 'CREATE', + 'filename': 'test.txt', 'content': 'Test content'}, + ] + + with patch('drd.cli.query.dynamic_command_handler.handle_shell_command', return_value="Skipping this step...") as mock_shell, \ + patch('drd.cli.query.dynamic_command_handler.handle_file_operation', return_value="Skipping this step...") as mock_file: + + success, steps_completed, error, output = execute_commands( + commands, self.executor, self.metadata_manager, debug=True) + + self.assertTrue(success) + self.assertEqual(steps_completed, 3) + self.assertIsNone(error) + self.assertIn("Explanation - Test explanation", output) + self.assertIn("Skipping this step...", output) + mock_print_info.assert_any_call("Step 2/3: Skipping this step...") + mock_print_info.assert_any_call("Step 3/3: Skipping this step...") + mock_print_debug.assert_has_calls([ + call("Completed step 1/3"), + call("Completed step 2/3"), + call("Completed step 3/3") + ])