Skip to content
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
31 changes: 30 additions & 1 deletion lib/bundler/source_list.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ def add_git_source(options = {})

def add_rubygems_source(options = {})
new_source = Source::Rubygems.new(options)
return @global_rubygems_source if @global_rubygems_source == new_source
if @global_rubygems_source == new_source
warn_on_cooldown_conflict(new_source, @global_rubygems_source)
return @global_rubygems_source
end

existing_source = @rubygems_sources.find {|s| s == new_source }
warn_on_cooldown_conflict(new_source, existing_source) if existing_source

add_source_to_list new_source, @rubygems_sources
end
Expand All @@ -60,6 +66,13 @@ def add_plugin_source(source, options = {})
end

def add_global_rubygems_remote(uri, cooldown: nil)
unless cooldown.nil?
new_source = source_class.new("remotes" => uri, "cooldown" => cooldown)
[global_rubygems_source, *@rubygems_sources].find do |existing_source|
warn_on_cooldown_conflict(new_source, existing_source)
end
end

global_rubygems_source.add_remote(uri, cooldown: cooldown)
global_rubygems_source
end
Expand Down Expand Up @@ -222,6 +235,22 @@ def source_list_for(source)
end
end

def warn_on_cooldown_conflict(new_source, existing_source)
new_source.remote_cooldowns.any? do |uri, cooldown|
next false unless existing_source.remotes.include?(uri)

existing_cooldown = existing_source.cooldown_for(uri)
next false if existing_cooldown == cooldown

previous = existing_cooldown ? "`cooldown: #{existing_cooldown}`" : "no cooldown"
Bundler.ui.warn "The source #{uri} is declared more than once with different cooldown " \
"values (`cooldown: #{cooldown}` here, #{previous} previously). All declarations of " \
"the same source URL share a single cooldown, so only one of these values will apply " \
"to all gems from this source."
true
end
end

def warn_on_git_protocol(source)
return if Bundler.settings["git.allow_insecure"]

Expand Down
1 change: 1 addition & 0 deletions spec/bundler/dsl_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
describe "#source with cooldown" do
before do
allow(@rubygems).to receive(:add_remote)
allow(@rubygems).to receive(:remote_cooldowns).and_return({})
end

it "accepts a non-negative integer" do
Expand Down
50 changes: 50 additions & 0 deletions spec/bundler/source_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,56 @@
end
end

describe "cooldown conflicts between duplicate source declarations" do
it "warns when a block source duplicates the global source with a different cooldown" do
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
expect(Bundler.ui).to receive(:warn).with(/declared more than once with different cooldown values \(`cooldown: 0` here, `cooldown: 7` previously\)/)
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 0)
end

it "warns when a global source duplicates a block source with a different cooldown" do
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 0)
expect(Bundler.ui).to receive(:warn).with(/declared more than once with different cooldown values \(`cooldown: 7` here, `cooldown: 0` previously\)/)
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
end

it "warns when a block source duplicates another block source with a different cooldown" do
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 7)
expect(Bundler.ui).to receive(:warn).with(/declared more than once with different cooldown values/)
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 0)
end

it "warns when a global remote is declared again with a different cooldown" do
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
expect(Bundler.ui).to receive(:warn).with(/declared more than once with different cooldown values/)
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 0)
end

it "warns when a duplicate declaration adds a cooldown to a source declared without one" do
source_list.add_global_rubygems_remote("https://rubygems.org")
expect(Bundler.ui).to receive(:warn).with(/declared more than once with different cooldown values \(`cooldown: 7` here, no cooldown previously\)/)
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 7)
end

it "does not warn when the duplicate declaration uses the same cooldown" do
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
expect(Bundler.ui).not_to receive(:warn)
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"], "cooldown" => 7)
end

it "does not warn when the duplicate declaration has no cooldown" do
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
expect(Bundler.ui).not_to receive(:warn)
source_list.add_rubygems_source("remotes" => ["https://rubygems.org"])
end

it "does not warn when different sources declare different cooldowns" do
source_list.add_global_rubygems_remote("https://rubygems.org", cooldown: 7)
expect(Bundler.ui).not_to receive(:warn)
source_list.add_rubygems_source("remotes" => ["https://other-rubygems.org"], "cooldown" => 0)
end
end

describe "#all_sources" do
it "includes the global rubygems source when rubygems sources have been added" do
source_list.add_git_source("uri" => "git://host/path.git")
Expand Down
39 changes: 39 additions & 0 deletions spec/install/cooldown_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,45 @@
expect(the_bundle).to include_gems("ripe_gem 1.0.0", "child 1.0.0")
end

it "warns when the same source is declared again with a different cooldown and keeps the first value" do
# https://github.com/rubygems/rubygems/issues/9723: a second declaration
# of the same URL is deduped into the first one, so its cooldown cannot
# act as a per-gem exemption.
install_gemfile <<-G, artifice: "compact_index_cooldown"
source "https://gem.repo3", cooldown: 7
source "https://gem.repo3", cooldown: 0 do
gem "ripe_gem"
end
G

expect(err).to include("The source https://gem.repo3/ is declared more than once with different cooldown values (`cooldown: 0` here, `cooldown: 7` previously).")
expect(the_bundle).to include_gems("ripe_gem 1.0.0")
end

it "does not warn when the same source is declared again without a cooldown" do
install_gemfile <<-G, artifice: "compact_index_cooldown"
source "https://gem.repo3", cooldown: 7
source "https://gem.repo3" do
gem "ripe_gem"
end
G

expect(err).not_to include("cooldown")
expect(the_bundle).to include_gems("ripe_gem 1.0.0")
end

it "does not warn when the same source is declared again with the same cooldown" do
install_gemfile <<-G, artifice: "compact_index_cooldown"
source "https://gem.repo3", cooldown: 7
source "https://gem.repo3", cooldown: 7 do
gem "ripe_gem"
end
G

expect(err).not_to include("cooldown")
expect(the_bundle).to include_gems("ripe_gem 1.0.0")
end

it "is overridden by CLI --cooldown when Gemfile sets a different per-source value" do
gemfile <<-G
source "https://gem.repo3", cooldown: 0
Expand Down