diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index fa1e907e2..a7117f584 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -47,6 +47,7 @@ jobs: e2e/npm_link_package e2e/npm_link_package-esm e2e/npm_translate_lock + e2e/npm_translate_lock_disable_hooks e2e/npm_translate_lock_empty e2e/npm_translate_lock_multi e2e/npm_translate_lock_partial_clone diff --git a/e2e/npm_translate_lock_disable_hooks/.bazelignore b/e2e/npm_translate_lock_disable_hooks/.bazelignore new file mode 100644 index 000000000..40b878db5 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/.bazelignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/e2e/npm_translate_lock_disable_hooks/.bazeliskrc b/e2e/npm_translate_lock_disable_hooks/.bazeliskrc new file mode 120000 index 000000000..0fbe20ff6 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/.bazeliskrc @@ -0,0 +1 @@ +../../.bazeliskrc \ No newline at end of file diff --git a/e2e/npm_translate_lock_disable_hooks/.bazelrc b/e2e/npm_translate_lock_disable_hooks/.bazelrc new file mode 100644 index 000000000..413c99502 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/.bazelrc @@ -0,0 +1,15 @@ +# Import Aspect bazelrc presets +try-import %workspace%/../../.aspect/bazelrc/bazel7.bazelrc +import %workspace%/../../.aspect/bazelrc/convenience.bazelrc +import %workspace%/../../.aspect/bazelrc/correctness.bazelrc +import %workspace%/../../.aspect/bazelrc/debug.bazelrc +import %workspace%/../../.aspect/bazelrc/javascript.bazelrc +import %workspace%/../../.aspect/bazelrc/performance.bazelrc + +### YOUR PROJECT SPECIFIC OPTIONS GO HERE ### + +# Load any settings & overrides specific to the current user from `.aspect/bazelrc/user.bazelrc`. +# This file should appear in `.gitignore` so that settings are not shared with team members. This +# should be last statement in this config so the user configuration is able to overwrite flags from +# this file. See https://bazel.build/configure/best-practices#bazelrc-file. +try-import %workspace%/../../.aspect/bazelrc/user.bazelrc diff --git a/e2e/npm_translate_lock_disable_hooks/.bazelversion b/e2e/npm_translate_lock_disable_hooks/.bazelversion new file mode 120000 index 000000000..96cf94962 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/.bazelversion @@ -0,0 +1 @@ +../../.bazelversion \ No newline at end of file diff --git a/e2e/npm_translate_lock_disable_hooks/BUILD.bazel b/e2e/npm_translate_lock_disable_hooks/BUILD.bazel new file mode 100644 index 000000000..b3c7980b1 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/BUILD.bazel @@ -0,0 +1,52 @@ +load("@aspect_bazel_lib//lib:write_source_files.bzl", "write_source_files") +load("@bazel_skylib//rules:build_test.bzl", "build_test") +load("@npm//:defs.bzl", "npm_link_all_packages") + +npm_link_all_packages(name = "node_modules") + +build_test( + name = "test", + targets = [ + ":node_modules", + ], +) + +genrule( + name = "snapshot-extracted-wksp", + srcs = ["@npm//:repositories.bzl"], + outs = ["snapshot-extracted-wksp.bzl"], + cmd = 'sed "s/system_tar = \\".*\\"/system_tar = \\"\\"/" "$<" > "$@"', + # Target names may be different on workspace vs bzlmod + target_compatible_with = select({ + "@aspect_bazel_lib//lib:bzlmod": ["@platforms//:incompatible"], + "//conditions:default": [], + }), + visibility = ["//visibility:private"], +) + +write_source_files( + name = "write_npm_translate_lock_wksp", + files = { + "snapshots/wksp/repositories.bzl": ":snapshot-extracted-wksp.bzl", + }, + # Target names may be different on bazel versions + tags = ["skip-on-bazel6"], + target_compatible_with = select({ + "@aspect_bazel_lib//lib:bzlmod": ["@platforms//:incompatible"], + "//conditions:default": [], + }), +) + +write_source_files( + name = "write_npm_translate_lock_defs", + files = { + "snapshots/defs.bzl": "@npm//:defs.bzl", + "snapshots/aspect_test_c_links_defs.bzl": "@npm__at_aspect-test_c__2.0.0__links//:defs.bzl", + }, + # Target names may be different on bazel versions + tags = ["skip-on-bazel6"], + target_compatible_with = select({ + "@aspect_bazel_lib//lib:bzlmod": [], + "//conditions:default": ["@platforms//:incompatible"], + }), +) diff --git a/e2e/npm_translate_lock_disable_hooks/MODULE.bazel b/e2e/npm_translate_lock_disable_hooks/MODULE.bazel new file mode 100644 index 000000000..1060835fa --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/MODULE.bazel @@ -0,0 +1,21 @@ +bazel_dep(name = "aspect_rules_js", version = "0.0.0", dev_dependency = True) +local_path_override( + module_name = "aspect_rules_js", + path = "../..", +) + +bazel_dep(name = "aspect_bazel_lib", version = "2.7.7", dev_dependency = True) +bazel_dep(name = "bazel_skylib", version = "1.5.0", dev_dependency = True) +bazel_dep(name = "platforms", version = "0.0.9", dev_dependency = True) + +npm = use_extension( + "@aspect_rules_js//npm:extensions.bzl", + "npm", +) +npm.npm_translate_lock( + name = "npm", + data = ["//:package.json"], + pnpm_lock = "//:pnpm-lock.yaml", + run_lifecycle_hooks = False, +) +use_repo(npm, "npm", "npm__at_aspect-test_c__2.0.0__links") diff --git a/e2e/npm_translate_lock_disable_hooks/WORKSPACE b/e2e/npm_translate_lock_disable_hooks/WORKSPACE new file mode 100644 index 000000000..e30b1f154 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/WORKSPACE @@ -0,0 +1,25 @@ +local_repository( + name = "aspect_rules_js", + path = "../..", +) + +load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies") + +rules_js_dependencies() + +load("@aspect_rules_js//js:toolchains.bzl", "DEFAULT_NODE_VERSION", "rules_js_register_toolchains") + +rules_js_register_toolchains(node_version = DEFAULT_NODE_VERSION) + +load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock") + +npm_translate_lock( + name = "npm", + data = ["//:package.json"], + pnpm_lock = "//:pnpm-lock.yaml", + run_lifecycle_hooks = False, +) + +load("@npm//:repositories.bzl", "npm_repositories") + +npm_repositories() diff --git a/e2e/npm_translate_lock_disable_hooks/WORKSPACE.bzlmod b/e2e/npm_translate_lock_disable_hooks/WORKSPACE.bzlmod new file mode 100644 index 000000000..3a956c2b7 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/WORKSPACE.bzlmod @@ -0,0 +1,2 @@ +# The presence of this file causes WORKSPACE to be ignored when bzlmod is enabled. +# See https://docs.google.com/document/d/1JtXIVnXyFZ4bmbiBCr5gsTH4-opZAFf5DMMb-54kES0/edit#heading=h.y054fjub9max diff --git a/e2e/npm_translate_lock_disable_hooks/package.json b/e2e/npm_translate_lock_disable_hooks/package.json new file mode 100644 index 000000000..4e709d236 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/package.json @@ -0,0 +1,10 @@ +{ + "dependencies": { + "@aspect-test/c": "2.0.0" + }, + "pnpm": { + "onlyBuiltDependencies": [ + "@aspect-test/c" + ] + } +} diff --git a/e2e/npm_translate_lock_disable_hooks/pnpm-lock.yaml b/e2e/npm_translate_lock_disable_hooks/pnpm-lock.yaml new file mode 100644 index 000000000..854a590a5 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/pnpm-lock.yaml @@ -0,0 +1,24 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +onlyBuiltDependencies: + - '@aspect-test/c' + +importers: + + .: + dependencies: + '@aspect-test/c': + specifier: 2.0.0 + version: 2.0.0 + +packages: + + /@aspect-test/c@2.0.0: + resolution: {integrity: sha512-vRuHi/8zxZ+IRGdgdX4VoMNFZrR9UqO87yQx61IGIkjgV7QcKUeu5jfvIE3Mr0WNQeMdO1JpyTx1UUpsE73iug==} + hasBin: true + requiresBuild: true + dev: false diff --git a/e2e/npm_translate_lock_disable_hooks/pnpm-workspace.yaml b/e2e/npm_translate_lock_disable_hooks/pnpm-workspace.yaml new file mode 100644 index 000000000..2cce0eb74 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - '.' diff --git a/e2e/npm_translate_lock_disable_hooks/snapshots/aspect_test_c_links_defs.bzl b/e2e/npm_translate_lock_disable_hooks/snapshots/aspect_test_c_links_defs.bzl new file mode 100644 index 000000000..0d10d069b --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/snapshots/aspect_test_c_links_defs.bzl @@ -0,0 +1,163 @@ +"@generated by @aspect_rules_js//npm/private:npm_import.bzl for npm package @aspect-test/c@2.0.0" + +# buildifier: disable=bzl-visibility +load("@aspect_rules_js//npm/private:npm_package_store_internal.bzl", _npm_package_store = "npm_package_store_internal") + +# buildifier: disable=bzl-visibility +load("@aspect_rules_js//npm/private:npm_link_package_store.bzl", _npm_link_package_store = "npm_link_package_store") + +# Generated npm_package_store targets for npm package @aspect-test/c@2.0.0 +# buildifier: disable=function-docstring +def npm_imported_package_store(name): + bazel_package = native.package_name() + root_package = "" + is_root = bazel_package == root_package + if not is_root: + msg = "No store links in bazel package '%s' for npm package npm package @aspect-test/c@2.0.0. This is neither the root package nor a link package of this package." % bazel_package + fail(msg) + if not name.endswith("/@aspect-test/c"): + msg = "name must end with one of '/@aspect-test/c' when linking the store in package '@aspect-test/c'; recommended value is 'node_modules/@aspect-test/c'" + fail(msg) + link_root_name = name[:-len("/@aspect-test/c")] + + deps = { + ":.aspect_rules_js/{}/@aspect-test+c@2.0.0/pkg".format(link_root_name): "@aspect-test/c", + } + ref_deps = {} + + store_target_name = ".aspect_rules_js/{}/@aspect-test+c@2.0.0".format(link_root_name) + + # reference target used to avoid circular deps + _npm_package_store( + name = "{}/ref".format(store_target_name), + package = "@aspect-test/c", + version = "2.0.0", + dev = False, + tags = ["manual"], + ) + + # post-lifecycle target with reference deps for use in terminal target with transitive closure + _npm_package_store( + name = "{}/pkg".format(store_target_name), + src = "{}/pkg_lc".format(store_target_name) if False else "@@aspect_rules_js~~npm~npm__at_aspect-test_c__2.0.0//:pkg", + package = "@aspect-test/c", + version = "2.0.0", + dev = False, + deps = ref_deps, + tags = ["manual"], + ) + + # package store target with transitive closure of all npm package dependencies + _npm_package_store( + name = store_target_name, + src = None if True else "@@aspect_rules_js~~npm~npm__at_aspect-test_c__2.0.0//:pkg", + package = "@aspect-test/c", + version = "2.0.0", + dev = False, + deps = deps, + visibility = ["//visibility:public"], + tags = ["manual"], + ) + + # filegroup target that provides a single file which is + # package directory for use in $(execpath) and $(rootpath) + native.filegroup( + name = "{}/dir".format(store_target_name), + srcs = [":{}".format(store_target_name)], + output_group = "package_directory", + visibility = ["//visibility:public"], + tags = ["manual"], + ) + +# Generated npm_package_store and npm_link_package_store targets for npm package @aspect-test/c@2.0.0 +# buildifier: disable=function-docstring +def npm_link_imported_package_store(name): + bazel_package = native.package_name() + link_packages = { + "": ["@aspect-test/c"], + } + if bazel_package in link_packages: + link_aliases = link_packages[bazel_package] + else: + link_aliases = ["@aspect-test/c"] + + link_alias = None + for _link_alias in link_aliases: + if name.endswith("/{}".format(_link_alias)): + # longest match wins + if not link_alias or len(_link_alias) > len(link_alias): + link_alias = _link_alias + if not link_alias: + msg = "name must end with one of '/{{ {link_aliases_comma_separated} }}' when called from package '@aspect-test/c'; recommended value(s) are 'node_modules/{{ {link_aliases_comma_separated} }}'".format(link_aliases_comma_separated = ", ".join(link_aliases)) + fail(msg) + + link_root_name = name[:-len("/{}".format(link_alias))] + store_target_name = ".aspect_rules_js/{}/@aspect-test+c@2.0.0".format(link_root_name) + + # terminal package store target to link + _npm_link_package_store( + name = name, + package = link_alias, + src = "//:{}".format(store_target_name), + visibility = ["//visibility:public"], + tags = ["manual"], + ) + + # filegroup target that provides a single file which is + # package directory for use in $(execpath) and $(rootpath) + native.filegroup( + name = "{}/dir".format(name), + srcs = [":{}".format(name)], + output_group = "package_directory", + visibility = ["//visibility:public"], + tags = ["manual"], + ) + + return [":{}".format(name)] if True else [] + +# Generated npm_package_store and npm_link_package_store targets for npm package @aspect-test/c@2.0.0 +# buildifier: disable=function-docstring +def npm_link_imported_package( + name = "node_modules", + link = None, + fail_if_no_link = True): + bazel_package = native.package_name() + root_package = "" + link_packages = { + "": ["@aspect-test/c"], + } + + if link_packages and link != None: + fail("link attribute cannot be specified when link_packages are set") + + is_link = (link == True) or (link == None and bazel_package in link_packages) + is_root = bazel_package == root_package + + if fail_if_no_link and not is_root and not link: + msg = "Nothing to link in bazel package '%s' for npm package npm package @aspect-test/c@2.0.0. This is neither the root package nor a link package of this package." % bazel_package + fail(msg) + + link_targets = [] + scoped_targets = {} + + if is_link: + link_aliases = [] + if bazel_package in link_packages: + link_aliases = link_packages[bazel_package] + if not link_aliases: + link_aliases = ["@aspect-test/c"] + for link_alias in link_aliases: + link_target_name = "{}/{}".format(name, link_alias) + npm_link_imported_package_store(name = link_target_name) + if True: + link_targets.append(":{}".format(link_target_name)) + link_scope = link_alias[:link_alias.find("/", 1)] if link_alias[0] == "@" else None + if link_scope: + if link_scope not in scoped_targets: + scoped_targets[link_scope] = [] + scoped_targets[link_scope].append(link_target_name) + + if is_root: + npm_imported_package_store("{}/@aspect-test/c".format(name)) + + return (link_targets, scoped_targets) diff --git a/e2e/npm_translate_lock_disable_hooks/snapshots/defs.bzl b/e2e/npm_translate_lock_disable_hooks/snapshots/defs.bzl new file mode 100644 index 000000000..fe21aaedb --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/snapshots/defs.bzl @@ -0,0 +1,66 @@ +"""@generated by npm_translate_lock(name = "npm", pnpm_lock = "@@//:pnpm-lock.yaml")""" + +load("@@aspect_rules_js~~npm~npm__at_aspect-test_c__2.0.0__links//:defs.bzl", link_0 = "npm_link_imported_package_store", store_0 = "npm_imported_package_store") + +# buildifier: disable=bzl-visibility +load("@aspect_rules_js//js:defs.bzl", _js_library = "js_library") + +_LINK_PACKAGES = [""] + +# buildifier: disable=function-docstring +def npm_link_all_packages(name = "node_modules", imported_links = []): + bazel_package = native.package_name() + root_package = "" + is_root = bazel_package == root_package + link = bazel_package in _LINK_PACKAGES + if not is_root and not link: + msg = "The npm_link_all_packages() macro loaded from @aspect_rules_js~~npm~npm//:defs.bzl and called in bazel package '%s' may only be called in bazel packages that correspond to the pnpm root package or pnpm workspace projects. Projects are discovered from the pnpm-lock.yaml and may be missing if the lockfile is out of date. Root package: '', pnpm workspace projects: %s" % (bazel_package, "'" + "', '".join(_LINK_PACKAGES) + "'") + fail(msg) + link_targets = [] + scope_targets = {} + + for link_fn in imported_links: + new_link_targets, new_scope_targets = link_fn(name) + link_targets.extend(new_link_targets) + for _scope, _targets in new_scope_targets.items(): + if _scope not in scope_targets: + scope_targets[_scope] = [] + scope_targets[_scope].extend(_targets) + + if is_root: + store_0(name = "{}/@aspect-test/c".format(name)) + if link: + if bazel_package == "": + link_0(name = "{}/@aspect-test/c".format(name)) + link_targets.append("//{}:{}/@aspect-test/c".format(bazel_package, name)) + if "@aspect-test" not in scope_targets: + scope_targets["@aspect-test"] = [link_targets[-1]] + else: + scope_targets["@aspect-test"].append(link_targets[-1]) + + for scope, scoped_targets in scope_targets.items(): + _js_library( + name = "{}/{}".format(name, scope), + srcs = scoped_targets, + tags = ["manual"], + visibility = ["//visibility:public"], + ) + + _js_library( + name = name, + srcs = link_targets, + tags = ["manual"], + visibility = ["//visibility:public"], + ) + +# buildifier: disable=function-docstring +def npm_link_targets(name = "node_modules", package = None): + bazel_package = package if package != None else native.package_name() + link = bazel_package in _LINK_PACKAGES + + link_targets = [] + + if link: + if bazel_package == "": + link_targets.append("//{}:{}/@aspect-test/c".format(bazel_package, name)) + return link_targets diff --git a/e2e/npm_translate_lock_disable_hooks/snapshots/wksp/repositories.bzl b/e2e/npm_translate_lock_disable_hooks/snapshots/wksp/repositories.bzl new file mode 100644 index 000000000..fee67c030 --- /dev/null +++ b/e2e/npm_translate_lock_disable_hooks/snapshots/wksp/repositories.bzl @@ -0,0 +1,24 @@ +"""@generated by npm_translate_lock(name = "npm", pnpm_lock = "@//:pnpm-lock.yaml")""" + +load("@aspect_rules_js//npm:repositories.bzl", "npm_import") + +# Generated npm_import repository rules corresponding to npm packages in @//:pnpm-lock.yaml +# buildifier: disable=function-docstring +def npm_repositories(): + npm_import( + name = "npm__at_aspect-test_c__2.0.0", + root_package = "", + link_workspace = "", + link_packages = { + "": ["@aspect-test/c"], + }, + package = "@aspect-test/c", + version = "2.0.0", + url = "https://registry.npmjs.org/@aspect-test/c/-/c-2.0.0.tgz", + system_tar = "", + package_visibility = ["//visibility:public"], + integrity = "sha512-vRuHi/8zxZ+IRGdgdX4VoMNFZrR9UqO87yQx61IGIkjgV7QcKUeu5jfvIE3Mr0WNQeMdO1JpyTx1UUpsE73iug==", + transitive_closure = { + "@aspect-test/c": ["2.0.0"], + }, + ) diff --git a/npm/private/npm_translate_lock.bzl b/npm/private/npm_translate_lock.bzl index a8af07f8a..298cc4578 100644 --- a/npm/private/npm_translate_lock.bzl +++ b/npm/private/npm_translate_lock.bzl @@ -581,7 +581,7 @@ def npm_translate_lock( public_hoist_packages = public_hoist_packages, dev = dev, no_optional = no_optional, - lifecycle_hooks = lifecycle_hooks, + lifecycle_hooks = lifecycle_hooks if lifecycle_hooks else {}, lifecycle_hooks_envs = lifecycle_hooks_envs, lifecycle_hooks_execution_requirements = lifecycle_hooks_execution_requirements, lifecycle_hooks_use_default_shell_env = lifecycle_hooks_use_default_shell_env, diff --git a/npm/private/npm_translate_lock_helpers.bzl b/npm/private/npm_translate_lock_helpers.bzl index eec4fa1bc..163aa8ad2 100644 --- a/npm/private/npm_translate_lock_helpers.bzl +++ b/npm/private/npm_translate_lock_helpers.bzl @@ -392,7 +392,7 @@ ERROR: can not apply both `pnpm.patchedDependencies` and `npm_translate_lock(pat elif name not in link_packages[public_hoist_package]: link_packages[public_hoist_package].append(name) - run_lifecycle_hooks = name in only_built_dependencies if only_built_dependencies != None else requires_build + run_lifecycle_hooks = all_lifecycle_hooks and (name in only_built_dependencies if only_built_dependencies != None else requires_build) if run_lifecycle_hooks: lifecycle_hooks, _ = _gather_values_from_matching_names(False, all_lifecycle_hooks, "*", name, friendly_name, unfriendly_name) lifecycle_hooks_env, _ = _gather_values_from_matching_names(True, attr.lifecycle_hooks_envs, "*", name, friendly_name, unfriendly_name)