Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
ca9c0f9
[rubygems/rubygems] Use File#chmod rather than FileUtils.chmod
tenderlove Sep 11, 2025
a71b339
[rubygems/rubygems] Pass the file size to IO.copy_stream
tenderlove Sep 12, 2025
9b45a25
[rubygems/rubygems] Fix `rubocop` config removal message
deivid-rodriguez Sep 9, 2025
1c7fd14
[rubygems/rubygems] Fix `--no-rubocop` deprecation message
deivid-rodriguez Sep 9, 2025
190a235
[rubygems/rubygems] Complete rubocop flags and settings removal
deivid-rodriguez Sep 9, 2025
6b0af31
[rubygems/rubygems] Remove `allow_offline_install` setting
deivid-rodriguez Sep 9, 2025
12aa9e7
[rubygems/rubygems] Use `IO.copy_stream` with IO object directly
tenderlove Sep 12, 2025
0a5a0ee
[rubygems/rubygems] Handle locked sources more simillarly to locked s…
deivid-rodriguez Sep 10, 2025
26f9911
[rubygems/rubygems] Multisource checks are only relevant when there's…
deivid-rodriguez Sep 10, 2025
9878060
[rubygems/rubygems] Simplify an edge case of not adding lower bound r…
deivid-rodriguez Sep 10, 2025
6adcc55
[rubygems/rubygems] Completely remove multisources support
deivid-rodriguez Sep 9, 2025
db027af
[rubygems/rubygems] Remove aggregate source mentions
deivid-rodriguez Sep 9, 2025
1213adf
[ruby/json] Better handle missing ostruct
etiennebarrie Sep 15, 2025
9711740
Add a macro to manage the condition of no-inline version rb_current_ec
junaruga Sep 4, 2025
a284923
Expect `git -C <path>` to work
nobu Sep 16, 2025
5480a9c
Reject git command that does not accept `-C` option
nobu Sep 16, 2025
a6a5fe3
Suppress verification messages
nobu Sep 16, 2025
809dfb8
Don't export rb_imemo_new
peterzhu2118 Sep 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions common.mk
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ RUBYLIB = $(PATH_SEPARATOR)
RUBYOPT = -
RUN_OPTS = --disable-gems

GIT_IN_SRC = $(GIT) -C $(srcdir)
GIT_LOG = $(GIT_IN_SRC) log --no-show-signature
GIT_LOG_FORMAT = $(GIT_LOG) --pretty=format:

# GITPULLOPTIONS = --no-tags

PRISM_SRCDIR = $(srcdir)/prism
Expand Down Expand Up @@ -1514,8 +1518,8 @@ update-bundled_gems: PHONY
$(tooldir)/update-bundled_gems.rb \
"$(srcdir)/gems/bundled_gems" | \
$(IFCHANGE) "$(srcdir)/gems/bundled_gems" -
$(GIT) -C "$(srcdir)" diff --no-ext-diff --ignore-submodules --exit-code || \
$(GIT) -C "$(srcdir)" commit -m "Update bundled_gems" gems/bundled_gems
$(GIT_IN_SRC) diff --no-ext-diff --ignore-submodules --exit-code || \
$(GIT_IN_SRC) commit -m "Update bundled_gems" gems/bundled_gems

PRECHECK_BUNDLED_GEMS = yes
test-bundled-gems-precheck: $(TEST_RUNNABLE)-test-bundled-gems-precheck
Expand Down Expand Up @@ -1899,8 +1903,8 @@ nightly: yesterday $(DOT_WAIT) install
yesterday: rewindable

rewindable:
$(GIT) -C $(srcdir) status --porcelain
$(GIT) -C $(srcdir) diff --quiet
$(GIT_IN_SRC) status --porcelain
$(GIT_IN_SRC) diff --quiet

HELP_EXTRA_TASKS = ""

Expand Down
12 changes: 10 additions & 2 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,18 @@ HAVE_GIT=yes
AC_ARG_WITH(git,
AS_HELP_STRING([--without-git], [never use git]),
[AS_CASE([$withval],
[no], [GIT=never-use HAVE_GIT=no],
[no], [HAVE_GIT=no],
[yes], [],
[GIT=$withval])])
AS_IF([test x"$HAVE_GIT" = xyes], [command -v "$GIT" > /dev/null || HAVE_GIT=no])
{
test x"$HAVE_GIT" = xyes &&
command -v "$GIT" > /dev/null &&
# `git -C`: 1.8.5
# `git log --no-show-signature`: 2.10.0
AS_CASE([`$GIT -C . --version 2> /dev/null | sed 's/.* //'`],
[0.*|1.*|2.@<:@0-9@:>@.*], [false],
[true])
} || HAVE_GIT=no GIT=never-use
AC_SUBST(GIT)
AC_SUBST(HAVE_GIT)

Expand Down
50 changes: 25 additions & 25 deletions defs/gmake.mk
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,8 @@ post-commit: $(if $(DOT_WAIT),,do-commit)
GITHUB_RUBY_URL = https://github.com/ruby/ruby
PR =

COMMIT_GPG_SIGN = $(shell $(GIT) -C "$(srcdir)" config commit.gpgsign)
REMOTE_GITHUB_URL = $(shell $(GIT) -C "$(srcdir)" config remote.github.url)
COMMIT_GPG_SIGN = $(shell $(GIT_IN_SRC) config commit.gpgsign)
REMOTE_GITHUB_URL = $(shell $(GIT_IN_SRC) config remote.github.url)
COMMITS_NOTES = commits

.PHONY: fetch-github
Expand All @@ -236,19 +236,19 @@ define fetch-github
$(eval REMOTE_GITHUB_URL := $(REMOTE_GITHUB_URL))
$(if $(REMOTE_GITHUB_URL),,
echo adding $(GITHUB_RUBY_URL) as remote github
$(GIT) -C "$(srcdir)" remote add github $(GITHUB_RUBY_URL)
$(GIT) -C "$(srcdir)" config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
$(GIT_IN_SRC) remote add github $(GITHUB_RUBY_URL)
$(GIT_IN_SRC) config --add remote.github.fetch +refs/notes/$(COMMITS_NOTES):refs/notes/$(COMMITS_NOTES)
$(eval REMOTE_GITHUB_URL := $(GITHUB_RUBY_URL))
)
$(if $(shell $(GIT) -C "$(srcdir)" rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
$(GIT) -C "$(srcdir)" branch -f "gh-$(1)" "github/pull/$(1)/head",
$(GIT) -C "$(srcdir)" fetch -f github "pull/$(1)/head:gh-$(1)"
$(if $(shell $(GIT_IN_SRC) rev-parse "github/pull/$(1)/head" -- 2> /dev/null),
$(GIT_IN_SRC) branch -f "gh-$(1)" "github/pull/$(1)/head",
$(GIT_IN_SRC) fetch -f github "pull/$(1)/head:gh-$(1)"
)
endef

.PHONY: checkout-github
checkout-github: fetch-github
$(GIT) -C "$(srcdir)" checkout "gh-$(PR)"
$(GIT_IN_SRC) checkout "gh-$(PR)"

.PHONY: update-github
update-github: fetch-github
Expand All @@ -261,25 +261,25 @@ update-github: fetch-github
$(eval PR_BRANCH := $(word 2,$(PULL_REQUEST_FORK_BRANCH)))

$(eval GITHUB_UPDATE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(PR)-XXXXXX"))
$(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
$(GIT_IN_SRC) worktree add $(notdir $(GITHUB_UPDATE_WORKTREE)) "gh-$(PR)"
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" merge master --no-edit
@$(BASERUBY) -e 'print "Are you sure to push this to PR=$(PR)? [Y/n]: "; exit(gets.chomp != "n")'
$(GIT) -C "$(srcdir)" remote add fork-$(PR) git@github.com:$(FORK_REPO).git
$(GIT_IN_SRC) remote add fork-$(PR) git@github.com:$(FORK_REPO).git
$(GIT) -C "$(GITHUB_UPDATE_WORKTREE)" push fork-$(PR) gh-$(PR):$(PR_BRANCH)
$(GIT) -C "$(srcdir)" remote rm fork-$(PR)
$(GIT) -C "$(srcdir)" worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
$(GIT) -C "$(srcdir)" branch -D gh-$(PR)
$(GIT_IN_SRC) remote rm fork-$(PR)
$(GIT_IN_SRC) worktree remove $(notdir $(GITHUB_UPDATE_WORKTREE))
$(GIT_IN_SRC) branch -D gh-$(PR)

.PHONY: pull-github
pull-github: fetch-github
$(call pull-github,$(PR))

define pull-github
$(eval GITHUB_MERGE_BASE := $(shell $(GIT) -C "$(srcdir)" log -1 --format=format:%H))
$(eval GITHUB_MERGE_BRANCH := $(shell $(GIT) -C "$(srcdir)" symbolic-ref --short HEAD))
$(eval GITHUB_MERGE_BASE := $(shell $(GIT_LOG_FORMAT):%H -1)
$(eval GITHUB_MERGE_BRANCH := $(shell $(GIT_IN_SRC) symbolic-ref --short HEAD))
$(eval GITHUB_MERGE_WORKTREE := $(shell mktemp -d "$(srcdir)/gh-$(1)-XXXXXX"))
$(GIT) -C "$(srcdir)" worktree prune
$(GIT) -C "$(srcdir)" worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
$(GIT_IN_SRC) worktree prune
$(GIT_IN_SRC) worktree add $(notdir $(GITHUB_MERGE_WORKTREE)) "gh-$(1)"
$(GIT) -C "$(GITHUB_MERGE_WORKTREE)" rebase $(GITHUB_MERGE_BRANCH)
$(eval COMMIT_GPG_SIGN := $(COMMIT_GPG_SIGN))
$(if $(filter true,$(COMMIT_GPG_SIGN)), \
Expand All @@ -294,7 +294,7 @@ fetch-github-%:

.PHONY: checkout-github-%
checkout-github-%: fetch-github-%
$(GIT) -C "$(srcdir)" checkout "gh-$*"
$(GIT_IN_SRC) checkout "gh-$*"

.PHONY: pr-% pull-github-%
pr-% pull-github-%: fetch-github-%
Expand Down Expand Up @@ -433,7 +433,7 @@ ifneq ($(DOT_WAIT),)
endif

ifeq ($(HAVE_GIT),yes)
REVISION_LATEST := $(shell $(CHDIR) $(srcdir) && $(GIT) log -1 --format=%H 2>/dev/null)
REVISION_LATEST := $(shell $(GIT_LOG_FORMAT)%H -1 2>/dev/null)
else
REVISION_LATEST := update
endif
Expand Down Expand Up @@ -495,7 +495,7 @@ endif
update-deps:
$(eval update_deps := $(shell date +update-deps-%Y%m%d))
$(eval deps_dir := $(shell mktemp -d)/$(update_deps))
$(eval GIT_DIR := $(shell $(GIT) -C $(srcdir) rev-parse --absolute-git-dir))
$(eval GIT_DIR := $(shell $(GIT_IN_SRC) rev-parse --absolute-git-dir))
$(GIT) --git-dir=$(GIT_DIR) worktree add $(deps_dir)
cp $(tooldir)/config.guess $(tooldir)/config.sub $(deps_dir)/tool
[ -f config.status ] && cp config.status $(deps_dir)
Expand Down Expand Up @@ -543,13 +543,13 @@ matz: up
$(eval NEW := $(MAJOR).$(MINOR).0)
$(eval message := Development of $(NEW) started.)
$(eval files := include/ruby/version.h include/ruby/internal/abi.h)
$(GIT) -C $(srcdir) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
$(GIT) -C $(srcdir) commit -m "[DOC] Flush NEWS.md"
$(GIT_IN_SRC) mv -f NEWS.md doc/NEWS/NEWS-$(OLD).md
$(GIT_IN_SRC) commit -m "[DOC] Flush NEWS.md"
sed -i~ \
-e "s/^\(#define RUBY_API_VERSION_MINOR\) .*/\1 $(MINOR)/" \
-e "s/^\(#define RUBY_ABI_VERSION\) .*/\1 0/" \
$(files:%=$(srcdir)/%)
$(GIT) -C $(srcdir) add $(files)
$(GIT_IN_SRC) add $(files)
$(BASERUBY) -C $(srcdir) -p -00 \
-e 'BEGIN {old, new = ARGV.shift(2); STDOUT.reopen("NEWS.md")}' \
-e 'case $$.' \
Expand All @@ -559,8 +559,8 @@ matz: up
-e 'next if /^[\[ *]/ =~ $$_' \
-e '$$_.sub!(/\n{2,}\z/, "\n\n")' \
$(OLD) $(NEW) doc/NEWS/NEWS-$(OLD).md
$(GIT) -C $(srcdir) add NEWS.md
$(GIT) -C $(srcdir) commit -m "$(message)"
$(GIT_IN_SRC) add NEWS.md
$(GIT_IN_SRC) commit -m "$(message)"

tags:
$(MAKE) GIT="$(GIT)" -C "$(srcdir)" -f defs/tags.mk
Expand Down
2 changes: 1 addition & 1 deletion internal/imemo.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ struct MEMO {
#ifndef RUBY_RUBYPARSER_H
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
#endif
VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size);
VALUE rb_imemo_tmpbuf_new(void);
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
static inline enum imemo_type imemo_type(VALUE imemo);
Expand All @@ -147,7 +148,6 @@ void rb_imemo_mark_and_move(VALUE obj, bool reference_updating);
void rb_imemo_free(VALUE obj);

RUBY_SYMBOL_EXPORT_BEGIN
VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size);
const char *rb_imemo_name(enum imemo_type type);
RUBY_SYMBOL_EXPORT_END

Expand Down
6 changes: 5 additions & 1 deletion lib/bundler/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ def viz
method_option :ext, type: :string, banner: "Generate the boilerplate for C extension code.", enum: EXTENSIONS
method_option :git, type: :boolean, default: true, banner: "Initialize a git repo inside your library."
method_option :mit, type: :boolean, banner: "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
method_option :rubocop, type: :boolean, banner: "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true` (removed)."
method_option :changelog, type: :boolean, banner: "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
method_option :test, type: :string, lazy_default: Bundler.settings["gem.test"] || "", aliases: "-t", banner: "Use the specified test framework for your library", enum: %w[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"] || "", enum: %w[github gitlab circle], banner: "Generate CI configuration, either GitHub Actions, GitLab CI or CircleCI. Set a default with `bundle config set --global gem.ci (github|gitlab|circle)`"
Expand All @@ -535,6 +535,10 @@ def viz

def gem(name)
require_relative "cli/gem"

raise InvalidOption, "--rubocop has been removed, use --linter=rubocop" if ARGV.include?("--rubocop")
raise InvalidOption, "--no-rubocop has been removed, use --no-linter" if ARGV.include?("--no-rubocop")

cmd_args = args + [self]
cmd_args.unshift(options)

Expand Down
22 changes: 0 additions & 22 deletions lib/bundler/cli/gem.rb
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,6 @@ def ask_and_set_ci
def ask_and_set_linter
return if skip?(:linter)
linter_template = options[:linter] || Bundler.settings["gem.linter"]
linter_template = deprecated_rubocop_option if linter_template.nil?

if linter_template.to_s.empty?
Bundler.ui.info "\nDo you want to add a code linter and formatter to your gem? " \
Expand Down Expand Up @@ -415,27 +414,6 @@ def ask_and_set_linter
linter_template
end

def deprecated_rubocop_option
if !options[:rubocop].nil?
if options[:rubocop]
Bundler::SharedHelpers.major_deprecation 2,
"--rubocop is deprecated, use --linter=rubocop",
removed_message: "--rubocop has been removed, use --linter=rubocop"
"rubocop"
else
Bundler::SharedHelpers.major_deprecation 2,
"--no-rubocop is deprecated, use --linter",
removed_message: "--no-rubocop has been removed, use --linter"
false
end
elsif !Bundler.settings["gem.rubocop"].nil?
Bundler::SharedHelpers.major_deprecation 2,
"config gem.rubocop is deprecated; we've updated your config to use gem.linter instead",
removed_message: "config gem.rubocop has been removed; we've updated your config to use gem.linter instead"
Bundler.settings["gem.rubocop"] ? "rubocop" : false
end
end

def bundler_dependency_version
v = Gem::Version.new(Bundler::VERSION)
req = v.segments[0..1]
Expand Down
16 changes: 0 additions & 16 deletions lib/bundler/cli/install.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ def run

Bundler::CLI::Common.output_post_install_messages installer.post_install_messages

warn_ambiguous_gems

if CLI::Common.clean_after_install?
require_relative "clean"
Bundler::CLI::Clean.new(options).run
Expand Down Expand Up @@ -126,19 +124,5 @@ def normalize_settings

options[:force] = options[:redownload] if options[:redownload]
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.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
end
34 changes: 16 additions & 18 deletions lib/bundler/definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,24 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
@locked_ruby_version = @locked_gems.ruby_version
@locked_deps = @locked_gems.dependencies
@originally_locked_specs = SpecSet.new(@locked_gems.specs)
@originally_locked_sources = @locked_gems.sources
@locked_checksums = @locked_gems.checksums

if @unlocking_all
@locked_specs = SpecSet.new([])
@locked_sources = []
else
@locked_specs = @originally_locked_specs
@locked_sources = @locked_gems.sources
@locked_sources = @originally_locked_sources
end

locked_gem_sources = @originally_locked_sources.select {|s| s.is_a?(Source::Rubygems) }
multisource_lockfile = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes?

if multisource_lockfile
msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure."

Bundler::SharedHelpers.feature_removed! msg
end
else
@locked_gems = nil
Expand All @@ -123,24 +133,12 @@ def initialize(lockfile, dependencies, sources, unlock, ruby_version = nil, opti
@platforms = []
@locked_deps = {}
@locked_specs = SpecSet.new([])
@originally_locked_specs = @locked_specs
@locked_sources = []
@originally_locked_specs = @locked_specs
@originally_locked_sources = @locked_sources
@locked_checksums = Bundler.feature_flag.lockfile_checksums?
end

locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@multisource_allowed = locked_gem_sources.size == 1 && locked_gem_sources.first.multiple_remotes? && Bundler.frozen_bundle?

if @multisource_allowed
unless sources.aggregate_global_source?
msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. Make sure you run `bundle install` in non frozen mode and commit the result to make your lockfile secure."

Bundler::SharedHelpers.major_deprecation 2, msg
end

@sources.merged_gem_lockfile_sections!(locked_gem_sources.first)
end

@unlocking_ruby ||= if @ruby_version && locked_ruby_version_object
@ruby_version.diff(locked_ruby_version_object)
end
Expand Down Expand Up @@ -763,7 +761,7 @@ def start_resolution
end

def precompute_source_requirements_for_indirect_dependencies?
sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && !sources.aggregate_global_source?
sources.non_global_rubygems_sources.all?(&:dependency_api_available?)
end

def current_platform_locked?
Expand Down Expand Up @@ -954,7 +952,7 @@ def converge_sources
sources.all_sources.each do |source|
# has to be done separately, because we want to keep the locked checksum
# store for a source, even when doing a full update
if @locked_checksums && @locked_gems && locked_source = @locked_gems.sources.find {|s| s == source && !s.equal?(source) }
if @locked_checksums && @locked_gems && locked_source = @originally_locked_sources.find {|s| s == source && !s.equal?(source) }
source.checksum_store.merge!(locked_source.checksum_store)
end
# If the source is unlockable and the current command allows an unlock of
Expand Down Expand Up @@ -1137,7 +1135,7 @@ def lockfiles_equal?(current, proposed, preserve_unknown_sections)
end

def additional_base_requirements_to_prevent_downgrades(resolution_base)
return resolution_base unless @locked_gems && !sources.expired_sources?(@locked_gems.sources)
return resolution_base unless @locked_gems
@originally_locked_specs.each do |locked_spec|
next if locked_spec.source.is_a?(Source::Path) || locked_spec.source_changed?

Expand Down
22 changes: 4 additions & 18 deletions lib/bundler/dsl.rb
Original file line number Diff line number Diff line change
Expand Up @@ -521,24 +521,10 @@ def check_rubygems_source_safety
end

def multiple_global_source_warning
if Bundler.feature_flag.bundler_4_mode?
msg = "This Gemfile contains multiple global sources. " \
"Each source after the first must include a block to indicate which gems " \
"should come from that source"
raise GemfileEvalError, msg
else
message =
"Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source."
removed_message =
"Your Gemfile contains multiple global sources. " \
"Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this error, use " \
"a block to indicate which gems should come from the secondary source."
Bundler::SharedHelpers.major_deprecation 2, message, removed_message: removed_message
end
msg = "This Gemfile contains multiple global sources. " \
"Each source after the first must include a block to indicate which gems " \
"should come from that source"
raise GemfileEvalError, msg
end

class DSLError < GemfileError
Expand Down
Loading