Skip to content

Commit

Permalink
feat: support pnpm lock v9
Browse files Browse the repository at this point in the history
Close #1652
  • Loading branch information
jbedard committed May 13, 2024
1 parent 49fa9e1 commit 9bf7831
Show file tree
Hide file tree
Showing 9 changed files with 276 additions and 3 deletions.
4 changes: 4 additions & 0 deletions e2e/pnpm_lockfiles/.bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ v60/projects/c/node_modules
v61/projects/a/node_modules
v61/projects/b/node_modules
v61/projects/c/node_modules
v90/node_modules
v90/projects/a/node_modules
v90/projects/b/node_modules
v90/projects/c/node_modules
6 changes: 6 additions & 0 deletions e2e/pnpm_lockfiles/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ npm = use_extension(
"//%s:patches/meaning-of-life@1.0.0-pnpm.patch" % version,
"//:pnpm-workspace.yaml",
],
# Must manually opt-in to lifecycle hooks for lockfile v9.
# Do not opt-in for earlier versions to ensure lifecycle hooks are determined from
# the lockfile when supported by lockfile <v9.
lifecycle_hooks = {"@aspect-test/c": ["postinstall"]} if version == "v90" else {"*": ["*"]},
npmrc = "//:.npmrc",
patch_args = {"*": ["-p1"]},
pnpm_lock = "//%s:pnpm-lock.yaml" % version,
Expand All @@ -43,6 +47,7 @@ npm = use_extension(
"v54",
"v60",
"v61",
"v90",
]
]

Expand All @@ -55,5 +60,6 @@ npm = use_extension(
"v54",
"v60",
"v61",
"v90",
]
]
8 changes: 8 additions & 0 deletions e2e/pnpm_lockfiles/WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock")
"//%s:patches/meaning-of-life@1.0.0-pnpm.patch" % version,
"//:pnpm-workspace.yaml",
],
# Must manually opt-in to lifecycle hooks for lockfile v9.
# Do not opt-in for earlier versions to ensure lifecycle hooks are determined from
# the lockfile when supported by lockfile <v9.
lifecycle_hooks = {"@aspect-test/c": ["postinstall"]} if version == "v90" else {"*": ["*"]},
npmrc = "//:.npmrc",
patch_args = {"*": ["-p1"]},
pnpm_lock = "//%s:pnpm-lock.yaml" % version,
Expand All @@ -30,15 +34,19 @@ load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock")
"v54",
"v60",
"v61",
"v90",
]
]

load("@lock-v54//:repositories.bzl", npm_repositories_v54 = "npm_repositories")
load("@lock-v60//:repositories.bzl", npm_repositories_v60 = "npm_repositories")
load("@lock-v61//:repositories.bzl", npm_repositories_v61 = "npm_repositories")
load("@lock-v90//:repositories.bzl", npm_repositories_v90 = "npm_repositories")

npm_repositories_v54()

npm_repositories_v60()

npm_repositories_v61()

npm_repositories_v90()
2 changes: 2 additions & 0 deletions e2e/pnpm_lockfiles/setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
# 5.4 - pnpm v7.0.0 bumped the lockfile version to 5.4
# 6.0 - pnpm v8.0.0 bumped the lockfile version to 6.0; this included breaking changes
# 6.1 - pnpm v8.6.0 bumped the lockfile version to 6.1
# 9.0 - pnpm v9.0.0 bumped the lockfile version to 9.0

mv v54/pnpm-lock.yaml . && npx pnpm@^7.0 install --lockfile-only && mv pnpm-lock.yaml v54/

# pnpm v8.0.0 bumped the lockfile version to 6.0, 8.6.0 bumped it to 6.1 which was then reverted to 6.0
# while still presenting minor differences from <8.6.0.
mv v60/pnpm-lock.yaml . && npx pnpm@8.5.1 install --lockfile-only && mv pnpm-lock.yaml v60/
mv v61/pnpm-lock.yaml . && npx pnpm@8.6.0 install --lockfile-only && mv pnpm-lock.yaml v61/
mv v90/pnpm-lock.yaml . && npx pnpm@^9.0 install --lockfile-only && mv pnpm-lock.yaml v90/
6 changes: 6 additions & 0 deletions e2e/pnpm_lockfiles/v90/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
load("@lock-v90//:defs.bzl", "npm_link_all_packages")
load("//:lockfile-test.bzl", "lockfile_test")

npm_link_all_packages()

lockfile_test()
1 change: 1 addition & 0 deletions e2e/pnpm_lockfiles/v90/patches
172 changes: 172 additions & 0 deletions e2e/pnpm_lockfiles/v90/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion npm/private/test/utils_tests.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,13 @@ def test_version_supported(ctx):
msg = utils.assert_lockfile_version(1.2, testonly = True)
asserts.equals(env, "npm_translate_lock requires lock_version at least 5.4, but found 1.2. Please upgrade to pnpm v7 or greater.", msg)
msg = utils.assert_lockfile_version(99.99, testonly = True)
asserts.equals(env, "npm_translate_lock currently supports a maximum lock_version of 6.1, but found 99.99. Please file an issue on rules_js", msg)
asserts.equals(env, "npm_translate_lock currently supports a maximum lock_version of 9.0, but found 99.99. Please file an issue on rules_js", msg)

# supported versions
utils.assert_lockfile_version(5.4)
utils.assert_lockfile_version(6.0)
utils.assert_lockfile_version(6.1)
utils.assert_lockfile_version(9.0)

return unittest.end(env)

Expand Down
77 changes: 75 additions & 2 deletions npm/private/utils.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,74 @@ def _convert_v6_packages(packages):
package_info[key] = dependencies

result[_convert_pnpm_v6_package_name(package)] = package_info

return result

def _convert_pnpm_v9_package_name(package_name):
# Covert a pnpm lock file v9 name/version@version string of the format
# @scope/name@version(@scope/name@version)(@scope/name@version)@version
# to a pnpm lock file v5 @scope/name/version_peer_version format that is compatible with rules_js.
package_name = _convert_pnpm_v6_version_peer_dep(package_name)
segments = package_name.rsplit("@", 1)
if len(segments) != 2:
msg = "unexpected pnpm versioned name {}".format(package_name)
fail(msg)
return "/%s/%s" % (segments[0], segments[1])

# v9 importers are the same as v6 importers
_convert_v9_importers = _convert_v6_importers

def _convert_v9_packages(packages, snapshots):
# Convert pnpm lockfile v9 importers to a rules_js compatible format.

# v9 split package metadata (v6 "packages" field) into 2:
#
# packages:
# '@scoped/name@5.0.2'
# hasBin
# resolution (integrity etc)
# peerDependencies which *might* be resolved
#
# snapshots:
# '@scoped/name@2.0.0(peer@2.0.2)'
# dependencies:
# a-dep@1.2.3
# peer@2.0.2
# b-dep@3.2.1(peer-b@4.5.6)
#
# Where the 'snapshots' keys contain the peer information while 'packages' contain the static information
# such as hasBin, resolution and peerDependencies that require resolution.

result = {}

# Snapshots contains the packages with the keys (which include peers) to return
for package, snapshot_info in snapshots.items():
# convert v6 package dependencies + optionalDependencies
for key in ["dependencies", "optionalDependencies"]:
deps = snapshot_info.get(key, None)
if deps != None:
dependencies = {}
for dep_name, dep_version in deps.items():
dependencies[dep_name] = _convert_pnpm_v6_version_peer_dep(dep_version)
snapshot_info[key] = dependencies

# Strip peer-dep info off to get the raw package
package_version = package
if package_version[-1] == ")":
package_version = package_version[:package_version.find("(")]

# Metadata for this snapshot persisted in the 'packages'
package_info = packages[package_version]
if package_info == None:
msg = "Failed to find pnpm-lock snapshot %s (%s) in packages" % (package, package_version)
fail(msg)

# Also include the static data from the 'packages'
for info_name, info_value in package_info.items():
snapshot_info[info_name] = info_value

result[_convert_pnpm_v9_package_name(package)] = snapshot_info

return result

def _parse_pnpm_lock_json(content):
Expand Down Expand Up @@ -209,7 +277,11 @@ def _parse_pnpm_lock_common(parsed, err):

packages = parsed.get("packages", {})

if lockfile_version >= 6.0:
if lockfile_version >= 9.0:
snapshots = parsed.get("snapshots", {})
importers = _convert_v9_importers(importers)
packages = _convert_v9_packages(packages, snapshots)
elif lockfile_version >= 6.0:
# special handling for lockfile v6 which had breaking changes
importers = _convert_v6_importers(importers)
packages = _convert_v6_packages(packages)
Expand All @@ -226,8 +298,9 @@ def _assert_lockfile_version(version, testonly = False):
# 5.4 - pnpm v7.0.0 bumped the lockfile version to 5.4
# 6.0 - pnpm v8.0.0 bumped the lockfile version to 6.0; this included breaking changes
# 6.1 - pnpm v8.6.0 bumped the lockfile version to 6.1
# 9.0 - pnpm v9.0.0 bumped the lockfile version to 9.0
min_lock_version = 5.4
max_lock_version = 6.1
max_lock_version = 9.0
msg = None

if version < min_lock_version:
Expand Down

0 comments on commit 9bf7831

Please sign in to comment.