diff --git a/src/main/bitbucket/repository-ref.test.ts b/src/main/bitbucket/repository-ref.test.ts index 6ea77cf41..a95bf8e85 100644 --- a/src/main/bitbucket/repository-ref.test.ts +++ b/src/main/bitbucket/repository-ref.test.ts @@ -36,6 +36,23 @@ describe('Bitbucket repository refs', () => { expect(parseBitbucketRepoRef('https://github.com/team/project.git')).toBeNull() }) + it('keeps malformed percent sequences as literal repo path text', async () => { + expect(parseBitbucketRepoRef('git@bitbucket.org:team/project%zz.git')).toEqual({ + workspace: 'team', + repoSlug: 'project%zz' + }) + + gitExecFileAsyncMock.mockResolvedValue({ + stdout: 'git@bitbucket.org:team/project%zz.git\n', + stderr: '' + }) + + await expect(getBitbucketRepoRef('/repo')).resolves.toEqual({ + workspace: 'team', + repoSlug: 'project%zz' + }) + }) + it('resolves origin through the WSL-aware git runner and caches the result', async () => { gitExecFileAsyncMock.mockResolvedValue({ stdout: 'git@bitbucket.org:team/project.git\n', diff --git a/src/main/bitbucket/repository-ref.ts b/src/main/bitbucket/repository-ref.ts index b51b7c137..4d17e0b63 100644 --- a/src/main/bitbucket/repository-ref.ts +++ b/src/main/bitbucket/repository-ref.ts @@ -12,6 +12,14 @@ export function _resetBitbucketRepoRefCache(): void { repoRefCache.clear() } +function decodeSegment(value: string): string { + try { + return decodeURIComponent(value) + } catch { + return value + } +} + function parseBitbucketPath(pathname: string): BitbucketRepoRef | null { const withoutSuffix = pathname.replace(/\.git$/i, '') const parts = withoutSuffix @@ -27,8 +35,8 @@ function parseBitbucketPath(pathname: string): BitbucketRepoRef | null { return null } return { - workspace: decodeURIComponent(workspace), - repoSlug: decodeURIComponent(repoSlug) + workspace: decodeSegment(workspace), + repoSlug: decodeSegment(repoSlug) } }