Merge RubyGems/Bundler master

Pick from ba3adad4d8
This commit is contained in:
Hiroshi SHIBATA 2022-12-20 09:43:53 +09:00
parent ad1f61fe80
commit 18ba89093a
Notes: git 2022-12-20 04:15:28 +00:00
11 changed files with 169 additions and 67 deletions

View file

@ -587,7 +587,7 @@ module Bundler
method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library", method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library",
:desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "", method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "",
:desc => "Generate CI configuration, either GitHub Actions, Travis CI, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|travis|gitlab|circle)`" :desc => "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
method_option :linter, :type => :string, :lazy_default => Bundler.settings["gem.linter"] || "", method_option :linter, :type => :string, :lazy_default => Bundler.settings["gem.linter"] || "",
:desc => "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`" :desc => "Add a linter and code formatter, either RuboCop or Standard. Set a default with `bundle config set --global gem.linter (rubocop|standard)`"
method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`." method_option :github_username, :type => :string, :default => Bundler.settings["gem.github_username"], :banner => "Set your username on GitHub", :desc => "Fill in GitHub username on README so that you don't have to do it manually. Set a default with `bundle config set --global gem.github_username <your_username>`."

View file

@ -31,6 +31,7 @@ module Bundler
@extension = options[:ext] @extension = options[:ext]
validate_ext_name if @extension validate_ext_name if @extension
travis_removal_info
end end
def run def run
@ -134,8 +135,6 @@ module Bundler
case config[:ci] case config[:ci]
when "github" when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml") templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
when "travis"
templates.merge!("travis.yml.tt" => ".travis.yml")
when "gitlab" when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml") templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
when "circle" when "circle"
@ -308,12 +307,11 @@ module Bundler
"* CircleCI: https://circleci.com/\n" \ "* CircleCI: https://circleci.com/\n" \
"* GitHub Actions: https://github.com/features/actions\n" \ "* GitHub Actions: https://github.com/features/actions\n" \
"* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \ "* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \
"* Travis CI: https://travis-ci.org/\n" \
"\n" "\n"
Bundler.ui.info hint_text("ci") Bundler.ui.info hint_text("ci")
result = Bundler.ui.ask "Enter a CI service. github/travis/gitlab/circle/(none):" result = Bundler.ui.ask "Enter a CI service. github/gitlab/circle/(none):"
if /github|travis|gitlab|circle/.match?(result) if /github|gitlab|circle/.match?(result)
ci_template = result ci_template = result
else else
ci_template = false ci_template = false
@ -428,5 +426,19 @@ module Bundler
def standard_version def standard_version
"1.3" "1.3"
end end
#
# TODO: remove at next minor release
def travis_removal_info
if options[:ci] == "travis"
Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator."
exit 1
end
if Bundler.settings["gem.ci"] == "travis"
Bundler.ui.error "Support for Travis CI was removed from gem skeleton generator, but it is present in bundle config. Please configure another provider using `bundle config set gem.ci SERVICE` (where SERVICE is one of github/gitlab/circle) or unset configuration using `bundle config unset gem.ci`."
exit 1
end
end
end end
end end

View file

@ -77,8 +77,8 @@ When Bundler is configured to not generate tests, an interactive prompt will be
When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\. When Bundler is unconfigured, an interactive prompt will be displayed and the answer will be saved in Bundler\'s global config for future \fBbundle gem\fR use\.
. .
.TP .TP
\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=travis\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR \fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=gitlab\fR, \fB\-\-ci=circle\fR
Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBtravis\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified: Specify the continuous integration service that Bundler should use when generating the project\. Acceptable values are \fBgithub\fR, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
. .
.IP .IP
When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\. When Bundler is configured to generate CI files, this defaults to Bundler\'s global config setting \fBgem\.ci\fR\.

View file

@ -76,9 +76,9 @@ configuration file using the following names:
the answer will be saved in Bundler's global config for future `bundle gem` the answer will be saved in Bundler's global config for future `bundle gem`
use. use.
* `--ci`, `--ci=github`, `--ci=travis`, `--ci=gitlab`, `--ci=circle`: * `--ci`, `--ci=github`, `--ci=gitlab`, `--ci=circle`:
Specify the continuous integration service that Bundler should use when Specify the continuous integration service that Bundler should use when
generating the project. Acceptable values are `github`, `travis`, `gitlab` generating the project. Acceptable values are `github`, `gitlab`
and `circle`. A configuration file will be generated in the project directory. and `circle`. A configuration file will be generated in the project directory.
Given no option is specified: Given no option is specified:

View file

@ -31,7 +31,6 @@ module Bundler
msg = String.new msg = String.new
msg << "Git error: command `#{command}` in directory #{path} has failed." msg << "Git error: command `#{command}` in directory #{path} has failed."
msg << "\n#{extra_info}" if extra_info msg << "\n#{extra_info}" if extra_info
msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist?
super msg super msg
end end
end end
@ -47,7 +46,7 @@ module Bundler
# All actions required by the Git source is encapsulated in this # All actions required by the Git source is encapsulated in this
# object. # object.
class GitProxy class GitProxy
attr_accessor :path, :uri, :branch, :tag, :ref attr_accessor :path, :uri, :branch, :tag, :ref, :explicit_ref
attr_writer :revision attr_writer :revision
def initialize(path, uri, options = {}, revision = nil, git = nil) def initialize(path, uri, options = {}, revision = nil, git = nil)
@ -56,6 +55,7 @@ module Bundler
@branch = options["branch"] @branch = options["branch"]
@tag = options["tag"] @tag = options["tag"]
@ref = options["ref"] @ref = options["ref"]
@explicit_ref = branch || tag || ref
@revision = revision @revision = revision
@git = git @git = git
end end
@ -94,9 +94,7 @@ module Bundler
unshallow_needed = clone_needs_unshallow? unshallow_needed = clone_needs_unshallow?
return unless extra_fetch_needed || unshallow_needed return unless extra_fetch_needed || unshallow_needed
fetch_args = unshallow_needed ? ["--unshallow"] : depth_args git_remote_fetch(unshallow_needed ? ["--unshallow"] : depth_args)
git_retry(*["fetch", "--force", "--quiet", "--no-tags", *fetch_args, "--", configured_uri, refspec].compact, :dir => path)
end end
def copy_to(destination, submodules = false) def copy_to(destination, submodules = false)
@ -132,6 +130,22 @@ module Bundler
private private
def git_remote_fetch(args)
command = ["fetch", "--force", "--quiet", "--no-tags", *args, "--", configured_uri, refspec].compact
command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{path}", [MissingGitRevisionError]).attempts do
out, err, status = capture(command, path)
return out if status.success?
if err.include?("couldn't find remote ref")
raise MissingGitRevisionError.new(command_with_no_credentials, path, explicit_ref, credential_filtered_uri)
else
raise GitCommandError.new(command_with_no_credentials, path, err)
end
end
end
def clone_needs_extra_fetch? def clone_needs_extra_fetch?
return true if path.exist? return true if path.exist?
@ -216,11 +230,7 @@ module Bundler
def git_null(*command, dir: nil) def git_null(*command, dir: nil)
check_allowed(command) check_allowed(command)
out, status = SharedHelpers.with_clean_git_env do capture(command, dir, :ignore_err => true)
capture_and_ignore_stderr(*capture3_args_for(command, dir))
end
[URICredentialsFilter.credential_filtered_string(out, uri), status]
end end
def git_retry(*command, dir: nil) def git_retry(*command, dir: nil)
@ -234,15 +244,13 @@ module Bundler
def git(*command, dir: nil) def git(*command, dir: nil)
command_with_no_credentials = check_allowed(command) command_with_no_credentials = check_allowed(command)
out, status = SharedHelpers.with_clean_git_env do out, err, status = capture(command, dir)
capture_and_filter_stderr(*capture3_args_for(command, dir))
end
filtered_out = URICredentialsFilter.credential_filtered_string(out, uri) Bundler.ui.warn err unless err.empty?
raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, filtered_out) unless status.success? raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, out) unless status.success?
filtered_out out
end end
def has_revision_cached? def has_revision_cached?
@ -254,10 +262,9 @@ module Bundler
end end
def find_local_revision def find_local_revision
options_ref = branch || tag || ref return head_revision if explicit_ref.nil?
return head_revision if options_ref.nil?
find_revision_for(options_ref) find_revision_for(explicit_ref)
end end
def head_revision def head_revision
@ -318,17 +325,17 @@ module Bundler
command_with_no_credentials command_with_no_credentials
end end
def capture_and_filter_stderr(*cmd) def capture(cmd, dir, ignore_err: false)
SharedHelpers.with_clean_git_env do
require "open3" require "open3"
return_value, captured_err, status = Open3.capture3(*cmd) out, err, status = Open3.capture3(*capture3_args_for(cmd, dir))
Bundler.ui.warn URICredentialsFilter.credential_filtered_string(captured_err, uri) unless captured_err.empty?
[return_value, status]
end
def capture_and_ignore_stderr(*cmd) filtered_out = URICredentialsFilter.credential_filtered_string(out, uri)
require "open3" return [filtered_out, status] if ignore_err
return_value, _, status = Open3.capture3(*cmd)
[return_value, status] filtered_err = URICredentialsFilter.credential_filtered_string(err, uri)
[filtered_out, filtered_err, status]
end
end end
def capture3_args_for(cmd, dir) def capture3_args_for(cmd, dir)

View file

@ -161,11 +161,17 @@ module Bundler
end end
def map_sources(replacement_sources) def map_sources(replacement_sources)
[@rubygems_sources, @path_sources, @git_sources, @plugin_sources].map do |sources| rubygems, git, plugin = [@rubygems_sources, @git_sources, @plugin_sources].map do |sources|
sources.map do |source| sources.map do |source|
replacement_sources.find {|s| s == source } || source replacement_sources.find {|s| s == source } || source
end end
end end
path = @path_sources.map do |source|
replacement_sources.find {|s| s == (source.is_a?(Source::Gemspec) ? source.as_path_source : source) } || source
end
[rubygems, path, git, plugin]
end end
def global_replacement_source(replacement_sources) def global_replacement_source(replacement_sources)

View file

@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git. # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(__dir__) do spec.files = Dir.chdir(__dir__) do
`git ls-files -z`.split("\x0").reject do |f| `git ls-files -z`.split("\x0").reject do |f|
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)}) (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
end end
end end
spec.bindir = "exe" spec.bindir = "exe"

View file

@ -1,6 +0,0 @@
---
language: ruby
cache: bundler
rvm:
- <%= RUBY_VERSION %>
before_install: gem install bundler -v <%= Bundler::VERSION %>

View file

@ -348,7 +348,6 @@ RSpec.describe "bundle gem" do
shared_examples_for "CI config is absent" do shared_examples_for "CI config is absent" do
it "does not create any CI files" do it "does not create any CI files" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end end
@ -888,12 +887,29 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name}" bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end end
end end
context "--ci set to travis" do
it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
end
end
context "--ci set to travis" do
it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=travis", :raise_on_error => false
expect(err).to include("Support for Travis CI was removed from gem skeleton generator.")
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
end
end
context "--ci set to github" do context "--ci set to github" do
it "generates a GitHub Actions config file" do it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=github" bundle "gem #{gem_name} --ci=github"
@ -918,23 +934,26 @@ RSpec.describe "bundle gem" do
end end
end end
context "--ci set to travis" do
it "generates a Travis CI config file" do
bundle "gem #{gem_name} --ci=travis"
expect(bundled_app("#{gem_name}/.travis.yml")).to exist
end
end
context "gem.ci setting set to none" do context "gem.ci setting set to none" do
it "doesn't generate any CI config" do it "doesn't generate any CI config" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to_not exist
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to_not exist
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist expect(bundled_app("#{gem_name}/.circleci/config.yml")).to_not exist
end end
end end
context "gem.ci setting set to travis" do
it "errors with friendly message" do
bundle "config set gem.ci travis"
bundle "gem #{gem_name}", :raise_on_error => false
expect(err).to include("Support for Travis CI was removed from gem skeleton generator,")
expect(err).to include("bundle config unset gem.ci")
expect(bundled_app("#{gem_name}/.travis.yml")).to_not exist
end
end
context "gem.ci setting set to github" do context "gem.ci setting set to github" do
it "generates a GitHub Actions config file" do it "generates a GitHub Actions config file" do
bundle "config set gem.ci github" bundle "config set gem.ci github"
@ -944,15 +963,6 @@ RSpec.describe "bundle gem" do
end end
end end
context "gem.ci setting set to travis" do
it "generates a Travis CI config file" do
bundle "config set gem.ci travis"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.travis.yml")).to exist
end
end
context "gem.ci setting set to gitlab" do context "gem.ci setting set to gitlab" do
it "generates a GitLab CI config file" do it "generates a GitLab CI config file" do
bundle "config set gem.ci gitlab" bundle "config set gem.ci gitlab"

View file

@ -361,6 +361,68 @@ RSpec.describe "bundle update" do
expect(out).to include("Installing quickbooks-ruby 1.0.19").and include("Installing oauth2 1.4.10") expect(out).to include("Installing quickbooks-ruby 1.0.19").and include("Installing oauth2 1.4.10")
end end
it "does not downgrade direct dependencies when using gemspec sources" do
create_file("rails.gemspec", <<-G)
Gem::Specification.new do |gem|
gem.name = "rails"
gem.version = "7.1.0.alpha"
gem.author = "DHH"
gem.summary = "Full-stack web application framework."
end
G
build_repo4 do
build_gem "rake", "12.3.3"
build_gem "rake", "13.0.6"
build_gem "sneakers", "2.11.0" do |s|
s.add_dependency "rake"
end
build_gem "sneakers", "2.12.0" do |s|
s.add_dependency "rake", "~> 12.3"
end
end
gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gemspec
gem "rake"
gem "sneakers"
G
lockfile <<~L
PATH
remote: .
specs:
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
rake (13.0.6)
sneakers (2.11.0)
rake
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rake
sneakers
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "update --verbose"
expect(out).not_to include("Installing sneakers 2.12.0")
expect(out).not_to include("Installing rake 12.3.3")
expect(out).to include("Installing sneakers 2.11.0").and include("Installing rake 13.0.6")
end
it "does not downgrade indirect dependencies unnecessarily" do it "does not downgrade indirect dependencies unnecessarily" do
build_repo4 do build_repo4 do
build_gem "a" do |s| build_gem "a" do |s|

View file

@ -22,6 +22,17 @@ RSpec.describe "bundle lock with git gems" do
expect(err).to be_empty expect(err).to be_empty
end end
it "prints a proper error when changing a locked Gemfile to point to a bad branch" do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem 'foo', :git => "#{lib_path("foo-1.0")}", :branch => "bad"
G
bundle "lock --update foo", :raise_on_error => false
expect(err).to include("Revision bad does not exist in the repository")
end
it "locks a git source to the current ref" do it "locks a git source to the current ref" do
update_git "foo" update_git "foo"
bundle :install bundle :install