Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure Corepack Usage for npm, pnpm, and yarn Command Execution #10944

Merged
78 changes: 74 additions & 4 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ def self.yarn_berry?(yarn_lock)
false
end

sig { returns(Integer) }
sig { returns(T.any(Integer, T.noreturn)) }
def self.yarn_major_version
retries = 0
output = run_single_yarn_command("--version")
Expand All @@ -171,6 +171,7 @@ def self.yarn_major_version
handle_subprocess_failure(e)
end

sig { params(error: StandardError).returns(T.noreturn) }
def self.handle_subprocess_failure(error)
message = error.message
if YARN_PATH_NOT_FOUND.match?(message)
Expand Down Expand Up @@ -224,6 +225,7 @@ def self.yarn_4_or_higher?
yarn_major_version >= 4
end

sig { returns(T.nilable(String)) }
def self.setup_yarn_berry
# Always disable immutable installs so yarn's CI detection doesn't prevent updates.
run_single_yarn_command("config set enableImmutableInstalls false")
Expand Down Expand Up @@ -260,24 +262,92 @@ def self.run_yarn_commands(*commands)
# NOTE: Needs to be explicitly run through corepack to respect the
# `packageManager` setting in `package.json`, because corepack does not
# add shims for NPM.
sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
def self.run_npm_command(command, fingerprint: command)
SharedHelpers.run_shell_command("corepack npm #{command}", fingerprint: "corepack npm #{fingerprint}")
if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
package_manager_run_command(NpmPackageManager::NAME, command, fingerprint: fingerprint)
else
SharedHelpers.run_shell_command("corepack npm #{command}", fingerprint: "corepack npm #{fingerprint}")
end
end

# Setup yarn and run a single yarn command returning stdout/stderr
sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
def self.run_yarn_command(command, fingerprint: nil)
setup_yarn_berry
run_single_yarn_command(command, fingerprint: fingerprint)
end

# Run single pnpm command returning stdout/stderr
sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
def self.run_pnpm_command(command, fingerprint: nil)
SharedHelpers.run_shell_command("pnpm #{command}", fingerprint: "pnpm #{fingerprint || command}")
if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
package_manager_run_command(PNPMPackageManager::NAME, command, fingerprint: fingerprint)
else
SharedHelpers.run_shell_command("pnpm #{command}", fingerprint: "pnpm #{fingerprint || command}")
end
end

# Run single yarn command returning stdout/stderr
sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
def self.run_single_yarn_command(command, fingerprint: nil)
SharedHelpers.run_shell_command("yarn #{command}", fingerprint: "yarn #{fingerprint || command}")
if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
package_manager_run_command(YarnPackageManager::NAME, command, fingerprint: fingerprint)
else
SharedHelpers.run_shell_command("yarn #{command}", fingerprint: "yarn #{fingerprint || command}")
end
end

# Install the package manager for specified version by using corepack
# and prepare it for use by using corepack
sig { params(name: String, version: String).void }
def self.install(name, version)
Dependabot.logger.info("Installing \"#{name}@#{version}\"")

package_manager_install(name, version)
package_manager_activate(name, version)
installed_version = package_manager_version(name)

Dependabot.logger.info("Installed version of #{name}: #{installed_version}")
end

# Install the package manager for specified version by using corepack
sig { params(name: String, version: String).void }
def self.package_manager_install(name, version)
SharedHelpers.run_shell_command(
"corepack install #{name}@#{version} --global --cache-only",
fingerprint: "corepack install <name>@<version> --global --cache-only"
)
end

Copy link
Contributor Author

@kbukum1 kbukum1 Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

moved from PackageManagerHelper into Helpers.

# Prepare the package manager for use by using corepack
sig { params(name: String, version: String).void }
def self.package_manager_activate(name, version)
SharedHelpers.run_shell_command(
"corepack prepare #{name}@#{version} --activate",
fingerprint: "corepack prepare --activate"
)
end

# Get the version of the package manager by using corepack
sig { params(name: String).returns(String) }
def self.package_manager_version(name)
package_manager_run_command(name, "-v")
end

# Run single command on package manager returning stdout/stderr
sig do
params(
name: String,
command: String,
fingerprint: T.nilable(String)
).returns(String)
end
def self.package_manager_run_command(name, command, fingerprint: nil)
SharedHelpers.run_shell_command(
"corepack #{name} #{command}",
fingerprint: "corepack #{name} #{fingerprint || command}"
)
end
private_class_method :run_single_yarn_command

Expand Down
5 changes: 5 additions & 0 deletions npm_and_yarn/lib/dependabot/npm_and_yarn/package_manager.rb
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ def raise_if_unsupported!(name, version)
end

def install(name, version)
if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
Helpers.install(name, version.to_s)
return
end

Dependabot.logger.info("Installing \"#{name}@#{version}\"")

SharedHelpers.run_shell_command(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@

let(:tmp_path) { Dependabot::Utils::BUMP_TMP_DIR_PATH }

# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
FileUtils.mkdir_p(tmp_path)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:npm_fallback_version_above_v6).and_return(npm_fallback_version_above_v6_enabled)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,18 @@

let(:repo_contents_path) { build_tmp_repo(project_name, path: "projects") }

before { FileUtils.mkdir_p(tmp_path) }
# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
FileUtils.mkdir_p(tmp_path)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Dependabot::Experiments.reset!
end

describe "errors" do
context "with a dependency version that can't be found" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,18 @@

let(:tmp_path) { Dependabot::Utils::BUMP_TMP_DIR_PATH }

before { FileUtils.mkdir_p(tmp_path) }
# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
FileUtils.mkdir_p(tmp_path)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Dependabot::Experiments.reset!
end

describe "errors" do
context "with a dependency version that can't be found" do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,15 @@

# Variable to control the npm fallback version feature flag
let(:npm_fallback_version_above_v6_enabled) { true }
# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
FileUtils.mkdir_p(tmp_path)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:npm_fallback_version_above_v6).and_return(npm_fallback_version_above_v6_enabled)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@
# Variable to control the npm fallback version feature flag
let(:npm_fallback_version_above_v6_enabled) { true }

# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:npm_fallback_version_above_v6).and_return(npm_fallback_version_above_v6_enabled)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@
# Variable to control the npm fallback version feature flag
let(:npm_fallback_version_above_v6_enabled) { true }

# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
stub_request(:get, react_dom_registry_listing_url)
.to_return(status: 200, body: react_dom_registry_response)
Expand All @@ -79,7 +82,7 @@
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:npm_fallback_version_above_v6).and_return(npm_fallback_version_above_v6_enabled)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:npm_fallback_version_above_v6).and_return(npm_fallback_version_above_v6_enabled)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate!

.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,20 @@
end
let(:registry_listing_url) { "#{registry_base}/#{escaped_dependency_name}" }
let(:registry_base) { "https://registry.npmjs.org" }
# Variable to control the enabling feature flag for the corepack fix
let(:enable_corepack_for_npm_and_yarn) { true }

before do
stub_request(:get, registry_listing_url)
.to_return(status: 200, body: registry_response)
stub_request(:head, "#{registry_base}/#{dependency_name}/-/#{unscoped_dependency_name}-#{target_version}.tgz")
.to_return(status: 200)
allow(Dependabot::Experiments).to receive(:enabled?)
.with(:enable_corepack_for_npm_and_yarn).and_return(enable_corepack_for_npm_and_yarn)
end

after do
Dependabot::Experiments.reset!
end

it_behaves_like "an update checker"
Expand Down
Loading