diff options
author | SHIBATA Hiroshi <hsbt@ruby-lang.org> | 2019-01-12 17:50:16 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-01-12 17:50:16 +0900 |
commit | f931aa37e737273abc1f0dda3b6717d9f382a0ee (patch) | |
tree | b24594e89babeed3b94d2b73ab38f5c65c95216d | |
parent | 5c5c009d818d906a229671bae12294875bb63122 (diff) | |
parent | a63a39d738865665f714f179fe42dd10006da26d (diff) | |
download | bundler-f931aa37e737273abc1f0dda3b6717d9f382a0ee.tar.gz |
Merge branch 'master' into remove-old-ruby
79 files changed, 836 insertions, 331 deletions
diff --git a/.github/bors.toml b/.github/bors.toml index db93b69597..8f4d9a640a 100644 --- a/.github/bors.toml +++ b/.github/bors.toml @@ -2,7 +2,8 @@ status = [ "continuous-integration/travis-ci/push" ] -timeout-sec = 14400 +timeout_sec = 14400 +delete_merged_branches = true [committer] name = "Bundlerbot" diff --git a/.github/config.yml b/.github/config.yml new file mode 100644 index 0000000000..2804985bfc --- /dev/null +++ b/.github/config.yml @@ -0,0 +1,9 @@ +newPRWelcomeComment: | + Thanks for opening a pull request and helping make Bundler better! Someone from the Bundler team will take a look at your pull request shortly and leave any feedback. Please make sure that your pull request has tests for any changes or added functionality. + + We use Travis CI to test and make sure your change works functionally and uses acceptable conventions, you can review the current progress of Travis CI in the PR status window below. + + If you have any questions or concerns that you wish to ask, feel free to leave a comment in this PR or join our #bundler channel on [Slack](http://slack.bundler.io/). + + For more information about contributing to the Bundler project feel free to review our [CONTRIBUTING](https://github.com/bundler/bundler/blob/master/doc/contributing/README.md) guide + diff --git a/.github/welcome_message.md b/.github/welcome_message.md deleted file mode 100644 index e3b0c98b97..0000000000 --- a/.github/welcome_message.md +++ /dev/null @@ -1,7 +0,0 @@ -Thanks for opening a pull request and helping make Bundler better! Someone from the Bundler team will take a look at your pull request shortly and leave any feedback. Please make sure that your pull request has tests for any changes or added functionality. - -We use Travis CI to test and make sure your change works functionally and uses acceptable conventions, you can review the current progress of Travis CI in the PR status window below. - -If you have any questions or concerns that you wish to ask, feel free to leave a comment in this PR or join our #bundler channel on [Slack](http://slack.bundler.io/). - -For more information about contributing to the Bundler project feel free to review our [CONTRIBUTING](https://github.com/bundler/bundler/blob/master/doc/contributing/README.md) guide diff --git a/.travis.yml b/.travis.yml index 8bca456612..7ae6d12339 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,9 +27,14 @@ addons: secure: "TrzIv116JLGUxm6PAUskCYrv8KTDguncKROVwbnjVPKTGDAgoDderd8JUdDEXrKoZ9qGLD2TPYKExt9/QDl71E+qHdWnVqWv4HKCUk2P9z/VLKzHuggOUBkCXiJUhjywUieCJhI3N92bfq2EjSBbu2/OFHqWOjLQ+QCooTEBjv8=" rvm: - - 2.5.1 - - 2.4.3 - - 2.3.7 + - 2.6.0 + - 2.5.3 + - 2.4.5 + - 2.3.8 + +stages: + - linting + - test # Rubygems versions MUST be available as rake tasks # see Rakefile:125 for the list of possible RGV values @@ -37,23 +42,40 @@ env: # We need to know if changes to rubygems will break bundler on release - RGV=master # Test the latest rubygems release with all of our supported rubies - - RGV=v2.7.7 + - RGV=v3.0.1 -matrix: +jobs: include: + - rvm: 2.6.0 + script: rake rubocop + stage: linting + # Ruby 2.5, Rubygems 2.7 and up + - rvm: 2.5.3 + env: RGV=v2.7.7 + stage: test # Ruby 2.4, Rubygems 2.6 and up - - rvm: 2.4.2 + - rvm: 2.4.5 env: RGV=v2.6.14 + stage: test + - rvm: 2.4.5 + env: RGV=v2.7.7 + stage: test # Ruby 2.3, Rubygems 2.5 and up - rvm: 2.3.7 env: RGV=v2.5.2 + stage: test - rvm: 2.3.7 env: RGV=v2.6.14 + stage: test + - rvm: 2.3.7 + env: RGV=v2.7.7 + stage: test # Ruby-head (we want to know how we're doing, but not fail the build) - rvm: ruby-head env: RGV=master + stage: test # 1.x mode (we want to keep stuff passing in 1.x mode for now) - - rvm: 2.5.1 + - rvm: 2.6.0 env: RGV=v2.7.7 BUNDLER_SPEC_SUB_VERSION=1.98 allow_failures: diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd024e21d..d86054b2ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,68 @@ +## 1.17.3 (2018-12-27) + +Bugfixes: + + - Fix a Bundler error when installing gems on old versions of RubyGems ([#6839](https://github.com/bundler/bundler/issues/6839), @colby-swandale) + - Fix a rare issue where Bundler was removing itself after a `bundle clean` ([#6829](https://github.com/bundler/bundler/issues/6829), @colby-swandale) + +Documentation: + + - Add entry for the `bundle remove` command to the main Bundler manual page + +## 1.17.2 (2018-12-11) + + - Add compatibility for bundler merge with Ruby 2.6 + +## 1.17.1 (2018-10-25) + + - Convert `Pathname`s to `String`s before sorting them, fixing #6760 and #6758 ([#6761](https://github.com/bundler/bundler/pull/6761), @alexggordon) + +## 1.17.0 (2018-10-25) + +No new changes. + +## 1.17.0.pre.2 (2018-10-13) + +Features: + + - Configure Bundler home, cache, config and plugin directories with `BUNDLE_USER_HOME`, `BUNDLE_USER_CACHE`, `BUNDLE_USER_CONFIG` and `BUNDLE_USER_PLUGIN` env vars ([#4333](https://github.com/bundler/bundler/issues/4333), @gwerbin) + - Add `--all` option to `bundle binstubs` that will generate an executable file for all gems with commands in the bundle + - Add `bundle remove` command to remove gems from the Gemfile via the CLI + - Improve checking file permissions and asking for `sudo` in Bundler when it doesn't need to + - Add error message to `bundle add` to check adding duplicate gems to the Gemfile + - When asking for `sudo`, Bundler will show a list of folders/files that require elevated permissions to write to. + +The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Improve deprecation warning message for `bundle show` command + - Improve deprecation warning message for the `--force` option in `bundle install` + +## 1.17.0.pre.1 (2018-09-24) + +Features: + + - Check folder/file permissions of the Bundle home directory in the `bundle doctor` command ([#5786](https://github.com/bundler/bundler/issues/5786), @ajwann) + - Remove compiled gem extensions when running `bundle clean` ([#5596](https://github.com/bundler/bundler/issues/5596), @akhramov) + - Add `--paths` option to `bundle list` command ([#6172](https://github.com/bundler/bundler/issues/6172), @colby-swandale) + - Add base error class to gems generated from `bundle gem` ([#6260](https://github.com/bundler/bundler/issues/6260), @christhekeele) + - Correctly re-install gem extensions with a git source when running `bundle pristine` ([#6294](https://github.com/bundler/bundler/issues/6294), @wagenet) + - Add config option to disable platform warnings ([#6124](https://github.com/bundler/bundler/issues/6124), @agrim123) + - Add `--skip-install` option to `bundle add` command to add gems to the Gemfile without installation ([#6511](https://github.com/bundler/bundler/issues/6511), @agrim123) + - Add `--only-explicit` option to `bundle outdated` to list only outdated gems in the Gemfile ([#5366](https://github.com/bundler/bundler/issues/5366), @peret) + - Support adding multiple gems to the Gemfile with `bundle add` ([#6543](https://github.com/bundler/bundler/issues/6543), @agrim123) + - Make registered plugin events easier to manage in the Plugin API (@jules2689) + - Add new gem install hooks to the Plugin API (@jules2689) + - Add `--optimistic` and `--strict` options to `bundle add` ([#6553](https://github.com/bundler/bundler/issues/6553), @agrim123) + - Add `--without-group` and `--only-group` options to `bundle list` ([#6564](https://github.com/bundler/bundler/issues/6564), @agrim123) + - Add `--gemfile` option to the `bundle exec` command ([#5924](https://github.com/bundler/bundler/issues/5924), @ankitkataria) + +The following new features are available but are not enabled by default. These are intended to be tested by users for the upcoming release of Bundler 2. + + - Make `install --path` relative to the current working directory ([#2048](https://github.com/bundler/bundler/issues/2048), @igorbozato) + - Auto-configure job count ([#5808](https://github.com/bundler/bundler/issues/5808), @segiddins) + - Use the Gem Version Promoter for major gem updates ([#5993](https://github.com/bundler/bundler/issues/5993), @segiddins) + - Add config option to add the Ruby scope to `bundle config path` when configured globally (@segiddins) + ## 1.16.6 (2018-10-05) Changes: @@ -5,7 +5,8 @@ $:.unshift File.expand_path("../lib", __FILE__) require "shellwords" require "benchmark" -RUBYGEMS_REPO = if `cd .. && git remote --verbose 2>/dev/null` =~ /rubygems/i +NULL_DEVICE = (Gem.win_platform? ? "NUL" : "/dev/null") +RUBYGEMS_REPO = if `git -C "#{File.expand_path("..")}" remote --verbose 2> #{NULL_DEVICE}` =~ /rubygems/i File.expand_path("..") else File.expand_path("tmp/rubygems") @@ -50,17 +51,10 @@ namespace :spec do deps.delete("rdiscount") end - if Gem::VERSION < "2.0.0" - deps.sort_by {|name, _| name }.map do |name, version| - gem_install_command = "install --no-ri --no-rdoc --conservative #{name} -v '#{version}'" - sh %(#{Gem.ruby} -S gem #{gem_install_command}) - end - else - gem_install_command = "install --no-document --conservative " + deps.sort_by {|name, _| name }.map do |name, version| - "'#{name}:#{version}'" - end.join(" ") - sh %(#{Gem.ruby} -S gem #{gem_install_command}) - end + gem_install_command = "install --no-document --conservative " + deps.sort_by {|name, _| name }.map do |name, version| + "'#{name}:#{version}'" + end.join(" ") + sh %(#{Gem.ruby} -S gem #{gem_install_command}) # Download and install gems used inside tests $LOAD_PATH.unshift("./spec") @@ -147,7 +141,7 @@ begin rubyopt = ENV["RUBYOPT"] # When editing this list, also edit .travis.yml! branches = %w[master] - releases = %w[v2.5.2 v2.6.14 v2.7.7] + releases = %w[v2.5.2 v2.6.14 v2.7.7 v3.0.1] (branches + releases).each do |rg| desc "Run specs with RubyGems #{rg}" RSpec::Core::RakeTask.new(rg) do |t| @@ -213,11 +207,6 @@ begin # disallow making network requests on CI ENV["BUNDLER_SPEC_PRE_RECORDED"] = "TRUE" - if RUBY_VERSION >= "2.0.0" - puts "\n\e[1;33m[Travis CI] Running bundler linter\e[m\n\n" - Rake::Task["rubocop"].invoke - end - puts "\n\e[1;33m[Travis CI] Running bundler specs against RubyGems #{rg}\e[m\n\n" specs = safe_task { Rake::Task["spec:rubygems:#{rg}"].invoke } diff --git a/bundler.gemspec b/bundler.gemspec index d04bf34e7c..12b1b59b98 100644 --- a/bundler.gemspec +++ b/bundler.gemspec @@ -1,8 +1,12 @@ # coding: utf-8 # frozen_string_literal: true -require File.expand_path("../lib/bundler/version", __FILE__) -require "shellwords" +begin + require File.expand_path("../lib/bundler/version", __FILE__) +rescue LoadError + # for Ruby core repository + require File.expand_path("../bundler/version", __FILE__) +end Gem::Specification.new do |s| s.name = "bundler" @@ -43,7 +47,8 @@ Gem::Specification.new do |s| s.add_development_dependency "ronn", "~> 0.7.3" s.add_development_dependency "rspec", "~> 3.6" - s.files = `git -C #{Shellwords.escape File.dirname(__FILE__)} ls-files -z`.split("\x0").select {|f| f.match(%r{^(lib|exe)/}) } + base_dir = File.dirname(__FILE__).gsub(%r{([^A-Za-z0-9_\-.,:\/@\n])}, "\\\\\\1") + s.files = IO.popen("git -C #{base_dir} ls-files -z", &:read).split("\x0").select {|f| f.match(%r{^(lib|exe)/}) } # we don't check in man pages, but we need to ship them because # we use them to generate the long-form help for each command. diff --git a/lib/bundler.rb b/lib/bundler.rb index 2411ac20c2..137d916cc6 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -280,10 +280,19 @@ EOF ORIGINAL_ENV.clone end - # @deprecated Use `original_env` instead - # @return [Hash] Environment with all bundler-related variables removed + # @deprecated Use `unbundled_env` instead def clean_env - Bundler::SharedHelpers.major_deprecation(2, "`Bundler.clean_env` has weird edge cases, use `.original_env` instead") + Bundler::SharedHelpers.major_deprecation( + 2, + "`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + ) + + unbundled_env + end + + # @return [Hash] Environment with all bundler-related variables removed + def unbundled_env env = original_env if env.key?("BUNDLER_ORIG_MANPATH") @@ -305,12 +314,25 @@ EOF env end + # Run block with environment present before Bundler was activated def with_original_env with_env(original_env) { yield } end + # @deprecated Use `with_unbundled_env` instead def with_clean_env - with_env(clean_env) { yield } + Bundler::SharedHelpers.major_deprecation( + 2, + "`Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + ) + + with_env(unbundled_env) { yield } + end + + # Run block with all bundler-related variables removed + def with_unbundled_env + with_env(unbundled_env) { yield } end def clean_system(*args) @@ -371,7 +393,7 @@ EOF unwritable_files = files.reject {|f| File.writable?(f) } sudo_needed = !unwritable_files.empty? if sudo_needed - Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.sort.map(&:to_s).join("\n ")}" + Bundler.ui.warn "Following files may not be writable, so sudo is needed:\n #{unwritable_files.map(&:to_s).sort.join("\n ")}" end end diff --git a/lib/bundler/build_metadata.rb b/lib/bundler/build_metadata.rb index c9d7482b24..33f91e9162 100644 --- a/lib/bundler/build_metadata.rb +++ b/lib/bundler/build_metadata.rb @@ -28,14 +28,19 @@ module Bundler # If Bundler has been installed without its .git directory and without a # commit instance variable then we can't determine its commits SHA. git_dir = File.join(File.expand_path("../../..", __FILE__), ".git") - # Check for both a file or folder because RubyGems runs Bundler's test suite in a submodule - # which does not have a .git folder - return "unknown" unless File.exist?(git_dir) + if File.directory?(git_dir) + return @git_commit_sha = Dir.chdir(git_dir) { `git rev-parse --short HEAD`.strip.freeze } + end - # Otherwise shell out to git. - @git_commit_sha = Dir.chdir(File.expand_path("..", __FILE__)) do - `git rev-parse --short HEAD`.strip.freeze + # If Bundler is a submodule in RubyGems, get the submodule commit + git_sub_dir = File.join(File.expand_path("../../../..", __FILE__), ".git") + if File.directory?(git_sub_dir) + return @git_commit_sha = Dir.chdir(git_sub_dir) do + `git ls-tree --abbrev=8 HEAD bundler`.split(/\s/).fetch(2, "").strip.freeze + end end + + @git_commit_sha ||= "unknown" end # Whether this is an official release build of Bundler. diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index ad2c7c969c..c591884263 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -618,6 +618,8 @@ module Bundler "do not attempt to fetch remote gemspecs and use the local gem cache only" method_option "print", :type => :boolean, :default => false, :banner => "print the lockfile to STDOUT instead of writing to the file system" + method_option "gemfile", :type => :string, :banner => + "Use the specified gemfile instead of Gemfile" method_option "lockfile", :type => :string, :default => nil, :banner => "the path the lockfile should be written to" method_option "full-index", :type => :boolean, :default => false, :banner => diff --git a/lib/bundler/cli/common.rb b/lib/bundler/cli/common.rb index 8084405b38..09a1753337 100644 --- a/lib/bundler/cli/common.rb +++ b/lib/bundler/cli/common.rb @@ -72,7 +72,7 @@ module Bundler end def self.ensure_all_gems_in_lockfile!(names, locked_gems = Bundler.locked_gems) - locked_names = locked_gems.specs.map(&:name) + locked_names = locked_gems.specs.map(&:name).uniq names.-(locked_names).each do |g| raise GemNotFound, gem_not_found_message(g, locked_names) end diff --git a/lib/bundler/cli/install.rb b/lib/bundler/cli/install.rb index b40e5f0e9e..03edc7fbd2 100644 --- a/lib/bundler/cli/install.rb +++ b/lib/bundler/cli/install.rb @@ -202,15 +202,16 @@ module Bundler end def warn_ambiguous_gems + # TODO: remove this when we drop Bundler 1.x support Installer.ambiguous_gems.to_a.each do |name, installed_from_uri, *also_found_in_uris| - Bundler.ui.error "Warning: the gem '#{name}' was found in multiple sources." - Bundler.ui.error "Installed from: #{installed_from_uri}" - Bundler.ui.error "Also found in:" - also_found_in_uris.each {|uri| Bundler.ui.error " * #{uri}" } - Bundler.ui.error "You should add a source requirement to restrict this gem to your preferred source." - Bundler.ui.error "For example:" - Bundler.ui.error " gem '#{name}', :source => '#{installed_from_uri}'" - Bundler.ui.error "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." + Bundler.ui.warn "Warning: the gem '#{name}' was found in multiple sources." + Bundler.ui.warn "Installed from: #{installed_from_uri}" + Bundler.ui.warn "Also found in:" + also_found_in_uris.each {|uri| Bundler.ui.warn " * #{uri}" } + Bundler.ui.warn "You should add a source requirement to restrict this gem to your preferred source." + Bundler.ui.warn "For example:" + Bundler.ui.warn " gem '#{name}', :source => '#{installed_from_uri}'" + Bundler.ui.warn "Then uninstall the gem '#{name}' (or delete all bundled gems) and then install again." end end end diff --git a/lib/bundler/cli/plugin.rb b/lib/bundler/cli/plugin.rb index 92d4653bda..b5dd5b6d4b 100644 --- a/lib/bundler/cli/plugin.rb +++ b/lib/bundler/cli/plugin.rb @@ -5,7 +5,7 @@ module Bundler class CLI::Plugin < Thor desc "install PLUGINS", "Install the plugin from the source" long_desc <<-D - Install plugins either from the rubygems source provided (with --source option) or from a git source provided with (--git option). If no sources are provided, it uses Gem.sources + Install plugins either from the rubygems source provided (with --source option) or from a git source provided with --git (for remote repos) or --local_git (for local repos). If no sources are provided, it uses Gem.sources D method_option "source", :type => :string, :default => nil, :banner => "URL of the RubyGems source to fetch the plugin from" @@ -13,6 +13,8 @@ module Bundler "The version of the plugin to fetch" method_option "git", :type => :string, :default => nil, :banner => "URL of the git repo to fetch from" + method_option "local_git", :type => :string, :default => nil, :banner => + "Path of the local git repo to fetch from" method_option "branch", :type => :string, :default => nil, :banner => "The git branch to checkout" method_option "ref", :type => :string, :default => nil, :banner => diff --git a/lib/bundler/current_ruby.rb b/lib/bundler/current_ruby.rb index d5efaad6c5..ae5fae841e 100644 --- a/lib/bundler/current_ruby.rb +++ b/lib/bundler/current_ruby.rb @@ -19,6 +19,7 @@ module Bundler 2.4 2.5 2.6 + 2.7 ].freeze KNOWN_MAJOR_VERSIONS = KNOWN_MINOR_VERSIONS.map {|v| v.split(".", 2).first }.uniq.freeze diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index ffcc7ff326..9d6fbfff59 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -977,7 +977,9 @@ module Bundler dependencies_by_name = dependencies.inject({}) {|memo, dep| memo.update(dep.name => dep) } @locked_gems.specs.reduce({}) do |requirements, locked_spec| name = locked_spec.name - next requirements if @locked_gems.dependencies[name] != dependencies_by_name[name] + dependency = dependencies_by_name[name] + next requirements if @locked_gems.dependencies[name] != dependency + next requirements if dependency && dependency.source.is_a?(Source::Path) dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") requirements[name] = DepProxy.new(dep, locked_spec.platform) requirements diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 80d208e463..6707fc5893 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -305,7 +305,7 @@ module Bundler # end repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/") # TODO: 2.0 upgrade this setting to the default - if Bundler.settings["github.https"] + if Bundler.feature_flag.github_https? Bundler::SharedHelpers.major_deprecation 2, "The `github.https` setting will be removed" "https://github.com/#{repo_name}.git" else diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index 83e7ff0389..249170c4b2 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -60,6 +60,8 @@ module Bundler settings_option(:default_cli_command) { bundler_2_mode? ? :cli_help : :install } + settings_method(:github_https?, "github.https") { bundler_2_mode? } + def initialize(bundler_version) @bundler_version = Gem::Version.create(bundler_version) end diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index 1bb29f0b36..e67469f2dd 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -123,7 +123,7 @@ module Bundler end end - # evalutes a gemfile to remove the specified gem + # evaluates a gemfile to remove the specified gem # from it. def remove_deps(gemfile_path) initial_gemfile = IO.readlines(gemfile_path) @@ -136,8 +136,8 @@ module Bundler removed_deps = remove_gems_from_dependencies(builder, @deps, gemfile_path) - # abort the opertion if no gems were removed - # no need to operate on gemfile furthur + # abort the operation if no gems were removed + # no need to operate on gemfile further return [] if removed_deps.empty? cleaned_gemfile = remove_gems_from_gemfile(@deps, gemfile_path) @@ -153,8 +153,8 @@ module Bundler # @param [Dsl] builder Dsl object of current Gemfile. # @param [Array] gems Array of names of gems to be removed. - # @param [Pathname] path of the Gemfile - # @return [Array] removed_deps Array of removed dependencies. + # @param [Pathname] gemfile_path Path of the Gemfile. + # @return [Array] Array of removed dependencies. def remove_gems_from_dependencies(builder, gems, gemfile_path) removed_deps = [] @@ -206,7 +206,7 @@ module Bundler nested_blocks -= 1 gemfile.each_with_index do |line, index| - next unless !line.nil? && line.include?(block_name) + next unless !line.nil? && line.strip.start_with?(block_name) if gemfile[index + 1] =~ /^\s*end\s*$/ gemfile[index] = nil gemfile[index + 1] = nil @@ -222,7 +222,7 @@ module Bundler # @param [Array] removed_deps Array of removed dependencies. # @param [Array] initial_gemfile Contents of original Gemfile before any operation. def cross_check_for_errors(gemfile_path, original_deps, removed_deps, initial_gemfile) - # evalute the new gemfile to look for any failure cases + # evaluate the new gemfile to look for any failure cases builder = Dsl.new builder.eval_gemfile(gemfile_path) diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index 9d25f3261a..93355c9460 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -36,6 +36,7 @@ def gemfile(install = false, options = {}, &gemfile) opts = options.dup ui = opts.delete(:ui) { Bundler::UI::Shell.new } + ui.level = "silent" if opts.delete(:quiet) raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? old_root = Bundler.method(:root) diff --git a/lib/bundler/lockfile_parser.rb b/lib/bundler/lockfile_parser.rb index ff706fca1d..a7d4dc56b7 100644 --- a/lib/bundler/lockfile_parser.rb +++ b/lib/bundler/lockfile_parser.rb @@ -27,12 +27,10 @@ module Bundler SOURCE = [GIT, GEM, PATH, PLUGIN].freeze SECTIONS_BY_VERSION_INTRODUCED = { - # The strings have to be dup'ed for old RG on Ruby 2.3+ - # TODO: remove dup in Bundler 2.0 - Gem::Version.create("1.0".dup) => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, - Gem::Version.create("1.10".dup) => [BUNDLED].freeze, - Gem::Version.create("1.12".dup) => [RUBY].freeze, - Gem::Version.create("1.13".dup) => [PLUGIN].freeze, + Gem::Version.create("1.0") => [DEPENDENCIES, PLATFORMS, GIT, GEM, PATH].freeze, + Gem::Version.create("1.10") => [BUNDLED].freeze, + Gem::Version.create("1.12") => [RUBY].freeze, + Gem::Version.create("1.13") => [PLUGIN].freeze, }.freeze KNOWN_SECTIONS = SECTIONS_BY_VERSION_INTRODUCED.values.flatten.freeze diff --git a/lib/bundler/plugin.rb b/lib/bundler/plugin.rb index 422d4acfbc..996d29aafb 100644 --- a/lib/bundler/plugin.rb +++ b/lib/bundler/plugin.rb @@ -73,20 +73,22 @@ module Bundler # @param [Pathname] gemfile path # @param [Proc] block that can be evaluated for (inline) Gemfile def gemfile_install(gemfile = nil, &inline) - builder = DSL.new - if block_given? - builder.instance_eval(&inline) - else - builder.eval_gemfile(gemfile) - end - definition = builder.to_definition(nil, true) + Bundler.settings.temporary(:frozen => false, :deployment => false) do + builder = DSL.new + if block_given? + builder.instance_eval(&inline) + else + builder.eval_gemfile(gemfile) + end + definition = builder.to_definition(nil, true) - return if definition.dependencies.empty? + return if definition.dependencies.empty? - plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } - installed_specs = Installer.new.install_definition(definition) + plugins = definition.dependencies.map(&:name).reject {|p| index.installed? p } + installed_specs = Installer.new.install_definition(definition) - save_plugins plugins, installed_specs, builder.inferred_plugins + save_plugins plugins, installed_specs, builder.inferred_plugins + end rescue RuntimeError => e unless e.is_a?(GemfileError) Bundler.ui.error "Failed to install plugin: #{e.message}\n #{e.backtrace[0]}" diff --git a/lib/bundler/plugin/index.rb b/lib/bundler/plugin/index.rb index 642e7c8163..faabf3a8d1 100644 --- a/lib/bundler/plugin/index.rb +++ b/lib/bundler/plugin/index.rb @@ -58,7 +58,10 @@ module Bundler raise SourceConflict.new(name, common) unless common.empty? sources.each {|k| @sources[k] = name } - hooks.each {|e| (@hooks[e] ||= []) << name } + hooks.each do |event| + event_hooks = (@hooks[event] ||= []) << name + event_hooks.uniq! + end @plugin_paths[name] = path @load_paths[name] = load_paths diff --git a/lib/bundler/plugin/installer.rb b/lib/bundler/plugin/installer.rb index 5379c38979..713d679f12 100644 --- a/lib/bundler/plugin/installer.rb +++ b/lib/bundler/plugin/installer.rb @@ -12,10 +12,15 @@ module Bundler autoload :Git, "bundler/plugin/installer/git" def install(names, options) + check_sources_consistency!(options) + version = options[:version] || [">= 0"] + Bundler.settings.temporary(:lockfile_uses_separate_rubygems_sources => false, :disable_multisource => false) do if options[:git] install_git(names, version, options) + elsif options[:local_git] + install_local_git(names, version, options) else sources = options[:source] || Bundler.rubygems.sources install_rubygems(names, version, sources) @@ -38,22 +43,29 @@ module Bundler private + # Rubocop misunderstands the semantics of this method, assuming an `else` code block + # that doesn't exist. See https://github.com/bbatsov/rubocop/issues/5702. + # + # rubocop:disable Style/GuardClause + def check_sources_consistency!(options) + if options.key?(:git) && options.key?(:local_git) + raise InvalidOption, "Remote and local plugin git sources can't be both specified" + end + end + # rubocop:enable Style/GuardClause + def install_git(names, version, options) uri = options.delete(:git) options["uri"] = uri - source_list = SourceList.new - source_list.add_git_source(options) - - # To support both sources - if options[:source] - source_list.add_rubygems_source("remotes" => options[:source]) - end + install_all_sources(names, version, options, options[:source]) + end - deps = names.map {|name| Dependency.new name, version } + def install_local_git(names, version, options) + uri = options.delete(:local_git) + options["uri"] = uri - definition = Definition.new(nil, deps, source_list, true) - install_definition(definition) + install_all_sources(names, version, options, options[:source]) end # Installs the plugin from rubygems source and returns the path where the @@ -65,10 +77,16 @@ module Bundler # # @return [Hash] map of names to the specs of plugins installed def install_rubygems(names, version, sources) - deps = names.map {|name| Dependency.new name, version } + install_all_sources(names, version, nil, sources) + end + def install_all_sources(names, version, git_source_options, rubygems_source) source_list = SourceList.new - source_list.add_rubygems_source("remotes" => sources) + + source_list.add_git_source(git_source_options) if git_source_options + source_list.add_rubygems_source("remotes" => rubygems_source) if rubygems_source + + deps = names.map {|name| Dependency.new name, version } definition = Definition.new(nil, deps, source_list, true) install_definition(definition) diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index fac28ced90..aaa7bb7583 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -414,7 +414,7 @@ module Bundler msg = msg.join("\n") raise SecurityError, msg if multisource_disabled - Bundler.ui.error "Warning: #{msg}" + Bundler.ui.warn "Warning: #{msg}" end end end diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index dca17885dd..e09e5e8b74 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -275,7 +275,15 @@ module Bundler until !File.directory?(current) || current == previous if ENV["BUNDLE_SPEC_RUN"] # avoid stepping above the tmp directory when testing - return nil if File.file?(File.join(current, "bundler.gemspec")) + gemspec = if ENV["BUNDLE_RUBY"] && ENV["BUNDLE_GEM"] + # for Ruby Core + "lib/bundler.gemspec" + else + "bundler.gemspec" + end + + # avoid stepping above the tmp directory when testing + return nil if File.file?(File.join(current, gemspec)) end names.each do |name| @@ -304,10 +312,12 @@ module Bundler unless File.exist?(exe_file) exe_file = File.expand_path("../../../exe/bundle", __FILE__) end - Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file rescue Gem::GemNotFoundException - Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", File.expand_path("../../../exe/bundle", __FILE__) + exe_file = File.expand_path("../../../exe/bundle", __FILE__) + # for Ruby core repository + exe_file = File.expand_path("../../../../bin/bundle", __FILE__) unless File.exist?(exe_file) + Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file end # Set BUNDLE_GEMFILE diff --git a/lib/bundler/source/metadata.rb b/lib/bundler/source/metadata.rb index 47a751debb..559b912ffd 100644 --- a/lib/bundler/source/metadata.rb +++ b/lib/bundler/source/metadata.rb @@ -21,9 +21,8 @@ module Bundler # can't point to the actual gemspec or else the require paths will be wrong s.loaded_from = File.expand_path("..", __FILE__) end - if loaded_spec = Bundler.rubygems.loaded_specs("bundler") - idx << loaded_spec # this has to come after the fake gemspec, to override it - elsif local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } + + if local_spec = Bundler.rubygems.find_name("bundler").find {|s| s.version.to_s == VERSION } idx << local_spec end diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index e6c30603f0..2c5d9e6580 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -1,18 +1,13 @@ # frozen_string_literal: true require "tsort" -require "forwardable" require "set" module Bundler class SpecSet - extend Forwardable include Enumerable include TSort - def_delegators :@specs, :<<, :length, :add, :remove, :size, :empty? - def_delegators :sorted, :each - def initialize(specs) @specs = specs end @@ -132,6 +127,26 @@ module Bundler what_required(req) << spec end + def <<(spec) + @specs << spec + end + + def length + @specs.length + end + + def size + @specs.size + end + + def empty? + @specs.empty? + end + + def each(&b) + sorted.each(&b) + end + private def sorted diff --git a/lib/bundler/templates/Executable.bundler b/lib/bundler/templates/Executable.bundler index eeda90b584..3adac41e74 100644 --- a/lib/bundler/templates/Executable.bundler +++ b/lib/bundler/templates/Executable.bundler @@ -11,7 +11,7 @@ require "rubygems" m = Module.new do - module_function + module_function def invoked_as_script? File.expand_path($0) == File.expand_path(__FILE__) diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index 113bf82eb2..c1a50fe912 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -21,18 +21,11 @@ Gem::Specification.new do |spec| spec.license = "MIT" <%- end -%> - # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' - # to allow pushing to a single host or delete this section to allow pushing to any host. - if spec.respond_to?(:metadata) - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" + spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" - spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." - else - raise "RubyGems 2.0 or newer is required to protect against " \ - "public gem pushes." - end + spec.metadata["homepage_uri"] = spec.homepage + spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." + spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." # Specify which files should be added to the gem when it is released. # The `git ls-files -z` loads the files in the RubyGem that have been added into git. diff --git a/man/bundle-config.ronn b/man/bundle-config.ronn index 4d8bda61f7..379b778348 100644 --- a/man/bundle-config.ronn +++ b/man/bundle-config.ronn @@ -227,7 +227,7 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). is used, defaults to vendor/bundle. * `path.system` (`BUNDLE_PATH__SYSTEM`): Whether Bundler will install gems into the default system path (`Gem.dir`). -* `path_relative_to_cwd` (`PATH_RELATIVE_TO_CWD`) +* `path_relative_to_cwd` (`BUNDLE_PATH_RELATIVE_TO_CWD`) Makes `--path` relative to the CWD instead of the `Gemfile`. * `plugins` (`BUNDLE_PLUGINS`): Enable Bundler's experimental plugin system. @@ -381,3 +381,17 @@ This is especially useful for private repositories on hosts such as Github, where you can use personal OAuth tokens: export BUNDLE_GITHUB__COM=abcd0123generatedtoken:x-oauth-basic + + +## CONFIGURE BUNDLER DIRECTORIES + +Bundler's home, config, cache and plugin directories are able to be configured +through environment variables. The default location for Bundler's home directory is +`~/.bundle`, which all directories inherit from by default. The following +outlines the available environment variables and their default values + + BUNDLE_USER_HOME : $HOME/.bundle + BUNDLE_USER_CACHE : $BUNDLE_USER_HOME/cache + BUNDLE_USER_CONFIG : $BUNDLE_USER_HOME/config + BUNDLE_USER_PLUGIN : $BUNDLE_USER_HOME/plugin + diff --git a/man/bundle.ronn b/man/bundle.ronn index c03201a30c..0005692abd 100644 --- a/man/bundle.ronn +++ b/man/bundle.ronn @@ -94,6 +94,9 @@ We divide `bundle` subcommands into primary commands and utilities: * [`bundle doctor(1)`](bundle-doctor.1.html): Display warnings about common problems +* [`bundle remove(1)`](bundle-remove.1.html): + Removes gems from the Gemfile + ## PLUGINS When running a command that isn't listed in PRIMARY COMMANDS or UTILITIES, diff --git a/man/gemfile.5.ronn b/man/gemfile.5.ronn index f4772f6d8d..c941463edc 100644 --- a/man/gemfile.5.ronn +++ b/man/gemfile.5.ronn @@ -216,13 +216,13 @@ used on platforms with Ruby 2.3, use: The full list of platforms and supported versions includes: * `ruby`: - 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 + 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mri`: - 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 + 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `mingw`: - 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 + 1.8, 1.9, 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 * `x64_mingw`: - 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 + 2.0, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6 As with groups, you can specify one or more platforms: diff --git a/spec/bundler/bundler_spec.rb b/spec/bundler/bundler_spec.rb index 4759005c0c..194d6752b2 100644 --- a/spec/bundler/bundler_spec.rb +++ b/spec/bundler/bundler_spec.rb @@ -378,9 +378,11 @@ EOF before do allow(Bundler).to receive(:which).with("sudo").and_return("/usr/bin/sudo") FileUtils.mkdir_p("tmp/vendor/bundle") + FileUtils.mkdir_p("tmp/vendor/bin_dir") end after do FileUtils.rm_rf("tmp/vendor/bundle") + FileUtils.rm_rf("tmp/vendor/bin_dir") if Bundler.respond_to?(:remove_instance_variable) Bundler.remove_instance_variable(:@requires_sudo_ran) Bundler.remove_instance_variable(:@requires_sudo) @@ -401,13 +403,24 @@ EOF before do FileUtils.touch("tmp/vendor/bundle/unwritable1.txt") FileUtils.touch("tmp/vendor/bundle/unwritable2.txt") + FileUtils.touch("tmp/vendor/bin_dir/unwritable3.txt") FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable1.txt") FileUtils.chmod(0o400, "tmp/vendor/bundle/unwritable2.txt") + FileUtils.chmod(0o400, "tmp/vendor/bin_dir/unwritable3.txt") end it "should return true and display warn message" do allow(Bundler).to receive(:bundle_path).and_return(Pathname("tmp/vendor/bundle")) + bin_dir = Pathname("tmp/vendor/bin_dir/") + + # allow File#writable? to be called with args other than the stubbed on below + allow(File).to receive(:writable?).and_call_original + + # fake make the directory unwritable + allow(File).to receive(:writable?).with(bin_dir).and_return(false) + allow(Bundler).to receive(:system_bindir).and_return(Pathname("tmp/vendor/bin_dir/")) message = <<-MESSAGE.chomp Following files may not be writable, so sudo is needed: + tmp/vendor/bin_dir/ tmp/vendor/bundle/unwritable1.txt tmp/vendor/bundle/unwritable2.txt MESSAGE diff --git a/spec/bundler/cli_spec.rb b/spec/bundler/cli_spec.rb index 73868d10fb..c82d46587e 100644 --- a/spec/bundler/cli_spec.rb +++ b/spec/bundler/cli_spec.rb @@ -15,7 +15,8 @@ RSpec.describe "bundle executable" do it "looks for a binary and executes it if it's named bundler-<task>" do File.open(tmp("bundler-testtasks"), "w", 0o755) do |f| - f.puts "#!/usr/bin/env ruby\nputs 'Hello, world'\n" + ruby = ENV["BUNDLE_RUBY"] || "/usr/bin/env ruby" + f.puts "#!#{ruby}\nputs 'Hello, world'\n" end with_path_added(tmp) do diff --git a/spec/bundler/definition_spec.rb b/spec/bundler/definition_spec.rb index 2ed87ec81d..ceb7b4bf05 100644 --- a/spec/bundler/definition_spec.rb +++ b/spec/bundler/definition_spec.rb @@ -13,6 +13,7 @@ RSpec.describe Bundler::Definition do subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) } it "raises an PermissionError with explanation" do + allow(File).to receive(:open).and_call_original expect(File).to receive(:open).with("Gemfile.lock", "wb"). and_raise(Errno::EACCES) expect { subject.lock("Gemfile.lock") }. @@ -23,6 +24,7 @@ RSpec.describe Bundler::Definition do subject { Bundler::Definition.new(nil, [], Bundler::SourceList.new, []) } it "raises a TemporaryResourceError with explanation" do + allow(File).to receive(:open).and_call_original expect(File).to receive(:open).with("Gemfile.lock", "wb"). and_raise(Errno::EAGAIN) expect { subject.lock("Gemfile.lock") }. diff --git a/spec/bundler/dsl_spec.rb b/spec/bundler/dsl_spec.rb index bffe4f1608..89528eb745 100644 --- a/spec/bundler/dsl_spec.rb +++ b/spec/bundler/dsl_spec.rb @@ -25,7 +25,23 @@ RSpec.describe Bundler::Dsl do expect { subject.git_source(:example) }.to raise_error(Bundler::InvalidOption) end + context "github_https feature flag" do + it "is true when github.https is true" do + bundle "config github.https true" + expect(Bundler.feature_flag.github_https?).to eq "true" + end + end + context "default hosts (git, gist)", :bundler => "< 2" do + context "when github.https config is true" do + before { bundle "config github.https true" } + it "converts :github to :git using https" do + subject.gem("sparks", :github => "indirect/sparks") + github_uri = "https://github.com/indirect/sparks.git" + expect(subject.dependencies.first.source.uri).to eq(github_uri) + end + end + it "converts :github to :git" do subject.gem("sparks", :github => "indirect/sparks") github_uri = "git://github.com/indirect/sparks.git" diff --git a/spec/bundler/env_spec.rb b/spec/bundler/env_spec.rb index 10762b3cd2..20bd38b021 100644 --- a/spec/bundler/env_spec.rb +++ b/spec/bundler/env_spec.rb @@ -141,7 +141,7 @@ RSpec.describe Bundler::Env do end end - describe ".version_of" do + describe ".version_of", :ruby_repo do let(:parsed_version) { described_class.send(:version_of, "ruby") } it "strips version of new line characters" do diff --git a/spec/bundler/gem_helper_spec.rb b/spec/bundler/gem_helper_spec.rb index 3620035fe1..e2cd7e8bc6 100644 --- a/spec/bundler/gem_helper_spec.rb +++ b/spec/bundler/gem_helper_spec.rb @@ -29,15 +29,6 @@ RSpec.describe Bundler::GemHelper do end context "interpolates the name" do - before do - # Remove exception that prevents public pushes on older RubyGems versions - if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.0") - content = File.read(app_gemspec_path) - content.sub!(/raise "RubyGems 2\.0 or newer.*/, "") - File.open(app_gemspec_path, "w") {|f| f.write(content) } - end - end - it "when there is only one gemspec" do expect(subject.gemspec.name).to eq(app_name) end @@ -72,7 +63,7 @@ RSpec.describe Bundler::GemHelper do let(:app_version) { "0.1.0" } let(:app_gem_dir) { app_path.join("pkg") } let(:app_gem_path) { app_gem_dir.join("#{app_name}-#{app_version}.gem") } - let(:app_gemspec_content) { remove_push_guard(File.read(app_gemspec_path)) } + let(:app_gemspec_content) { File.read(app_gemspec_path) } before(:each) do content = app_gemspec_content.gsub("TODO: ", "") @@ -81,14 +72,6 @@ RSpec.describe Bundler::GemHelper do File.open(app_gemspec_path, "w") {|file| file << content } end - def remove_push_guard(gemspec_content) - # Remove exception that prevents public pushes on older RubyGems versions - if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.0") - gemspec_content.sub!(/raise "RubyGems 2\.0 or newer.*/, "") - end - gemspec_content - end - it "uses a shell UI for output" do expect(Bundler.ui).to be_a(Bundler::UI::Shell) end diff --git a/spec/bundler/mirror_spec.rb b/spec/bundler/mirror_spec.rb index 0a8b9f8926..acd0895f2f 100644 --- a/spec/bundler/mirror_spec.rb +++ b/spec/bundler/mirror_spec.rb @@ -304,7 +304,7 @@ RSpec.describe Bundler::Settings::TCPSocketProbe do server.close unless server.closed? end - it "probes the server correctly" do + it "probes the server correctly", :ruby_repo do with_server_and_mirror do |server, mirror| expect(server.closed?).to be_falsey expect(probe.replies?(mirror)).to be_truthy diff --git a/spec/bundler/plugin/index_spec.rb b/spec/bundler/plugin/index_spec.rb index ca3476ea2a..e18e960fb8 100644 --- a/spec/bundler/plugin/index_spec.rb +++ b/spec/bundler/plugin/index_spec.rb @@ -86,6 +86,17 @@ RSpec.describe Bundler::Plugin::Index do expect(new_index.hook_plugins("after-bar")).to eq([plugin_name]) end + it "only registers a gem once for an event" do + path = lib_path(plugin_name) + index.register_plugin(plugin_name, + path.to_s, + [path.join("lib").to_s], + commands, + sources, + hooks + hooks) + expect(index.hook_plugins("after-bar")).to eq([plugin_name]) + end + context "that are not registered", :focused do let(:file) { double("index-file") } diff --git a/spec/bundler/plugin/installer_spec.rb b/spec/bundler/plugin/installer_spec.rb index f8bf8450c9..71fef76042 100644 --- a/spec/bundler/plugin/installer_spec.rb +++ b/spec/bundler/plugin/installer_spec.rb @@ -3,10 +3,6 @@ RSpec.describe Bundler::Plugin::Installer do subject(:installer) { Bundler::Plugin::Installer.new } - before do - # allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(Pathname.new("/Gemfile")) - end - describe "cli install" do it "uses Gem.sources when non of the source is provided" do sources = double(:sources) @@ -29,6 +25,14 @@ RSpec.describe Bundler::Plugin::Installer do to eq("new-plugin" => spec) end + it "returns the installed spec after installing local git plugins" do + allow(installer).to receive(:install_local_git). + and_return("new-plugin" => spec) + + expect(installer.install(["new-plugin"], :local_git => "/phony/path/repo")). + to eq("new-plugin" => spec) + end + it "returns the installed spec after installing rubygems plugins" do allow(installer).to receive(:install_rubygems). and_return("new-plugin" => spec) @@ -69,6 +73,29 @@ RSpec.describe Bundler::Plugin::Installer do end end + context "local git plugins" do + before do + build_git "ga-plugin", :path => lib_path("ga-plugin") do |s| + s.write "plugins.rb" + end + end + + let(:result) do + installer.install(["ga-plugin"], :local_git => lib_path("ga-plugin").to_s) + end + + it "returns the installed spec after installing" do + spec = result["ga-plugin"] + expect(spec.full_name).to eq "ga-plugin-1.0" + end + + it "has expected full gem path" do + rev = revision_for(lib_path("ga-plugin")) + expect(result["ga-plugin"].full_gem_path). + to eq(Bundler::Plugin.root.join("bundler", "gems", "ga-plugin-#{rev[0..11]}").to_s) + end + end + context "rubygems plugins" do let(:result) do installer.install(["re-plugin"], :source => "file://#{gem_repo2}") diff --git a/spec/bundler/settings_spec.rb b/spec/bundler/settings_spec.rb index 1a31493e20..339428eb48 100644 --- a/spec/bundler/settings_spec.rb +++ b/spec/bundler/settings_spec.rb @@ -130,13 +130,15 @@ that would suck --ehhh=oh geez it looks like i might have broken bundler somehow describe "#temporary" do it "reset after used" do - Bundler.settings.set_local :no_install, true + Bundler.settings.set_command_option :no_install, true Bundler.settings.temporary(:no_install => false) do expect(Bundler.settings[:no_install]).to eq false end expect(Bundler.settings[:no_install]).to eq true + + Bundler.settings.set_command_option :no_install, nil end it "returns the return value of the block" do diff --git a/spec/bundler/shared_helpers_spec.rb b/spec/bundler/shared_helpers_spec.rb index 72b1c2a51f..b66c43fd92 100644 --- a/spec/bundler/shared_helpers_spec.rb +++ b/spec/bundler/shared_helpers_spec.rb @@ -384,7 +384,8 @@ RSpec.describe Bundler::SharedHelpers do it "sets BUNDLE_BIN_PATH to the bundle executable file" do subject.set_bundle_environment - expect(ENV["BUNDLE_BIN_PATH"]).to eq(File.expand_path("../../../exe/bundle", __FILE__)) + bundle_exe = ruby_core? ? "../../../../exe/bundle" : "../../../exe/bundle" + expect(ENV["BUNDLE_BIN_PATH"]).to eq(File.expand_path(bundle_exe, __FILE__)) end end diff --git a/spec/bundler/source/git/git_proxy_spec.rb b/spec/bundler/source/git/git_proxy_spec.rb index 3a29c97461..016105ccde 100644 --- a/spec/bundler/source/git/git_proxy_spec.rb +++ b/spec/bundler/source/git/git_proxy_spec.rb @@ -10,29 +10,33 @@ RSpec.describe Bundler::Source::Git::GitProxy do context "with configured credentials" do it "adds username and password to URI" do - Bundler.settings.temporary(uri => "u:p") - expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) - subject.checkout + Bundler.settings.temporary(uri => "u:p") do + expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) + subject.checkout + end end it "adds username and password to URI for host" do - Bundler.settings.temporary("github.com" => "u:p") - expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) - subject.checkout + Bundler.settings.temporary("github.com" => "u:p") do + expect(subject).to receive(:git_retry).with(match("https://u:p@github.com/bundler/bundler.git")) + subject.checkout + end end it "does not add username and password to mismatched URI" do - Bundler.settings.temporary("https://u:p@github.com/bundler/bundler-mismatch.git" => "u:p") - expect(subject).to receive(:git_retry).with(match(uri)) - subject.checkout + Bundler.settings.temporary("https://u:p@github.com/bundler/bundler-mismatch.git" => "u:p") do + expect(subject).to receive(:git_retry).with(match(uri)) + subject.checkout + end end it "keeps original userinfo" do - Bundler.settings.temporary("github.com" => "u:p") - original = "https://orig:info@github.com/bundler/bundler.git" - subject = described_class.new(Pathname("path"), original, "HEAD") - expect(subject).to receive(:git_retry).with(match(original)) - subject.checkout + Bundler.settings.temporary("github.com" => "u:p") do + original = "https://orig:info@github.com/bundler/bundler.git" + subject = described_class.new(Pathname("path"), original, "HEAD") + expect(subject).to receive(:git_retry).with(match(original)) + subject.checkout + end end end diff --git a/spec/bundler/source/rubygems/remote_spec.rb b/spec/bundler/source/rubygems/remote_spec.rb index 9a7ab42128..52fb4e7f1c 100644 --- a/spec/bundler/source/rubygems/remote_spec.rb +++ b/spec/bundler/source/rubygems/remote_spec.rb @@ -22,8 +22,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do end it "applies configured credentials" do - Bundler.settings.temporary(uri_no_auth.to_s => credentials) - expect(remote(uri_no_auth).uri).to eq(uri_with_auth) + Bundler.settings.temporary(uri_no_auth.to_s => credentials) do + expect(remote(uri_no_auth).uri).to eq(uri_with_auth) + end end end @@ -33,8 +34,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do end it "does not apply given credentials" do - Bundler.settings.temporary(uri_no_auth.to_s => credentials) - expect(remote(uri_no_auth).anonymized_uri).to eq(uri_no_auth) + Bundler.settings.temporary(uri_no_auth.to_s => credentials) do + expect(remote(uri_no_auth).anonymized_uri).to eq(uri_no_auth) + end end end @@ -44,8 +46,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do end it "only applies the given user" do - Bundler.settings.temporary(uri_no_auth.to_s => credentials) - expect(remote(uri_no_auth).cache_slug).to eq("gems.example.com.username.443.MD5HEX(gems.example.com.username.443./)") + Bundler.settings.temporary(uri_no_auth.to_s => credentials) do + expect(remote(uri_no_auth).cache_slug).to eq("gems.example.com.username.443.MD5HEX(gems.example.com.username.443./)") + end end end end @@ -106,7 +109,9 @@ RSpec.describe Bundler::Source::Rubygems::Remote do let(:mirror_uri_with_auth) { URI("https://username:password@rubygems-mirror.org/") } let(:mirror_uri_no_auth) { URI("https://rubygems-mirror.org/") } - before { Bundler.settings.set_local("mirror.https://rubygems.org/", mirror_uri_with_auth.to_s) } + before { Bundler.settings.temporary("mirror.https://rubygems.org/" => mirror_uri_with_auth.to_s) } + + after { Bundler.settings.temporary("mirror.https://rubygems.org/" => nil) } specify "#uri returns the mirror URI with credentials" do expect(remote(uri).uri).to eq(mirror_uri_with_auth) @@ -135,6 +140,11 @@ RSpec.describe Bundler::Source::Rubygems::Remote do Bundler.settings.temporary(mirror_uri_no_auth.to_s => credentials) end + after do + Bundler.settings.temporary("mirror.https://rubygems.org/" => nil) + Bundler.settings.temporary(mirror_uri_no_auth.to_s => nil) + end + specify "#uri returns the mirror URI with credentials" do expect(remote(uri).uri).to eq(mirror_uri_with_auth) end diff --git a/spec/bundler/ssl_certs/certificate_manager_spec.rb b/spec/bundler/ssl_certs/certificate_manager_spec.rb index 2e43193359..8403b554b5 100644 --- a/spec/bundler/ssl_certs/certificate_manager_spec.rb +++ b/spec/bundler/ssl_certs/certificate_manager_spec.rb @@ -11,13 +11,18 @@ RSpec.describe Bundler::SSLCerts::CertificateManager do # Pretend bundler root is rubygems root before do + # Backing up rubygems certificates + FileUtils.mv(rubygems_certs_dir, rubygems_certs_dir + ".back") if ruby_core? + FileUtils.mkdir_p(rubygems_certs_dir) FileUtils.touch(stub_cert) end after do - rubygems_dir = File.join(root.to_s, "lib", "rubygems") - FileUtils.rm_rf(rubygems_dir) + FileUtils.rm_rf(rubygems_certs_dir) + + # Restore rubygems certificates + FileUtils.mv(rubygems_certs_dir + ".back", rubygems_certs_dir) if ruby_core? end describe "#update_from" do diff --git a/spec/commands/binstubs_spec.rb b/spec/commands/binstubs_spec.rb index ad859a21d5..2f014f2631 100644 --- a/spec/commands/binstubs_spec.rb +++ b/spec/commands/binstubs_spec.rb @@ -202,7 +202,7 @@ RSpec.describe "bundle binstubs <gem>" do context "when requesting a different bundler version" do before { lockfile lockfile.gsub(Bundler::VERSION, "999.999.999") } - it "attempts to load that version" do + it "attempts to load that version", :ruby_repo do sys_exec bundled_app("bin/rackup").to_s expect(exitstatus).to eq(42) if exitstatus expect(last_command.stderr).to include("Activating bundler (999.999.999) failed:"). diff --git a/spec/commands/clean_spec.rb b/spec/commands/clean_spec.rb index ff3317bb1d..37cbeeb4e7 100644 --- a/spec/commands/clean_spec.rb +++ b/spec/commands/clean_spec.rb @@ -712,7 +712,7 @@ RSpec.describe "bundle clean" do should_not_have_gems "foo-1.0" end - it "doesn't remove extensions artifacts from bundled git gems after clean", :rubygems => "2.2" do + it "doesn't remove extensions artifacts from bundled git gems after clean", :ruby_repo, :rubygems => "2.2" do build_git "very_simple_git_binary", &:add_c_extension revision = revision_for(lib_path("very_simple_git_binary-1.0")) @@ -734,7 +734,7 @@ RSpec.describe "bundle clean" do expect(vendored_gems("bundler/gems/very_simple_git_binary-1.0-#{revision[0..11]}")).to exist end - it "removes extension directories", :rubygems => "2.2" do + it "removes extension directories", :ruby_repo, :rubygems => "2.2" do gemfile <<-G source "file://#{gem_repo1}" diff --git a/spec/commands/config_spec.rb b/spec/commands/config_spec.rb index c76135d72c..61734ef005 100644 --- a/spec/commands/config_spec.rb +++ b/spec/commands/config_spec.rb @@ -1,13 +1,6 @@ # frozen_string_literal: true RSpec.describe ".bundle/config" do - before :each do - gemfile <<-G - source "file://#{gem_repo1}" - gem "rack", "1.0.0" - G - end - describe "config" do before { bundle "config foo bar" } @@ -42,7 +35,14 @@ RSpec.describe ".bundle/config" do end end - describe "BUNDLE_APP_CONFIG" do + describe "location" do + before :each do + gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end + it "can be moved with an environment variable" do ENV["BUNDLE_APP_CONFIG"] = tmp("foo/bar").to_s bundle "install", forgotten_command_line_options(:path => "vendor/bundle") @@ -66,7 +66,12 @@ RSpec.describe ".bundle/config" do end describe "global" do - before(:each) { bundle :install } + before(:each) do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end it "is the default" do bundle "config foo global" @@ -155,7 +160,12 @@ RSpec.describe ".bundle/config" do end describe "local" do - before(:each) { bundle :install } + before(:each) do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end it "can also be set explicitly" do bundle "config --local foo local" @@ -208,7 +218,12 @@ RSpec.describe ".bundle/config" do end describe "env" do - before(:each) { bundle :install } + before(:each) do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end it "can set boolean properties via the environment" do ENV["BUNDLE_FROZEN"] = "true" @@ -276,7 +291,12 @@ RSpec.describe ".bundle/config" do end describe "gem mirrors" do - before(:each) { bundle :install } + before(:each) do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end it "configures mirrors using keys with `mirror.`" do bundle "config --local mirror.http://gems.example.org http://gem-mirror.example.org" @@ -338,7 +358,12 @@ E end describe "very long lines" do - before(:each) { bundle :install } + before(:each) do + install_gemfile <<-G + source "file://#{gem_repo1}" + gem "rack", "1.0.0" + G + end let(:long_string) do "--with-xml2-include=/usr/pkg/include/libxml2 --with-xml2-lib=/usr/pkg/lib " \ diff --git a/spec/commands/exec_spec.rb b/spec/commands/exec_spec.rb index acf12ced79..7503b9db5f 100644 --- a/spec/commands/exec_spec.rb +++ b/spec/commands/exec_spec.rb @@ -33,7 +33,7 @@ RSpec.describe "bundle exec" do expect(out).to eq("1.0.0") end - it "works when running from a random directory" do + it "works when running from a random directory", :ruby_repo do install_gemfile <<-G gem "rack" G @@ -226,7 +226,7 @@ RSpec.describe "bundle exec" do expect(out).to include("bundler: exec needs a command to run") end - it "raises a helpful error when exec'ing to something outside of the bundle", :rubygems => ">= 2.5.2" do + it "raises a helpful error when exec'ing to something outside of the bundle", :ruby_repo, :rubygems => ">= 2.5.2" do bundle! "config clean false" # want to keep the rackup binstub install_gemfile! <<-G source "file://#{gem_repo1}" @@ -342,7 +342,7 @@ RSpec.describe "bundle exec" do end describe "with gem executables" do - describe "run from a random directory" do + describe "run from a random directory", :ruby_repo do before(:each) do install_gemfile <<-G gem "rack" @@ -445,7 +445,7 @@ RSpec.describe "bundle exec" do expect(out).to include("Installing foo 1.0") end - describe "with gems bundled via :path with invalid gemspecs" do + describe "with gems bundled via :path with invalid gemspecs", :ruby_repo do it "outputs the gemspec validation errors", :rubygems => ">= 1.7.2" do build_lib "foo" @@ -633,7 +633,7 @@ RSpec.describe "bundle exec" do it_behaves_like "it runs" end - context "when the file uses the current ruby shebang" do + context "when the file uses the current ruby shebang", :ruby_repo do let(:shebang) { "#!#{Gem.ruby}" } it_behaves_like "it runs" end @@ -800,10 +800,11 @@ __FILE__: #{path.to_s.inspect} it "overrides disable_shared_gems so bundler can be found" do skip "bundler 1.16.x is not support with Ruby 2.6 on Travis CI" if RUBY_VERSION >= "2.6" + system_gems :bundler file = bundled_app("file_that_bundle_execs.rb") create_file(file, <<-RB) #!#{Gem.ruby} - puts `bundle exec echo foo` + puts `#{system_bundle_bin_path} exec echo foo` RB file.chmod(0o777) bundle! "exec #{file}", :system_bundler => true diff --git a/spec/commands/info_spec.rb b/spec/commands/info_spec.rb index a08965ec0e..a9ab8fc210 100644 --- a/spec/commands/info_spec.rb +++ b/spec/commands/info_spec.rb @@ -24,7 +24,7 @@ RSpec.describe "bundle info" do end end - context "given a default gem shippped in ruby" do + context "given a default gem shippped in ruby", :ruby_repo do it "prints information about the default gem", :if => (RUBY_VERSION >= "2.0") do bundle "info rdoc" expect(out).to include("* rdoc") diff --git a/spec/commands/lock_spec.rb b/spec/commands/lock_spec.rb index f4997b0620..d99ddaf294 100644 --- a/spec/commands/lock_spec.rb +++ b/spec/commands/lock_spec.rb @@ -89,6 +89,33 @@ RSpec.describe "bundle lock" do expect(out).to match(/sources listed in your Gemfile|installed locally/) end + it "works with --gemfile flag" do + create_file "CustomGemfile", <<-G + source "file://localhost#{repo}" + gem "foo" + G + lockfile = strip_lockfile(normalize_uri_file(<<-L)) + GEM + remote: file://localhost#{repo}/ + specs: + foo (1.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + foo + + BUNDLED WITH + #{Bundler::VERSION} + L + bundle "lock --gemfile CustomGemfile" + + expect(out).to match(/Writing lockfile to.+CustomGemfile\.lock/) + expect(read_lockfile("CustomGemfile.lock")).to eq(lockfile) + expect { read_lockfile }.to raise_error(Errno::ENOENT) + end + it "writes to a custom location using --lockfile" do bundle "lock --lockfile=lock" diff --git a/spec/commands/newgem_spec.rb b/spec/commands/newgem_spec.rb index 4b5db87b00..2914ba66c5 100644 --- a/spec/commands/newgem_spec.rb +++ b/spec/commands/newgem_spec.rb @@ -6,18 +6,8 @@ RSpec.describe "bundle gem" do global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false" end - def remove_push_guard(gem_name) - # Remove exception that prevents public pushes on older RubyGems versions - if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.0") - path = "#{gem_name}/#{gem_name}.gemspec" - content = File.read(path).sub(/raise "RubyGems 2\.0 or newer.*/, "") - File.open(path, "w") {|f| f.write(content) } - end - end - - def execute_bundle_gem(gem_name, flag = "", to_remove_push_guard = true) + def execute_bundle_gem(gem_name, flag = "") bundle! "gem #{gem_name} #{flag}" - remove_push_guard(gem_name) if to_remove_push_guard # reset gemspec cache for each test because of commit 3d4163a Bundler.clear_gemspec_cache end @@ -96,7 +86,7 @@ RSpec.describe "bundle gem" do shared_examples_for "--coc flag" do before do - execute_bundle_gem(gem_name, "--coc", false) + execute_bundle_gem(gem_name, "--coc") end it "generates a gem skeleton with MIT license" do gem_skeleton_assertions(gem_name) @@ -113,7 +103,7 @@ RSpec.describe "bundle gem" do shared_examples_for "--no-coc flag" do before do - execute_bundle_gem(gem_name, "--no-coc", false) + execute_bundle_gem(gem_name, "--no-coc") end it "generates a gem skeleton without Code of Conduct" do gem_skeleton_assertions(gem_name) @@ -149,7 +139,6 @@ RSpec.describe "bundle gem" do reset! in_app_root bundle "gem #{gem_name}" - remove_push_guard(gem_name) end it "contribute URL set to [USERNAME]" do @@ -202,16 +191,16 @@ RSpec.describe "bundle gem" do line.gsub(/\=.*$/, "= %q{A short summary of my new gem.}") when /spec\.description/ line.gsub(/\=.*$/, "= %q{A longer description of my new gem.}") - # Remove exception that prevents public pushes on older RubyGems versions - when /raise "RubyGems 2.0 or newer/ - line.gsub(/.*/, "") if Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.0") else line end end Dir.chdir(bundled_app("newgem")) do - system_gems ["rake-10.0.2", :bundler], :path => :bundle_path + gems = ["rake-10.0.2", :bundler] + # for Ruby core repository, Ruby 2.6+ has bundler as standard library. + gems.delete(:bundler) if ruby_core? + system_gems gems, :path => :bundle_path bundle! "exec rake build" end @@ -295,7 +284,6 @@ RSpec.describe "bundle gem" do reset! in_app_root bundle "gem #{gem_name}" - remove_push_guard(gem_name) end it_should_behave_like "git config is absent" @@ -327,7 +315,7 @@ RSpec.describe "bundle gem" do end Dir.chdir(bundled_app(gem_name)) do - sys_exec("rake") + sys_exec(rake) expect(out).to include("SUCCESS") end end @@ -394,7 +382,6 @@ RSpec.describe "bundle gem" do end it "depends on a specific version of rspec", :rubygems => ">= 1.8.1" do - remove_push_guard(gem_name) rspec_dep = generated_gem.gemspec.development_dependencies.find {|d| d.name == "rspec" } expect(rspec_dep).to be_specific end @@ -445,7 +432,6 @@ RSpec.describe "bundle gem" do end it "depends on a specific version of minitest", :rubygems => ">= 1.8.1" do - remove_push_guard(gem_name) rspec_dep = generated_gem.gemspec.development_dependencies.find {|d| d.name == "minitest" } expect(rspec_dep).to be_specific end @@ -589,7 +575,6 @@ RSpec.describe "bundle gem" do reset! in_app_root bundle "gem #{gem_name}" - remove_push_guard(gem_name) end it_should_behave_like "git config is absent" @@ -612,7 +597,7 @@ RSpec.describe "bundle gem" do end Dir.chdir(bundled_app(gem_name)) do - sys_exec("rake") + sys_exec(rake) expect(out).to include("SUCCESS") end end diff --git a/spec/commands/pristine_spec.rb b/spec/commands/pristine_spec.rb index de3cb8054b..a868465c03 100644 --- a/spec/commands/pristine_spec.rb +++ b/spec/commands/pristine_spec.rb @@ -2,7 +2,7 @@ require "bundler/vendored_fileutils" -RSpec.describe "bundle pristine" do +RSpec.describe "bundle pristine", :ruby_repo do before :each do build_lib "baz", :path => bundled_app do |s| s.version = "1.0.0" @@ -48,9 +48,7 @@ RSpec.describe "bundle pristine" do bundle! "install" bundle! "pristine", :system_bundler => true bundle! "-v", :system_bundler => true - # An old rubygems couldn't handle a correct version of vendoered bundler. - bundler_version = Gem::VERSION < "2.1" ? "1.16.0" : Bundler::VERSION - expect(out).to end_with(bundler_version) + expect(out).to end_with(Bundler::VERSION) end end diff --git a/spec/commands/remove_spec.rb b/spec/commands/remove_spec.rb index 37594b1ece..daed91c034 100644 --- a/spec/commands/remove_spec.rb +++ b/spec/commands/remove_spec.rb @@ -140,6 +140,30 @@ RSpec.describe "bundle remove" do end end + context "when gem to be removed is outside block" do + it "does not modify group" do + gemfile <<-G + source "file://#{gem_repo1}" + + gem "rack" + group :test do + gem "coffee-script-source" + end + G + + bundle! "remove rack" + + expect(out).to include("rack was removed.") + gemfile_should_be <<-G + source "file://#{gem_repo1}" + + group :test do + gem "coffee-script-source" + end + G + end + end + context "when an empty block is also present" do it "removes all empty blocks" do gemfile <<-G diff --git a/spec/commands/update_spec.rb b/spec/commands/update_spec.rb index 6eb49d3acd..6f29032dd2 100644 --- a/spec/commands/update_spec.rb +++ b/spec/commands/update_spec.rb @@ -8,6 +8,7 @@ RSpec.describe "bundle update" do source "file://#{gem_repo2}" gem "activesupport" gem "rack-obama" + gem "platform_specific" G end @@ -116,8 +117,8 @@ RSpec.describe "bundle update" do expect(out).to include "Could not find gem 'halting-problem-solver'" end it "should suggest alternatives" do - bundle "update active-support" - expect(out).to include "Did you mean activesupport?" + bundle "update platformspecific" + expect(out).to include "Did you mean platform_specific?" end end diff --git a/spec/install/deploy_spec.rb b/spec/install/deploy_spec.rb index 491801e27a..3b9d68982a 100644 --- a/spec/install/deploy_spec.rb +++ b/spec/install/deploy_spec.rb @@ -64,7 +64,7 @@ RSpec.describe "install with --deployment or --frozen" do bundle! :install, forgotten_command_line_options(:deployment => true, :without => "test") end - it "works when you bundle exec bundle" do + it "works when you bundle exec bundle", :ruby_repo do bundle :install bundle "install --deployment" bundle! "exec bundle check" diff --git a/spec/install/gemfile/gemspec_spec.rb b/spec/install/gemfile/gemspec_spec.rb index 7ce037730e..833b409801 100644 --- a/spec/install/gemfile/gemspec_spec.rb +++ b/spec/install/gemfile/gemspec_spec.rb @@ -263,6 +263,20 @@ RSpec.describe "bundle install from an existing gemspec" do expect(out).to eq("WIN") end + it "works with only_update_to_newer_versions" do + build_lib "omg", "2.0", :path => lib_path("omg") + + install_gemfile <<-G + gemspec :path => "#{lib_path("omg")}" + G + + build_lib "omg", "1.0", :path => lib_path("omg") + + bundle! :install, :env => { "BUNDLE_BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS" => "true" } + + expect(the_bundle).to include_gems "omg 1.0" + 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 diff --git a/spec/install/gemfile/git_spec.rb b/spec/install/gemfile/git_spec.rb index 651deb3265..08fe21cacf 100644 --- a/spec/install/gemfile/git_spec.rb +++ b/spec/install/gemfile/git_spec.rb @@ -922,12 +922,11 @@ RSpec.describe "bundle install with git sources" do build_git "foo", :path => lib_path("nested") build_git "bar", :path => lib_path("nested") - gemfile <<-G + install_gemfile <<-G gem "foo", :git => "#{lib_path("nested")}" gem "bar", :git => "#{lib_path("nested")}" G - bundle "install" expect(File.read(bundled_app("Gemfile.lock")).scan("GIT").size).to eq(1) end @@ -1010,13 +1009,11 @@ RSpec.describe "bundle install with git sources" do install_gemfile <<-G gem "foo", :git => "file://#{lib_path("foo-1.0")}", :ref => "#{revision}" G - bundle "install" expect(out).to_not match(/Revision.*does not exist/) install_gemfile <<-G gem "foo", :git => "file://#{lib_path("foo-1.0")}", :ref => "deadbeef" G - bundle "install" expect(out).to include("Revision deadbeef does not exist in the repository") end end @@ -1099,7 +1096,7 @@ RSpec.describe "bundle install with git sources" do end context "with an extension" do - it "installs the extension" do + it "installs the extension", :ruby_repo do build_git "foo" do |s| s.add_dependency "rake" s.extensions << "Rakefile" @@ -1131,7 +1128,7 @@ RSpec.describe "bundle install with git sources" do expect(out).to eq(Pathname.glob(default_bundle_path("bundler/gems/extensions/**/foo-1.0-*")).first.to_s) end - it "does not use old extension after ref changes" do + it "does not use old extension after ref changes", :ruby_repo do git_reader = build_git "foo", :no_default => true do |s| s.extensions = ["ext/extconf.rb"] s.write "ext/extconf.rb", <<-RUBY @@ -1193,7 +1190,7 @@ In Gemfile: expect(out).not_to include("gem install foo") end - it "does not reinstall the extension", :rubygems => ">= 2.3.0" do + it "does not reinstall the extension", :ruby_repo, :rubygems => ">= 2.3.0" do build_git "foo" do |s| s.add_dependency "rake" s.extensions << "Rakefile" @@ -1423,7 +1420,6 @@ In Gemfile: end G - bundle :install expect(last_command.stdboth).to_not include("password1") expect(last_command.stdout).to include("Fetching https://user1@github.com/company/private-repo") end @@ -1439,7 +1435,6 @@ In Gemfile: end G - bundle :install expect(last_command.stdboth).to_not include("oauth_token") expect(last_command.stdout).to include("Fetching https://x-oauth-basic@github.com/company/private-repo") end diff --git a/spec/install/gemfile/path_spec.rb b/spec/install/gemfile/path_spec.rb index f7789e7ea5..44d1e67106 100644 --- a/spec/install/gemfile/path_spec.rb +++ b/spec/install/gemfile/path_spec.rb @@ -132,6 +132,20 @@ RSpec.describe "bundle install with explicit source paths" do expect(the_bundle).to include_gems "foo 1.0" end + it "works with only_update_to_newer_versions" do + build_lib "omg", "2.0", :path => lib_path("omg") + + install_gemfile <<-G + gem "omg", :path => "#{lib_path("omg")}" + G + + build_lib "omg", "1.0", :path => lib_path("omg") + + bundle! :install, :env => { "BUNDLE_BUNDLE_ONLY_UPDATE_TO_NEWER_VERSIONS" => "true" } + + expect(the_bundle).to include_gems "omg 1.0" + end + it "prefers gemspecs closer to the path root" do build_lib "premailer", "1.0.0", :path => lib_path("premailer") do |s| s.write "gemfiles/ruby187.gemspec", <<-G diff --git a/spec/install/gemfile/platform_spec.rb b/spec/install/gemfile/platform_spec.rb index 6c226eb29f..bfdf9b68c8 100644 --- a/spec/install/gemfile/platform_spec.rb +++ b/spec/install/gemfile/platform_spec.rb @@ -102,7 +102,7 @@ RSpec.describe "bundle install across platforms" do gem "pry" G - expect(the_bundle.lockfile).to read_as strip_whitespace(<<-L) + expect(the_bundle.lockfile).to read_as normalize_uri_file(strip_whitespace(<<-L)) GEM remote: file://localhost/#{gem_repo4}/ specs: @@ -160,7 +160,7 @@ RSpec.describe "bundle install across platforms" do #{Bundler::VERSION} L - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) bad_lockfile = strip_whitespace <<-L GEM @@ -196,23 +196,23 @@ RSpec.describe "bundle install across platforms" do aggregate_failures do lockfile bad_lockfile bundle! :install - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) lockfile bad_lockfile bundle! :update, :all => true - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) lockfile bad_lockfile bundle! "update ffi" - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) lockfile bad_lockfile bundle! "update empyrean" - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) lockfile bad_lockfile bundle! :lock - expect(the_bundle.lockfile).to read_as good_lockfile + expect(the_bundle.lockfile).to read_as normalize_uri_file(good_lockfile) end end diff --git a/spec/install/gems/native_extensions_spec.rb b/spec/install/gems/native_extensions_spec.rb index c8252b81f1..ea616f60d3 100644 --- a/spec/install/gems/native_extensions_spec.rb +++ b/spec/install/gems/native_extensions_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe "installing a gem with native extensions" do +RSpec.describe "installing a gem with native extensions", :ruby_repo do it "installs" do build_repo2 do build_gem "c_extension" do |s| diff --git a/spec/install/gems/resolving_spec.rb b/spec/install/gems/resolving_spec.rb index f581522c71..ddf803ed7d 100644 --- a/spec/install/gems/resolving_spec.rb +++ b/spec/install/gems/resolving_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe "bundle install with install-time dependencies" do - it "installs gems with implicit rake dependencies" do + it "installs gems with implicit rake dependencies", :ruby_repo do install_gemfile <<-G source "file://#{gem_repo1}" gem "with_implicit_rake_dep" @@ -48,7 +48,7 @@ RSpec.describe "bundle install with install-time dependencies" do expect(the_bundle).to include_gems "net_b 1.0" end - it "installs plugins depended on by other plugins" do + it "installs plugins depended on by other plugins", :ruby_repo do install_gemfile <<-G source "file://#{gem_repo1}" gem "net_a" @@ -57,7 +57,7 @@ RSpec.describe "bundle install with install-time dependencies" do expect(the_bundle).to include_gems "net_a 1.0", "net_b 1.0" end - it "installs multiple levels of dependencies" do + it "installs multiple levels of dependencies", :ruby_repo do install_gemfile <<-G source "file://#{gem_repo1}" gem "net_c" diff --git a/spec/install/gems/standalone_spec.rb b/spec/install/gems/standalone_spec.rb index b149d9d00b..10ce589eef 100644 --- a/spec/install/gems/standalone_spec.rb +++ b/spec/install/gems/standalone_spec.rb @@ -67,7 +67,7 @@ RSpec.shared_examples "bundle install --standalone" do include_examples "common functionality" end - describe "with gems with native extension" do + describe "with gems with native extension", :ruby_repo do before do install_gemfile <<-G, forgotten_command_line_options(:path => bundled_app("bundle")).merge(:standalone => true) source "file://#{gem_repo1}" diff --git a/spec/install/global_cache_spec.rb b/spec/install/global_cache_spec.rb index 3664d3963a..e41e7e0157 100644 --- a/spec/install/global_cache_spec.rb +++ b/spec/install/global_cache_spec.rb @@ -187,7 +187,7 @@ RSpec.describe "global gem caching" do end end - describe "extension caching", :rubygems => "2.2" do + describe "extension caching", :ruby_repo, :rubygems => "2.2" do it "works" do build_git "very_simple_git_binary", &:add_c_extension build_lib "very_simple_path_binary", &:add_c_extension diff --git a/spec/install/path_spec.rb b/spec/install/path_spec.rb index 5f3fedb862..44439c275e 100644 --- a/spec/install/path_spec.rb +++ b/spec/install/path_spec.rb @@ -207,7 +207,7 @@ RSpec.describe "bundle install" do expect(the_bundle).to include_gems "rack 1.0.0" end - it "re-installs gems whose extensions have been deleted", :rubygems => ">= 2.3" do + it "re-installs gems whose extensions have been deleted", :ruby_repo, :rubygems => ">= 2.3" do build_lib "very_simple_binary", "1.0.0", :to_system => true do |s| s.write "lib/very_simple_binary.rb", "raise 'FAIL'" end diff --git a/spec/lock/lockfile_bundler_1_spec.rb b/spec/lock/lockfile_bundler_1_spec.rb index a8615d4c89..638b40f5f4 100644 --- a/spec/lock/lockfile_bundler_1_spec.rb +++ b/spec/lock/lockfile_bundler_1_spec.rb @@ -75,10 +75,10 @@ RSpec.describe "the lockfile format", :bundler => "< 2" do G end - it "does not update the lockfile's bundler version if nothing changed during bundle install" do + it "does not update the lockfile's bundler version if nothing changed during bundle install", :ruby_repo do version = "#{Bundler::VERSION.split(".").first}.0.0.0.a" - lockfile <<-L + lockfile normalize_uri_file(<<-L) GEM remote: file://localhost#{gem_repo1}/ specs: @@ -94,13 +94,13 @@ RSpec.describe "the lockfile format", :bundler => "< 2" do #{version} L - install_gemfile <<-G + install_gemfile normalize_uri_file(<<-G) source "file://localhost#{gem_repo1}" gem "rack" G - lockfile_should_be <<-G + lockfile_should_be normalize_uri_file(<<-G) GEM remote: file://localhost#{gem_repo1}/ specs: diff --git a/spec/other/major_deprecation_spec.rb b/spec/other/major_deprecation_spec.rb index fba177b497..ce2735ba94 100644 --- a/spec/other/major_deprecation_spec.rb +++ b/spec/other/major_deprecation_spec.rb @@ -41,10 +41,12 @@ RSpec.describe "major deprecations", :bundler => "< 2" do describe "Bundler" do describe ".clean_env" do - it "is deprecated in favor of .original_env" do + it "is deprecated in favor of .unbundled_env" do source = "Bundler.clean_env" bundle "exec ruby -e #{source.dump}" - expect(warnings).to have_major_deprecation "`Bundler.clean_env` has weird edge cases, use `.original_env` instead" + expect(warnings).to have_major_deprecation \ + "`Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" end end diff --git a/spec/plugins/install_spec.rb b/spec/plugins/install_spec.rb index 9304d78062..29017c2afa 100644 --- a/spec/plugins/install_spec.rb +++ b/spec/plugins/install_spec.rb @@ -122,6 +122,24 @@ RSpec.describe "bundler plugin install" do expect(out).to include("Installed plugin foo") plugin_should_be_installed("foo") end + + it "installs form a local git source" do + build_git "foo" do |s| + s.write "plugins.rb" + end + + bundle "plugin install foo --local_git #{lib_path("foo-1.0")}" + + expect(out).to include("Installed plugin foo") + plugin_should_be_installed("foo") + end + + it "raises an error when both git and local git sources are specified" do + bundle "plugin install foo --local_git /phony/path/project --git git@gitphony.com:/repo/project" + + expect(exitstatus).not_to eq(0) if exitstatus + expect(out).to eq("Remote and local plugin git sources can't be both specified") + end end context "Gemfile eval" do @@ -173,6 +191,28 @@ RSpec.describe "bundler plugin install" do expect(out).to include("Installed plugin ga-plugin") plugin_should_be_installed("ga-plugin") end + + context "in deployment mode" do + it "installs plugins" do + install_gemfile! <<-G + source 'file://#{gem_repo2}' + gem 'rack', "1.0.0" + G + + install_gemfile! <<-G, forgotten_command_line_options(:deployment => true) + source 'file://#{gem_repo2}' + plugin 'foo' + gem 'rack', "1.0.0" + G + + expect(out).to include("Installed plugin foo") + + expect(out).to include("Bundle complete!") + + expect(the_bundle).to include_gems("rack 1.0.0") + plugin_should_be_installed("foo") + end + end end context "inline gemfiles" do diff --git a/spec/quality_spec.rb b/spec/quality_spec.rb index f8aec009ef..64590befdf 100644 --- a/spec/quality_spec.rb +++ b/spec/quality_spec.rb @@ -108,7 +108,8 @@ RSpec.describe "The library itself" do exempt = /\.gitmodules|\.marshal|fixtures|vendor|ssl_certs|LICENSE|vcr_cassettes/ error_messages = [] Dir.chdir(root) do - `git ls-files -z`.split("\x0").each do |filename| + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb spec/bundler` : `git ls-files -z -- lib` + lib_files.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_tab_characters(filename) error_messages << check_for_extra_spaces(filename) @@ -121,7 +122,8 @@ RSpec.describe "The library itself" do exempt = %r{quality_spec.rb|support/helpers|vcr_cassettes|\.md|\.ronn} error_messages = [] Dir.chdir(root) do - `git ls-files -z`.split("\x0").each do |filename| + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb spec/bundler` : `git ls-files -z -- lib` + lib_files.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_debugging_mechanisms(filename) end @@ -133,7 +135,8 @@ RSpec.describe "The library itself" do error_messages = [] exempt = %r{lock/lockfile_(bundler_1_)?spec|quality_spec|vcr_cassettes|\.ronn|lockfile_parser\.rb} Dir.chdir(root) do - `git ls-files -z`.split("\x0").each do |filename| + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb spec/bundler` : `git ls-files -z -- lib` + lib_files.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_git_merge_conflicts(filename) end @@ -158,7 +161,8 @@ RSpec.describe "The library itself" do error_messages = [] exempt = /vendor/ Dir.chdir(root) do - `git ls-files -z -- lib`.split("\x0").each do |filename| + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb` : `git ls-files -z -- lib` + lib_files.split("\x0").each do |filename| next if filename =~ exempt error_messages << check_for_expendable_words(filename) error_messages << check_for_specific_pronouns(filename) @@ -191,7 +195,8 @@ RSpec.describe "The library itself" do Dir.chdir(root) do key_pattern = /([a-z\._-]+)/i - `git ls-files -z -- lib`.split("\x0").each do |filename| + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb` : `git ls-files -z -- lib` + lib_files.split("\x0").each do |filename| File.readlines(filename).each_with_index do |line, number| line.scan(/Bundler\.settings\[:#{key_pattern}\]/).flatten.each {|s| all_settings[s] << "referenced at `#{filename}:#{number.succ}`" } end @@ -219,7 +224,7 @@ RSpec.describe "The library itself" do it "can still be built" do Dir.chdir(root) do begin - gem_command! :build, "bundler.gemspec" + gem_command! :build, gemspec if Bundler.rubygems.provides?(">= 2.4") # there's no way around this warning last_command.stderr.sub!(/^YAML safe loading.*/, "") @@ -230,7 +235,8 @@ RSpec.describe "The library itself" do end ensure # clean up the .gem generated - FileUtils.rm("bundler-#{Bundler::VERSION}.gem") + path_prefix = ruby_core? ? "lib/" : "./" + FileUtils.rm("#{path_prefix}bundler-#{Bundler::VERSION}.gem") end end end @@ -244,7 +250,8 @@ RSpec.describe "The library itself" do lib/bundler/vlad.rb lib/bundler/templates/gems.rb ] - lib_files = `git ls-files -z -- lib`.split("\x0").grep(/\.rb$/) - exclusions + lib_files = ruby_core? ? `git ls-files -z -- lib/bundler lib/bundler.rb` : `git ls-files -z -- lib` + lib_files = lib_files.split("\x0").grep(/\.rb$/) - exclusions lib_files.reject! {|f| f.start_with?("lib/bundler/vendor") } lib_files.map! {|f| f.chomp(".rb") } sys_exec!("ruby -w -Ilib") do |input, _, _| @@ -253,7 +260,11 @@ RSpec.describe "The library itself" do end end - expect(last_command.stdboth.split("\n")).to be_well_formed + warnings = last_command.stdboth.split("\n") + # ignore warnings around deprecated Object#=~ method in RubyGems + warnings.reject! {|w| w =~ %r{rubygems\/version.rb.*deprecated\ Object#=~} } + + expect(warnings).to be_well_formed end end end diff --git a/spec/runtime/gem_tasks_spec.rb b/spec/runtime/gem_tasks_spec.rb index 5fc87a6d46..de72869dc3 100644 --- a/spec/runtime/gem_tasks_spec.rb +++ b/spec/runtime/gem_tasks_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -RSpec.describe "require 'bundler/gem_tasks'" do +RSpec.describe "require 'bundler/gem_tasks'", :ruby_repo do before :each do bundled_app("foo.gemspec").open("w") do |f| f.write <<-GEMSPEC @@ -19,7 +19,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do it "includes the relevant tasks" do with_gem_path_as(Spec::Path.base_system_gems.to_s) do - sys_exec "ruby -S rake -T" + sys_exec "#{rake} -T" end expect(err).to eq("") @@ -37,7 +37,7 @@ RSpec.describe "require 'bundler/gem_tasks'" do it "adds 'pkg' to rake/clean's CLOBBER" do with_gem_path_as(Spec::Path.base_system_gems.to_s) do - sys_exec! %('#{Gem.ruby}' -S rake -e 'load "Rakefile"; puts CLOBBER.inspect') + sys_exec! %(#{rake} -e 'load "Rakefile"; puts CLOBBER.inspect') end expect(last_command.stdout).to eq '["pkg"]' end diff --git a/spec/runtime/inline_spec.rb b/spec/runtime/inline_spec.rb index 18ca246199..09493e0cbf 100644 --- a/spec/runtime/inline_spec.rb +++ b/spec/runtime/inline_spec.rb @@ -112,6 +112,19 @@ RSpec.describe "bundler/inline#gemfile" do expect(exitstatus).to be_zero if exitstatus end + it "has an option for quiet installation" do + script <<-RUBY, :artifice => "endpoint" + require 'bundler' + + gemfile(true, :quiet => true) do + source "https://notaserver.com" + gem "activesupport", :require => true + end + RUBY + + expect(out).to be_empty + end + it "raises an exception if passed unknown arguments" do script <<-RUBY gemfile(true, :arglebargle => true) do diff --git a/spec/runtime/setup_spec.rb b/spec/runtime/setup_spec.rb index 93a25b1ea8..941c3d34e7 100644 --- a/spec/runtime/setup_spec.rb +++ b/spec/runtime/setup_spec.rb @@ -119,7 +119,7 @@ RSpec.describe "Bundler.setup" do lp.map! {|p| p.sub(/^#{Regexp.union system_gem_path.to_s, default_bundle_path.to_s}/i, "") } end - it "puts loaded gems after -I and RUBYLIB" do + it "puts loaded gems after -I and RUBYLIB", :ruby_repo do install_gemfile <<-G source "file://#{gem_repo1}" gem "rack" @@ -824,7 +824,7 @@ end expect(out).to eq("yay") end - it "should clean $LOAD_PATH properly" do + it "should clean $LOAD_PATH properly", :ruby_repo do gem_name = "very_simple_binary" full_gem_name = gem_name + "-1.0" ext_dir = File.join(tmp("extensions", full_gem_name)) @@ -860,7 +860,7 @@ end context "with bundler is located in symlinked GEM_HOME" do let(:gem_home) { Dir.mktmpdir } let(:symlinked_gem_home) { Tempfile.new("gem_home").path } - let(:bundler_dir) { File.expand_path("../../..", __FILE__) } + let(:bundler_dir) { ruby_core? ? File.expand_path("../../../..", __FILE__) : File.expand_path("../../..", __FILE__) } let(:bundler_lib) { File.join(bundler_dir, "lib") } before do @@ -872,7 +872,8 @@ end FileUtils.ln_s(bundler_dir, File.join(gems_dir, "bundler-#{Bundler::VERSION}")) - gemspec = File.read("#{bundler_dir}/bundler.gemspec"). + gemspec_file = ruby_core? ? "#{bundler_dir}/lib/bundler.gemspec" : "#{bundler_dir}/bundler.gemspec" + gemspec = File.read(gemspec_file). sub("Bundler::VERSION", %("#{Bundler::VERSION}")) gemspec = gemspec.lines.reject {|line| line =~ %r{lib/bundler/version} }.join @@ -881,7 +882,9 @@ end end end - it "should successfully require 'bundler/setup'" do + # Can't make this pass on 2.6 since the ruby standard library has the same $LOAD_PATH + # entry as bundler (since it's a default gem) + it "should successfully require 'bundler/setup'", :ruby_repo, :ruby => "< 2.6" do install_gemfile "" ruby <<-'R', :env => { "GEM_PATH" => symlinked_gem_home }, :no_lib => true diff --git a/spec/runtime/with_clean_env_spec.rb b/spec/runtime/with_unbundled_env_spec.rb index fd621071ad..83eb1eac13 100644 --- a/spec/runtime/with_clean_env_spec.rb +++ b/spec/runtime/with_unbundled_env_spec.rb @@ -2,6 +2,7 @@ RSpec.describe "Bundler.with_env helpers" do def bundle_exec_ruby!(code, *args) + build_bundler_context opts = args.last.is_a?(Hash) ? args.pop : {} env = opts[:env] ||= {} env[:RUBYOPT] ||= "-r#{spec_dir.join("support/hax")}" @@ -9,13 +10,13 @@ RSpec.describe "Bundler.with_env helpers" do bundle! "exec '#{Gem.ruby}' -e #{code}", *args end - describe "Bundler.original_env" do - before do - bundle "config path vendor/bundle" - gemfile "" - bundle "install" - end + def build_bundler_context + bundle "config path vendor/bundle" + gemfile "" + bundle "install" + end + describe "Bundler.original_env" do it "should return the PATH present before bundle was activated" do code = "print Bundler.original_env['PATH']" path = `getconf PATH`.strip + "#{File::PATH_SEPARATOR}/foo" @@ -34,7 +35,7 @@ RSpec.describe "Bundler.with_env helpers" do end end - it "works with nested bundle exec invocations" do + it "works with nested bundle exec invocations", :ruby_repo do create_file("exe.rb", <<-'RB') count = ARGV.first.to_i exit if count < 0 @@ -46,6 +47,7 @@ RSpec.describe "Bundler.with_env helpers" do RB path = `getconf PATH`.strip + File::PATH_SEPARATOR + File.dirname(Gem.ruby) with_path_as(path) do + build_bundler_context bundle! "exec '#{Gem.ruby}' #{bundled_app("exe.rb")} 2", :env => { :RUBYOPT => "-r#{spec_dir.join("support/hax")}" } end expect(err).to eq <<-EOS.strip @@ -55,48 +57,72 @@ RSpec.describe "Bundler.with_env helpers" do EOS end - it "removes variables that bundler added" do + it "removes variables that bundler added", :ruby_repo do original = ruby!('puts ENV.to_a.map {|e| e.join("=") }.sort.join("\n")', :env => { :RUBYOPT => "-r#{spec_dir.join("support/hax")}" }) code = 'puts Bundler.original_env.to_a.map {|e| e.join("=") }.sort.join("\n")' - bundle! "exec '#{Gem.ruby}' -e #{code.dump}", :env => { :RUBYOPT => "-r#{spec_dir.join("support/hax")}" } + bundle_exec_ruby! code.dump expect(out).to eq original end end - describe "Bundler.clean_env", :bundler => "< 2" do - before do - bundle "config path vendor/bundle" - gemfile "" - bundle "install" - end - + shared_examples_for "an unbundling helper" do it "should delete BUNDLE_PATH" do - code = "print Bundler.clean_env.has_key?('BUNDLE_PATH')" + code = "print #{modified_env}.has_key?('BUNDLE_PATH')" ENV["BUNDLE_PATH"] = "./foo" bundle_exec_ruby! code.dump - expect(last_command.stdboth).to eq "false" + expect(last_command.stdboth).to include "false" end it "should remove '-rbundler/setup' from RUBYOPT" do - code = "print Bundler.clean_env['RUBYOPT']" + code = "print #{modified_env}['RUBYOPT']" ENV["RUBYOPT"] = "-W2 -rbundler/setup" bundle_exec_ruby! code.dump expect(last_command.stdboth).not_to include("-rbundler/setup") end - it "should clean up RUBYLIB" do - code = "print Bundler.clean_env['RUBYLIB']" + it "should clean up RUBYLIB", :ruby_repo do + code = "print #{modified_env}['RUBYLIB']" ENV["RUBYLIB"] = root.join("lib").to_s + File::PATH_SEPARATOR + "/foo" bundle_exec_ruby! code.dump - expect(last_command.stdboth).to eq("/foo") + expect(last_command.stdboth).to include("/foo") end it "should restore the original MANPATH" do - code = "print Bundler.clean_env['MANPATH']" + code = "print #{modified_env}['MANPATH']" ENV["MANPATH"] = "/foo" ENV["BUNDLER_ORIG_MANPATH"] = "/foo-original" bundle_exec_ruby! code.dump - expect(last_command.stdboth).to eq("/foo-original") + expect(last_command.stdboth).to include("/foo-original") + end + end + + describe "Bundler.unbundled_env" do + let(:modified_env) { "Bundler.unbundled_env" } + + it_behaves_like "an unbundling helper" + end + + describe "Bundler.clean_env" do + let(:modified_env) { "Bundler.clean_env" } + + it_behaves_like "an unbundling helper" + + it "prints a deprecation", :bundler => 2 do + code = "Bundler.clean_env" + bundle_exec_ruby! code.dump + expect(last_command.stdboth).to include( + "[DEPRECATED FOR 2.0] `Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + ) + end + + it "does not print a deprecation", :bundler => "< 2" do + code = "Bundler.clean_env" + bundle_exec_ruby! code.dump + expect(last_command.stdboth).not_to include( + "[DEPRECATED FOR 2.0] `Bundler.clean_env` has been deprecated in favor of `Bundler.unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.original_env`" + ) end end @@ -116,9 +142,9 @@ RSpec.describe "Bundler.with_env helpers" do end end - describe "Bundler.with_clean_env", :bundler => "< 2" do - it "should set ENV to clean_env in the block" do - expected = Bundler.clean_env + describe "Bundler.with_clean_env" do + it "should set ENV to unbundled_env in the block" do + expected = Bundler.unbundled_env actual = Bundler.with_clean_env { ENV.to_hash } expect(actual).to eq(expected) end @@ -130,6 +156,40 @@ RSpec.describe "Bundler.with_env helpers" do expect(ENV).not_to have_key("FOO") end + + it "prints a deprecation", :bundler => 2 do + code = "Bundler.with_clean_env {}" + bundle_exec_ruby! code.dump + expect(last_command.stdboth).to include( + "[DEPRECATED FOR 2.0] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + ) + end + + it "does not print a deprecation", :bundler => "< 2" do + code = "Bundler.with_clean_env {}" + bundle_exec_ruby! code.dump + expect(last_command.stdboth).not_to include( + "[DEPRECATED FOR 2.0] `Bundler.with_clean_env` has been deprecated in favor of `Bundler.with_unbundled_env`. " \ + "If you instead want the environment before bundler was originally loaded, use `Bundler.with_original_env`" + ) + end + end + + describe "Bundler.with_unbundled_env" do + it "should set ENV to unbundled_env in the block" do + expected = Bundler.unbundled_env + actual = Bundler.with_unbundled_env { ENV.to_hash } + expect(actual).to eq(expected) + end + + it "should restore the environment after execution" do + Bundler.with_unbundled_env do + ENV["FOO"] = "hello" + end + + expect(ENV).not_to have_key("FOO") + end end describe "Bundler.clean_system", :ruby => ">= 1.9", :bundler => "< 2" do diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1091c0b7f3..9355bfb33f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -52,6 +52,12 @@ ENV["THOR_COLUMNS"] = "10000" Spec::CodeClimate.setup +module Gem + def self.ruby=(ruby) + @ruby = ruby + end +end + RSpec.configure do |config| config.include Spec::Builders config.include Spec::Helpers @@ -93,6 +99,7 @@ RSpec.configure do |config| config.filter_run_excluding :git => LessThanProc.with(git_version) config.filter_run_excluding :rubygems_master => (ENV["RGV"] != "master") config.filter_run_excluding :bundler => LessThanProc.with(Bundler::VERSION.split(".")[0, 2].join(".")) + config.filter_run_excluding :ruby_repo => !(ENV["BUNDLE_RUBY"] && ENV["BUNDLE_GEM"]).nil? config.filter_run_when_matching :focus unless ENV["CI"] @@ -107,6 +114,21 @@ RSpec.configure do |config| mocks.allow_message_expectations_on_nil = false end + config.around :each do |example| + if ENV["BUNDLE_RUBY"] + orig_ruby = Gem.ruby + Gem.ruby = ENV["BUNDLE_RUBY"] + end + example.run + Gem.ruby = orig_ruby if ENV["BUNDLE_RUBY"] + end + + config.before :suite do + if ENV["BUNDLE_RUBY"] + FileUtils.cp_r Spec::Path.bindir, File.join(Spec::Path.root, "lib", "exe") + end + end + config.before :all do build_repo1 end @@ -131,4 +153,10 @@ RSpec.configure do |config| Dir.chdir(original_wd) ENV.replace(original_env) end + + config.after :suite do + if ENV["BUNDLE_RUBY"] + FileUtils.rm_rf File.join(Spec::Path.root, "lib", "exe") + end + end end diff --git a/spec/support/builders.rb b/spec/support/builders.rb index fa32b12b65..188b1d3eb7 100644 --- a/spec/support/builders.rb +++ b/spec/support/builders.rb @@ -210,12 +210,7 @@ module Spec # The yard gem iterates over Gem.source_index looking for plugins build_gem "yard" do |s| s.write "lib/yard.rb", <<-Y - if Gem::Version.new(Gem::VERSION) >= Gem::Version.new("1.8.10") - specs = Gem::Specification - else - specs = Gem.source_index.find_name('') - end - specs.sort_by(&:name).each do |gem| + Gem::Specification.sort_by(&:name).each do |gem| puts gem.full_name end Y diff --git a/spec/support/helpers.rb b/spec/support/helpers.rb index d14ac20cae..9126256f8e 100644 --- a/spec/support/helpers.rb +++ b/spec/support/helpers.rb @@ -104,7 +104,7 @@ module Spec bundle_bin = options.delete("bundle_bin") || bindir.join("bundle") if system_bundler = options.delete(:system_bundler) - bundle_bin = "-S bundle" + bundle_bin = system_bundle_bin_path end env = options.delete(:env) || {} @@ -212,10 +212,15 @@ module Spec args = args.gsub(/(?=")/, "\\") args = %("#{args}") end - sys_exec("#{Gem.ruby} -rrubygems -S gem --backtrace #{command} #{args}") + gem = ENV["BUNDLE_GEM"] || "#{Gem.ruby} -rrubygems -S gem --backtrace" + sys_exec("#{gem} #{command} #{args}") end bang :gem_command + def rake + "#{Gem.ruby} -S #{ENV["GEM_PATH"]}/bin/rake" + end + def sys_exec(cmd) command_execution = CommandExecution.new(cmd.to_s, Dir.pwd) @@ -223,9 +228,9 @@ module Spec yield stdin, stdout, wait_thr if block_given? stdin.close - command_execution.exitstatus = wait_thr && wait_thr.value.exitstatus command_execution.stdout = Thread.new { stdout.read }.value.strip command_execution.stderr = Thread.new { stderr.read }.value.strip + command_execution.exitstatus = wait_thr && wait_thr.value.exitstatus end (@command_executions ||= []) << command_execution @@ -309,7 +314,11 @@ module Spec gems.each do |g| path = if g == :bundler Dir.chdir(root) { gem_command! :build, gemspec.to_s } - bundler_path = root + "bundler-#{Bundler::VERSION}.gem" + bundler_path = if ruby_core? + root + "lib/bundler-#{Bundler::VERSION}.gem" + else + root + "bundler-#{Bundler::VERSION}.gem" + end elsif g.to_s =~ %r{\A/.*\.gem\z} g else @@ -318,11 +327,8 @@ module Spec raise "OMG `#{path}` does not exist!" unless File.exist?(path) - if Gem::VERSION < "2.0.0" - gem_command! :install, "--no-rdoc --no-ri --ignore-dependencies '#{path}'" - else - gem_command! :install, "--no-document --ignore-dependencies '#{path}'" - end + gem_command! :install, "--no-document --ignore-dependencies '#{path}'" + bundler_path && bundler_path.rmtree end end diff --git a/spec/support/path.rb b/spec/support/path.rb index b24ac16d5b..f85fbf330f 100644 --- a/spec/support/path.rb +++ b/spec/support/path.rb @@ -5,19 +5,19 @@ require "pathname" module Spec module Path def root - @root ||= Pathname.new(File.expand_path("../../..", __FILE__)) + @root ||= Pathname.new(ruby_core? ? "../../../.." : "../../..").expand_path(__FILE__) end def gemspec - @gemspec ||= Pathname.new(File.expand_path(root.join("bundler.gemspec"), __FILE__)) + @gemspec ||= root.join(ruby_core? ? "lib/bundler.gemspec" : "bundler.gemspec") end def bindir - @bindir ||= Pathname.new(File.expand_path(root.join("exe"), __FILE__)) + @bindir ||= root.join(ruby_core? ? "libexec" : "exe") end def spec_dir - @spec_dir ||= Pathname.new(File.expand_path(root.join("spec"), __FILE__)) + @spec_dir ||= root.join(ruby_core? ? "spec/bundler" : "spec") end def tmp(*path) @@ -90,12 +90,16 @@ module Spec tmp("gems/system", *path) end + def system_bundle_bin_path + system_gem_path("bin/bundle") + end + def lib_path(*args) tmp("libs", *args) end def bundler_path - Pathname.new(File.expand_path(root.join("lib"), __FILE__)) + root.join("lib") end def global_plugin_gem(*args) @@ -110,6 +114,17 @@ module Spec tmp "tmpdir", *args end + def ruby_core? + # avoid to wornings + @ruby_core ||= nil + + if @ruby_core.nil? + @ruby_core = true & (ENV["BUNDLE_RUBY"] && ENV["BUNDLE_GEM"]) + else + @ruby_core + end + end + extend self end end diff --git a/spec/support/rubygems_ext.rb b/spec/support/rubygems_ext.rb index 806933fe2f..7a69d713cb 100644 --- a/spec/support/rubygems_ext.rb +++ b/spec/support/rubygems_ext.rb @@ -33,17 +33,17 @@ module Spec ENV["BUNDLE_PATH"] = nil ENV["GEM_HOME"] = ENV["GEM_PATH"] = Path.base_system_gems.to_s - ENV["PATH"] = ["#{Path.root}/exe", "#{Path.system_gem_path}/bin", ENV["PATH"]].join(File::PATH_SEPARATOR) + ENV["PATH"] = [Path.bindir, Path.system_gem_path.join("bin"), ENV["PATH"]].join(File::PATH_SEPARATOR) manifest = DEPS.to_a.sort_by(&:first).map {|k, v| "#{k} => #{v}\n" } - manifest_path = "#{Path.base_system_gems}/manifest.txt" + manifest_path = Path.base_system_gems.join("manifest.txt") # it's OK if there are extra gems - if !File.exist?(manifest_path) || !(manifest - File.readlines(manifest_path)).empty? + if !manifest_path.file? || !(manifest - manifest_path.readlines).empty? FileUtils.rm_rf(Path.base_system_gems) FileUtils.mkdir_p(Path.base_system_gems) puts "installing gems for the tests to use..." install_gems(DEPS) - File.open(manifest_path, "w") {|f| f << manifest.join } + manifest_path.open("w") {|f| f << manifest.join } end ENV["HOME"] = Path.home.to_s @@ -59,11 +59,7 @@ module Spec no_reqs.map!(&:first) reqs.map! {|name, req| "'#{name}:#{req}'" } deps = reqs.concat(no_reqs).join(" ") - cmd = if Gem::VERSION < "2.0.0" - "gem install #{deps} --no-rdoc --no-ri --conservative" - else - "gem install #{deps} --no-document --conservative" - end + cmd = "#{Gem.ruby} -S gem install #{deps} --no-document --conservative" puts cmd system(cmd) || raise("Installing gems #{deps} for the tests to use failed!") end |