Remote parser truncates project paths ending in "git" when the remote has no .git suffix

Checklist

Summary

parseGitLabRemote in src/desktop/git/git_remote_parser.ts cuts the last four characters off the project path when the remote URL has no .git suffix and the project path ends in any character followed by "git", such as legit, my-git or my_git. The optional suffix in the regex is written (?:.git)? with an unescaped dot, which matches any character, and the lazy project path group ([^/]+?) lets the suffix group take those four characters. The extension then looks the project up at the truncated path.

Steps to reproduce

  1. Add this row to the it.each table of should parse %s in src/desktop/git/git_remote_parser.test.ts:

    ['https://gitlab.com/group/legit', ['gitlab.com', 'gitlab.com', 'https:', 'group', 'legit']],
  2. Run npx jest src/desktop/git/git_remote_parser.test.ts.

The same parse happens for a repository whose remote is, for example, https://gitlab.com/group/legit or git@gitlab.com:group/subgroup/my_git (no .git at the end): detectProjects in src/desktop/gitlab/gitlab_project_repository.ts and the account preselection in src/desktop/accounts/account_preselection_service.ts look the project up with the parsed namespaceWithPath.

What is the current bug behavior?

https://gitlab.com/group/legit parses as namespace group and project path l (group/l). https://gitlab.com/group/my-git and https://gitlab.com/group/my-git/ parse as group/my, and git@gitlab.com:group/subgroup/my_git as group/subgroup/my. The project lookup then finds nothing, so the repository is left without a GitLab project, or it finds a different project if one exists at the truncated path.

What is the expected correct behavior?

The full project path is kept: group/legit, group/my-git and group/subgroup/my_git. Only a literal .git suffix is removed, as it already is for https://gitlab.com/group/my-git.git.

Relevant logs and/or screenshots

With the row above, rows for the other three remotes and a row for https://gitlab.com/group/my-git.git (which passes), on main at 2fb019cf, jest reports for https://gitlab.com/group/legit:

    - Expected  - 2
    + Received  + 2

      Object {
        "host": "gitlab.com",
        "hostname": "gitlab.com",
        "namespace": "group",
    -   "namespaceWithPath": "group/legit",
    -   "projectPath": "legit",
    +   "namespaceWithPath": "group/l",
    +   "projectPath": "l",
        "protocol": "https:",
      }

The other three fail the same way (my, my, my instead of my-git, my-git, my_git), and the file ends with Tests: 4 failed, 30 passed, 34 total.

Possible fixes

Escape the dot at src/desktop/git/git_remote_parser.ts#L105: (?:\\.git)? inside the template literal, so that the regex reads (?:\.git)?. I am opening a merge request with this change and the test rows.

The language server has its own copy of this parser with the same pattern, at packages/core/repositories/src/git/utils/git_remote_parser.ts#L150, so it derives the same truncated path for the features it serves. It is reported in gitlab-org/editor-extensions/gitlab-lsp#3365 (closed), and gitlab-org/editor-extensions/gitlab-lsp!4523 (merged) makes the same change there.

Edited by José M. Requena Plens