From e76c3e7b22da5adf033c4a3b10f1b8f12e89cd0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Thu, 11 May 2023 21:26:53 +0200 Subject: [PATCH] Allow updating the version of PNPM itself --- common/lib/dependabot/dependency.rb | 10 ++++-- common/lib/dependabot/update_checkers/base.rb | 3 +- .../dependabot/npm_and_yarn/file_parser.rb | 32 ++++++++++++++++++- .../file_updater/package_json_updater.rb | 30 +++++++++++++++-- .../file_updater/pnpm_lockfile_updater.rb | 6 ++-- .../update_checker/version_resolver.rb | 2 +- 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/common/lib/dependabot/dependency.rb b/common/lib/dependabot/dependency.rb index 1f179556b4..6866fe6eba 100644 --- a/common/lib/dependabot/dependency.rb +++ b/common/lib/dependabot/dependency.rb @@ -42,7 +42,7 @@ def self.register_name_normaliser(package_manager, name_builder) def initialize(name:, requirements:, package_manager:, version: nil, previous_version: nil, previous_requirements: nil, - subdependency_metadata: [], removed: false, metadata: {}) + subdependency_metadata: [], removed: false, on_package_manager: false, metadata: {}) @name = name @version = version @requirements = requirements.map { |req| symbolize_keys(req) } @@ -55,6 +55,7 @@ def initialize(name:, requirements:, package_manager:, version: nil, &.map { |h| symbolize_keys(h) } end @removed = removed + @on_package_manager = on_package_manager @metadata = symbolize_keys(metadata || {}) check_values @@ -68,6 +69,10 @@ def removed? @removed end + def on_package_manager? + @on_package_manager + end + def numeric_version @numeric_version ||= version_class.new(version) if version && version_class.correct?(version) end @@ -81,7 +86,8 @@ def to_h "previous_requirements" => previous_requirements, "package_manager" => package_manager, "subdependency_metadata" => subdependency_metadata, - "removed" => removed? ? true : nil + "removed" => removed? ? true : nil, + "on_package_manager" => on_package_manager? ? true : nil }.compact end diff --git a/common/lib/dependabot/update_checkers/base.rb b/common/lib/dependabot/update_checkers/base.rb index 9012f6a87d..70ff840376 100644 --- a/common/lib/dependabot/update_checkers/base.rb +++ b/common/lib/dependabot/update_checkers/base.rb @@ -184,7 +184,8 @@ def updated_dependency_with_own_req_unlock previous_requirements: dependency.requirements, package_manager: dependency.package_manager, metadata: dependency.metadata, - subdependency_metadata: dependency.subdependency_metadata + subdependency_metadata: dependency.subdependency_metadata, + on_package_manager: dependency.on_package_manager? ) end diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser.rb index a6b33cc477..c2685efc9c 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_parser.rb @@ -9,6 +9,7 @@ require "dependabot/shared_helpers" require "dependabot/npm_and_yarn/helpers" require "dependabot/npm_and_yarn/native_helpers" +require "dependabot/npm_and_yarn/package_manager" require "dependabot/npm_and_yarn/version" require "dependabot/npm_and_yarn/requirement" require "dependabot/git_metadata_fetcher" @@ -78,9 +79,30 @@ def manifest_dependencies end end + pnpm_version = package_manager.locked_version("pnpm") + + if pnpm_version + dependency_set << Dependency.new( + name: "pnpm", + version: pnpm_version, + package_manager: "npm_and_yarn", + requirements: [{ + requirement: pnpm_version, + file: "package.json", + groups: ["dependencies"], + source: nil + }], + on_package_manager: true + ) + end + dependency_set end + def package_manager + @package_manager ||= PackageManager.new(parsed_root_package_file) + end + def lockfile_parser @lockfile_parser ||= LockfileParser.new( dependency_files: dependency_files @@ -334,6 +356,10 @@ def url_for_relevant_cred(resolved_url) resolved_url.gsub(/#{Regexp.quote(reg)}.*/, "") + reg end + def parsed_root_package_file + JSON.parse(root_package_file.content) + end + def package_files @package_files ||= begin @@ -345,12 +371,16 @@ def package_files .reject(&:support_file?) [ - dependency_files.find { |f| f.name == "package.json" }, + root_package_file, *sub_packages ].compact end end + def root_package_file + @root_package_file ||= dependency_files.find { |f| f.name == "package.json" } + end + def version_class NpmAndYarn::Version end diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb index 5d409c0c22..1106a8efe3 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/package_json_updater.rb @@ -29,7 +29,7 @@ def updated_package_json_content new_content = update_package_json_declaration( package_json_content: content, - dependency_name: dep.name, + dependency: dep, old_req: old_req, new_req: new_req ) @@ -80,7 +80,23 @@ def updated_requirements(dependency) end def update_package_json_declaration(package_json_content:, new_req:, - dependency_name:, old_req:) + dependency:, old_req:) + args = { + package_json_content: package_json_content, + new_req: new_req, + dependency_name: dependency.name, + old_req: old_req + } + + if dependency.on_package_manager? + update_package_manager_declaration(**args) + else + update_dependency_declaration(**args) + end + end + + def update_dependency_declaration(package_json_content:, new_req:, + dependency_name:, old_req:) original_line = declaration_line( dependency_name: dependency_name, dependency_req: old_req, @@ -140,6 +156,16 @@ def update_package_json_resolutions(package_json_content:, new_req:, content end + def update_package_manager_declaration(package_json_content:, new_req:, + dependency_name:, old_req:) + parsed_json_content = JSON.parse(package_json_content) + package_manager = parsed_json_content["packageManager"] + + return package_json_content unless package_manager == "#{dependency_name}@#{old_req[:requirement]}" + + package_json_content.sub("\"#{package_manager}\"", "\"#{dependency_name}@#{new_req[:requirement]}\"") + end + def declaration_line(dependency_name:, dependency_req:, content:) git_dependency = dependency_req.dig(:source, :type) == "git" diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb index ab0d71dd16..1f343d37a9 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb @@ -42,11 +42,11 @@ def run_pnpm_update(pnpm_lock:) File.write(".npmrc", npmrc_content(pnpm_lock)) SharedHelpers.with_git_configured(credentials: credentials) do - run_pnpm_updater + run_pnpm_updater unless dependencies.first.on_package_manager? write_final_package_json_files - run_pnpm_install + sync_lockfile File.read(pnpm_lock.name) end @@ -64,7 +64,7 @@ def run_pnpm_updater ) end - def run_pnpm_install + def sync_lockfile SharedHelpers.run_shell_command( "pnpm install --lockfile-only" ) diff --git a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb index 15b6758fc8..ab6ca3040a 100644 --- a/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb +++ b/npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/version_resolver.rb @@ -93,7 +93,7 @@ def initialize(dependency:, credentials:, dependency_files:, end def latest_resolvable_version - return latest_allowable_version if git_dependency?(dependency) + return latest_allowable_version if git_dependency?(dependency) || dependency.on_package_manager? return if part_of_tightly_locked_monorepo? return if types_update_available? return if original_package_update_available?