1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/bundler/commands/newgem_spec.rb
fiveNinePlusR 105e037fe8 [rubygems/rubygems] Fix possible malicious website to example.com
example.com is the canonical stand in for domain examples and will never have a backing website.

via https://www.rfc-editor.org/rfc/rfc2606.html

https://github.com/rubygems/rubygems/commit/26622c81c2
2021-09-22 10:14:04 +09:00

1502 lines
49 KiB
Ruby

# frozen_string_literal: true
RSpec.describe "bundle gem" do
def gem_skeleton_assertions
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to exist
expect(bundled_app("#{gem_name}/README.md")).to exist
expect(bundled_app("#{gem_name}/Gemfile")).to exist
expect(bundled_app("#{gem_name}/Rakefile")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
end
def bundle_exec_rubocop
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
bundle "config set path #{rubocop_gems}", :dir => bundled_app(gem_name)
bundle "exec rubocop --debug --config .rubocop.yml", :dir => bundled_app(gem_name)
end
def bundle_exec_standardrb
prepare_gemspec(bundled_app(gem_name, "#{gem_name}.gemspec"))
bundle "config set path #{standard_gems}", :dir => bundled_app(gem_name)
bundle "exec standardrb --debug", :dir => bundled_app(gem_name)
end
let(:generated_gemspec) { Bundler.load_gemspec_uncached(bundled_app(gem_name).join("#{gem_name}.gemspec")) }
let(:gem_name) { "mygem" }
let(:require_path) { "mygem" }
before do
sys_exec("git config --global user.name 'Bundler User'")
sys_exec("git config --global user.email user@example.com")
sys_exec("git config --global github.user bundleuser")
end
describe "git repo initialization" do
it "generates a gem skeleton with a .git folder", :readline do
bundle "gem #{gem_name}"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
it "generates a gem skeleton with a .git folder when passing --git", :readline do
bundle "gem #{gem_name} --git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).to exist
end
it "generates a gem skeleton without a .git folder when passing --no-git", :readline do
bundle "gem #{gem_name} --no-git"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/.git")).not_to exist
end
context "on a path with spaces" do
before do
Dir.mkdir(bundled_app("path with spaces"))
end
it "properly initializes git repo", :readline do
bundle "gem #{gem_name}", :dir => bundled_app("path with spaces")
expect(bundled_app("path with spaces/#{gem_name}/.git")).to exist
end
end
end
shared_examples_for "--mit flag" do
before do
bundle "gem #{gem_name} --mit"
end
it "generates a gem skeleton with MIT license" do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/LICENSE.txt")).to exist
expect(generated_gemspec.license).to eq("MIT")
end
end
shared_examples_for "--no-mit flag" do
before do
bundle "gem #{gem_name} --no-mit"
end
it "generates a gem skeleton without MIT license" do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/LICENSE.txt")).to_not exist
end
end
shared_examples_for "--coc flag" do
it "generates a gem skeleton with MIT license" do
bundle "gem #{gem_name} --coc"
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to exist
end
it "generates the README with a section for the Code of Conduct" do
bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end
it "generates the README with a section for the Code of Conduct, respecting the configured git default branch", :git => ">= 2.28.0" do
sys_exec("git config --global init.defaultBranch main")
bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/main/CODE_OF_CONDUCT.md")
end
end
shared_examples_for "--no-coc flag" do
before do
bundle "gem #{gem_name} --no-coc"
end
it "generates a gem skeleton without Code of Conduct" do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to_not exist
end
it "generates the README without a section for the Code of Conduct" do
expect(bundled_app("#{gem_name}/README.md").read).not_to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).not_to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end
end
shared_examples_for "--changelog flag" do
before do
bundle "gem #{gem_name} --changelog"
end
it "generates a gem skeleton with a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to exist
end
end
shared_examples_for "--no-changelog flag" do
before do
bundle "gem #{gem_name} --no-changelog"
end
it "generates a gem skeleton without a CHANGELOG", :readline do
gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CHANGELOG.md")).to_not exist
end
end
shared_examples_for "--rubocop flag" do
context "is deprecated", :bundler => "< 3" do
before do
bundle "gem #{gem_name} --rubocop"
end
it "generates a gem skeleton with rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(
include("# frozen_string_literal: true").
and(include('require "rubocop/rake_task"').
and(include("RuboCop::RakeTask.new").
and(match(/default:.+:rubocop/))))
)
end
it "includes rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).not_to be_nil
end
it "generates a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
end
end
shared_examples_for "--no-rubocop flag" do
context "is deprecated", :bundler => "< 3" do
define_negated_matcher :exclude, :include
before do
bundle "gem #{gem_name} --no-rubocop"
end
it "generates a gem skeleton without rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop"))
expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
end
it "does not include rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).to be_nil
end
it "doesn't generate a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
end
end
shared_examples_for "--linter=rubocop flag" do
before do
bundle "gem #{gem_name} --linter=rubocop"
end
it "generates a gem skeleton with rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(
include("# frozen_string_literal: true").
and(include('require "rubocop/rake_task"').
and(include("RuboCop::RakeTask.new").
and(match(/default:.+:rubocop/))))
)
end
it "includes rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).not_to be_nil
end
it "generates a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
end
shared_examples_for "--linter=standard flag" do
before do
bundle "gem #{gem_name} --linter=standard"
end
it "generates a gem skeleton with standard" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(
include('require "standard/rake"').
and(match(/default:.+:standard/))
)
end
it "includes standard in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
expect(standard_dep).not_to be_nil
end
it "generates a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
end
end
shared_examples_for "--linter=none flag" do
define_negated_matcher :exclude, :include
before do
bundle "gem #{gem_name} --linter=none"
end
it "generates a gem skeleton without rubocop" do
gem_skeleton_assertions
expect(bundled_app("test-gem/Rakefile")).to read_as(exclude("rubocop"))
expect(bundled_app("test-gem/#{gem_name}.gemspec")).to read_as(exclude("rubocop"))
end
it "does not include rubocop in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rubocop_dep = builder.dependencies.find {|d| d.name == "rubocop" }
expect(rubocop_dep).to be_nil
end
it "does not include standard in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
standard_dep = builder.dependencies.find {|d| d.name == "standard" }
expect(standard_dep).to be_nil
end
it "doesn't generate a default .rubocop.yml" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
it "doesn't generate a default .standard.yml" do
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
it "has no rubocop offenses when using --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --test=minitest, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=minitest --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --test=rspec, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=rspec --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no rubocop offenses when using --ext, --ext=test-unit, and --linter=rubocop flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --ext --test=test-unit --linter=rubocop"
bundle_exec_rubocop
expect(last_command).to be_success
end
it "has no standard offenses when using --linter=standard flag", :readline do
skip "ruby_core has an 'ast.rb' file that gets in the middle and breaks this spec" if ruby_core?
bundle "gem #{gem_name} --linter=standard"
bundle_exec_standardrb
expect(last_command).to be_success
end
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
end
shared_examples_for "test framework is absent" do
it "does not create any test framework files" do
expect(bundled_app("#{gem_name}/.rspec")).to_not exist
expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to_not exist
expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to_not exist
expect(bundled_app("#{gem_name}/test/#{require_path}.rb")).to_not exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to_not exist
end
end
context "README.md", :readline do
context "git config github.user present" do
before do
bundle "gem #{gem_name}"
end
it "contribute URL set to git username" do
expect(bundled_app("#{gem_name}/README.md").read).not_to include("[USERNAME]")
expect(bundled_app("#{gem_name}/README.md").read).to include("github.com/bundleuser")
end
end
context "git config github.user is absent" do
before do
sys_exec("git config --global --unset github.user")
bundle "gem #{gem_name}"
end
it "contribute URL set to [USERNAME]" do
expect(bundled_app("#{gem_name}/README.md").read).to include("[USERNAME]")
expect(bundled_app("#{gem_name}/README.md").read).not_to include("github.com/bundleuser")
end
end
end
it "creates a new git repository", :readline do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.git")).to exist
end
context "when git is not available", :readline do
# This spec cannot have `git` available in the test env
before do
load_paths = [lib_dir, spec_dir]
load_path_str = "-I#{load_paths.join(File::PATH_SEPARATOR)}"
sys_exec "#{Gem.ruby} #{load_path_str} #{bindir.join("bundle")} gem #{gem_name}", :env => { "PATH" => "" }
end
it "creates the gem without the need for git" do
expect(bundled_app("#{gem_name}/README.md")).to exist
end
it "doesn't create a git repo" do
expect(bundled_app("#{gem_name}/.git")).to_not exist
end
it "doesn't create a .gitignore file" do
expect(bundled_app("#{gem_name}/.gitignore")).to_not exist
end
end
it "generates a valid gemspec", :readline, :ruby_repo do
bundle "gem newgem --bin"
prepare_gemspec(bundled_app("newgem", "newgem.gemspec"))
gems = ["rake-13.0.1"]
path = Bundler.feature_flag.default_install_uses_path? ? local_gem_path(:base => bundled_app("newgem")) : system_gem_path
system_gems gems, :path => path
bundle "exec rake build", :dir => bundled_app("newgem")
expect(last_command.stdboth).not_to include("ERROR")
end
context "gem naming with relative paths", :readline do
it "resolves ." do
create_temporary_dir("tmp")
bundle "gem .", :dir => bundled_app("tmp")
expect(bundled_app("tmp/lib/tmp.rb")).to exist
end
it "resolves .." do
create_temporary_dir("temp/empty_dir")
bundle "gem ..", :dir => bundled_app("temp/empty_dir")
expect(bundled_app("temp/lib/temp.rb")).to exist
end
it "resolves relative directory" do
create_temporary_dir("tmp/empty/tmp")
bundle "gem ../../empty", :dir => bundled_app("tmp/empty/tmp")
expect(bundled_app("tmp/empty/lib/empty.rb")).to exist
end
def create_temporary_dir(dir)
FileUtils.mkdir_p(bundled_app(dir))
end
end
shared_examples_for "--github-username option" do |github_username|
before do
bundle "gem #{gem_name} --github-username=#{github_username}"
end
it "generates a gem skeleton" do
gem_skeleton_assertions
end
it "contribute URL set to given github username" do
expect(bundled_app("#{gem_name}/README.md").read).not_to include("[USERNAME]")
expect(bundled_app("#{gem_name}/README.md").read).to include("github.com/#{github_username}")
end
end
shared_examples_for "github_username configuration" do
context "with github_username setting set to some value" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
bundle "gem #{gem_name}"
end
it "generates a gem skeleton" do
gem_skeleton_assertions
end
it "contribute URL set to bundle config setting" do
expect(bundled_app("#{gem_name}/README.md").read).not_to include("[USERNAME]")
expect(bundled_app("#{gem_name}/README.md").read).to include("github.com/different_username")
end
end
context "with github_username setting set to false" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
bundle "gem #{gem_name}"
end
it "generates a gem skeleton" do
gem_skeleton_assertions
end
it "contribute URL set to [USERNAME]" do
expect(bundled_app("#{gem_name}/README.md").read).to include("[USERNAME]")
expect(bundled_app("#{gem_name}/README.md").read).not_to include("github.com/bundleuser")
end
end
end
shared_examples_for "generating a gem" do
it "generates a gem skeleton" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/#{gem_name}.gemspec")).to exist
expect(bundled_app("#{gem_name}/Gemfile")).to exist
expect(bundled_app("#{gem_name}/Rakefile")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb")).to exist
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb")).to exist
expect(bundled_app("#{gem_name}/.gitignore")).to exist
expect(bundled_app("#{gem_name}/bin/setup")).to exist
expect(bundled_app("#{gem_name}/bin/console")).to exist
expect(bundled_app("#{gem_name}/bin/setup")).to be_executable
expect(bundled_app("#{gem_name}/bin/console")).to be_executable
expect(bundled_app("#{gem_name}/bin/setup").read).to start_with("#!")
expect(bundled_app("#{gem_name}/bin/console").read).to start_with("#!")
end
it "starts with version 0.1.0" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/VERSION = "0.1.0"/)
end
context "git config user.{name,email} is set" do
before do
bundle "gem #{gem_name}"
end
it "sets gemspec author to git user.name if available" do
expect(generated_gemspec.authors.first).to eq("Bundler User")
end
it "sets gemspec email to git user.email if available" do
expect(generated_gemspec.email.first).to eq("user@example.com")
end
end
context "git config user.{name,email} is not set" do
before do
sys_exec("git config --global --unset user.name")
sys_exec("git config --global --unset user.email")
bundle "gem #{gem_name}"
end
it "sets gemspec author to default message if git user.name is not set or empty" do
expect(generated_gemspec.authors.first).to eq("TODO: Write your name")
end
it "sets gemspec email to default message if git user.email is not set or empty" do
expect(generated_gemspec.email.first).to eq("TODO: Write your email address")
end
end
it "sets gemspec metadata['allowed_push_host']" do
bundle "gem #{gem_name}"
expect(generated_gemspec.metadata["allowed_push_host"]).
to match(/example\.com/)
end
it "sets a minimum ruby version" do
bundle "gem #{gem_name}"
expect(generated_gemspec.required_ruby_version).to eq(Gem::Requirement.new(Gem.ruby_version < Gem::Version.new("2.4.a") ? ">= 2.3.0" : ">= 2.4.0"))
end
it "requires the version file" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(%r{require_relative "#{require_relative_path}/version"})
end
it "creates a base error class" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/class Error < StandardError; end$/)
end
it "does not include the gemspec file in files" do
bundle "gem #{gem_name}"
bundler_gemspec = Bundler::GemHelper.new(gemspec_dir).gemspec
expect(bundler_gemspec.files).not_to include("#{gem_name}.gemspec")
end
it "runs rake without problems" do
bundle "gem #{gem_name}"
system_gems ["rake-13.0.1"]
rakefile = strip_whitespace <<-RAKEFILE
task :default do
puts 'SUCCESS'
end
RAKEFILE
File.open(bundled_app("#{gem_name}/Rakefile"), "w") do |file|
file.puts rakefile
end
sys_exec(rake, :dir => bundled_app(gem_name))
expect(out).to include("SUCCESS")
end
context "--exe parameter set" do
before do
bundle "gem #{gem_name} --exe"
end
it "builds exe skeleton" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
end
it "requires the main file" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
end
end
context "--bin parameter set" do
before do
bundle "gem #{gem_name} --bin"
end
it "builds exe skeleton" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}")).to exist
end
it "requires the main file" do
expect(bundled_app("#{gem_name}/exe/#{gem_name}").read).to match(/require "#{require_path}"/)
end
end
context "no --test parameter" do
before do
bundle "gem #{gem_name}"
end
it_behaves_like "test framework is absent"
end
context "--test parameter set to rspec" do
before do
bundle "gem #{gem_name} --test=rspec"
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/.rspec")).to exist
expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
end
it "depends on a specific version of rspec in generated Gemfile" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
rspec_dep = builder.dependencies.find {|d| d.name == "rspec" }
expect(rspec_dep).to be_specific
end
it "requires the main file" do
expect(bundled_app("#{gem_name}/spec/spec_helper.rb").read).to include(%(require "#{require_path}"))
end
it "creates a default test which fails" do
expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb").read).to include("expect(false).to eq(true)")
end
end
context "gem.test setting set to rspec" do
before do
bundle "config set gem.test rspec"
bundle "gem #{gem_name}"
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/.rspec")).to exist
expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
end
end
context "gem.test setting set to rspec and --test is set to minitest" do
before do
bundle "config set gem.test rspec"
bundle "gem #{gem_name} --test=minitest"
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb")).to exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
end
context "--test parameter set to minitest" do
before do
bundle "gem #{gem_name} --test=minitest"
end
it "depends on a specific version of minitest" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
minitest_dep = builder.dependencies.find {|d| d.name == "minitest" }
expect(minitest_dep).to be_specific
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb")).to exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
it "requires the main file" do
expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
end
it "requires 'test_helper'" do
expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb").read).to include(%(require "test_helper"))
end
it "creates a default test which fails" do
expect(bundled_app("#{gem_name}/test/test_#{require_path}.rb").read).to include("assert false")
end
end
context "gem.test setting set to minitest" do
before do
bundle "config set gem.test minitest"
bundle "gem #{gem_name}"
end
it "creates a default rake task to run the test suite" do
rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList["test/**/test_*.rb"]
end
task default: :test
RAKEFILE
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
end
context "--test parameter set to test-unit" do
before do
bundle "gem #{gem_name} --test=test-unit"
end
it "depends on a specific version of test-unit" do
allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile)
builder = Bundler::Dsl.new
builder.eval_gemfile(bundled_app("#{gem_name}/Gemfile"))
builder.dependencies
test_unit_dep = builder.dependencies.find {|d| d.name == "test-unit" }
expect(test_unit_dep).to be_specific
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb")).to exist
expect(bundled_app("#{gem_name}/test/test_helper.rb")).to exist
end
it "requires the main file" do
expect(bundled_app("#{gem_name}/test/test_helper.rb").read).to include(%(require "#{require_path}"))
end
it "requires 'test_helper'" do
expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include(%(require "test_helper"))
end
it "creates a default test which fails" do
expect(bundled_app("#{gem_name}/test/#{require_path}_test.rb").read).to include("assert_equal(\"expected\", \"actual\")")
end
end
context "gem.test setting set to test-unit" do
before do
bundle "config set gem.test test-unit"
bundle "gem #{gem_name}"
end
it "creates a default rake task to run the test suite" do
rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rake/testtask"
Rake::TestTask.new(:test) do |t|
t.libs << "test"
t.libs << "lib"
t.test_files = FileList["test/**/*_test.rb"]
end
task default: :test
RAKEFILE
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
end
context "gem.test set to rspec and --test with no arguments", :hint_text do
before do
bundle "config set gem.test rspec"
bundle "gem #{gem_name} --test"
end
it "builds spec skeleton" do
expect(bundled_app("#{gem_name}/.rspec")).to exist
expect(bundled_app("#{gem_name}/spec/#{require_path}_spec.rb")).to exist
expect(bundled_app("#{gem_name}/spec/spec_helper.rb")).to exist
end
it "hints that --test is already configured" do
expect(out).to match("rspec is already configured, ignoring --test flag.")
end
end
context "gem.test setting set to false and --test with no arguments", :hint_text do
before do
bundle "config set gem.test false"
bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
expect(out).to match("Do you want to generate tests with your gem?")
end
it "hints that the choice will only be applied to the current gem" do
expect(out).to match("Your choice will only be applied to this gem.")
end
it_behaves_like "test framework is absent"
end
context "gem.test setting not set and --test with no arguments", :hint_text do
before do
bundle "gem #{gem_name} --test"
end
it "asks to generate test files" do
expect(out).to match("Do you want to generate tests with your gem?")
end
it "hints that the choice will be applied to future bundle gem calls" do
hint = "Future `bundle gem` calls will use your choice. " \
"This setting can be changed anytime with `bundle config gem.test`."
expect(out).to match(hint)
end
it_behaves_like "test framework is absent"
end
context "--ci with no argument" do
it "does not generate any CI config" 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 github" do
it "generates a GitHub Actions config file" do
bundle "gem #{gem_name} --ci=github"
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
end
context "--ci set to gitlab" do
it "generates a GitLab CI config file" do
bundle "gem #{gem_name} --ci=gitlab"
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
end
context "--ci set to circle" do
it "generates a CircleCI config file" do
bundle "gem #{gem_name} --ci=circle"
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
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 github" do
it "generates a GitHub Actions config file" do
bundle "config set gem.ci github"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
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"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.gitlab-ci.yml")).to exist
end
end
context "gem.ci setting set to circle" do
it "generates a CircleCI config file" do
bundle "config set gem.ci circle"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.circleci/config.yml")).to exist
end
end
context "gem.ci set to github and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci github"
bundle "gem #{gem_name} --ci"
end
it "generates a GitHub Actions config file" do
expect(bundled_app("#{gem_name}/.github/workflows/main.yml")).to exist
end
it "hints that --ci is already configured" do
expect(out).to match("github is already configured, ignoring --ci flag.")
end
end
context "gem.ci setting set to false and --ci with no arguments", :hint_text do
before do
bundle "config set gem.ci false"
bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
expect(out).to match("Do you want to set up continuous integration for your gem?")
end
it "hints that the choice will only be applied to the current gem" do
expect(out).to match("Your choice will only be applied to this gem.")
end
end
context "gem.ci setting not set and --ci with no arguments", :hint_text do
before do
bundle "gem #{gem_name} --ci"
end
it "asks to setup CI" do
expect(out).to match("Do you want to set up continuous integration for your gem?")
end
it "hints that the choice will be applied to future bundle gem calls" do
hint = "Future `bundle gem` calls will use your choice. " \
"This setting can be changed anytime with `bundle config gem.ci`."
expect(out).to match(hint)
end
end
context "--linter with no argument" do
it "does not generate any linter config" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "--linter set to rubocop" do
it "generates a RuboCop config" do
bundle "gem #{gem_name} --linter=rubocop"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "--linter set to standard" do
it "generates a Standard config" do
bundle "gem #{gem_name} --linter=standard"
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
end
end
context "gem.linter setting set to none" do
it "doesn't generate any linter config" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to_not exist
expect(bundled_app("#{gem_name}/.standard.yml")).to_not exist
end
end
context "gem.linter setting set to rubocop" do
it "generates a RuboCop config file" do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
end
context "gem.linter setting set to standard" do
it "generates a Standard config file" do
bundle "config set gem.linter standard"
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/.standard.yml")).to exist
end
end
context "gem.rubocop setting set to true", :bundler => "< 3" do
before do
bundle "config set gem.rubocop true"
bundle "gem #{gem_name}"
end
it "generates rubocop config" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
it "unsets gem.rubocop" do
bundle "config gem.rubocop"
expect(out).to include("You have not configured a value for `gem.rubocop`")
end
it "sets gem.linter=rubocop instead" do
bundle "config gem.linter"
expect(out).to match(/Set for the current user .*: "rubocop"/)
end
end
context "gem.linter set to rubocop and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter rubocop"
bundle "gem #{gem_name} --linter"
end
it "generates a RuboCop config file" do
expect(bundled_app("#{gem_name}/.rubocop.yml")).to exist
end
it "hints that --linter is already configured" do
expect(out).to match("rubocop is already configured, ignoring --linter flag.")
end
end
context "gem.linter setting set to false and --linter with no arguments", :hint_text do
before do
bundle "config set gem.linter false"
bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
expect(out).to match("Do you want to add a code linter and formatter to your gem?")
end
it "hints that the choice will only be applied to the current gem" do
expect(out).to match("Your choice will only be applied to this gem.")
end
end
context "gem.linter setting not set and --linter with no arguments", :hint_text do
before do
bundle "gem #{gem_name} --linter"
end
it "asks to setup a linter" do
expect(out).to match("Do you want to add a code linter and formatter to your gem?")
end
it "hints that the choice will be applied to future bundle gem calls" do
hint = "Future `bundle gem` calls will use your choice. " \
"This setting can be changed anytime with `bundle config gem.linter`."
expect(out).to match(hint)
end
end
context "--edit option" do
it "opens the generated gemspec in the user's text editor" do
output = bundle "gem #{gem_name} --edit=echo"
gemspec_path = File.join(bundled_app, gem_name, "#{gem_name}.gemspec")
expect(output).to include("echo \"#{gemspec_path}\"")
end
end
end
context "testing --mit and --coc options against bundle config settings", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
context "with mit option in bundle config settings set to true" do
before do
global_config "BUNDLE_GEM__MIT" => "true"
end
it_behaves_like "--mit flag"
it_behaves_like "--no-mit flag"
end
context "with mit option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__MIT" => "false"
end
it_behaves_like "--mit flag"
it_behaves_like "--no-mit flag"
end
context "with coc option in bundle config settings set to true" do
before do
global_config "BUNDLE_GEM__COC" => "true"
end
it_behaves_like "--coc flag"
it_behaves_like "--no-coc flag"
end
context "with coc option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__COC" => "false"
end
it_behaves_like "--coc flag"
it_behaves_like "--no-coc flag"
end
context "with rubocop option in bundle config settings set to true" do
before do
global_config "BUNDLE_GEM__RUBOCOP" => "true"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
context "with rubocop option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__RUBOCOP" => "false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
it_behaves_like "--rubocop flag"
it_behaves_like "--no-rubocop flag"
end
context "with linter option in bundle config settings set to rubocop" do
before do
global_config "BUNDLE_GEM__LINTER" => "rubocop"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to standard" do
before do
global_config "BUNDLE_GEM__LINTER" => "standard"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with linter option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__LINTER" => "false"
end
it_behaves_like "--linter=rubocop flag"
it_behaves_like "--linter=standard flag"
it_behaves_like "--linter=none flag"
end
context "with changelog option in bundle config settings set to true" do
before do
global_config "BUNDLE_GEM__CHANGELOG" => "true"
end
it_behaves_like "--changelog flag"
it_behaves_like "--no-changelog flag"
end
context "with changelog option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__CHANGELOG" => "false"
end
it_behaves_like "--changelog flag"
it_behaves_like "--no-changelog flag"
end
end
context "testing --github-username option against git and bundle config settings", :readline do
context "without git config set" do
before do
sys_exec("git config --global --unset github.user")
end
context "with github-username option in bundle config settings set to some value" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
end
it_behaves_like "--github-username option", "gh_user"
end
context "with github-username option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
end
it_behaves_like "--github-username option", "gh_user"
end
end
context "with git config set" do
context "with github-username option in bundle config settings set to some value" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "different_username"
end
it_behaves_like "--github-username option", "gh_user"
end
context "with github-username option in bundle config settings set to false" do
before do
global_config "BUNDLE_GEM__GITHUB_USERNAME" => "false"
end
it_behaves_like "--github-username option", "gh_user"
end
end
end
context "testing github_username bundle config against git config settings", :readline do
context "without git config set" do
before do
sys_exec("git config --global --unset github.user")
end
it_behaves_like "github_username configuration"
end
context "with git config set" do
it_behaves_like "github_username configuration"
end
end
context "gem naming with underscore", :readline do
let(:gem_name) { "test_gem" }
let(:require_path) { "test_gem" }
let(:require_relative_path) { "test_gem" }
let(:flags) { nil }
it "does not nest constants" do
bundle ["gem", gem_name, flags].compact.join(" ")
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/module TestGem/)
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/module TestGem/)
end
include_examples "generating a gem"
context "--ext parameter set" do
let(:flags) { "--ext" }
before do
bundle ["gem", gem_name, flags].compact.join(" ")
end
it "builds ext skeleton" do
expect(bundled_app("#{gem_name}/ext/#{gem_name}/extconf.rb")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.h")).to exist
expect(bundled_app("#{gem_name}/ext/#{gem_name}/#{gem_name}.c")).to exist
end
it "includes rake-compiler" do
expect(bundled_app("#{gem_name}/Gemfile").read).to include('gem "rake-compiler"')
end
it "depends on compile task for build" do
rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rake/extensiontask"
task build: :compile
Rake::ExtensionTask.new("#{gem_name}") do |ext|
ext.lib_dir = "lib/#{gem_name}"
end
task default: %i[clobber compile]
RAKEFILE
expect(bundled_app("#{gem_name}/Rakefile").read).to eq(rakefile)
end
end
end
context "gem naming with dashed", :readline do
let(:gem_name) { "test-gem" }
let(:require_path) { "test/gem" }
let(:require_relative_path) { "gem" }
it "nests constants so they work" do
bundle "gem #{gem_name}"
expect(bundled_app("#{gem_name}/lib/#{require_path}/version.rb").read).to match(/module Test\n module Gem/)
expect(bundled_app("#{gem_name}/lib/#{require_path}.rb").read).to match(/module Test\n module Gem/)
end
include_examples "generating a gem"
end
describe "uncommon gem names" do
it "can deal with two dashes", :readline do
bundle "gem a--a"
expect(bundled_app("a--a/a--a.gemspec")).to exist
end
it "fails gracefully with a ." do
bundle "gem foo.gemspec", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo.gemspec -- `Foo.gemspec` is an invalid constant name")
end
it "fails gracefully with a ^" do
bundle "gem ^", :raise_on_error => false
expect(err).to end_with("Invalid gem name ^ -- `^` is an invalid constant name")
end
it "fails gracefully with a space" do
bundle "gem 'foo bar'", :raise_on_error => false
expect(err).to end_with("Invalid gem name foo bar -- `Foo bar` is an invalid constant name")
end
it "fails gracefully when multiple names are passed" do
bundle "gem foo bar baz", :raise_on_error => false
expect(err).to eq(<<-E.strip)
ERROR: "bundle gem" was called with arguments ["foo", "bar", "baz"]
Usage: "bundle gem NAME [OPTIONS]"
E
end
end
describe "#ensure_safe_gem_name", :readline do
before do
bundle "gem #{subject}", :raise_on_error => false
end
context "with an existing const name" do
subject { "gem" }
it { expect(err).to include("Invalid gem name #{subject}") }
end
context "with an existing hyphenated const name" do
subject { "gem-specification" }
it { expect(err).to include("Invalid gem name #{subject}") }
end
context "starting with an existing const name" do
subject { "gem-somenewconstantname" }
it { expect(err).not_to include("Invalid gem name #{subject}") }
end
context "ending with an existing const name" do
subject { "somenewconstantname-gem" }
it { expect(err).not_to include("Invalid gem name #{subject}") }
end
end
context "on first run", :readline do
it "asks about test framework" do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "rspec"
end
expect(bundled_app("foobar/spec/spec_helper.rb")).to exist
rakefile = strip_whitespace <<-RAKEFILE
# frozen_string_literal: true
require "bundler/gem_tasks"
require "rspec/core/rake_task"
RSpec::Core::RakeTask.new(:spec)
task default: :spec
RAKEFILE
expect(bundled_app("foobar/Rakefile").read).to eq(rakefile)
expect(bundled_app("foobar/Gemfile").read).to include('gem "rspec"')
end
it "asks about CI service" do
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "github"
end
expect(bundled_app("foobar/.github/workflows/main.yml")).to exist
end
it "asks about MIT license" do
global_config "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "config list"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
end
expect(bundled_app("foobar/LICENSE.txt")).to exist
end
it "asks about CoC" do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
end
expect(bundled_app("foobar/CODE_OF_CONDUCT.md")).to exist
end
it "asks about CHANGELOG" do
global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__LINTER" => "false",
"BUNDLE_GEM__COC" => "false"
bundle "gem foobar" do |input, _, _|
input.puts "yes"
end
expect(bundled_app("foobar/CHANGELOG.md")).to exist
end
end
context "on conflicts with a previously created file", :readline do
it "should fail gracefully" do
FileUtils.touch(bundled_app("conflict-foobar"))
bundle "gem conflict-foobar", :raise_on_error => false
expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.")
expect(exitstatus).to eql(32)
end
end
context "on conflicts with a previously created directory", :readline do
it "should succeed" do
FileUtils.mkdir_p(bundled_app("conflict-foobar/Gemfile"))
bundle "gem conflict-foobar"
expect(out).to include("file_clash conflict-foobar/Gemfile").
and include "Initializing git repo in #{bundled_app("conflict-foobar")}"
end
end
end