diff --git a/cli/aitbc_cli/commands/config.py b/cli/aitbc_cli/commands/config.py index 40c2567..7d66688 100644 --- a/cli/aitbc_cli/commands/config.py +++ b/cli/aitbc_cli/commands/config.py @@ -2,6 +2,8 @@ import click import os +import shlex +import subprocess import yaml import json from pathlib import Path @@ -128,8 +130,9 @@ def edit(ctx, global_config: bool): yaml.dump(config_data, f, default_flow_style=False) # Open in editor - editor = os.getenv('EDITOR', 'nano') - os.system(f"{editor} {config_file}") + editor = os.getenv('EDITOR', 'nano').strip() or 'nano' + editor_cmd = shlex.split(editor) + subprocess.run([*editor_cmd, str(config_file)], check=False) @config.command() diff --git a/docs/8_development/1_overview.md b/docs/8_development/1_overview.md index adf645c..b0c20d0 100644 --- a/docs/8_development/1_overview.md +++ b/docs/8_development/1_overview.md @@ -153,7 +153,7 @@ Choose a tutorial based on your interest: ### Community - [Discord](https://discord.gg/aitbc) -- [GitHub Discussions](https://github.com/aitbc/discussions) +- [GitHub Discussions](https://github.com/oib/AITBC/discussions) - [Stack Overflow](https://stackoverflow.com/questions/tagged/aitbc) ## Development Workflow diff --git a/tests/cli/test_config.py b/tests/cli/test_config.py index 1f92b76..ad4f772 100644 --- a/tests/cli/test_config.py +++ b/tests/cli/test_config.py @@ -145,8 +145,8 @@ def test_path_global(self, runner, mock_config): assert result.exit_code == 0 assert '.config/aitbc/config.yaml' in result.output - @patch('os.system') - def test_edit_command(self, mock_system, runner, mock_config, tmp_path): + @patch('aitbc_cli.commands.config.subprocess.run') + def test_edit_command(self, mock_run, runner, mock_config, tmp_path): """Test editing configuration file""" # Change to the tmp_path directory @@ -160,9 +160,10 @@ def test_edit_command(self, mock_system, runner, mock_config, tmp_path): assert result.exit_code == 0 # Verify editor was called - mock_system.assert_called_once() - assert 'nano' in mock_system.call_args[0][0] - assert str(actual_config_file) in mock_system.call_args[0][0] + mock_run.assert_called_once() + args = mock_run.call_args[0][0] + assert args[0] == 'nano' + assert str(actual_config_file) in args def test_reset_config_cancelled(self, runner, mock_config, temp_config_file): """Test config reset cancelled by user""" @@ -267,6 +268,22 @@ def test_export_empty_yaml(self, runner, mock_config, tmp_path): data = json.loads(result.output) assert data == {} + + def test_export_empty_yaml_yaml_format(self, runner, mock_config, tmp_path): + """Test exporting an empty YAML config file as YAML""" + with runner.isolated_filesystem(temp_dir=tmp_path): + local_config = Path.cwd() / ".aitbc.yaml" + local_config.write_text("") + + result = runner.invoke(config, [ + 'export', + '--format', 'yaml' + ], obj={'config': mock_config, 'output_format': 'table'}) + + assert result.exit_code == 0 + data = yaml.safe_load(result.output) + assert data == {} + def test_export_no_config(self, runner, mock_config): """Test export when no config file exists""" with runner.isolated_filesystem():