diff options
Diffstat (limited to 'spec/bundler/install/gemfile/gemspec_spec.rb')
-rw-r--r-- | spec/bundler/install/gemfile/gemspec_spec.rb | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/spec/bundler/install/gemfile/gemspec_spec.rb b/spec/bundler/install/gemfile/gemspec_spec.rb new file mode 100644 index 0000000000..1ea613c9d2 --- /dev/null +++ b/spec/bundler/install/gemfile/gemspec_spec.rb @@ -0,0 +1,563 @@ +# frozen_string_literal: true +require "spec_helper" + +RSpec.describe "bundle install from an existing gemspec" do + before(:each) do + build_gem "bar", :to_system => true + build_gem "bar-dev", :to_system => true + end + + it "should install runtime and development dependencies" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("Gemfile", "source :rubygems\ngemspec") + s.add_dependency "bar", "=1.0.0" + s.add_development_dependency "bar-dev", "=1.0.0" + end + install_gemfile <<-G + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}' + G + + expect(the_bundle).to include_gems "bar 1.0.0" + expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development + end + + it "that is hidden should install runtime and development dependencies" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("Gemfile", "source :rubygems\ngemspec") + s.add_dependency "bar", "=1.0.0" + s.add_development_dependency "bar-dev", "=1.0.0" + end + FileUtils.mv tmp.join("foo", "foo.gemspec"), tmp.join("foo", ".gemspec") + + install_gemfile <<-G + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}' + G + + expect(the_bundle).to include_gems "bar 1.0.0" + expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development + end + + it "should handle a list of requirements" do + build_gem "baz", "1.0", :to_system => true + build_gem "baz", "1.1", :to_system => true + + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("Gemfile", "source :rubygems\ngemspec") + s.add_dependency "baz", ">= 1.0", "< 1.1" + end + install_gemfile <<-G + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}' + G + + expect(the_bundle).to include_gems "baz 1.0" + end + + it "should raise if there are no gemspecs available" do + build_lib("foo", :path => tmp.join("foo"), :gemspec => false) + + error = install_gemfile(<<-G) + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}' + G + expect(error).to match(/There are no gemspecs at #{tmp.join('foo')}/) + end + + it "should raise if there are too many gemspecs available" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("foo2.gemspec", build_spec("foo", "4.0").first.to_ruby) + end + + error = install_gemfile(<<-G) + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}' + G + expect(error).to match(/There are multiple gemspecs at #{tmp.join('foo')}/) + end + + it "should pick a specific gemspec" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("foo2.gemspec", "") + s.add_dependency "bar", "=1.0.0" + s.add_development_dependency "bar-dev", "=1.0.0" + end + + install_gemfile(<<-G) + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gems "bar 1.0.0" + expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :development + end + + it "should use a specific group for development dependencies" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("foo2.gemspec", "") + s.add_dependency "bar", "=1.0.0" + s.add_development_dependency "bar-dev", "=1.0.0" + end + + install_gemfile(<<-G) + source "file://#{gem_repo2}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo', :development_group => :dev + G + + expect(the_bundle).to include_gems "bar 1.0.0" + expect(the_bundle).not_to include_gems "bar-dev 1.0.0", :groups => :development + expect(the_bundle).to include_gems "bar-dev 1.0.0", :groups => :dev + end + + it "should match a lockfile even if the gemspec defines development dependencies" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.write("Gemfile", "source 'file://#{gem_repo1}'\ngemspec") + s.add_dependency "actionpack", "=2.3.2" + s.add_development_dependency "rake", "=10.0.2" + end + + Dir.chdir(tmp.join("foo")) do + bundle "install" + # This should really be able to rely on $stderr, but, it's not written + # right, so we can't. In fact, this is a bug negation test, and so it'll + # ghost pass in future, and will only catch a regression if the message + # doesn't change. Exit codes should be used correctly (they can be more + # than just 0 and 1). + output = bundle("install --deployment") + expect(output).not_to match(/You have added to the Gemfile/) + expect(output).not_to match(/You have deleted from the Gemfile/) + expect(output).not_to match(/install in deployment mode after changing/) + end + end + + it "should match a lockfile without needing to re-resolve" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "rack" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "install", :verbose => true + expect(out).to include("Found no changes, using resolution from the lockfile") + end + + it "should match a lockfile without needing to re-resolve with development dependencies" do + simulate_platform java + + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "rack" + s.add_development_dependency "thin" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "install", :verbose => true + expect(out).to include("Found no changes, using resolution from the lockfile") + end + + it "should match a lockfile on non-ruby platforms with a transitive platform dependency" do + simulate_platform java + simulate_ruby_engine "jruby" + + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "platform_specific" + end + + install_gem "platform_specific-1.0-java" + + install_gemfile! <<-G + gemspec :path => '#{tmp.join("foo")}' + G + + bundle! "update --bundler", :verbose => true + expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 JAVA" + end + + it "should evaluate the gemspec in its directory" do + build_lib("foo", :path => tmp.join("foo")) + File.open(tmp.join("foo/foo.gemspec"), "w") do |s| + s.write "raise 'ahh' unless Dir.pwd == '#{tmp.join("foo")}'" + end + + install_gemfile <<-G + gemspec :path => '#{tmp.join("foo")}' + G + expect(@err).not_to match(/ahh/) + end + + it "allows the gemspec to activate other gems" do + # see https://github.com/bundler/bundler/issues/5409 + # + # issue was caused by rubygems having an unresolved gem during a require, + # so emulate that + system_gems %w(rack-1.0.0 rack-0.9.1 rack-obama-1.0) + + build_lib("foo", :path => bundled_app) + gemspec = bundled_app("foo.gemspec").read + bundled_app("foo.gemspec").open("w") do |f| + f.write "#{gemspec.strip}.tap { gem 'rack-obama'; require 'rack-obama' }" + end + + install_gemfile! <<-G + gemspec + G + + expect(the_bundle).to include_gem "foo 1.0" + end + + it "allows conflicts" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.version = "1.0.0" + s.add_dependency "bar", "= 1.0.0" + end + build_gem "deps", :to_system => true do |s| + s.add_dependency "foo", "= 0.0.1" + end + build_gem "foo", "0.0.1", :to_system => true + + install_gemfile <<-G + source "file://#{gem_repo2}" + gem "deps" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gems "foo 1.0.0" + end + + it "does not break Gem.finish_resolve with conflicts", :rubygems => ">= 2" do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.version = "1.0.0" + s.add_dependency "bar", "= 1.0.0" + end + build_repo2 do + build_gem "deps" do |s| + s.add_dependency "foo", "= 0.0.1" + end + build_gem "foo", "0.0.1" + end + + install_gemfile! <<-G + source "file://#{gem_repo2}" + gem "deps" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gems "foo 1.0.0" + + run! "Gem.finish_resolve; puts 'WIN'" + expect(out).to eq("WIN") + end + + context "in deployment mode" do + context "when the lockfile was not updated after a change to the gemspec's dependencies" do + it "reports that installation failed" do + build_lib "cocoapods", :path => bundled_app do |s| + s.add_dependency "activesupport", ">= 1" + end + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec + G + + expect(the_bundle).to include_gems("cocoapods 1.0", "activesupport 2.3.5") + + build_lib "cocoapods", :path => bundled_app do |s| + s.add_dependency "activesupport", ">= 1.0.1" + end + + bundle "install --deployment" + + expect(out).to include("changed") + end + end + end + + context "when child gemspecs conflict with a released gemspec" do + before do + # build the "parent" gem that depends on another gem in the same repo + build_lib "source_conflict", :path => bundled_app do |s| + s.add_dependency "rack_middleware" + end + + # build the "child" gem that is the same version as a released gem, but + # has completely different and conflicting dependency requirements + build_lib "rack_middleware", "1.0", :path => bundled_app("rack_middleware") do |s| + s.add_dependency "rack", "1.0" # anything other than 0.9.1 + end + end + + it "should install the child gemspec's deps" do + install_gemfile <<-G + source "file://#{gem_repo1}" + gemspec + G + + expect(the_bundle).to include_gems "rack 1.0" + end + end + + context "with a lockfile and some missing dependencies" do + let(:source_uri) { "http://localgemserver.test" } + + context "previously bundled for Ruby" do + let(:platform) { "ruby" } + let(:explicit_platform) { false } + + before do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.add_dependency "rack", "=1.0.0" + end + + if explicit_platform + create_file( + tmp.join("foo", "foo-#{platform}.gemspec"), + build_spec("foo", "1.0", platform) do + dep "rack", "=1.0.0" + @spec.authors = "authors" + @spec.summary = "summary" + end.first.to_ruby + ) + end + + gemfile <<-G + source "#{source_uri}" + gemspec :path => "../foo" + G + + lockfile <<-L + PATH + remote: ../foo + specs: + foo (1.0) + rack (= 1.0.0) + + GEM + remote: #{source_uri} + specs: + rack (1.0.0) + + PLATFORMS + #{generic_local_platform} + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + + context "using JRuby with explicit platform" do + let(:platform) { "java" } + let(:explicit_platform) { true } + + it "should install" do + simulate_ruby_engine "jruby" do + simulate_platform "java" do + results = bundle "install", :artifice => "endpoint" + expect(results).to include("Installing rack 1.0.0") + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + end + end + + context "using JRuby" do + let(:platform) { "java" } + + it "should install" do + simulate_ruby_engine "jruby" do + simulate_platform "java" do + results = bundle "install", :artifice => "endpoint" + expect(results).to include("Installing rack 1.0.0") + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + end + end + + context "using Windows" do + it "should install" do + simulate_windows do + results = bundle "install", :artifice => "endpoint" + expect(results).to include("Installing rack 1.0.0") + expect(the_bundle).to include_gems "rack 1.0.0" + end + end + end + end + + context "bundled for ruby and jruby" do + let(:platform_specific_type) { :runtime } + let(:dependency) { "platform_specific" } + before do + build_repo2 do + build_gem "indirect_platform_specific" do |s| + s.add_runtime_dependency "platform_specific" + end + end + + build_lib "foo", :path => "." do |s| + if platform_specific_type == :runtime + s.add_runtime_dependency dependency + elsif platform_specific_type == :development + s.add_development_dependency dependency + else + raise "wrong dependency type #{platform_specific_type}, can only be :development or :runtime" + end + end + + %w(ruby jruby).each do |platform| + simulate_platform(platform) do + install_gemfile <<-G + source "file://#{gem_repo2}" + gemspec + G + end + end + end + + context "on ruby" do + before do + simulate_platform("ruby") + bundle :install + end + + context "as a runtime dependency" do + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + PATH + remote: . + specs: + foo (1.0) + platform_specific + + GEM + remote: file:#{gem_repo2}/ + specs: + platform_specific (1.0) + platform_specific (1.0-java) + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "as a development dependency" do + let(:platform_specific_type) { :development } + + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + PATH + remote: . + specs: + foo (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + platform_specific (1.0) + platform_specific (1.0-java) + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + + context "with an indirect platform-specific development dependency" do + let(:platform_specific_type) { :development } + let(:dependency) { "indirect_platform_specific" } + + it "keeps java dependencies in the lockfile" do + expect(the_bundle).to include_gems "foo 1.0", "indirect_platform_specific 1.0", "platform_specific 1.0 RUBY" + expect(lockfile).to eq strip_whitespace(<<-L) + PATH + remote: . + specs: + foo (1.0) + + GEM + remote: file:#{gem_repo2}/ + specs: + indirect_platform_specific (1.0) + platform_specific + platform_specific (1.0) + platform_specific (1.0-java) + + PLATFORMS + java + ruby + + DEPENDENCIES + foo! + indirect_platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + L + end + end + end + end + end + + context "with multiple platforms" do + before do + build_lib("foo", :path => tmp.join("foo")) do |s| + s.version = "1.0.0" + s.add_development_dependency "rack" + s.write "foo-universal-java.gemspec", build_spec("foo", "1.0.0", "universal-java") {|sj| sj.runtime "rack", "1.0.0" }.first.to_ruby + end + end + + it "installs the ruby platform gemspec" do + simulate_platform "ruby" + + install_gemfile! <<-G + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gems "foo 1.0.0", "rack 1.0.0" + end + + it "installs the ruby platform gemspec and skips dev deps with --without development" do + simulate_platform "ruby" + + install_gemfile! <<-G, :without => "development" + source "file://#{gem_repo1}" + gemspec :path => '#{tmp.join("foo")}', :name => 'foo' + G + + expect(the_bundle).to include_gem "foo 1.0.0" + expect(the_bundle).not_to include_gem "rack" + end + end +end |