appraisal 2.0.1 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3ab623ad895ec0d2c27cd4a0865a476ca268c355
4
- data.tar.gz: 7525addf1bd53d5b424bcb314390b620ddee77e5
2
+ SHA256:
3
+ metadata.gz: 0fe7f7616c7aef0aaa5544853800eb05b08f3bb619b4fc292b8e89bbd2e9ea4d
4
+ data.tar.gz: 43ef79f1e190735adc4fec2413b84b614938d2a94cae68760972ffe37ca3dff4
5
5
  SHA512:
6
- metadata.gz: 564306857e229c592407c8f1c027d7da3a1b34ed62c49e51b4d3186a39346e1d68d6d14e0bad0887a15241dd4cb5597e7f0fea69125bdd4980ef0a3b9db6caa3
7
- data.tar.gz: e24f07952fc90e2c088a2932dcd827d1a4590faa63469ae45168a1a870d6af48c65bd302eb8c75ca0dbd134977820c37b1c167afe4a12a10978f5d883537b6df
6
+ metadata.gz: 45cb2de8908bd80ab3331a8c452d5f77e0d573670c48e92441cf359c6ae615e7297d5a22e3c157197d659358cd8d9d776aea5c4b55782c3c94fb14c56f356acc
7
+ data.tar.gz: e6f88c11dbd4e09849c2318bc14174a482a9e738790fe7ccbcee376856c06d964888d54663c81a2901ef448a7e8de22d64de098ec3dfe2c527ae68ff7ce6415f
data/.travis.yml CHANGED
@@ -1,22 +1,18 @@
1
- sudo: false
2
-
3
- before_install: gem install bundler
1
+ ---
2
+ before_install: gem install bundler:2.1.4
4
3
 
5
4
  rvm:
6
- - 1.8
7
- - 1.9
8
- - 2.0
9
- - 2.1
10
- - 2.2
11
- - rbx-2
12
- - jruby-19mode
5
+ - 2.3
6
+ - 2.4
7
+ - 2.5
8
+ - 2.6
9
+ - 2.7
10
+ - jruby-9.2.9.0
13
11
  - ruby-head
14
12
  - jruby-head
15
13
 
16
14
  matrix:
17
15
  fast_finish: true
18
16
  allow_failures:
19
- - rvm: rbx-2
20
- - rvm: jruby-19mode
21
17
  - rvm: ruby-head
22
18
  - rvm: jruby-head
data/Gemfile CHANGED
@@ -1,11 +1,6 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
5
  # This here to make sure appraisal works with Rails 3.0.0.
6
- gem 'thor', '~> 0.14.0'
7
-
8
- if RUBY_VERSION < "1.9"
9
- gem "i18n", "~> 0.6.0"
10
- gem "activesupport", "~> 3.2.21"
11
- end
6
+ gem "thor", "~> 0.14.0"
data/README.md CHANGED
@@ -5,7 +5,7 @@ Appraisal
5
5
 
6
6
  Find out what your Ruby gems are worth.
7
7
 
8
- [Build Status Image]: https://secure.travis-ci.org/thoughtbot/appraisal.png?branch=master
8
+ [Build Status Image]: https://secure.travis-ci.org/thoughtbot/appraisal.svg?branch=master
9
9
  [Build Status]: http://travis-ci.org/thoughtbot/appraisal
10
10
 
11
11
  Synopsis
@@ -19,22 +19,23 @@ without interfering with day-to-day development using Bundler.
19
19
  Installation
20
20
  ------------
21
21
 
22
- In your Gemfile:
22
+ In your package's `.gemspec`:
23
23
 
24
- gem "appraisal"
24
+ s.add_development_dependency "appraisal"
25
25
 
26
- Note that gems must be bundled in the global namespace. Bundling gems to a local
27
- location or vendoring plugins is not supported. If you do not want to pollute the
28
- global namespace, one alternative is [RVM's Gemsets](http://rvm.io/gemsets).
26
+ Note that gems must be bundled in the global namespace. Bundling gems to a
27
+ local location or vendoring plugins is not supported. If you do not want to
28
+ pollute the global namespace, one alternative is
29
+ [RVM's Gemsets](http://rvm.io/gemsets).
29
30
 
30
31
  Setup
31
32
  -----
32
33
 
33
- Setting up appraisal requires an Appraisals file (similar to a Gemfile) in your
34
- project root, named "Appraisals" (note the case), and some slight changes to
35
- your project's Rakefile.
34
+ Setting up appraisal requires an `Appraisals` file (similar to a `Gemfile`) in
35
+ your project root, named "Appraisals" (note the case), and some slight changes
36
+ to your project's `Rakefile`.
36
37
 
37
- An Appraisals file consists of several appraisal definitions. An appraisal
38
+ An `Appraisals` file consists of several appraisal definitions. An appraisal
38
39
  definition is simply a list of gem dependencies. For example, to test with a
39
40
  few versions of Rails:
40
41
 
@@ -46,35 +47,29 @@ few versions of Rails:
46
47
  gem "rails", "4.0.0"
47
48
  end
48
49
 
49
- The dependencies in your Appraisals file are combined with dependencies in your
50
- Gemfile, so you don't need to repeat anything that's the same for each
50
+ The dependencies in your `Appraisals` file are combined with dependencies in
51
+ your `Gemfile`, so you don't need to repeat anything that's the same for each
51
52
  appraisal. If something is specified in both the Gemfile and an appraisal, the
52
53
  version from the appraisal takes precedence.
53
54
 
54
- It's also recommended that you setup bundler at the very top of your Rakefile,
55
- so that you don't need to constantly run bundle exec:
56
-
57
- require "rubygems"
58
- require "bundler/setup"
59
-
60
55
  Usage
61
56
  -----
62
57
 
63
58
  Once you've configured the appraisals you want to use, you need to install the
64
59
  dependencies for each appraisal:
65
60
 
66
- appraisal install
61
+ $ bundle exec appraisal install
67
62
 
68
63
  This will resolve, install, and lock the dependencies for that appraisal using
69
64
  bundler. Once you have your dependencies set up, you can run any command in a
70
65
  single appraisal:
71
66
 
72
- appraisal rails-3 rake test
67
+ $ bundle exec appraisal rails-3 rake test
73
68
 
74
69
  This will run `rake test` using the dependencies configured for Rails 3. You can
75
70
  also run each appraisal in turn:
76
71
 
77
- appraisal rake test
72
+ $ bundle exec appraisal rake test
78
73
 
79
74
  If you want to use only the dependencies from your Gemfile, just run `rake
80
75
  test` as normal. This allows you to keep running with the latest versions of
@@ -96,6 +91,18 @@ Note that this may conflict with your CI setup if you decide to split the test
96
91
  into multiple processes by Appraisal and you are using `rake` to run tests by
97
92
  default. Please see **Travis CI Integration** for more detail.
98
93
 
94
+ ### Commands
95
+
96
+ ```bash
97
+ appraisal clean # Remove all generated gemfiles and lockfiles from gemfiles folder
98
+ appraisal generate # Generate a gemfile for each appraisal
99
+ appraisal help [COMMAND] # Describe available commands or one specific command
100
+ appraisal install # Resolve and install dependencies for each appraisal
101
+ appraisal list # List the names of the defined appraisals
102
+ appraisal update [LIST_OF_GEMS] # Remove all generated gemfiles and lockfiles, resolve, and install dependencies again
103
+ appraisal version # Display the version and exit
104
+ ```
105
+
99
106
  Under the hood
100
107
  --------------
101
108
 
@@ -108,6 +115,46 @@ When you prefix a command with `appraisal`, the command is run with the
108
115
  appropriate Gemfile for that appraisal, ensuring the correct dependencies
109
116
  are used.
110
117
 
118
+ Removing Gems using Appraisal
119
+ -------
120
+
121
+ It is common while managing multiple Gemfiles for dependencies to become deprecated and no
122
+ longer necessary, meaning they need to be removed from the Gemfile for a specific `appraisal`.
123
+ To do this, use the `remove_gem` declaration within the necessary `appraise` block in your
124
+ `Appraisals` file.
125
+
126
+ ### Example Usage
127
+
128
+ **Gemfile**
129
+ ```ruby
130
+ gem 'rails', '~> 4.2'
131
+
132
+ group :test do
133
+ gem 'rspec', '~> 4.0'
134
+ gem 'test_after_commit'
135
+ end
136
+ ```
137
+
138
+ **Appraisals**
139
+ ```ruby
140
+ appraise 'rails-5' do
141
+ gem 'rails', '~> 5.2'
142
+
143
+ group :test do
144
+ remove_gem :test_after_commit
145
+ end
146
+ end
147
+ ```
148
+
149
+ Using the `Appraisals` file defined above, this is what the resulting `Gemfile` will look like:
150
+ ```ruby
151
+ gem 'rails', '~> 5.2'
152
+
153
+ group :test do
154
+ gem 'rspec', '~> 4.0'
155
+ end
156
+ ```
157
+
111
158
  Version Control
112
159
  ---------------
113
160
 
@@ -139,15 +186,38 @@ all versions of its dependency, you might have to set a `script` setting:
139
186
  That will make sure that each of the test sub-job are not getting run more than
140
187
  one time.
141
188
 
142
- You can also running your test against multiple versions of Ruby locally, just
189
+ You can also run your tests against multiple versions of Ruby locally, just
143
190
  like running on Travis CI, by using [WWTD].
144
191
 
145
192
  [WWTD]: https://github.com/grosser/wwtd
146
193
 
194
+ Circle CI Integration
195
+ ---------------------
196
+
197
+ In Circle CI you can override the default testing behaviour to customize your
198
+ testing. Using this feature you can configure appraisal to execute your tests.
199
+
200
+ In order to this you can put the following configuration in your circle.yml file:
201
+
202
+ ```yml
203
+ dependencies:
204
+ post:
205
+ - bundle exec appraisal install
206
+ test:
207
+ pre:
208
+ - bundle exec appraisal rake db:create
209
+ - bundle exec appraisal rake db:migrate
210
+ override:
211
+ - bundle exec appraisal rspec
212
+ ```
213
+
214
+ Notice that we are running an rspec suite. You can customize your testing
215
+ command in the `override` section and use your favourite one.
216
+
147
217
  Credits
148
218
  -------
149
219
 
150
- ![thoughtbot](http://thoughtbot.com/images/tm/logo.png)
220
+ ![thoughtbot](http://presskit.thoughtbot.com/images/thoughtbot-logo-for-readmes.svg)
151
221
 
152
222
  Appraisal is maintained and funded by [thoughtbot, inc][thoughtbot]
153
223
 
data/appraisal.gemspec CHANGED
@@ -18,10 +18,12 @@ Gem::Specification.new do |s|
18
18
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
19
  s.require_paths = ["lib"]
20
20
 
21
+ s.required_ruby_version = ">= 2.3.0"
22
+
21
23
  s.add_runtime_dependency('rake')
22
24
  s.add_runtime_dependency('bundler')
23
25
  s.add_runtime_dependency('thor', '>= 0.14.0')
24
- s.add_runtime_dependency("activesupport", ">= 3.2.21")
25
26
 
27
+ s.add_development_dependency("activesupport", ">= 3.2.21")
26
28
  s.add_development_dependency('rspec', '~> 3.0')
27
29
  end
@@ -7,6 +7,8 @@ require 'pathname'
7
7
  module Appraisal
8
8
  # Represents one appraisal and its dependencies
9
9
  class Appraisal
10
+ DEFAULT_INSTALL_OPTIONS = { "jobs" => 1 }.freeze
11
+
10
12
  attr_reader :name, :gemfile
11
13
 
12
14
  def initialize(name, source_gemfile)
@@ -18,8 +20,12 @@ module Appraisal
18
20
  gemfile.gem(*args)
19
21
  end
20
22
 
21
- def source(*args)
22
- gemfile.source(*args)
23
+ def remove_gem(*args)
24
+ gemfile.remove_gem(*args)
25
+ end
26
+
27
+ def source(*args, &block)
28
+ gemfile.source(*args, &block)
23
29
  end
24
30
 
25
31
  def ruby(*args)
@@ -46,26 +52,36 @@ module Appraisal
46
52
  gemfile.gemspec(options)
47
53
  end
48
54
 
55
+ def git_source(*args, &block)
56
+ gemfile.git_source(*args, &block)
57
+ end
58
+
49
59
  def write_gemfile
50
- ::File.open(gemfile_path, "w") do |file|
60
+ File.open(gemfile_path, "w") do |file|
51
61
  signature = "# This file was generated by Appraisal"
52
62
  file.puts([signature, gemfile.to_s].join("\n\n"))
53
63
  end
54
64
  end
55
65
 
56
- def install(job_size = 1)
57
- command = [
58
- check_command,
59
- "||",
60
- install_command(job_size)
61
- ].flatten.join(" ")
66
+ def install(options = {})
67
+ commands = [install_command(options).join(" ")]
68
+
69
+ if options["without"].nil? || options["without"].empty?
70
+ commands.unshift(check_command.join(" "))
71
+ end
72
+
73
+ command = commands.join(" || ")
62
74
 
63
- Command.new(command).run
75
+ if Bundler.settings[:path]
76
+ env = { 'BUNDLE_DISABLE_SHARED_GEMS' => '1' }
77
+ Command.new(command, :env => env).run
78
+ else
79
+ Command.new(command).run
80
+ end
64
81
  end
65
82
 
66
83
  def update(gems = [])
67
- command, env = update_command(gems)
68
- Command.new(command, :env => env).run
84
+ Command.new(update_command(gems), :gemfile => gemfile_path).run
69
85
  end
70
86
 
71
87
  def gemfile_path
@@ -77,15 +93,15 @@ module Appraisal
77
93
  end
78
94
 
79
95
  def relative_gemfile_path
80
- ::File.join("gemfiles", gemfile_name)
96
+ File.join("gemfiles", gemfile_name)
81
97
  end
82
98
 
83
99
  def relativize
84
100
  current_directory = Pathname.new(Dir.pwd)
85
101
  relative_path = current_directory.relative_path_from(gemfile_root).cleanpath
86
- lockfile_content = ::File.read(lockfile_path)
102
+ lockfile_content = File.read(lockfile_path)
87
103
 
88
- ::File.open(lockfile_path, 'w') do |file|
104
+ File.open(lockfile_path, 'w') do |file|
89
105
  file.write lockfile_content.gsub(/#{current_directory}/, relative_path.to_s)
90
106
  end
91
107
  end
@@ -97,19 +113,21 @@ module Appraisal
97
113
  ['bundle', 'check', gemfile_option]
98
114
  end
99
115
 
100
- def install_command(job_size)
116
+ def install_command(options = {})
101
117
  gemfile_option = "--gemfile='#{gemfile_path}'"
102
- ['bundle', 'install', gemfile_option, bundle_parallel_option(job_size)].compact
118
+ ['bundle', 'install', gemfile_option, bundle_options(options)].compact
103
119
  end
104
120
 
105
121
  def update_command(gems)
106
- env = { "BUNDLE_GEMFILE" => gemfile_path }
107
- command = ['bundle', 'update', *gems].compact
108
- [command, env]
122
+ ['bundle', 'update', *gems].compact
109
123
  end
110
124
 
111
125
  def gemfile_root
112
- Pathname.new(::File.join(Dir.pwd, "gemfiles"))
126
+ project_root + "gemfiles"
127
+ end
128
+
129
+ def project_root
130
+ Pathname.new(Dir.pwd)
113
131
  end
114
132
 
115
133
  def gemfile_name
@@ -124,15 +142,30 @@ module Appraisal
124
142
  name.gsub(/[^\w\.]/, '_')
125
143
  end
126
144
 
127
- def bundle_parallel_option(job_size)
128
- if job_size > 1
145
+ def bundle_options(options)
146
+ full_options = DEFAULT_INSTALL_OPTIONS.dup.merge(options)
147
+ options_strings = []
148
+ jobs = full_options.delete("jobs")
149
+ if jobs > 1
129
150
  if Utils.support_parallel_installation?
130
- "--jobs=#{job_size}"
151
+ options_strings << "--jobs=#{jobs}"
131
152
  else
132
153
  warn 'Your current version of Bundler does not support parallel installation. Please ' +
133
154
  'upgrade Bundler to version >= 1.4.0, or invoke `appraisal` without `--jobs` option.'
134
155
  end
135
156
  end
157
+
158
+ path = full_options.delete("path")
159
+ if path
160
+ relative_path = project_root.join(options["path"])
161
+ options_strings << "--path #{relative_path}"
162
+ end
163
+
164
+ full_options.each do |flag, val|
165
+ options_strings << "--#{flag} #{val}"
166
+ end
167
+
168
+ options_strings.join(" ") if options_strings != []
136
169
  end
137
170
  end
138
171
  end
@@ -4,7 +4,7 @@ require 'appraisal/gemfile'
4
4
 
5
5
  module Appraisal
6
6
  # Loads and parses Appraisals file
7
- class File
7
+ class AppraisalFile
8
8
  attr_reader :appraisals, :gemfile
9
9
 
10
10
  def self.each(&block)
@@ -16,7 +16,7 @@ module Appraisal
16
16
  @gemfile = Gemfile.new
17
17
  @gemfile.load(ENV['BUNDLE_GEMFILE'] || 'Gemfile')
18
18
 
19
- if ::File.exist? path
19
+ if File.exist? path
20
20
  run IO.read(path)
21
21
  else
22
22
  raise AppraisalsNotFound
@@ -1,22 +1,23 @@
1
1
  require "appraisal/dependency_list"
2
- require "active_support/ordered_hash"
3
2
 
4
3
  module Appraisal
5
4
  class BundlerDSL
6
5
  attr_reader :dependencies
7
6
 
8
- PARTS = %w(source ruby_version git_sources path_sources dependencies groups
9
- platforms gemspec)
7
+ PARTS = %w(source ruby_version gits paths dependencies groups
8
+ platforms source_blocks gemspec)
10
9
 
11
10
  def initialize
12
11
  @sources = []
13
12
  @ruby_version = nil
14
13
  @dependencies = DependencyList.new
15
- @gemspec = nil
16
- @groups = ActiveSupport::OrderedHash.new
17
- @platforms = ActiveSupport::OrderedHash.new
18
- @git_sources = ActiveSupport::OrderedHash.new
19
- @path_sources = ActiveSupport::OrderedHash.new
14
+ @gemspecs = []
15
+ @groups = Hash.new
16
+ @platforms = Hash.new
17
+ @gits = Hash.new
18
+ @paths = Hash.new
19
+ @source_blocks = Hash.new
20
+ @git_sources = {}
20
21
  end
21
22
 
22
23
  def run(&block)
@@ -24,23 +25,35 @@ module Appraisal
24
25
  end
25
26
 
26
27
  def gem(name, *requirements)
27
- @dependencies.add(name, requirements)
28
+ @dependencies.add(name, substitute_git_source(requirements))
29
+ end
30
+
31
+ def remove_gem(name)
32
+ @dependencies.remove(name)
28
33
  end
29
34
 
30
35
  def group(*names, &block)
31
- @groups[names] ||= Group.new(names)
36
+ @groups[names] ||=
37
+ Group.new(names).tap { |g| g.git_sources = @git_sources.dup }
32
38
  @groups[names].run(&block)
33
39
  end
34
40
 
35
41
  def platforms(*names, &block)
36
- @platforms[names] ||= Platform.new(names)
42
+ @platforms[names] ||=
43
+ Platform.new(names).tap { |g| g.git_sources = @git_sources.dup }
37
44
  @platforms[names].run(&block)
38
45
  end
39
46
 
40
47
  alias_method :platform, :platforms
41
48
 
42
- def source(source)
43
- @sources << source
49
+ def source(source, &block)
50
+ if block_given?
51
+ @source_blocks[source] ||=
52
+ Source.new(source).tap { |g| g.git_sources = @git_sources.dup }
53
+ @source_blocks[source].run(&block)
54
+ else
55
+ @sources << source
56
+ end
44
57
  end
45
58
 
46
59
  def ruby(ruby_version)
@@ -48,13 +61,15 @@ module Appraisal
48
61
  end
49
62
 
50
63
  def git(source, options = {}, &block)
51
- @git_sources[source] ||= GitSource.new(source, options)
52
- @git_sources[source].run(&block)
64
+ @gits[source] ||=
65
+ Git.new(source, options).tap { |g| g.git_sources = @git_sources.dup }
66
+ @gits[source].run(&block)
53
67
  end
54
68
 
55
69
  def path(source, options = {}, &block)
56
- @path_sources[source] ||= PathSource.new(source, options)
57
- @path_sources[source].run(&block)
70
+ @paths[source] ||=
71
+ Path.new(source, options).tap { |g| g.git_sources = @git_sources.dup }
72
+ @paths[source].run(&block)
58
73
  end
59
74
 
60
75
  def to_s
@@ -66,9 +81,17 @@ module Appraisal
66
81
  end
67
82
 
68
83
  def gemspec(options = {})
69
- @gemspec = Gemspec.new(options)
84
+ @gemspecs << Gemspec.new(options)
70
85
  end
71
86
 
87
+ def git_source(source, &block)
88
+ @git_sources[source] = block
89
+ end
90
+
91
+ protected
92
+
93
+ attr_writer :git_sources
94
+
72
95
  private
73
96
 
74
97
  def source_entry
@@ -85,25 +108,24 @@ module Appraisal
85
108
 
86
109
  alias_method :ruby_version_entry_for_dup, :ruby_version_entry
87
110
 
88
- [:dependencies, :gemspec].each do |method_name|
89
- class_eval <<-METHODS, __FILE__, __LINE__
90
- private
111
+ def gemspec_entry
112
+ @gemspecs.map(&:to_s).join("\n")
113
+ end
91
114
 
92
- def #{method_name}_entry
93
- if @#{method_name}
94
- @#{method_name}.to_s
95
- end
96
- end
115
+ def gemspec_entry_for_dup
116
+ @gemspecs.map(&:for_dup).join("\n")
117
+ end
97
118
 
98
- def #{method_name}_entry_for_dup
99
- if @#{method_name}
100
- @#{method_name}.for_dup
101
- end
102
- end
103
- METHODS
119
+ def dependencies_entry
120
+ @dependencies.to_s
121
+ end
122
+
123
+ def dependencies_entry_for_dup
124
+ @dependencies.for_dup
104
125
  end
105
126
 
106
- [:git_sources, :path_sources, :platforms, :groups].each do |method_name|
127
+ [:gits, :paths, :platforms, :groups, :source_blocks].
128
+ each do |method_name|
107
129
  class_eval <<-METHODS, __FILE__, __LINE__
108
130
  private
109
131
 
@@ -120,5 +142,16 @@ module Appraisal
120
142
  def indent(string)
121
143
  string.strip.gsub(/^(.+)$/, ' \1')
122
144
  end
145
+
146
+ def substitute_git_source(requirements)
147
+ requirements.each do |requirement|
148
+ if requirement.is_a?(Hash)
149
+ (requirement.keys & @git_sources.keys).each do |matching_source|
150
+ value = requirement.delete(matching_source)
151
+ requirement[:git] = @git_sources[matching_source].call(value)
152
+ end
153
+ end
154
+ end
155
+ end
123
156
  end
124
157
  end