appraisal 0.5.2 → 1.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +12 -4
- data/README.md +87 -36
- data/appraisal.gemspec +10 -7
- data/bin/appraisal +7 -0
- data/features/appraisals.feature +16 -2
- data/features/bundler_gemfile_compatibility.feature +70 -0
- data/features/gemspec.feature +0 -11
- data/features/missing_appraisals_file.feature +23 -0
- data/features/step_definitions/dependency_steps.rb +17 -24
- data/features/support/dependency_helpers.rb +29 -0
- data/lib/appraisal/appraisal.rb +52 -12
- data/lib/appraisal/cli.rb +87 -0
- data/lib/appraisal/command.rb +4 -2
- data/lib/appraisal/errors.rb +8 -0
- data/lib/appraisal/file.rb +8 -2
- data/lib/appraisal/gemfile.rb +40 -10
- data/lib/appraisal/gemspec.rb +1 -7
- data/lib/appraisal/git_source.rb +23 -0
- data/lib/appraisal/group.rb +17 -0
- data/lib/appraisal/task.rb +20 -18
- data/lib/appraisal/utils.rb +8 -0
- data/lib/appraisal/version.rb +1 -1
- data/spec/acceptance/cli_spec.rb +233 -0
- data/spec/appraisal/appraisal_spec.rb +61 -7
- data/spec/appraisal/file_spec.rb +9 -0
- data/spec/appraisal/gemfile_spec.rb +43 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/support/acceptance_test_helpers.rb +113 -0
- metadata +61 -11
- data/GOALS +0 -5
@@ -0,0 +1,29 @@
|
|
1
|
+
module DependencyHelpers
|
2
|
+
def build_gem(name, version)
|
3
|
+
create_dir(name)
|
4
|
+
cd(name)
|
5
|
+
create_dir("lib")
|
6
|
+
gem_path = "#{name}.gemspec"
|
7
|
+
version_path = "lib/#{name}.rb"
|
8
|
+
spec = <<-SPEC
|
9
|
+
Gem::Specification.new do |s|
|
10
|
+
s.name = '#{name}'
|
11
|
+
s.version = '#{version}'
|
12
|
+
s.authors = 'Mr. Smith'
|
13
|
+
s.summary = 'summary'
|
14
|
+
s.files = '#{version_path}'
|
15
|
+
end
|
16
|
+
SPEC
|
17
|
+
write_file(gem_path, spec)
|
18
|
+
write_file(version_path, "$#{name}_version = '#{version}'")
|
19
|
+
in_current_dir { `gem build #{gem_path} 2>&1` }
|
20
|
+
set_env("GEM_HOME", TMP_GEM_ROOT)
|
21
|
+
in_current_dir { `gem install #{name}-#{version}.gem 2>&1` }
|
22
|
+
FileUtils.rm_rf(File.join(current_dir, name))
|
23
|
+
dirs.pop
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if respond_to?(:World)
|
28
|
+
World(DependencyHelpers)
|
29
|
+
end
|
data/lib/appraisal/appraisal.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'appraisal/gemfile'
|
2
2
|
require 'appraisal/command'
|
3
|
+
require 'appraisal/utils'
|
3
4
|
require 'fileutils'
|
5
|
+
require 'pathname'
|
4
6
|
|
5
7
|
module Appraisal
|
6
8
|
# Represents one appraisal and its dependencies
|
@@ -18,37 +20,75 @@ module Appraisal
|
|
18
20
|
|
19
21
|
def write_gemfile
|
20
22
|
::File.open(gemfile_path, "w") do |file|
|
21
|
-
|
22
|
-
file.puts
|
23
|
-
file.write(gemfile.to_s)
|
23
|
+
signature = "# This file was generated by Appraisal"
|
24
|
+
file.puts([signature, gemfile.to_s].reject {|s| s.empty? }.join("\n\n"))
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
def install
|
28
|
-
Command.new(
|
28
|
+
def install(job_size = 1)
|
29
|
+
Command.new(check_command + ' || ' + install_command(job_size)).run
|
30
|
+
end
|
31
|
+
|
32
|
+
def update(gems = [])
|
33
|
+
Command.new(update_command(gems)).run
|
29
34
|
end
|
30
35
|
|
31
36
|
def gemfile_path
|
32
|
-
unless
|
33
|
-
|
37
|
+
unless gemfile_root.exist?
|
38
|
+
gemfile_root.mkdir
|
34
39
|
end
|
35
40
|
|
36
|
-
|
41
|
+
gemfile_root.join("#{clean_name}.gemfile").to_s
|
37
42
|
end
|
38
43
|
|
39
|
-
def
|
40
|
-
|
41
|
-
|
44
|
+
def relativize
|
45
|
+
current_directory = Pathname.new(Dir.pwd)
|
46
|
+
relative_path = current_directory.relative_path_from(gemfile_root).cleanpath
|
47
|
+
lockfile_content = ::File.read(lockfile_path)
|
48
|
+
|
49
|
+
::File.open(lockfile_path, 'w') do |file|
|
50
|
+
file.write lockfile_content.gsub(/#{current_directory}/, relative_path.to_s)
|
51
|
+
end
|
42
52
|
end
|
43
53
|
|
44
54
|
private
|
45
55
|
|
56
|
+
def check_command
|
57
|
+
gemfile_option = "--gemfile='#{gemfile_path}'"
|
58
|
+
['bundle', 'check', gemfile_option].join(' ')
|
59
|
+
end
|
60
|
+
|
61
|
+
def install_command(job_size)
|
62
|
+
gemfile_option = "--gemfile='#{gemfile_path}'"
|
63
|
+
['bundle', 'install', gemfile_option, bundle_parallel_option(job_size)].compact.join(' ')
|
64
|
+
end
|
65
|
+
|
66
|
+
def update_command(gems)
|
67
|
+
gemfile_config = "BUNDLE_GEMFILE='#{gemfile_path}'"
|
68
|
+
[gemfile_config, 'bundle', 'update', *gems].compact.join(' ')
|
69
|
+
end
|
70
|
+
|
46
71
|
def gemfile_root
|
47
|
-
::File.join(Dir.pwd, "gemfiles")
|
72
|
+
Pathname.new(::File.join(Dir.pwd, "gemfiles"))
|
73
|
+
end
|
74
|
+
|
75
|
+
def lockfile_path
|
76
|
+
"#{gemfile_path}.lock"
|
48
77
|
end
|
49
78
|
|
50
79
|
def clean_name
|
51
80
|
name.gsub(/[^\w\.]/, '_')
|
52
81
|
end
|
82
|
+
|
83
|
+
def bundle_parallel_option(job_size)
|
84
|
+
if job_size > 1
|
85
|
+
if Utils.support_parallel_installation?
|
86
|
+
"--jobs=#{job_size}"
|
87
|
+
else
|
88
|
+
warn 'Your current version of Bundler does not support parallel installation. Please ' +
|
89
|
+
'upgrade Bundler to version >= 1.4.0, or invoke `appraisal` without `--jobs` option.'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
53
93
|
end
|
54
94
|
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'thor'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Appraisal
|
5
|
+
class CLI < Thor
|
6
|
+
default_task :install
|
7
|
+
|
8
|
+
# Override help command to print out usage
|
9
|
+
def self.help(shell, subcommand = false)
|
10
|
+
shell.say strip_heredoc(<<-help)
|
11
|
+
Appraisal: Find out what your Ruby gems are worth.
|
12
|
+
|
13
|
+
Usage:
|
14
|
+
appraisal [APPRAISAL_NAME] EXTERNAL_COMMAND
|
15
|
+
|
16
|
+
If APPRAISAL_NAME is given, only run that EXTERNAL_COMMAND against the given
|
17
|
+
appraisal, otherwise it runs the EXTERNAL_COMMAND against all appraisals.
|
18
|
+
|
19
|
+
Available Appraisal(s):
|
20
|
+
help
|
21
|
+
|
22
|
+
File.each do |appraisal|
|
23
|
+
shell.say " - #{appraisal.name}"
|
24
|
+
end
|
25
|
+
|
26
|
+
shell.say
|
27
|
+
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.exit_on_failure?
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'install', 'Resolve and install dependencies for each appraisal'
|
36
|
+
method_option 'jobs', aliases: 'j', type: :numeric, default: 1, banner: 'SIZE',
|
37
|
+
desc: 'Install gems in parallel using the given number of workers.'
|
38
|
+
def install
|
39
|
+
invoke :generate, [], {}
|
40
|
+
|
41
|
+
File.each do |appraisal|
|
42
|
+
appraisal.install(options[:jobs])
|
43
|
+
appraisal.relativize
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'generate', 'Generate a gemfile for each appraisal'
|
48
|
+
def generate
|
49
|
+
File.each do |appraisal|
|
50
|
+
appraisal.write_gemfile
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'clean', 'Remove all generated gemfiles and lockfiles from gemfiles folder'
|
55
|
+
def clean
|
56
|
+
FileUtils.rm_f Dir['gemfiles/*.{gemfile,gemfile.lock}']
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'update [LIST_OF_GEMS]', 'Remove all generated gemfiles and lockfiles, resolve, and install dependencies again'
|
60
|
+
def update(*gems)
|
61
|
+
invoke :generate, []
|
62
|
+
|
63
|
+
File.each do |appraisal|
|
64
|
+
appraisal.update(gems)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def method_missing(name, *args, &block)
|
71
|
+
matching_appraisal = File.new.appraisals.detect { |appraisal| appraisal.name == name.to_s }
|
72
|
+
|
73
|
+
if matching_appraisal
|
74
|
+
Command.new(args.join(' '), matching_appraisal.gemfile_path).run
|
75
|
+
else
|
76
|
+
File.each do |appraisal|
|
77
|
+
Command.new(ARGV.join(' '), appraisal.gemfile_path).run
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.strip_heredoc(string)
|
83
|
+
indent = string.scan(/^[ \t]*(?=\S)/).min.size || 0
|
84
|
+
string.gsub(/^[ \t]{#{indent}}/, '')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/appraisal/command.rb
CHANGED
@@ -4,14 +4,15 @@ module Appraisal
|
|
4
4
|
BUNDLER_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE).freeze
|
5
5
|
|
6
6
|
def self.from_args(gemfile)
|
7
|
-
|
7
|
+
ARGV.shift
|
8
|
+
command = ([$0] + ARGV).join(' ')
|
8
9
|
new(command, gemfile)
|
9
10
|
end
|
10
11
|
|
11
12
|
def initialize(command, gemfile = nil)
|
12
13
|
@original_env = {}
|
13
14
|
@gemfile = gemfile
|
14
|
-
if command =~ /^bundle/
|
15
|
+
if command =~ /^(bundle|BUNDLE_GEMFILE)/
|
15
16
|
@command = command
|
16
17
|
else
|
17
18
|
@command = "bundle exec #{command}"
|
@@ -37,6 +38,7 @@ module Appraisal
|
|
37
38
|
def with_clean_env
|
38
39
|
unset_bundler_env_vars
|
39
40
|
ENV['BUNDLE_GEMFILE'] = @gemfile
|
41
|
+
ENV['APPRAISAL_INITIALIZED'] = '1'
|
40
42
|
yield
|
41
43
|
ensure
|
42
44
|
restore_env
|
data/lib/appraisal/file.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'appraisal/appraisal'
|
2
|
+
require 'appraisal/errors'
|
2
3
|
require 'appraisal/gemfile'
|
3
4
|
|
4
5
|
module Appraisal
|
5
|
-
# Loads and parses
|
6
|
+
# Loads and parses Appraisals file
|
6
7
|
class File
|
7
8
|
attr_reader :appraisals, :gemfile
|
8
9
|
|
@@ -14,7 +15,12 @@ module Appraisal
|
|
14
15
|
@appraisals = []
|
15
16
|
@gemfile = Gemfile.new
|
16
17
|
@gemfile.load(ENV['BUNDLE_GEMFILE'] || 'Gemfile')
|
17
|
-
|
18
|
+
|
19
|
+
if ::File.exists? path
|
20
|
+
run IO.read(path)
|
21
|
+
else
|
22
|
+
raise AppraisalsNotFound
|
23
|
+
end
|
18
24
|
end
|
19
25
|
|
20
26
|
def each(&block)
|
data/lib/appraisal/gemfile.rb
CHANGED
@@ -8,8 +8,11 @@ module Appraisal
|
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
@sources = []
|
11
|
+
@ruby_version = nil
|
11
12
|
@dependencies = []
|
12
13
|
@gemspec = nil
|
14
|
+
@groups = []
|
15
|
+
@git_sources = []
|
13
16
|
end
|
14
17
|
|
15
18
|
def load(path)
|
@@ -17,7 +20,7 @@ module Appraisal
|
|
17
20
|
end
|
18
21
|
|
19
22
|
def run(definitions)
|
20
|
-
instance_eval(definitions, __FILE__, __LINE__)
|
23
|
+
instance_eval(definitions, __FILE__, __LINE__) if definitions
|
21
24
|
end
|
22
25
|
|
23
26
|
def gem(name, *requirements)
|
@@ -25,25 +28,38 @@ module Appraisal
|
|
25
28
|
@dependencies << Dependency.new(name, requirements)
|
26
29
|
end
|
27
30
|
|
28
|
-
def group(*names)
|
29
|
-
|
31
|
+
def group(*names, &block)
|
32
|
+
require 'appraisal/group'
|
33
|
+
|
34
|
+
group = Group.new(names)
|
35
|
+
group.run(&block)
|
36
|
+
@groups << group
|
30
37
|
end
|
31
38
|
|
32
39
|
def source(source)
|
33
40
|
@sources << source
|
34
41
|
end
|
35
42
|
|
43
|
+
def ruby(ruby_version)
|
44
|
+
@ruby_version = ruby_version
|
45
|
+
end
|
46
|
+
|
47
|
+
def git(source, options = {}, &block)
|
48
|
+
require 'appraisal/git_source'
|
49
|
+
|
50
|
+
git_source = GitSource.new(source, options)
|
51
|
+
git_source.run(&block)
|
52
|
+
@git_sources << git_source
|
53
|
+
end
|
54
|
+
|
36
55
|
def to_s
|
37
|
-
[source_entry, dependencies_entry,
|
56
|
+
[source_entry, ruby_version_entry, git_sources_entry, dependencies_entry, groups_entry,
|
57
|
+
gemspec_entry].reject{ |s| s.nil? || s.empty? }.join("\n\n").strip
|
38
58
|
end
|
39
59
|
|
40
60
|
def dup
|
41
61
|
gemfile = Gemfile.new
|
42
|
-
|
43
|
-
dependencies.each do |dependency|
|
44
|
-
gemfile.gem(dependency.name, *dependency.requirements)
|
45
|
-
end
|
46
|
-
gemfile.gemspec(@gemspec.options) if @gemspec
|
62
|
+
gemfile.run(to_s)
|
47
63
|
gemfile
|
48
64
|
end
|
49
65
|
|
@@ -57,8 +73,22 @@ module Appraisal
|
|
57
73
|
@sources.map { |source| "source #{source.inspect}" }.join("\n")
|
58
74
|
end
|
59
75
|
|
76
|
+
def ruby_version_entry
|
77
|
+
if @ruby_version
|
78
|
+
"ruby #{@ruby_version.inspect}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def git_sources_entry
|
83
|
+
@git_sources.map(&:to_s).join("\n\n")
|
84
|
+
end
|
85
|
+
|
60
86
|
def dependencies_entry
|
61
|
-
dependencies.map
|
87
|
+
dependencies.map(&:to_s).join("\n")
|
88
|
+
end
|
89
|
+
|
90
|
+
def groups_entry
|
91
|
+
@groups.map(&:to_s).join("\n\n")
|
62
92
|
end
|
63
93
|
|
64
94
|
def gemspec_entry
|
data/lib/appraisal/gemspec.rb
CHANGED
@@ -9,14 +9,8 @@ module Appraisal
|
|
9
9
|
@options[:path] ||= '.'
|
10
10
|
end
|
11
11
|
|
12
|
-
def exists?
|
13
|
-
Dir[::File.join(@options[:path], "*.gemspec")].size > 0
|
14
|
-
end
|
15
|
-
|
16
12
|
def to_s
|
17
|
-
|
18
|
-
"gemspec #{exported_options.inspect.gsub(/^\{|\}$/, '')}"
|
19
|
-
end
|
13
|
+
"gemspec #{exported_options.inspect.gsub(/^\{|\}$/, '')}"
|
20
14
|
end
|
21
15
|
|
22
16
|
private
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Appraisal
|
2
|
+
class GitSource < Gemfile
|
3
|
+
def initialize(source, options = {})
|
4
|
+
super()
|
5
|
+
@source = source
|
6
|
+
@options = options
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(&block)
|
10
|
+
instance_exec(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_s
|
14
|
+
dependencies = super.strip.gsub(/^/, ' ')
|
15
|
+
|
16
|
+
if @options.empty?
|
17
|
+
"git #{@source.inspect} do\n#{dependencies}\nend"
|
18
|
+
else
|
19
|
+
"git #{@source.inspect}, #{@options.inspect} do\n#{dependencies}\nend"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Appraisal
|
2
|
+
class Group < Gemfile
|
3
|
+
def initialize(group_names)
|
4
|
+
super()
|
5
|
+
@group_names = group_names
|
6
|
+
end
|
7
|
+
|
8
|
+
def run(&block)
|
9
|
+
instance_exec(&block)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_s
|
13
|
+
"group #{@group_names.map(&:inspect).join(', ')} do\n" +
|
14
|
+
super.strip.gsub(/^/, ' ') + "\nend"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/appraisal/task.rb
CHANGED
@@ -7,38 +7,40 @@ module Appraisal
|
|
7
7
|
class Task < Rake::TaskLib
|
8
8
|
def initialize
|
9
9
|
namespace :appraisal do
|
10
|
-
desc "Generate a Gemfile for each appraisal"
|
10
|
+
desc "DEPRECATED: Generate a Gemfile for each appraisal"
|
11
11
|
task :gemfiles do
|
12
|
-
|
13
|
-
appraisal
|
14
|
-
|
12
|
+
warn "`rake appraisal:gemfile` task is deprecated and will be removed soon. " +
|
13
|
+
"Please use `appraisal generate`."
|
14
|
+
exec 'bundle exec appraisal generate'
|
15
15
|
end
|
16
16
|
|
17
|
-
desc "Resolve and install dependencies for each appraisal"
|
18
|
-
task :install
|
19
|
-
|
20
|
-
appraisal
|
21
|
-
|
17
|
+
desc "DEPRECATED: Resolve and install dependencies for each appraisal"
|
18
|
+
task :install do
|
19
|
+
warn "`rake appraisal:install` task is deprecated and will be removed soon. " +
|
20
|
+
"Please use `appraisal install`."
|
21
|
+
exec 'bundle exec appraisal install'
|
22
22
|
end
|
23
23
|
|
24
|
-
desc "Remove all generated gemfiles from gemfiles/ folder"
|
24
|
+
desc "DEPRECATED: Remove all generated gemfiles from gemfiles/ folder"
|
25
25
|
task :cleanup do
|
26
|
-
|
27
|
-
|
26
|
+
warn "`rake appraisal:cleanup` task is deprecated and will be removed soon. " +
|
27
|
+
"Please use `appraisal clean`."
|
28
|
+
exec 'bundle exec appraisal clean'
|
28
29
|
end
|
29
30
|
|
30
31
|
File.each do |appraisal|
|
31
|
-
desc "Run the given task for appraisal #{appraisal.name}"
|
32
|
+
desc "DEPRECATED: Run the given task for appraisal #{appraisal.name}"
|
32
33
|
task appraisal.name do
|
33
|
-
|
34
|
+
ARGV.shift
|
35
|
+
warn "`rake appraisal:#{appraisal.name}` task is deprecated and will be removed soon. " +
|
36
|
+
"Please use `appraisal #{appraisal.name} rake #{ARGV.join(' ')}`."
|
37
|
+
exec "bundle exec appraisal #{appraisal.name} rake #{ARGV.join(' ')}"
|
34
38
|
end
|
35
39
|
end
|
36
40
|
|
37
41
|
task :all do
|
38
|
-
|
39
|
-
|
40
|
-
end
|
41
|
-
exit
|
42
|
+
ARGV.shift
|
43
|
+
exec "bundle exec appraisal rake #{ARGV.join(' ')}"
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|