diff --git a/redbot/cogs/downloader/repo_manager.py b/redbot/cogs/downloader/repo_manager.py index 8d9b3fa06cc..ef07d69b992 100644 --- a/redbot/cogs/downloader/repo_manager.py +++ b/redbot/cogs/downloader/repo_manager.py @@ -1044,7 +1044,7 @@ def repos_folder(self) -> Path: return data_folder / "repos" def does_repo_exist(self, name: str) -> bool: - return name in self._repos + return name.lower() in self._repos @staticmethod def validate_and_normalize_repo_name(name: str) -> str: @@ -1070,6 +1070,7 @@ async def add_repo(self, url: str, name: str, branch: Optional[str] = None) -> R New Repo object representing the cloned repository. """ + name = name.lower() # convert the repo name to lower case if self.does_repo_exist(name): raise errors.ExistingGitRepo( "That repo name you provided already exists. Please choose another." @@ -1102,6 +1103,7 @@ def get_repo(self, name: str) -> Optional[Repo]: Repo object for the repository, if it exists. """ + name = name.lower() return self._repos.get(name, None) @property @@ -1146,6 +1148,7 @@ async def delete_repo(self, name: str) -> None: If the repo does not exist. """ + name = name.lower() repo = self.get_repo(name) if repo is None: raise errors.MissingGitRepo(f"There is no repo with the name {name}") @@ -1172,6 +1175,7 @@ async def update_repo(self, repo_name: str) -> Tuple[Repo, Tuple[str, str]]: A 2-`tuple` with Repo object and a 2-`tuple` of `str` containing old and new commit hashes. """ + repo_name = repo_name.lower() repo = self._repos[repo_name] old, new = await repo.update() return (repo, (old, new)) diff --git a/tests/cogs/downloader/test_repo_manager_unittest.py b/tests/cogs/downloader/test_repo_manager_unittest.py new file mode 100644 index 00000000000..7afb4899b0b --- /dev/null +++ b/tests/cogs/downloader/test_repo_manager_unittest.py @@ -0,0 +1,84 @@ +import pytest +import asyncio +from pathlib import Path +from unittest.mock import AsyncMock, patch + +from redbot.cogs.downloader.repo_manager import RepoManager, errors, Repo + + +@pytest.mark.asyncio +async def test_add_repo_case_insensitive(tmp_path): + manager = RepoManager() + await manager.initialize() + + # Mock Repo.clone so it doesn't actually clone anything + with patch("redbot.cogs.downloader.repo_manager.Repo.clone", new_callable=AsyncMock): + # Add repo with uppercase name + repo1 = await manager.add_repo("https://example.com/repo.git", "TestRepo") + + # Adding same repo with lowercase name should raise ExistingGitRepo + with pytest.raises(errors.ExistingGitRepo): + await manager.add_repo("https://example.com/repo.git", "testrepo") + + # Check that repo is stored with lowercase key + assert "testrepo" in manager._repos + assert manager._repos["testrepo"] == repo1 + + +@pytest.mark.asyncio +async def test_delete_repo_case_insensitive(tmp_path): + manager = RepoManager() + await manager.initialize() + + with patch("redbot.cogs.downloader.repo_manager.Repo.clone", new_callable=AsyncMock): + await manager.add_repo("https://example.com/repo.git", "MyRepo") + + # Deleting with different casing should succeed + await manager.delete_repo("myrepo") # lowercase + assert "myrepo" not in manager._repos + + # Deleting a non-existent repo should raise MissingGitRepo + with pytest.raises(errors.MissingGitRepo): + await manager.delete_repo("myrepo") + + +@pytest.mark.asyncio +async def test_update_repo_case_insensitive(tmp_path): + manager = RepoManager() + await manager.initialize() + + # Mock Repo.update to return fake commit hashes + fake_update = AsyncMock(return_value=("oldhash", "newhash")) + with patch("redbot.cogs.downloader.repo_manager.Repo.clone", new_callable=AsyncMock): + repo = await manager.add_repo("https://example.com/repo.git", "UpdateRepo") + repo.update = fake_update + + # Call update_repo with different casing + updated_repo, (old, new) = await manager.update_repo("updaterepo") + assert updated_repo == repo + assert old == "oldhash" + assert new == "newhash" + + +@pytest.mark.asyncio +async def test_repo_existing_git_repo(tmp_path): + # Create a Repo instance + repo = Repo( + name="TestRepo", + url="https://example.com/repo.git", + branch=None, + commit="", + folder_path=tmp_path, + ) + + # Case 1: .git folder does not exist + exists, path = repo._existing_git_repo() + assert exists is False + assert path == tmp_path / ".git" + + # Case 2: .git folder exists + git_dir = tmp_path / ".git" + git_dir.mkdir() + exists, path = repo._existing_git_repo() + assert exists is True + assert path == git_dir