Skip to content

Commit 4b777e5

Browse files
Copilotrobaiken
authored andcommitted
Try pnpm update --depth Infinity before pnpm audit --fix
Adds a first-tier fallback that runs pnpm update --depth Infinity <dep> (with -r --include-workspace-root for workspaces) when the regular update is a no-op. This updates transitive dependencies in the lockfile without modifying any package.json (unlike pnpm audit --fix). If --depth Infinity is also a no-op we fall through to the existing audit --fix path.
1 parent 1867676 commit 4b777e5

5 files changed

Lines changed: 75 additions & 0 deletions

File tree

npm_and_yarn/lib/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,11 @@ def run_pnpm_update(pnpm_lock:, updated_pnpm_workspace_content: nil)
167167
run_pnpm_install
168168

169169
updated_content = File.read(pnpm_lock.name)
170+
if updated_content == original_content && Dependabot::Experiments.enabled?(:enable_audit_fix_fallback)
171+
run_pnpm_deep_update_fallback
172+
updated_content = File.read(pnpm_lock.name)
173+
end
174+
170175
if updated_content == original_content && Dependabot::Experiments.enabled?(:enable_audit_fix_fallback)
171176
run_pnpm_audit_fix_fallback(pnpm_lock, original_content)
172177
updated_content = File.read(pnpm_lock.name)
@@ -196,6 +201,23 @@ def run_pnpm_install
196201
)
197202
end
198203

204+
# Tries `pnpm update --depth Infinity <dep>` for each dependency as a
205+
# first-tier fallback when the regular update is a no-op (typically
206+
# transitive deps not listed in any package.json). Unlike `audit --fix`
207+
# this does not write `overrides` to package.json.
208+
sig { void }
209+
def run_pnpm_deep_update_fallback
210+
recursive = workspace_files.any?
211+
dependencies.each do |dep|
212+
NativeHelpers.run_pnpm_deep_update_command(dep.name, recursive: recursive)
213+
dep.metadata[:deep_update_used] = true
214+
end
215+
rescue SharedHelpers::HelperSubprocessFailed
216+
Dependabot.logger.info(
217+
"pnpm update --depth Infinity failed or partially fixed — continuing with any changes made"
218+
)
219+
end
220+
199221
# Runs `pnpm audit --fix` as a fallback when the primary update is a no-op.
200222
# `pnpm audit --fix` adds `overrides` to `package.json` — since we can
201223
# only return lockfile content from `run_pnpm_update`, any manifest

npm_and_yarn/lib/dependabot/npm_and_yarn/native_helpers.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,20 @@ def self.run_pnpm_audit_fix_command
6969
)
7070
end
7171

72+
sig { params(dependency_name: String, recursive: T::Boolean).returns(String) }
73+
def self.run_pnpm_deep_update_command(dependency_name, recursive: false)
74+
# `pnpm update --depth Infinity <dep>` traverses the full dependency
75+
# graph, allowing transitive dependencies to be updated in the lockfile
76+
# without modifying any package.json (unlike `pnpm audit --fix`).
77+
# `-r --include-workspace-root` is required for workspace repos so the
78+
# update is applied across all packages.
79+
flags = recursive ? "-r --include-workspace-root " : ""
80+
Helpers.run_pnpm_command(
81+
"#{flags}update #{dependency_name} --depth Infinity --lockfile-only",
82+
fingerprint: "#{flags}update <dependency_name> --depth Infinity --lockfile-only"
83+
)
84+
end
85+
7286
sig { returns(String) }
7387
def self.run_yarn_audit_fix_command
7488
# Fallback for transitive dependencies where `yarn up -R` is a no-op.

npm_and_yarn/lib/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,11 @@ def run_pnpm_updater(path, lockfile_name)
235235
)
236236

237237
updated_content = File.read(lockfile_name)
238+
if updated_content == original_content && Dependabot::Experiments.enabled?(:enable_audit_fix_fallback)
239+
run_pnpm_deep_update_fallback
240+
updated_content = File.read(lockfile_name)
241+
end
242+
238243
if updated_content == original_content && Dependabot::Experiments.enabled?(:enable_audit_fix_fallback)
239244
run_pnpm_audit_fix_fallback(lockfile_name, original_content)
240245
updated_content = File.read(lockfile_name)
@@ -245,6 +250,20 @@ def run_pnpm_updater(path, lockfile_name)
245250
end
246251
end
247252

253+
# First-tier fallback: try `pnpm update --depth Infinity <dep>` to
254+
# update transitive dependencies in the lockfile without modifying
255+
# any package.json (unlike `pnpm audit --fix`).
256+
sig { void }
257+
def run_pnpm_deep_update_fallback
258+
recursive = Dir.glob("**/pnpm-workspace.yaml").any?
259+
NativeHelpers.run_pnpm_deep_update_command(dependency.name, recursive: recursive)
260+
dependency.metadata[:deep_update_used] = true
261+
rescue SharedHelpers::HelperSubprocessFailed
262+
Dependabot.logger.info(
263+
"pnpm update --depth Infinity failed or partially fixed — continuing with any changes made"
264+
)
265+
end
266+
248267
# Runs `pnpm audit --fix` as a fallback when `pnpm update` is a no-op.
249268
# `pnpm audit --fix` adds `overrides` to `package.json`, but this method
250269
# only returns the lockfile. If audit-fix modifies any package.json we

npm_and_yarn/spec/dependabot/npm_and_yarn/file_updater/pnpm_lockfile_updater_spec.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,13 @@
770770
expect(Dependabot::NpmAndYarn::Helpers).to receive(:run_pnpm_command)
771771
.with("install --lockfile-only")
772772
.ordered
773+
expect(Dependabot::NpmAndYarn::Helpers).to receive(:run_pnpm_command)
774+
.with(
775+
"-r --include-workspace-root update prettier --depth Infinity --lockfile-only",
776+
{ fingerprint: "-r --include-workspace-root update <dependency_name> --depth Infinity --lockfile-only" }
777+
)
778+
.ordered
779+
.and_return("")
773780
expect(Dependabot::NpmAndYarn::Helpers).to receive(:run_pnpm_command)
774781
.with("audit --fix", { fingerprint: "audit --fix" })
775782
.ordered

npm_and_yarn/spec/dependabot/npm_and_yarn/update_checker/subdependency_version_resolver_spec.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,19 @@
210210
latest_resolvable_version
211211
end
212212

213+
it "tries pnpm update --depth Infinity before pnpm audit --fix" do
214+
allow(Dependabot::NpmAndYarn::Helpers).to receive(:run_pnpm_command).and_return("")
215+
allow(Dependabot::NpmAndYarn::NativeHelpers)
216+
.to receive_messages(run_pnpm_deep_update_command: "", run_pnpm_audit_fix_command: "")
217+
218+
expect(Dependabot::NpmAndYarn::NativeHelpers)
219+
.to receive(:run_pnpm_deep_update_command).once.ordered
220+
expect(Dependabot::NpmAndYarn::NativeHelpers)
221+
.to receive(:run_pnpm_audit_fix_command).once.ordered
222+
223+
latest_resolvable_version
224+
end
225+
213226
context "when pnpm audit --fix fails" do
214227
it "logs and continues without raising" do
215228
allow(Dependabot::NpmAndYarn::Helpers).to receive(:run_pnpm_command).and_return("")

0 commit comments

Comments
 (0)