Skip to content

Adding a GitHub owner in different letter case (e.g. KTSU-DEV) makes its repos throw KeyNotFoundException when compared, show "Clone" though cloned, and never auto-fetch #451

Description

@matt-edmondson

What's wrong

SyncGitHubRepoInfoForOwner (ProjectDirector/ProjectDirector.cs:1012-1024) builds a repo's dictionary key and its OwnerName from two sources, and neither is case-normalised:

  • The Options.Repos key comes from the API's canonical remoteRepo.FullName via GetFullyQualifiedRepoName(remoteRepo), e.g. ktsu-dev.Foo.
  • gitHubRepo.OwnerName = owner is the string the user typed in "Add New GitHub Owner" (:910), or one parsed from a clone's remote URL (:1188-1193), e.g. KTSU-DEV.

GitHub logins are case-insensitive, so the API calls succeed with KTSU-DEV. SemanticString equality is ordinal, though. Everything that later rebuilds a name from OwnerName + RepoName produces KTSU-DEV.Foo, which is not a key in Options.Repos:

Site Effect
UpdateClonedStatus (:1066) stores ClonedRepos[path] = "KTSU-DEV.Foo" FetchAllReposIfStale, Fetch All and Pull All call Options.Repos.TryGetValue(...), which fails. The repo is never fetched or pulled, and nothing is logged.
ShowTopPanel (:704) ClonedRepos.ContainsValue(Options.BaseRepo) Finds nothing. The panel offers Clone for an already-cloned repo, and clicking it fails with "destination path already exists". Pull, Commit and Push are hidden.
PairSiblings keys SimilarRepoDiffs by KTSU-DEV.Bar Clicking a similar repo calls SwitchPage(BaseRepo, "KTSU-DEV.Bar") (:1513), which reaches Options.Repos[compareRepo] in SwitchCompareBrowserPath (:2231) and throws KeyNotFoundException on the render thread. The Propagate popup throws the same way from FilePropagation.ResolveDestinations (repos[kvp.Key], FilePropagation.cs:96).

No typing mistake is needed to hit this. If a clone's remote is https://github.com/KTSU-DEV/foo, Scan Dev Dir registers owner KTSU-DEV, and the next GitHub scan keys that owner's repos by the API's lowercase names.

Token lookup has the same problem: TokenStorage derives the persona from the owner string as given, so a token saved for ktsu-dev is not found for KTSU-DEV.

Evidence

A probe test built two repos the way SyncGitHubRepoInfoForOwner does (key from "ktsu-dev/Foo".Replace('/', '.'), OwnerName = "KTSU-DEV") and then called ProjectDirector.PairSiblings:

sibling key 'KTSU-DEV.Bar' in Options.Repos: False
Repos keys: ktsu-dev.Foo, ktsu-dev.Bar

Suggested fix

  • In SyncGitHubRepoInfoForOwner, set OwnerName from remoteRepo.Owner.Login rather than from the typed owner, so the key and the name come from one source.
  • Store owners in canonical case: when an owner is added, replace the typed name with User.Get(...).Login, and do the same in the dev-dir scan.
  • Alternatively, compare names case-insensitively throughout. Changing the persona seed in TokenStorage needs a migration.
  • As a safety net, have SwitchCompareBrowserPath and ResolveDestinations use TryGetValue instead of the indexer.

Acceptance criteria

  • After adding KTSU-DEV and scanning, that owner's cloned repos show Pull/Commit/Push and are auto-fetched.
  • Clicking any similar repo opens the comparison without throwing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions