diff --git a/aider/main.py b/aider/main.py index c7364dc84..2162ec8a2 100644 --- a/aider/main.py +++ b/aider/main.py @@ -19,6 +19,54 @@ def get_git_root(): return None +def setup_git(git_root, io): + if git_root: + return git_root + + if not io.confirm_ask("No git repo found, create one to track GPT's changes (recommended)?"): + return + + repo = git.Repo.init(Path.cwd()) + global_git_config = git.GitConfigParser([str(Path.home() / ".gitconfig")], read_only=True) + with repo.config_writer() as git_config: + if not global_git_config.has_option("user", "name"): + git_config.set_value("user", "name", "Your Name") + io.tool_error('Update git name with: git config --global user.name "Your Name"') + if not global_git_config.has_option("user", "email"): + git_config.set_value("user", "email", "you@example.com") + io.tool_error('Update git email with: git config --global user.email "you@example.com"') + + io.tool_output("Git repository created in the current working directory.") + git_root = str(Path.cwd().resolve()) + check_gitignore(git_root, io, False) + return git_root + + +def check_gitignore(git_root, io, ask=True): + if not git_root: + return + + pat = ".aider*" + + gitignore_file = Path(git_root) / ".gitignore" + if gitignore_file.exists(): + content = io.read_text(gitignore_file) + if pat in content.splitlines(): + return + else: + content = "" + + if ask and not io.confirm_ask(f"Add {pat} to .gitignore (recommended)?"): + return + + if content and not content.endswith("\n"): + content += "\n" + content += pat + "\n" + io.write_text(gitignore_file, content) + + io.tool_output(f"Added {pat} to .gitignore") + + def main(args=None, input=None, output=None): if args is None: args = sys.argv[1:] @@ -321,26 +369,13 @@ def main(args=None, input=None, output=None): io.tool_output(f"Aider v{__version__}") - if not git_root and args.git: - if io.confirm_ask("No git repo found, create one to track GPT's changes (recommended)?"): - repo = git.Repo.init(os.getcwd()) - global_git_config = git.GitConfigParser( - [str(Path.home() / ".gitconfig")], read_only=True - ) - with repo.config_writer() as git_config: - if not global_git_config.has_option("user", "name"): - git_config.set_value("user", "name", "Your Name") - io.tool_error('Update git name with: git config --global user.name "Your Name"') - if not global_git_config.has_option("user", "email"): - git_config.set_value("user", "email", "you@example.com") - io.tool_error( - 'Update git email with: git config --global user.email "you@example.com"' - ) - io.tool_output("Git repository created in the current working directory.") + if args.git: + git_root = setup_git(git_root, io) + check_gitignore(git_root, io) def scrub_sensitive_info(text): # Replace sensitive information with placeholder - return text.replace(args.openai_api_key, '***') + return text.replace(args.openai_api_key, "***") if args.verbose: show = scrub_sensitive_info(parser.format_values()) diff --git a/tests/test_main.py b/tests/test_main.py index c8fdf9406..e85c8439d 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -6,11 +6,14 @@ from pathlib import Path from unittest import TestCase from unittest.mock import patch +import git from prompt_toolkit.input import DummyInput from prompt_toolkit.output import DummyOutput from aider.dump import dump # noqa: F401 -from aider.main import main +from aider.io import InputOutput +from aider.main import check_gitignore, main, setup_git +from tests.utils import make_repo class TestMain(TestCase): @@ -36,20 +39,16 @@ class TestMain(TestCase): self.assertTrue(os.path.exists("foo.txt")) def test_main_with_empty_git_dir_new_file(self): - subprocess.run(["git", "init"]) - subprocess.run(["git", "config", "user.email", "dummy@example.com"]) - subprocess.run(["git", "config", "user.name", "Dummy User"]) + make_repo() main(["--yes", "foo.txt"], input=DummyInput(), output=DummyOutput()) self.assertTrue(os.path.exists("foo.txt")) def test_main_with_git_config_yml(self): - subprocess.run(["git", "init"]) - subprocess.run(["git", "config", "user.email", "dummy@example.com"]) - subprocess.run(["git", "config", "user.name", "Dummy User"]) + make_repo() Path(".aider.conf.yml").write_text("no-auto-commits: true\n") with patch("aider.main.Coder.create") as MockCoder: - main([], input=DummyInput(), output=DummyOutput()) + main(["--yes"], input=DummyInput(), output=DummyOutput()) _, kwargs = MockCoder.call_args assert kwargs["auto_commits"] is False @@ -60,9 +59,7 @@ class TestMain(TestCase): assert kwargs["auto_commits"] is True def test_main_with_empty_git_dir_new_subdir_file(self): - subprocess.run(["git", "init"]) - subprocess.run(["git", "config", "user.email", "dummy@example.com"]) - subprocess.run(["git", "config", "user.name", "Dummy User"]) + make_repo() subdir = Path("subdir") subdir.mkdir() fname = subdir / "foo.txt" @@ -75,6 +72,45 @@ class TestMain(TestCase): # Because aider will try and `git add` a file that's already in the repo. main(["--yes", str(fname)], input=DummyInput(), output=DummyOutput()) + def test_setup_git(self): + io = InputOutput(pretty=False, yes=True) + git_root = setup_git(None, io) + git_root = Path(git_root).resolve() + self.assertEqual(git_root, Path(self.tempdir).resolve()) + + self.assertTrue(git.Repo(self.tempdir)) + + gitignore = Path.cwd() / ".gitignore" + self.assertTrue(gitignore.exists()) + self.assertEqual(".aider*", gitignore.read_text().splitlines()[0]) + + def test_check_gitignore(self): + make_repo() + io = InputOutput(pretty=False, yes=True) + cwd = Path.cwd() + gitignore = cwd / ".gitignore" + + self.assertFalse(gitignore.exists()) + check_gitignore(cwd, io) + self.assertTrue(gitignore.exists()) + + self.assertEqual(".aider*", gitignore.read_text().splitlines()[0]) + + gitignore.write_text("one\ntwo\n") + check_gitignore(cwd, io) + self.assertEqual("one\ntwo\n.aider*\n", gitignore.read_text()) + + def test_main_git_ignore(self): + cwd = Path().cwd() + self.assertFalse((cwd / ".git").exists()) + self.assertFalse((cwd / ".gitignore").exists()) + + with patch("aider.main.Coder.create"): + main(["--yes"], input=DummyInput()) + + self.assertTrue((cwd / ".git").exists()) + self.assertTrue((cwd / ".gitignore").exists()) + def test_main_args(self): with patch("aider.main.Coder.create") as MockCoder: # --yes will just ok the git repo without blocking on input