Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Appraisal doesn't support gemspec inside group #76

Closed
maxlinc opened this issue Nov 9, 2014 · 4 comments
Closed

Appraisal doesn't support gemspec inside group #76

maxlinc opened this issue Nov 9, 2014 · 4 comments
Assignees
Milestone

Comments

@maxlinc
Copy link

maxlinc commented Nov 9, 2014

Overview

Although Appraisal does support gemspec (#48) and other Bundler DSL methods, there are some discrepancies in where the gemspec method is allowed.

I'd like to use Appraisal to test a vagrant plugin against multiple releases of Vagrant. Vagrant and Vagrant plugins are just gems, but Vagrant plugin development follows less common Gemfile conventions that don't seem to work with Appraisal.

Background

This is a brief explanation of how Vagrant and Vagrant plugin installs work, and why that's resulted in unusual Gemfile conventions. If you don't care why Vagrant plugins use special bundler groups than you can skip to the next section. Nothing in this section needs to be supported by Appraisal.

Vagrant is no longer distributed via RubyGems. Instead, it's distributed via native package installers that include an embedded Ruby, so Vagrant has more control over non-Ruby dependencies (e.g. Virtualbox) and is easy to install for non-Ruby users. This also means plugins are installed to the embedded ruby with vagrant plugin install rather than gem install or bundle install.

The result is that Gemfiles for Vagrant development follow different conventions than many Ruby projects:

  • The plugin's gemspec should not depend on Vagrant since it won't be installed as a gem.
  • The plugins Gemfile should depend on Vagrant, but using a git branch/tag rather than a RubyGem release
  • Any plugins (including the plugin under development) should be put into a special bundler group called "plugins" so Vagrant can detect and auto-load them the same way it would plugins that had been installed via vagrant plugin install.

Examples

Appraisals file

I would like to use these Appraisals:

appraise "latest-stable" do
  group :development do
    gem "vagrant", :git => 'git:https://github.com/mitchellh/vagrant.git', :branch => 'v1.4.2'
  end
end

# Oldest (current release)
appraise "oldest-current" do
  group :development do
    gem "vagrant", :git => 'git:https://github.com/mitchellh/vagrant.git', :branch => 'v1.4.0'
  end
end

# Latest patch (previous release)
appraise "previous-release" do
  group :development do
    gem "vagrant", :git => 'git:https://github.com/mitchellh/vagrant.git', :branch => 'v1.3.5'
  end
end

appraise "windows-wip" do
  group :development do
    gem "vagrant", :git => 'git:https://github.com/maxlinc/vagrant.git', :branch => 'winrmssl'
  end
end

That will test my plugin the last several releases of Vagrant, as well as a fork where new features are being added for Windows.

Appraisal actually overrides the vagrant dependencies properly. It has an issue with the gem under development.

Approach 1 - gemspec

This is what I have in my Gemfile:

source 'https://rubygems.org'

group :development do
  gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
  gem 'appraisal', '~> 1.0'
end

group :plugins do
  gemspec
end

This doesn't work, because although Appraisal handles the gemspec method it doesn't seem to allow it within a group:

$ bundle exec appraisal install
/opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:39:in `block in run': undefined local variable or method `gemspec' for #<Appraisal::Group:0x007fb09c299c40> (NameError)
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/group.rb:12:in `instance_exec'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/group.rb:12:in `run'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:38:in `group'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:38:in `run'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:29:in `instance_eval'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:29:in `run'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/gemfile.rb:25:in `load'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/file.rb:17:in `initialize'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/file.rb:11:in `new'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/file.rb:11:in `each'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/task.rb:32:in `block in initialize'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/rake-10.3.2/lib/rake/task_manager.rb:209:in `in_namespace'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/rake-10.3.2/lib/rake/dsl_definition.rb:146:in `namespace'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal/task.rb:9:in `initialize'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal.rb:4:in `new'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/lib/appraisal.rb:4:in `<top (required)>'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/bin/appraisal:4:in `require'
    from /opt/boxen/rbenv/versions/2.1.0/lib/ruby/gems/2.1.0/gems/appraisal-1.0.2/bin/appraisal:4:in `<top (required)>'
    from /opt/boxen/rbenv/versions/2.1.0/bin/appraisal:23:in `load'
    from /opt/boxen/rbenv/versions/2.1.0/bin/appraisal:23:in `<main>'

Approach 2 - gem with path

Alternately, the vagrant plugin development guide uses gem "my-plugin", path: "." instead of gemspec.

source 'https://rubygems.org'

group :development do
  gem "vagrant", git: "https://github.com/mitchellh/vagrant.git"
  gem 'appraisal', '~> 1.0'
end

group :plugins do
  gem "vagrant-rackspace", path: "."
end

This doesn't work either, probably because support for rewriting path wasn't completed/merged (#19). The result:

$ bundle exec appraisal install
bundle check --gemfile='/Users/Thoughtworker/repos/rackspace/vagrant-rackspace/gemfiles/latest_stable.gemfile' || bundle install --gemfile='/Users/Thoughtworker/repos/rackspace/vagrant-rackspace/gemfiles/latest_stable.gemfile'
Resolving dependencies...
Bundler can't satisfy your Gemfile's dependencies.
Install missing gems with `bundle install`.
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
Could not find gem 'vagrant-rackspace (>= 0) ruby' in source at ..
Source does not contain any versions of 'vagrant-rackspace (>= 0) ruby'
@sikachu
Copy link
Contributor

sikachu commented Nov 9, 2014

Thanks for an awesome bug report. I think we should fix both of this to make them work.

For (1), we'll add support for gemspec in the group. That seems trivial.

For (2), we do have relativize task, but I don't think I have a case where the path is CWD. I'll make sure that's support in the next version.

@sikachu sikachu added this to the v1.0.2 milestone Nov 9, 2014
@sikachu sikachu self-assigned this Nov 9, 2014
@maxlinc
Copy link
Author

maxlinc commented Nov 9, 2014

FYI - I was reading thru the bundler code and found that the implementation of the DSL is "flat", not "hierarchical" like I would have assumed and appraisal seems to be.

What I mean is that methods that take a block (group, platform, and env - not sure what env does) do not change the scope. Bundler doesn't yield the block to a group, it just stores the group name (for later option normalization) and then yields the block to itself - the top-level DSL.

See:

So basically this:

gem "appraisal"
group :plugins do
  gem "vagrant-rackspace", path: "."
end

Is normalized and evaluated like this:

gem "appraisal", :groups => :default
gem "vagrant-rackspace", :groups => :plugins

I imagine you probably don't want to do quite the same in Appraisal - you want to generate gemfiles that are maintain a structure similar to the original Gemfile rather than normalizing them - but the point is that all DSL methods should be supported inside any block, not just specifically gemspec within group.

@sikachu
Copy link
Contributor

sikachu commented Nov 10, 2014

Right. If I could make it flat like Bundler, it would definitely be easier to read. However, we want to maintain the hierarchy, so that's why it's a bit more complex. >_>

@sikachu
Copy link
Contributor

sikachu commented Jan 2, 2015

I've extracted the :path problem to #82. This issue will focus on making gemspec works in group.

@sikachu sikachu closed this as completed in 74d612c Jan 2, 2015
sikachu pushed a commit that referenced this issue Mar 4, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants