diff --git a/.changeset/clean-dolphins-lay.md b/.changeset/clean-dolphins-lay.md new file mode 100644 index 0000000000..4403e9f6f6 --- /dev/null +++ b/.changeset/clean-dolphins-lay.md @@ -0,0 +1,5 @@ +--- +"@pnpm/git-resolver": patch +--- + +Don't break URLs with ports. diff --git a/packages/git-resolver/src/parsePref.ts b/packages/git-resolver/src/parsePref.ts index 6598802b85..a97d2ae979 100644 --- a/packages/git-resolver/src/parsePref.ts +++ b/packages/git-resolver/src/parsePref.ts @@ -61,7 +61,7 @@ export default async function parsePref (pref: string): Promise e.replace(/:([^/])/, ':/$1')) + const escapedBacks = backs.map(e => e.replace(/:([^/\d]|\d+[^:/\d])/, ':/$1')) return [front, ...escapedBacks].join('@') } @@ -161,7 +161,7 @@ function matchGitScp (spec: string) { // git+ssh://git@my.custom.git.com:username/project.git#deadbeef // // ...and various combinations. The username in the beginning is *required*. - const matched = spec.match(/^git\+ssh:\/\/([^:#]+:[^#]+(?:\.git)?)(?:#(.*))?$/i) + const matched = spec.match(/^git\+ssh:\/\/([^:]+:[^#]+(?:\.git)?)(?:#(.*))$/i) return (matched != null) && (matched[1].match(/:[0-9]+\/?.*$/i) == null) && { fetchSpec: matched[1], gitCommittish: matched[2], diff --git a/packages/git-resolver/test/index.ts b/packages/git-resolver/test/index.ts index 39ed3e4ad3..761c60a0aa 100644 --- a/packages/git-resolver/test/index.ts +++ b/packages/git-resolver/test/index.ts @@ -331,6 +331,18 @@ test('resolveFromGit() normalizes full url', async () => { }) }) +test('resolveFromGit() normalizes full url with port', async () => { + const resolveResult = await resolveFromGit({ pref: 'git+ssh://git@github.com:22:zkochan/is-negative.git#2.0.1' }) + expect(resolveResult).toStrictEqual({ + id: 'github.com/zkochan/is-negative/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5', + normalizedPref: 'github:zkochan/is-negative#2.0.1', + resolution: { + tarball: 'https://codeload.github.com/zkochan/is-negative/tar.gz/2fa0531ab04e300a24ef4fd7fb3a280eccb7ccc5', + }, + resolvedVia: 'git-repository', + }) +}) + test('resolveFromGit() normalizes full url (alternative form)', async () => { const resolveResult = await resolveFromGit({ pref: 'git+ssh://git@github.com/zkochan/is-negative.git#2.0.1' }) expect(resolveResult).toStrictEqual({ diff --git a/packages/git-resolver/test/parsePref.test.ts b/packages/git-resolver/test/parsePref.test.ts index b2e4239bbf..a362a6d270 100644 --- a/packages/git-resolver/test/parsePref.test.ts +++ b/packages/git-resolver/test/parsePref.test.ts @@ -3,7 +3,12 @@ import parsePref from '@pnpm/git-resolver/lib/parsePref' test.each([ ['ssh://username:password@example.com:repo.git', 'ssh://username:password@example.com/repo.git'], ['ssh://username:password@example.com:repo/@foo.git', 'ssh://username:password@example.com/repo/@foo.git'], -])('the right colon is escaped', async (input, output) => { + ['ssh://username:password@example.com:22/repo/@foo.git', 'ssh://username:password@example.com:22/repo/@foo.git'], + ['ssh://username:password@example.com:22repo/@foo.git', 'ssh://username:password@example.com/22repo/@foo.git'], + ['git+ssh://username:password@example.com:repo.git', 'ssh://username:password@example.com/repo.git'], + ['git+ssh://username:password@example.com:repo/@foo.git', 'ssh://username:password@example.com/repo/@foo.git'], + ['git+ssh://username:password@example.com:22/repo/@foo.git', 'ssh://username:password@example.com:22/repo/@foo.git'], +])('the right colon is escaped in %s', async (input, output) => { const parsed = await parsePref(input) expect(parsed?.fetchSpec).toBe(output) })