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",
: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"] || "",
: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"] || "",
: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>`."

View file

@ -31,6 +31,7 @@ module Bundler
@extension = options[:ext]
validate_ext_name if @extension
travis_removal_info
end
def run
@ -134,8 +135,6 @@ module Bundler
case config[:ci]
when "github"
templates.merge!("github/workflows/main.yml.tt" => ".github/workflows/main.yml")
when "travis"
templates.merge!("travis.yml.tt" => ".travis.yml")
when "gitlab"
templates.merge!("gitlab-ci.yml.tt" => ".gitlab-ci.yml")
when "circle"
@ -308,12 +307,11 @@ module Bundler
"* CircleCI: https://circleci.com/\n" \
"* GitHub Actions: https://github.com/features/actions\n" \
"* GitLab CI: https://docs.gitlab.com/ee/ci/\n" \
"* Travis CI: https://travis-ci.org/\n" \
"\n"
Bundler.ui.info hint_text("ci")
result = Bundler.ui.ask "Enter a CI service. github/travis/gitlab/circle/(none):"
if /github|travis|gitlab|circle/.match?(result)
result = Bundler.ui.ask "Enter a CI service. github/gitlab/circle/(none):"
if /github|gitlab|circle/.match?(result)
ci_template = result
else
ci_template = false
@ -428,5 +426,19 @@ module Bundler
def standard_version
"1.3"
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

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\.
.
.TP
\fB\-\-ci\fR, \fB\-\-ci=github\fR, \fB\-\-ci=travis\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:
\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, \fBgitlab\fR and \fBcircle\fR\. A configuration file will be generated in the project directory\. Given no option is specified:
.
.IP
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`
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
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.
Given no option is specified:

View file

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

View file

@ -161,11 +161,17 @@ module Bundler
end
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|
replacement_sources.find {|s| s == source } || source
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
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.
spec.files = Dir.chdir(__dir__) do
`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
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
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}/.travis.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
end
@ -888,12 +887,29 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name}"
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}/.circleci/config.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 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
it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=github"
@ -918,23 +934,26 @@ RSpec.describe "bundle gem" do
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
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}/.travis.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
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
it "generates a GitHub Actions config file" do
bundle "config set gem.ci github"
@ -944,15 +963,6 @@ RSpec.describe "bundle gem" do
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
it "generates a GitLab CI config file" do
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")
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
build_repo4 do
build_gem "a" do |s|

View file

@ -22,6 +22,17 @@ RSpec.describe "bundle lock with git gems" do
expect(err).to be_empty
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
update_git "foo"
bundle :install