From abd91cac080dc2f7bd97c6976cee949c4389e83d Mon Sep 17 00:00:00 2001 From: IceOfSummer <72915970+IceOfSummer@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:02:42 +0800 Subject: [PATCH] fix: `ERR_PNPM_TARBALL_EXTRACT` when the URL's hash contains a slash (#8761) close #7697 --- .changeset/serious-yaks-dance.md | 6 ++++++ pnpm/test/install/misc.ts | 12 ++++++++++++ resolving/tarball-resolver/src/index.ts | 5 +++++ resolving/tarball-resolver/test/index.ts | 10 ++++++++++ 4 files changed, 33 insertions(+) create mode 100644 .changeset/serious-yaks-dance.md diff --git a/.changeset/serious-yaks-dance.md b/.changeset/serious-yaks-dance.md new file mode 100644 index 0000000000..94ddb908e8 --- /dev/null +++ b/.changeset/serious-yaks-dance.md @@ -0,0 +1,6 @@ +--- +"@pnpm/tarball-resolver": patch +"pnpm": patch +--- + +Fix `ERR_PNPM_TARBALL_EXTRACT` error while installing a dependency from GitHub having a slash in branch name [#7697](https://github.com/pnpm/pnpm/issues/7697). diff --git a/pnpm/test/install/misc.ts b/pnpm/test/install/misc.ts index c57ce78b46..3a39db0b25 100644 --- a/pnpm/test/install/misc.ts +++ b/pnpm/test/install/misc.ts @@ -562,3 +562,15 @@ test('do not hang on circular peer dependencies', () => { expect(result.status).toBe(0) expect(fs.existsSync(path.join(tempDir, WANTED_LOCKFILE))).toBeTruthy() }) + +// Covers https://github.com/pnpm/pnpm/issues/7697 +test('install success even though the url\'s hash contains slash', async () => { + prepare() + const settings = ['--fetch-retries=0'] + const result = execPnpmSync([ + 'add', + 'https://github.com/pnpm-e2e/simple-pkg.git#branch/with-slash', + ...settings, + ]) + expect(result.status).toBe(0) +}) diff --git a/resolving/tarball-resolver/src/index.ts b/resolving/tarball-resolver/src/index.ts index 34c50e3640..24142e61ca 100644 --- a/resolving/tarball-resolver/src/index.ts +++ b/resolving/tarball-resolver/src/index.ts @@ -26,6 +26,11 @@ const GIT_HOSTERS = new Set([ ]) function isRepository (pref: string): boolean { + const url = new URL(pref) + if (url.hash && url.hash.includes('/')) { + url.hash = encodeURIComponent(url.hash.substring(1)) + pref = url.href + } if (pref.endsWith('/')) { pref = pref.slice(0, -1) } diff --git a/resolving/tarball-resolver/test/index.ts b/resolving/tarball-resolver/test/index.ts index f94c7ee83e..4c15f0541a 100644 --- a/resolving/tarball-resolver/test/index.ts +++ b/resolving/tarball-resolver/test/index.ts @@ -60,3 +60,13 @@ test('ignore direct URLs to repositories', async () => { expect(await resolveFromTarball({ pref: 'https://gitlab.com/foo/bar' })).toBe(null) expect(await resolveFromTarball({ pref: 'https://bitbucket.org/foo/bar' })).toBe(null) }) + +test('ignore slash in hash', async () => { + // expect resolve from git. + let hash = 'path:/packages/simple-react-app' + expect(await resolveFromTarball({ pref: `RexSkz/test-git-subdir-fetch#${hash}` })).toBe(null) + expect(await resolveFromTarball({ pref: `RexSkz/test-git-subdir-fetch#${encodeURIComponent(hash)}` })).toBe(null) + hash = 'heads/canary' + expect(await resolveFromTarball({ pref: `zkochan/is-negative#${hash}` })).toBe(null) + expect(await resolveFromTarball({ pref: `zkochan/is-negative#${encodeURIComponent(hash)}` })).toBe(null) +})