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

Bundler 2 [pre-release]: Detect bundler version to use when bundler 2 is available #3350

Merged
merged 3 commits into from
Mar 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bundler/helpers/v2/run.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

require "functions"

MIN_BUNDLER_VERSION = "2.0.0"
MIN_BUNDLER_VERSION = "2.1.0"
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 actually rely on the Bundler v2.1.0 API for Bundler::URI, which was private in 2.0.x


def validate_bundler_version!
return true if correct_bundler_version?
Expand Down
32 changes: 23 additions & 9 deletions bundler/lib/dependabot/bundler/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,37 @@ module Bundler
module Helpers
V1 = "1"
V2 = "2"
# If we are updating a project with no Gemfile.lock, we default to the
# newest version we support
DEFAULT = V2
# If we are updating a project with a Gemfile.lock that does not specify
# the version it was bundled with, with failover to V1 on the assumption
# it was created with an old version that didn't add this information
FAILOVER = V1

# NOTE: options is a manditory argument to ensure we pass it from all calling classes
def self.bundler_version(_lockfile, options:)
# For now, force V2 if bundler_2_available
return V2 if options[:bundler_2_available]
BUNDLER_MAJOR_VERSION_REGEX = /BUNDLED WITH\s+(?<version>\d+)\./m.freeze

# TODO: Add support for bundler v2 based on lockfile
# return V2 if lockfile.content.match?(/BUNDLED WITH\s+2/m)
# NOTE: options is a manditory argument to ensure we pass it from all calling classes
def self.bundler_version(lockfile, options:)
# TODO: Remove once bundler 2 is fully supported
return V1 unless options[:bundler_2_available]
return DEFAULT unless lockfile

V1
if (matches = lockfile.content.match(BUNDLER_MAJOR_VERSION_REGEX))
matches[:version].to_i >= 2 ? V2 : V1
else
FAILOVER
end
end

def self.detected_bundler_version(lockfile)
return "unknown" unless lockfile
return V2 if lockfile.content.match?(/BUNDLED WITH\s+2/m)

V1
if (matches = lockfile.content.match(BUNDLER_MAJOR_VERSION_REGEX))
matches[:version]
else
FAILOVER
end
end
end
end
Expand Down
124 changes: 124 additions & 0 deletions bundler/spec/dependabot/bundler/helper_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# frozen_string_literal: true

require "spec_helper"

require "dependabot/bundler/helpers"

RSpec.describe Dependabot::Bundler::Helpers do
let(:no_lockfile) { nil }

let(:lockfile_bundled_with_missing) do
Dependabot::DependencyFile.new(name: "Gemfile.lock", content: <<~LOCKFILE)
Mock Gemfile.lock Content Goes Here
LOCKFILE
end

let(:lockfile_bundled_with_v1) do
Dependabot::DependencyFile.new(name: "Gemfile.lock", content: <<~LOCKFILE)
Mock Gemfile.lock Content Goes Here

BUNDLED WITH
1.17.3
LOCKFILE
end

let(:lockfile_bundled_with_v2) do
Dependabot::DependencyFile.new(name: "Gemfile.lock", content: <<~LOCKFILE)
Mock Gemfile.lock Content Goes Here

BUNDLED WITH
2.2.11
LOCKFILE
end

let(:lockfile_bundled_with_future_version) do
Dependabot::DependencyFile.new(name: "Gemfile.lock", content: <<~LOCKFILE)
Mock Gemfile.lock Content Goes Here

BUNDLED WITH
3.9.99
LOCKFILE
end

describe "#bundler_version" do
def described_method(lockfile)
described_class.bundler_version(lockfile, options: options)
end

context "when bundler 2 is not available" do
let(:options) { {} }

it "is 1 if there is no lockfile" do
expect(described_method(no_lockfile)).to eql("1")
end

it "is 1 if there is no bundled with string" do
expect(described_method(lockfile_bundled_with_missing)).to eql("1")
end

it "is 1 if it was bundled with a v1.x version" do
expect(described_method(lockfile_bundled_with_v1)).to eql("1")
end

it "is 1 if it was bundled with a v2.x version" do
expect(described_method(lockfile_bundled_with_v2)).to eql("1")
end

it "is 1 if it was bundled with a future version" do
expect(described_method(lockfile_bundled_with_future_version)).to eql("1")
end
end

context "when bundler 2 is available" do
let(:options) do
{ bundler_2_available: true }
end

it "is 2 if there is no lockfile" do
expect(described_method(no_lockfile)).to eql("2")
end

it "is 1 if there is no bundled with string" do
expect(described_method(lockfile_bundled_with_missing)).to eql("1")
end

it "is 1 if it was bundled with a v1.x version" do
expect(described_method(lockfile_bundled_with_v1)).to eql("1")
end

it "is 2 if it was bundled with a v2.x version" do
expect(described_method(lockfile_bundled_with_v2)).to eql("2")
end

it "is 2 if it was bundled with a future version" do
expect(described_method(lockfile_bundled_with_future_version)).to eql("2")
end
end
end

describe "#detected_bundler_version" do
def described_method(lockfile)
described_class.detected_bundler_version(lockfile)
end

it "is unknown if there is no lockfile" do
expect(described_method(no_lockfile)).to eql("unknown")
end

it "is 1 if there is no bundled with string" do
expect(described_method(lockfile_bundled_with_missing)).to eql("1")
end

it "is 1 if it was bundled with a v1.x version" do
expect(described_method(lockfile_bundled_with_v1)).to eql("1")
end

it "is 2 if it was bundled with a v2.x version" do
expect(described_method(lockfile_bundled_with_v2)).to eql("2")
end

it "is 1 if it was bundled with a future version" do
expect(described_method(lockfile_bundled_with_future_version)).to eql("3")
end
end
end