Repository: Cog-Creators/Red-DiscordBot

Issue:
[Downloader] Repo names cropped after restart
### What Red version are you using?

Reproduced on 3.4.18 and 3.5.0.dev287+gf02491a0

### What were you trying to do?

Add a repo with a repo name that included a period.

### What did you expect to happen?

The repo name to remain the same across restarts.

### What actually happened?

Everything in the repo name after the period was cropped.

### How can we reproduce this error?

1. `[p]repo add flame_3.5 https://github.com/Flame442/FlameCogs/`
2. `I agree` (if required)
3. `[p]repo list`, notice that the name is `flame_3.5`
4. `[p]restart`
5. `[p]repo list`, notice that the name is now `flame_3`


### Anything else?

There is a check "Repo names cannot start or end with a dot.", so unfortunately you cannot make a repo name that is completely unable to be entered after a restart.


Discussion:

Resolving patch:
diff --git a/redbot/cogs/downloader/downloader.py b/redbot/cogs/downloader/downloader.py
--- a/redbot/cogs/downloader/downloader.py
+++ b/redbot/cogs/downloader/downloader.py
@@ -529,7 +529,8 @@ async def _repo_add(
             - `[p]repo add 26-Cogs https://github.com/Twentysix26/x26-Cogs`
             - `[p]repo add Laggrons-Dumb-Cogs https://github.com/retke/Laggrons-Dumb-Cogs v3`
 
-        Repo names can only contain characters A-z, numbers, underscores, and hyphens.
+        Repo names can only contain characters A-z, numbers, underscores, hyphens, and dots (but they cannot start or end with a dot).
+
         The branch will be the default branch if not specified.
 
         **Arguments**
diff --git a/redbot/cogs/downloader/installable.py b/redbot/cogs/downloader/installable.py
--- a/redbot/cogs/downloader/installable.py
+++ b/redbot/cogs/downloader/installable.py
@@ -84,7 +84,7 @@ def __init__(self, location: Path, repo: Optional[Repo] = None, commit: str = ""
         self._location = location
 
         self.repo = repo
-        self.repo_name = self._location.parent.stem
+        self.repo_name = self._location.parent.name
         self.commit = commit
 
         self.end_user_data_statement: str
@@ -129,7 +129,7 @@ async def copy_to(self, target_dir: Path) -> bool:
 
         # noinspection PyBroadException
         try:
-            copy_func(src=str(self._location), dst=str(target_dir / self._location.stem))
+            copy_func(src=str(self._location), dst=str(target_dir / self._location.name))
         except:  # noqa: E722
             log.exception("Error occurred when copying path: %s", self._location)
             return False
diff --git a/redbot/cogs/downloader/repo_manager.py b/redbot/cogs/downloader/repo_manager.py
--- a/redbot/cogs/downloader/repo_manager.py
+++ b/redbot/cogs/downloader/repo_manager.py
@@ -998,7 +998,7 @@ def available_libraries(self) -> Tuple[Installable, ...]:
 
     @classmethod
     async def from_folder(cls, folder: Path, branch: str = "") -> Repo:
-        repo = cls(name=folder.stem, url="", branch=branch, commit="", folder_path=folder)
+        repo = cls(name=folder.name, url="", branch=branch, commit="", folder_path=folder)
         repo.url = await repo.current_url()
         if branch == "":
             repo.branch = await repo.current_branch()
@@ -1214,14 +1214,14 @@ async def _load_repos(self, set_repos: bool = False) -> Dict[str, Repo]:
             if not folder.is_dir():
                 continue
             try:
-                branch = await self.config.repos.get_raw(folder.stem, default="")
-                ret[folder.stem] = await Repo.from_folder(folder, branch)
+                branch = await self.config.repos.get_raw(folder.name, default="")
+                ret[folder.name] = await Repo.from_folder(folder, branch)
                 if branch == "":
-                    await self.config.repos.set_raw(folder.stem, value=ret[folder.stem].branch)
+                    await self.config.repos.set_raw(folder.name, value=ret[folder.name].branch)
             except errors.NoRemoteURL:
-                log.warning("A remote URL does not exist for repo %s", folder.stem)
+                log.warning("A remote URL does not exist for repo %s", folder.name)
             except errors.DownloaderException as err:
-                log.error("Ignoring repo %s due to error.", folder.stem, exc_info=err)
+                log.error("Ignoring repo %s due to error.", folder.name, exc_info=err)
                 # Downloader should NOT remove the repo on generic errors like this one.
                 # We were removing whole repo folder here in the past,
                 # but it's quite destructive for such a generic error.


Test patch: