Skip to content

fix: keep the path of git-hosted tarball resolutions in the lockfile#12344

Merged
zkochan merged 4 commits into
pnpm:mainfrom
truffle-dev:fix/git-tarball-path-in-lockfile
Jun 13, 2026
Merged

fix: keep the path of git-hosted tarball resolutions in the lockfile#12344
zkochan merged 4 commits into
pnpm:mainfrom
truffle-dev:fix/git-tarball-path-in-lockfile

Conversation

@truffle-dev

@truffle-dev truffle-dev commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Closes #12304

When a git dependency points to a subdirectory of a repository (github:user/repo#commit&path:/sub/dir), the lockfile resolution loses its path field on any install that actually downloads the tarball. Installs served from the store keep it, which is why the field disappears "randomly and frequently" — it depends on store state, not on the project.

Root cause

Since #11481 (pin integrity of git-hosted tarballs in the lockfile), a real download attaches the computed integrity to the resolution object (installing/package-requester/src/packageRequester.ts, the if (fetchedResult.integrity && ...) block). With integrity present, toLockfileResolution no longer passes the resolution through unchanged — it rebuilds the kept-URL form as { integrity, tarball, gitHosted }, dropping path. Without a download there is no integrity, the early !resolution['integrity'] return fires, and the resolution (including path) is written as-is.

The consequence is worse than a broken lockfile diff: path is what the git-hosted tarball fetcher passes to preparePackage to extract the subdirectory. A frozen install from the damaged lockfile silently unpacks the repository root instead of the requested package.

The Rust port already preserves the field — LockfileResolution::to_lockfile_form clones path into its kept-URL branch (pacquet/crates/lockfile/src/resolution.rs) — so this aligns the TS original with it.

Reproduction (pnpm 11.2.2, also on latest)

{ "dependencies": { "simple-react-app": "github:RexSkz/test-git-subfolder-fetch#beta&path:/packages/simple-react-app" } }

Cold store (tarball downloaded):

resolution: {gitHosted: true, integrity: sha512-p1pyn..., tarball: https://codeload.github.com/RexSkz/test-git-subfolder-fetch/tar.gz/777e8a3...}

path gone. Same project, warm store (no download):

resolution: {gitHosted: true, path: /packages/simple-react-app, tarball: https://codeload.github.com/RexSkz/test-git-subfolder-fetch/tar.gz/777e8a3...}

path kept. A --frozen-lockfile install from the cold-store lockfile on a fresh store then installs the monorepo root (monorepo-example, private: true) under the dependency's name, with no error.

Fix

toLockfileResolution builds its kept-URL form in one place (mirroring the Rust port's keep_url()) and carries path through. Regression tests cover both the default and the lockfileIncludeTarballUrl: true branches.

Summary by CodeRabbit

  • Bug Fixes

    • Ensure git dependencies that point to a subdirectory consistently resolve to the intended subdirectory on subsequent installs.
  • Documentation

    • Clarified lockfile behavior for git subdirectory dependencies and when tarball URL/path fields may appear or disappear.
  • Tests

    • Added tests verifying lockfile resolutions preserve tarball URL, integrity, git-hosted flag, and subdirectory path across scenarios.

@truffle-dev truffle-dev requested a review from zkochan as a code owner June 12, 2026 03:34
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider

Great, no issues found!

Qodo reviewed your code and found no material issues that require review

Grey Divider

Previous review results

Review updated until commit bd9b738

Results up to commit 7cbf4a8


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Results up to commit f06ef86


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Results up to commit a10a313


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Results up to commit 16ce549


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Results up to commit 04f6937


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Results up to commit 4a04657


🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0)

Great, no issues found!

Qodo reviewed your code and found no material issues that require review
Qodo Logo

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Centralizes tarball-URL preservation in toLockfileResolution via a keepTarballUrl() helper so the resolver path is retained for git-hosted (and file:) tarball resolutions; adds JS and Rust tests and a changeset documenting the fix.

Changes

Git Tarball Path Preservation

Layer / File(s) Summary
Path preservation in tarball resolution
lockfile/utils/src/toLockfileResolution.ts
Introduces a keepTarballUrl() helper that preserves integrity, the original tarball URL, and conditionally the resolver path. Applied across branches handling lockfileIncludeTarballUrl, local file: tarballs, git-hosted tarballs, and tarball URL mismatch handling so path isn't dropped during lockfile regeneration.
Path preservation validation (JS)
lockfile/utils/test/toLockfileResolution.ts
Adds Jest tests asserting toLockfileResolution retains the path field for git-hosted tarball resolutions with lockfileIncludeTarballUrl both false and true, and that returned resolutions include integrity, tarball, gitHosted: true, and path.
Path preservation validation (Rust)
pacquet/crates/lockfile/src/resolution/tests.rs
Adds a SHA512 constant and tests verifying LockfileResolution::to_lockfile_form drops reconstructible registry tarball URLs (becomes Registry resolution keeping integrity) and preserves the path field for git_hosted tarballs when include_tarball_url is false and true.
Changeset documentation
.changeset/git-tarball-path-in-lockfile.md
Patch-level changelog entry for @pnpm/lockfile.utils and pnpm describing the fix and prior behavior where missing path caused incorrect unpacking of the repository root instead of the specified subdirectory.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #12304: Reports the path property being removed from git-subdirectory dependencies in lockfiles; this PR addresses that behavior.

Possibly related PRs

  • pnpm/pnpm#11509: Modifies the same toLockfileResolution.ts area with overlapping tarball-resolution behavior changes.
  • pnpm/pnpm#11481: Related changes around integrity propagation for git-hosted tarball resolutions.
  • pnpm/pnpm#12096: Adjusts lockfile resolution construction for remote tarball dependencies during re-resolution.

Suggested reviewers

  • zkochan

Poem

🐰 A tarball path went missing one day,
I hopped through the code to chase it away,
A helper I planted to hold it tight,
Now subdirs unpack just right at night,
Hoppity fix—lockfiles shining bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: preserving the path field in git-hosted tarball resolutions in the lockfile, which is the core issue addressed.
Linked Issues check ✅ Passed The PR directly addresses issue #12304 by preserving the path property in lockfile resolutions for git-hosted tarballs with subdirectories, including regression tests.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the git-hosted tarball path preservation: the changeset entry, TypeScript implementation updates, and regression tests for both branches.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix lockfile to preserve path for git-hosted tarball subdirectory deps
🐞 Bug fix 🧪 Tests 📝 Documentation 🕐 10-20 Minutes

Grey Divider

Walkthroughs

Description
• Preserve resolution.path when serializing git-hosted tarball resolutions to the lockfile.
• Prevent frozen installs from unpacking repo root instead of the requested subdirectory.
• Add regression tests for both lockfileIncludeTarballUrl branches.
Diagram
graph TD
  A["Install flow"] --> B["Resolution (tarball)"] --> C["toLockfileResolution"] --> D[("pnpm-lock.yaml")]
  D --> E["Git tarball fetcher"] --> F["preparePackage (extract)"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Preserve original resolution object when adding integrity
  • ➕ Avoids field-loss bugs by not rebuilding partial kept-URL objects
  • ➕ Less duplication of resolution fields over time
  • ➖ Could unintentionally persist fields that should not be lockfile-stable
  • ➖ Might encode more resolver-internal shape into the lockfile format
2. Add an integration test that installs a git subdir dependency end-to-end
  • ➕ Covers the full regression: lockfile write + frozen install rehydrate + extraction
  • ➕ Protects against future behavior changes across packages
  • ➖ Slower and more brittle than unit tests (network/tarball fixtures)
  • ➖ Harder to maintain in CI compared to the current unit-level guardrails

Recommendation: The chosen approach is best: keep the existing lockfile canonicalization behavior, but centralize the kept-URL construction and explicitly carry path through for git-hosted tarballs. The added unit tests cover both lockfileIncludeTarballUrl branches with minimal maintenance cost.

Grey Divider

File Changes

Bug fix (1)
toLockfileResolution.ts Preserve 'path' in kept-URL lockfile resolutions for git-hosted tarballs +14/-10

Preserve 'path' in kept-URL lockfile resolutions for git-hosted tarballs

• Refactors the kept-tarball-URL logic into a shared helper and ensures 'TarballResolution.path' is included when present. This prevents lockfile writes from dropping 'path' when integrity is pinned, which would otherwise cause later installs to unpack the repository root.

lockfile/utils/src/toLockfileResolution.ts


Tests (1)
toLockfileResolution.ts Add regression tests for git-hosted tarball 'path' retention +31/-0

Add regression tests for git-hosted tarball 'path' retention

• Adds two Jest tests asserting that 'path' is retained in the lockfile resolution for git-hosted tarballs, both when 'lockfileIncludeTarballUrl' is true and when it is false.

lockfile/utils/test/toLockfileResolution.ts


Documentation (1)
git-tarball-path-in-lockfile.md Add patch changeset documenting git tarball 'path' preservation +6/-0

Add patch changeset documenting git tarball 'path' preservation

• Adds a changeset for '@pnpm/lockfile.utils' and 'pnpm' describing the regression and the behavioral fix for git subdirectory dependencies.

.changeset/git-tarball-path-in-lockfile.md


Grey Divider

Qodo Logo

@zkochan zkochan force-pushed the fix/git-tarball-path-in-lockfile branch from 4a04657 to 04f6937 Compare June 12, 2026 23:32
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 04f6937

…file_form

Adds regression tests guarding that to_lockfile_form keeps the
TarballResolution.path of git-hosted subdirectory tarballs in both the
default and include_tarball_url branches, mirroring the TypeScript
toLockfileResolution tests added for pnpm#12304.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 12, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 16ce549

@codecov-commenter

codecov-commenter commented Jun 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.19%. Comparing base (1310ab5) to head (bd9b738).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12344      +/-   ##
==========================================
+ Coverage   88.18%   88.19%   +0.01%     
==========================================
  Files         296      296              
  Lines       37944    37951       +7     
==========================================
+ Hits        33460    33471      +11     
+ Misses       4484     4480       -4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit a10a313

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit f06ef86

…L return

Invert the branching so the canonical-registry case is the early return and
the kept-URL resolution (integrity + tarball + optional gitHosted/path) is the
single fall-through. This removes the keepTarballUrl closure and the
preservingGitHosted helper; the URL-reconstruction check moves into
isCanonicalRegistryTarballUrl. No behavior change.
@zkochan zkochan force-pushed the fix/git-tarball-path-in-lockfile branch from f06ef86 to 7cbf4a8 Compare June 13, 2026 00:23
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit 7cbf4a8

…form

Apply the same inversion as the TypeScript toLockfileResolution: the
canonical-registry case becomes the early return and the kept-URL resolution
is the single fall-through, removing the keep_url closure. The URL-match check
moves into is_canonical_registry_tarball_url. No behavior change; the three
to_lockfile_form tests still pass.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Jun 13, 2026

Copy link
Copy Markdown

Code review by qodo was updated up to the latest commit bd9b738

@github-actions

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Each scenario reports direct installs and pnpr installs. Bencher consumes pacquet@HEAD and pnpr@HEAD.

Scenario: Isolated linker: fresh restore, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.052 ± 0.079 3.914 4.149 2.03 ± 0.13
pacquet@main 4.111 ± 0.147 3.938 4.295 2.06 ± 0.14
pnpr@HEAD 1.996 ± 0.119 1.914 2.307 1.00
pnpr@main 2.135 ± 0.141 1.967 2.368 1.07 ± 0.09
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.05213986552,
      "stddev": 0.0785391947215144,
      "median": 4.07175035712,
      "user": 4.00579764,
      "system": 3.40077332,
      "min": 3.91400591562,
      "max": 4.14948833662,
      "times": [
        4.13156883162,
        4.094147277619999,
        3.95258684862,
        4.01684275262,
        4.06106767162,
        4.11715334962,
        4.00210462862,
        4.08243304262,
        3.91400591562,
        4.14948833662
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.11116962642,
      "stddev": 0.14686412525651948,
      "median": 4.03437754712,
      "user": 3.97370504,
      "system": 3.3674522199999997,
      "min": 3.93765541162,
      "max": 4.29498322062,
      "times": [
        4.29498322062,
        4.268943966619999,
        4.29372907262,
        3.93765541162,
        4.03337953162,
        4.253488690619999,
        4.02331834162,
        4.002837899619999,
        3.96798456662,
        4.03537556262
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 1.99640305362,
      "stddev": 0.118612108443758,
      "median": 1.95433983462,
      "user": 2.70988834,
      "system": 2.85293662,
      "min": 1.91352036062,
      "max": 2.3069068606200003,
      "times": [
        1.96804228562,
        2.02764267462,
        1.91846729162,
        1.91352036062,
        1.9406373836200002,
        2.3069068606200003,
        1.93412991862,
        1.9771872876199998,
        1.9254674576200002,
        2.05202901562
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.1350770102200003,
      "stddev": 0.14072499599289862,
      "median": 2.11283413762,
      "user": 2.67010064,
      "system": 2.8584072199999997,
      "min": 1.96733200762,
      "max": 2.36761638262,
      "times": [
        2.02788545362,
        2.36761638262,
        2.19084702662,
        1.96733200762,
        2.03482124862,
        2.19264573562,
        2.26638974562,
        2.0237106056200003,
        2.00126241862,
        2.2782594776200003
      ]
    }
  ]
}

Scenario: Isolated linker: fresh restore, hot cache + hot store

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 613.0 ± 12.3 593.8 639.7 1.00
pacquet@main 635.6 ± 16.1 618.2 667.0 1.04 ± 0.03
pnpr@HEAD 665.3 ± 19.0 643.6 702.8 1.09 ± 0.04
pnpr@main 676.7 ± 20.1 651.7 706.2 1.10 ± 0.04
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.6129616412400002,
      "stddev": 0.012286329315236821,
      "median": 0.61209962344,
      "user": 0.36055792000000003,
      "system": 1.27908312,
      "min": 0.5937686884400001,
      "max": 0.63970497144,
      "times": [
        0.6234416224400001,
        0.6051056334400001,
        0.60509062944,
        0.60778743444,
        0.6146957674400001,
        0.63970497144,
        0.5937686884400001,
        0.6110846484400001,
        0.6158224184400001,
        0.61311459844
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.63560200854,
      "stddev": 0.01610810145627245,
      "median": 0.6316561919400001,
      "user": 0.37808592,
      "system": 1.30603072,
      "min": 0.6181911284400001,
      "max": 0.66704277044,
      "times": [
        0.62528562744,
        0.62510377244,
        0.6181911284400001,
        0.6380267564400001,
        0.6392586574400001,
        0.6395246694400001,
        0.6574463154400001,
        0.6237889454400001,
        0.66704277044,
        0.6223514424400001
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6653052152400001,
      "stddev": 0.018959929906848052,
      "median": 0.6640394014400001,
      "user": 0.36534802,
      "system": 1.32592572,
      "min": 0.6435638154400001,
      "max": 0.7027513234400001,
      "times": [
        0.6486917294400001,
        0.6446776724400001,
        0.6765931794400001,
        0.6818106114400001,
        0.6435638154400001,
        0.65242319244,
        0.66578105744,
        0.7027513234400001,
        0.6744618254400001,
        0.6622977454400001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6767036136400002,
      "stddev": 0.020139430244034445,
      "median": 0.67348565894,
      "user": 0.38984102,
      "system": 1.3255887200000003,
      "min": 0.6517290184400001,
      "max": 0.7061821454400001,
      "times": [
        0.7021705424400001,
        0.6517290184400001,
        0.6711727914400001,
        0.6978795604400001,
        0.6616887824400001,
        0.6841315154400001,
        0.6635981674400001,
        0.67579852644,
        0.7061821454400001,
        0.6526850864400001
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + cold store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 4.086 ± 0.077 3.985 4.200 1.84 ± 0.10
pacquet@main 4.135 ± 0.099 4.003 4.264 1.86 ± 0.11
pnpr@HEAD 2.245 ± 0.135 2.027 2.420 1.01 ± 0.08
pnpr@main 2.223 ± 0.117 2.055 2.412 1.00
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 4.086195172559999,
      "stddev": 0.07720287402635818,
      "median": 4.07629366466,
      "user": 3.7264787600000004,
      "system": 3.2535927,
      "min": 3.9845192586600002,
      "max": 4.1998557736599995,
      "times": [
        3.9845192586600002,
        4.03243880466,
        4.08835269866,
        4.06423463066,
        4.1609010156599995,
        4.03552064166,
        3.99129985666,
        4.1998557736599995,
        4.12912111166,
        4.17570793366
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 4.13483446386,
      "stddev": 0.09897322488124125,
      "median": 4.12275247266,
      "user": 3.78675846,
      "system": 3.2655794,
      "min": 4.002919008659999,
      "max": 4.2636077306599995,
      "times": [
        4.2636077306599995,
        4.25813028466,
        4.23166740966,
        4.002919008659999,
        4.041949315659999,
        4.18368984666,
        4.1828037156599995,
        4.06270122966,
        4.06269280366,
        4.05818329366
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 2.24522761946,
      "stddev": 0.13501396740979438,
      "median": 2.29314626566,
      "user": 2.53255906,
      "system": 2.7586581000000003,
      "min": 2.02650421566,
      "max": 2.4202772506600003,
      "times": [
        2.06188309066,
        2.08980985466,
        2.31843153466,
        2.28743850766,
        2.31046657466,
        2.28353426066,
        2.02650421566,
        2.35507688166,
        2.4202772506600003,
        2.29885402366
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 2.2227252522599996,
      "stddev": 0.11704715947647382,
      "median": 2.24877710266,
      "user": 2.51233666,
      "system": 2.804182,
      "min": 2.05522545466,
      "max": 2.41248348966,
      "times": [
        2.26427734866,
        2.41248348966,
        2.23960031566,
        2.35349458766,
        2.25795388966,
        2.1897659536600003,
        2.2710238936600002,
        2.05522545466,
        2.11554516466,
        2.06788242466
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, hot cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 1.216 ± 0.021 1.195 1.250 1.91 ± 0.05
pacquet@main 1.256 ± 0.093 1.214 1.518 1.97 ± 0.15
pnpr@HEAD 0.636 ± 0.014 0.618 0.667 1.00
pnpr@main 0.639 ± 0.013 0.626 0.670 1.00 ± 0.03
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 1.2156292371399997,
      "stddev": 0.02101844585969297,
      "median": 1.20561789924,
      "user": 1.1959720199999997,
      "system": 1.66536222,
      "min": 1.19542181374,
      "max": 1.2502084147399999,
      "times": [
        1.23735635774,
        1.20594335174,
        1.24794700774,
        1.19707455574,
        1.20529244674,
        1.19542181374,
        1.2086262637399998,
        1.20479329974,
        1.20362885974,
        1.2502084147399999
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.2557947184399998,
      "stddev": 0.09250681264506788,
      "median": 1.22723726724,
      "user": 1.2325027199999998,
      "system": 1.7078360199999998,
      "min": 1.2144865677399999,
      "max": 1.51815945774,
      "times": [
        1.2144865677399999,
        1.23538813974,
        1.2346868597399998,
        1.51815945774,
        1.2197643487399998,
        1.2283732087399999,
        1.22610132574,
        1.22084510774,
        1.22178575774,
        1.23835641074
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6362998080400001,
      "stddev": 0.014225014935037417,
      "median": 0.63314515524,
      "user": 0.31593782,
      "system": 1.2476881199999998,
      "min": 0.6175687577400001,
      "max": 0.66705936574,
      "times": [
        0.6277746297400001,
        0.6175687577400001,
        0.62291383974,
        0.64474007174,
        0.66705936574,
        0.62979920674,
        0.64161674674,
        0.6364911037400001,
        0.64550240674,
        0.6295319517400001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.63947599894,
      "stddev": 0.013467262649056025,
      "median": 0.63392616924,
      "user": 0.33478582000000007,
      "system": 1.26068242,
      "min": 0.6257257177400001,
      "max": 0.66957977374,
      "times": [
        0.64735350374,
        0.6289637237400001,
        0.6330877567400001,
        0.66957977374,
        0.63168759974,
        0.65343685074,
        0.6370727247400001,
        0.63334185874,
        0.6345104797400001,
        0.6257257177400001
      ]
    }
  ]
}

Scenario: Isolated linker: fresh install, cold cache + hot store

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.903 ± 0.049 2.855 3.022 4.63 ± 0.11
pacquet@main 2.909 ± 0.030 2.873 2.967 4.64 ± 0.09
pnpr@HEAD 0.626 ± 0.010 0.618 0.646 1.00
pnpr@main 0.660 ± 0.076 0.623 0.875 1.05 ± 0.12
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.9031241892400006,
      "stddev": 0.04946516856036864,
      "median": 2.89088735714,
      "user": 1.6377351399999998,
      "system": 1.9658668000000001,
      "min": 2.8554925406400002,
      "max": 3.02188654964,
      "times": [
        2.89820538364,
        2.92327823864,
        2.93922910264,
        2.89874784464,
        2.8554925406400002,
        2.88356933064,
        2.88008986064,
        2.85726733564,
        3.02188654964,
        2.8734757056399998
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 2.90850666924,
      "stddev": 0.030296709546101395,
      "median": 2.90781671964,
      "user": 1.6915931400000002,
      "system": 1.9674521999999999,
      "min": 2.87266316764,
      "max": 2.96686942464,
      "times": [
        2.88329969164,
        2.88119302764,
        2.9113823976399997,
        2.93444590064,
        2.87959300264,
        2.87266316764,
        2.92006135964,
        2.93130767864,
        2.96686942464,
        2.9042510416400003
      ]
    },
    {
      "command": "pnpr@HEAD",
      "mean": 0.6264605051400001,
      "stddev": 0.010077070703272269,
      "median": 0.62185758664,
      "user": 0.30399144,
      "system": 1.2420826999999999,
      "min": 0.6176750136400001,
      "max": 0.64571807964,
      "times": [
        0.6404109296400001,
        0.64571807964,
        0.6207637046400001,
        0.6186818096400001,
        0.62078815064,
        0.6236045816400001,
        0.61911622064,
        0.6176750136400001,
        0.6229270226400001,
        0.6349195386400001
      ]
    },
    {
      "command": "pnpr@main",
      "mean": 0.6604159278400001,
      "stddev": 0.07579103364254736,
      "median": 0.6409355116400002,
      "user": 0.33992714,
      "system": 1.2500078999999997,
      "min": 0.6232368586400001,
      "max": 0.8748104226400001,
      "times": [
        0.6232368586400001,
        0.6373992586400001,
        0.6444574646400001,
        0.6379809876400001,
        0.6439940606400001,
        0.6262938936400001,
        0.6452352276400001,
        0.6268610686400001,
        0.8748104226400001,
        0.6438900356400001
      ]
    }
  ]
}

@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12344
Testbedpacquet
Click to view all benchmark results
BenchmarkLatencyBenchmark Result
milliseconds (ms)
(Result Δ%)
Upper Boundary
milliseconds (ms)
(Limit %)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
🚷 view threshold
4,086.20 ms
(-22.99%)Baseline: 5,306.40 ms
6,367.68 ms
(64.17%)
isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
🚷 view threshold
2,903.12 ms
(-11.64%)Baseline: 3,285.61 ms
3,942.73 ms
(73.63%)
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
🚷 view threshold
1,215.63 ms
(+0.88%)Baseline: 1,205.07 ms
1,446.08 ms
(84.06%)
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
🚷 view threshold
4,052.14 ms
(-30.27%)Baseline: 5,811.11 ms
6,973.33 ms
(58.11%)
isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
🚷 view threshold
612.96 ms
(-6.91%)Baseline: 658.49 ms
790.19 ms
(77.57%)
🐰 View full continuous benchmarking report in Bencher

@github-actions

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchpr/12344
Testbedpnpr

⚠️ WARNING: No Threshold found!

Without a Threshold, no Alerts will ever be generated.

Click here to create a new Threshold
For more information, see the Threshold documentation.
To only post results if a Threshold exists, set the --ci-only-thresholds flag.

Click to view all benchmark results
BenchmarkLatencymilliseconds (ms)
isolated-linker.fresh-install.cold-cache.cold-store📈 view plot
⚠️ NO THRESHOLD
2,245.23 ms
isolated-linker.fresh-install.cold-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
626.46 ms
isolated-linker.fresh-install.hot-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
636.30 ms
isolated-linker.fresh-restore.cold-cache.cold-store📈 view plot
⚠️ NO THRESHOLD
1,996.40 ms
isolated-linker.fresh-restore.hot-cache.hot-store📈 view plot
⚠️ NO THRESHOLD
665.31 ms
🐰 View full continuous benchmarking report in Bencher

@zkochan zkochan merged commit f20ad8f into pnpm:main Jun 13, 2026
21 of 23 checks passed
@welcome

welcome Bot commented Jun 13, 2026

Copy link
Copy Markdown

Congrats on merging your first pull request! 🎉🎉🎉

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Git repositories dependencies get their path removed from the lockfile

3 participants