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

Raise Error for Unsupported Bundler Version #10601

Merged
merged 19 commits into from
Sep 17, 2024

Conversation

kbukum1
Copy link
Contributor

@kbukum1 kbukum1 commented Sep 13, 2024

What are you trying to accomplish?

This PR introduces logic to raise an error when the version of Bundler is unsupported. The change is controlled by the bundler_v1_unsupported_error feature flag, allowing the error to be activated only when the flag is enabled.

Anything you want to highlight for special attention from reviewers?

The feature flag bundler_v1_unsupported_error controls whether the error is raised for unsupported Bundler v1 versions.

How will you know you've accomplished your goal?

The goal is achieved if:

  • The error is raised correctly when the feature flag is enabled and Bundler v1 is unsupported.
  • The error will be displayed on the Dependabot Insights page and the Security Alerts page.
  • The behavior is properly controlled by the feature flag.

Checklist

  • I have run the complete test suite to ensure all tests and linters pass.
  • I have thoroughly tested my code changes to ensure they work as expected, including adding additional tests for new functionality.
  • I have written clear and descriptive commit messages.
  • I have provided a detailed description of the changes in the pull request, including the problem it addresses, how it fixes the problem, and any relevant details about the implementation.
  • I have ensured that the code is well-documented and easy to understand.

@github-actions github-actions bot added the L: ruby:bundler RubyGems via bundler label Sep 13, 2024
show_alert: true
)
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was originally created to follow the notice structure when implementing the deprecation feature. However, after implementing the unsupported error, I realized we don’t need a similar structure to the deprecation notice. We already have a specialized error (Dependabot::ToolVersionNotSupported) used in other cases, so we are generalizing that for unsupported versions.

Reference code: https://github.com/dependabot/dependabot-core/blob/main/common/lib/dependabot/errors.rb#L435


generate_pm_unsupported_notice(package_manager)
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was originally created to follow the notice structure when implementing the deprecation feature. However, after implementing the unsupported error, I realized we don’t need a similar structure to the deprecation notice. We already have a specialized error (Dependabot::ToolVersionNotSupported) used in other cases, so we are generalizing that for unsupported versions.

Reference code: https://github.com/dependabot/dependabot-core/blob/main/common/lib/dependabot/errors.rb#L435

return true if unsupported_versions.include?(version)

supported_versions = self.supported_versions
return version < supported_versions.first if supported_versions.any?
Copy link
Contributor Author

@kbukum1 kbukum1 Sep 13, 2024

Choose a reason for hiding this comment

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

This method was added during the deprecation warning but wasn’t used. We're now refining it for the unsupported error, returning false and leave the implementation to the sub class package manager.

supported_versions_message
)
end

# Checks if the current version is unsupported.
# Returns true if the version is in the unsupported_versions array; false otherwise.
# @example
# package_manager.unsupported? #=> false
sig { returns(T::Boolean) }
def unsupported?
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just note that this method written in general however the implementation can override this so bundler v1 package manager currently implementing this.

return false unless Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)

# Determine if the Bundler version is unsupported.
version < supported_versions.first
Copy link
Contributor Author

@kbukum1 kbukum1 Sep 13, 2024

Choose a reason for hiding this comment

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

We expect the version to be lower then the first element of supported versions list if it is not supported. In other cases we are unable to determine if it is not supported.

sig { override.returns(T::Boolean) }
def unsupported?
!deprecated? && version < supported_versions.first
# Check if the feature flag for Bundler v1 unsupported error is enabled.
return false unless Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)
Copy link
Contributor Author

@kbukum1 kbukum1 Sep 13, 2024

Choose a reason for hiding this comment

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

This feature flag will be used to activate the unsupported version error for Bundler v1 on the specified unsupported date.

@kbukum1 kbukum1 force-pushed the kamil/bundler_v1_unsupported_error branch from 3eb843c to f818ef8 Compare September 16, 2024 03:00
@@ -96,86 +114,6 @@ def initialize(name:, version:, deprecated_versions: [], unsupported_versions: [
end
end

describe ".generate_support_notice" do
Copy link
Contributor Author

@kbukum1 kbukum1 Sep 16, 2024

Choose a reason for hiding this comment

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

Not used generate_support_notice method is removed after finding out that we don't need to create error notice for unsupported package manager. Instead we are using general error flow to raise unsupported error.

@@ -204,33 +142,4 @@ def initialize(name:, version:, deprecated_versions: [], unsupported_versions: [
})
end
end

describe ".generate_pm_unsupported_notice" do
Copy link
Contributor Author

@kbukum1 kbukum1 Sep 16, 2024

Choose a reason for hiding this comment

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

Not used generate_pm_unsupported_notice method is removed after finding out that we don't need to create error notice for unsupported package manager. Instead we are using general error flow to raise unsupported error.

Version.new("2")
].freeze, T::Array[Dependabot::Version])
# Keep versions in ascending order
SUPPORTED_BUNDLER_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version])
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Keeping the array in ascending order is important because we compare the first element of supported_versions with the current version (version < supported_versions.first) to determine if it is unsupported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We added specs to check if this array is ordered, so we don't need to run sorting.

Copy link
Member

Choose a reason for hiding this comment

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

Assuming that we'd only support versions greater than X, we could remove the requirement of having developers manually sorting by checking that a version is greater than all versions in this collection.

That would fall apart if we supported, say PackageManager v1 and v3, but not v2. However, that would also fall apart here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

applied the change to compare with each of them.

sig { override.returns(T::Boolean) }
def unsupported?
# Check if the feature flag for Bundler v1 unsupported error is enabled.
return false unless Dependabot::Experiments.enabled?(:bundler_v1_unsupported_error)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The feature flag going to be activated when we are not supporting the version anymore.

@kbukum1 kbukum1 marked this pull request as ready for review September 16, 2024 20:37
@kbukum1 kbukum1 requested a review from a team as a code owner September 16, 2024 20:37
@kbukum1
Copy link
Contributor Author

kbukum1 commented Sep 16, 2024

Tested the operations locally.

When the feature flag is ON:

Feature Flag ON Screenshot

When the feature flag is OFF:

Feature Flag OFF Screenshot

@kbukum1 kbukum1 marked this pull request as draft September 16, 2024 21:15
@kbukum1 kbukum1 marked this pull request as ready for review September 16, 2024 21:52
@@ -15,23 +15,6 @@

require "dependabot/bundler"

# Stub PackageManagerBase
class StubPackageManager < Dependabot::PackageManagerBase
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved into DummyPkgHelpers

@@ -16,23 +16,6 @@

require "dependabot/bundler"

# Stub PackageManagerBase
class StubPackageManager < Dependabot::PackageManagerBase
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved into DummyPkgHelpers

@@ -18,23 +18,6 @@

require "dependabot/bundler"

# Stub PackageManagerBase
class StubPackageManager < Dependabot::PackageManagerBase
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved into DummyPkgHelpers

bundler/lib/dependabot/bundler/package_manager.rb Outdated Show resolved Hide resolved

it "returns false" do
it "returns false, as unsupported takes precedence" do
Copy link
Member

Choose a reason for hiding this comment

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

🤔 I can see room for confusion if #deprecated? goes from true to false when support is dropped, but I think this is correct.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, currently Bundler v1 is supported but deprecated. With the feature flag off, we show deprecation warnings. Once we switch the unsupported v1 feature flag on, Bundler v1 will no longer be supported, and instead of showing deprecation warnings, an unsupported error will be raised, stopping the process.

@@ -64,12 +67,23 @@ def deprecated?
# package_manager.unsupported? #=> false
sig { returns(T::Boolean) }
def unsupported?
return true if unsupported_versions.include?(version)
false
Copy link
Member

Choose a reason for hiding this comment

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

⚠️ I'm concerned that this might have unintended consequences. Have you audited all package managers to ensure they'll still be supported when this merges?

Outside of the scope of this work, but #supported?, with a default of true would be a little easier for me to reason about 😅

Copy link
Contributor Author

@kbukum1 kbukum1 Sep 17, 2024

Choose a reason for hiding this comment

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

Bundler was the first package manager to implement this feature, and I initially added the unsupported? method, though it wasn’t used at the time since it was part of a future task. For other package managers, we assume the version is supported by default, unless the unsupported? condition is explicitly implemented in the related eco-system.

Note: Currently, only Bundler is implementing this package manager, but we plan to have all ecosystems implement it in the future.

Comment on lines +244 to +245
# Raise an error if the package manager version is unsupported
dependency_snapshot.package_manager&.raise_if_unsupported!
Copy link
Member

Choose a reason for hiding this comment

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

🔎 Is the &. needed here for changes which happen across ecosystems?

Copy link
Contributor Author

@kbukum1 kbukum1 Sep 17, 2024

Choose a reason for hiding this comment

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

Yes, because the other ecosystems don't yet have a package_manager implementation. We always need the package_manager object from the ecosystem to perform these operations.

Note: Currently, only Bundler has implemented this package manager, but we plan to extend it to all ecosystems in the future.

updater/spec/support/dummy_pkg_helpers.rb Outdated Show resolved Hide resolved
Version.new("2")
].freeze, T::Array[Dependabot::Version])
# Keep versions in ascending order
SUPPORTED_BUNDLER_VERSIONS = T.let([Version.new("2")].freeze, T::Array[Dependabot::Version])
Copy link
Member

Choose a reason for hiding this comment

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

Assuming that we'd only support versions greater than X, we could remove the requirement of having developers manually sorting by checking that a version is greater than all versions in this collection.

That would fall apart if we supported, say PackageManager v1 and v3, but not v2. However, that would also fall apart here.

@kbukum1
Copy link
Contributor Author

kbukum1 commented Sep 17, 2024

@landongrindheim

Thank you for the review! I’ve addressed all the comments and provided responses.

Just a quick note: Currently, only Bundler has implemented this package manager (also only deprecation is active), but we plan to extend it to all ecosystems in the future.

@kbukum1 kbukum1 force-pushed the kamil/bundler_v1_unsupported_error branch from 1a7f064 to f1a4759 Compare September 17, 2024 20:43
@kbukum1 kbukum1 force-pushed the kamil/bundler_v1_unsupported_error branch from f1a4759 to 9c344de Compare September 17, 2024 21:00
@kbukum1 kbukum1 merged commit 93e1827 into main Sep 17, 2024
123 checks passed
@kbukum1 kbukum1 deleted the kamil/bundler_v1_unsupported_error branch September 17, 2024 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
L: ruby:bundler RubyGems via bundler
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants