Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial commit: basic rake tasks for running with different gemfiles

  • Loading branch information...
commit ff75e901a143bcad0a245d65d8546340b3495458 0 parents
@jferris jferris authored
2  .bundle/config
@@ -0,0 +1,2 @@
+---
+BUNDLE_DISABLE_SHARED_GEMS: "1"
6 .gitignore
@@ -0,0 +1,6 @@
+*.swp
+tmp
+pkg
+.swo
+*~
+
5 Gemfile
@@ -0,0 +1,5 @@
+source "http://rubygems.org"
+gem "cucumber"
+gem "aruba"
+gem "rake"
+gem "rspec"
38 Gemfile.lock
@@ -0,0 +1,38 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ aruba (0.2.4)
+ background_process
+ cucumber (~> 0.9.3)
+ background_process (1.2)
+ builder (2.1.2)
+ cucumber (0.9.4)
+ builder (~> 2.1.2)
+ diff-lcs (~> 1.1.2)
+ gherkin (~> 2.2.9)
+ json (~> 1.4.6)
+ term-ansicolor (~> 1.0.5)
+ diff-lcs (1.1.2)
+ gherkin (2.2.9)
+ json (~> 1.4.6)
+ term-ansicolor (~> 1.0.5)
+ json (1.4.6)
+ rake (0.8.7)
+ rspec (2.1.0)
+ rspec-core (~> 2.1.0)
+ rspec-expectations (~> 2.1.0)
+ rspec-mocks (~> 2.1.0)
+ rspec-core (2.1.0)
+ rspec-expectations (2.1.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.1.0)
+ term-ansicolor (1.0.5)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ aruba
+ cucumber
+ rake
+ rspec
19 Rakefile
@@ -0,0 +1,19 @@
+require 'rubygems'
+require 'bundler/setup'
+require 'rake/gempackagetask'
+require 'cucumber/rake/task'
+
+eval("$specification = #{IO.read('appraisal.gemspec')}")
+Rake::GemPackageTask.new($specification) do |package|
+ package.need_zip = true
+ package.need_tar = true
+end
+
+Cucumber::Rake::Task.new(:cucumber) do |t|
+ t.fork = true
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
+end
+
+desc "Default: run the cucumber scenarios"
+task :default => :cucumber
+
26 appraisal.gemspec
@@ -0,0 +1,26 @@
+Gem::Specification.new do |s|
+ s.name = %q{appraisal}
+ s.version = '0.1'
+ s.summary = %q{Find out how much your Ruby gems are worth}
+ s.description = %q{appraisal integrates with bundler and rake to test your library against different versions of dependencies in repeatable scenarios called "appraisals."}
+
+ s.files = Dir['[A-Z]*', 'lib/**/*.rb', 'features/**/*']
+ s.require_path = 'lib'
+ s.test_files = Dir['features/**/*']
+
+ s.has_rdoc = false
+
+ s.authors = ["Joe Ferris"]
+ s.email = %q{jferris@thoughtbot.com}
+ s.homepage = "http://github.com/thoughtbot/appraisal"
+
+ s.add_development_dependency('cucumber')
+ s.add_development_dependency('aruba')
+
+ s.add_runtime_dependency('rake')
+ s.add_runtime_dependency('bundler')
+
+ s.platform = Gem::Platform::RUBY
+ s.rubygems_version = %q{1.2.0}
+end
+
57 features/appraisals.feature
@@ -0,0 +1,57 @@
+Feature: run a rake task through several appraisals
+
+ Background:
+ Given a directory named "projecto"
+ When I cd to "projecto"
+ And I write to "Gemfile" with:
+ """
+ source "http://rubygems.org"
+ gem "rake"
+ gem "factory_girl"
+ """
+ When I add "appraisal" from this project as a dependency
+ And I write to "Appraisals" with:
+ """
+ appraise "1.3.2" do
+ gem "factory_girl", "1.3.2"
+ end
+ appraise "1.3.0" do
+ gem "factory_girl", "1.3.0"
+ end
+ """
+ When I write to "Rakefile" with:
+ """
+ require 'rubygems'
+ require 'bundler/setup'
+ require 'appraisal'
+ task :version do
+ require 'factory_girl'
+ puts "Loaded #{Factory::VERSION}"
+ end
+ task :default => :version
+ """
+ When I successfully run "rake appraisal:install --trace"
+
+ @disable-bundler
+ Scenario: run a specific task with one appraisal
+ When I successfully run "rake appraisal:1.3.0 version --trace"
+ Then the output should contain "Loaded 1.3.0"
+
+ @disable-bundler
+ Scenario: run a specific task with all appraisals
+ When I successfully run "rake appraisal version --trace"
+ Then the output should contain "Loaded 1.3.0"
+ And the output should contain "Loaded 1.3.2"
+ And the output should not contain "Invoke version"
+
+ @disable-bundler
+ Scenario: run the default task with one appraisal
+ When I successfully run "rake appraisal:1.3.0 --trace"
+ Then the output should contain "Loaded 1.3.0"
+
+ @disable-bundler
+ Scenario: run the default task with all appraisals
+ When I successfully run "rake appraisal --trace"
+ Then the output should contain "Loaded 1.3.0"
+ And the output should contain "Loaded 1.3.2"
+
4 features/step_definitions/dependency_steps.rb
@@ -0,0 +1,4 @@
+When /^I add "([^"]*)" from this project as a dependency$/ do |gem_name|
+ append_to_file('Gemfile', %{\ngem "#{gem_name}", :path => "#{PROJECT_ROOT}"})
+end
+
4 features/support/env.rb
@@ -0,0 +1,4 @@
+require 'aruba'
+
+PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..')).freeze
+
4 lib/appraisal.rb
@@ -0,0 +1,4 @@
+require 'appraisal/task'
+
+Appraisal::Task.new
+
46 lib/appraisal/appraisal.rb
@@ -0,0 +1,46 @@
+require 'appraisal/gemfile'
+require 'appraisal/command'
+require 'fileutils'
+
+module Appraisal
+ # Represents one appraisal and its dependencies
+ class Appraisal
+ attr_reader :name, :gemfile
+
+ def initialize(name, source_gemfile)
+ @name = name
+ @gemfile = source_gemfile.dup
+ end
+
+ def gem(name, *requirements)
+ gemfile.gem(name, *requirements)
+ end
+
+ def write_gemfile
+ ::File.open(gemfile_path, "w") do |file|
+ file.puts("# This file was generated by Appraisal")
+ file.puts
+ file.write(gemfile.to_s)
+ end
+ end
+
+ def install
+ Command.new("bundle install --gemfile=#{gemfile_path}").run
+ end
+
+ def gemfile_path
+ unless ::File.exist?(gemfile_root)
+ FileUtils.mkdir(gemfile_root)
+ end
+
+ ::File.join(gemfile_root, "#{name}.gemfile")
+ end
+
+ private
+
+ def gemfile_root
+ "gemfiles"
+ end
+ end
+end
+
53 lib/appraisal/command.rb
@@ -0,0 +1,53 @@
+module Appraisal
+ # Executes commands with a clean environment
+ class Command
+ BUNDLER_ENV_VARS = %w(RUBYOPT BUNDLE_PATH BUNDLE_BIN_PATH BUNDLE_GEMFILE).freeze
+
+ def self.from_args(gemfile)
+ command = ([$0] + ARGV.slice(1, ARGV.size)).join(' ')
+ new(command, gemfile)
+ end
+
+ def initialize(command, gemfile = nil)
+ @original_env = {}
+ @gemfile = gemfile
+ @command = command
+ end
+
+ def run
+ announce
+ with_clean_env { Kernel.system(@command) }
+ end
+
+ def exec
+ announce
+ with_clean_env { Kernel.exec(@command) }
+ end
+
+ private
+
+ def with_clean_env
+ unset_bundler_env_vars
+ ENV['BUNDLE_GEMFILE'] = @gemfile
+ yield
+ ensure
+ restore_env
+ end
+
+ def announce
+ puts ">> BUNDLE_GEMFILE=#{@gemfile} #{@command}"
+ end
+
+ def unset_bundler_env_vars
+ BUNDLER_ENV_VARS.each do |key|
+ @original_env[key] = ENV[key]
+ ENV[key] = nil
+ end
+ end
+
+ def restore_env
+ @original_env.each { |key, value| ENV[key] = value }
+ end
+ end
+end
+
27 lib/appraisal/dependency.rb
@@ -0,0 +1,27 @@
+module Appraisal
+ # Dependency on a gem and optional version requirements
+ class Dependency
+ attr_reader :name, :requirements
+
+ def initialize(name, requirements)
+ @name = name
+ @requirements = requirements
+ end
+
+ def to_s
+ gem_name = %{gem "#{name}"}
+ if requirements.nil? || requirements.empty?
+ gem_name
+ else
+ "#{gem_name}, #{inspect_requirements}"
+ end
+ end
+
+ private
+
+ def inspect_requirements
+ requirements.map { |requirement| requirement.inspect }.join(", ")
+ end
+ end
+end
+
41 lib/appraisal/file.rb
@@ -0,0 +1,41 @@
+require 'appraisal/appraisal'
+require 'appraisal/gemfile'
+
+module Appraisal
+ # Loads and parses Appraisal files
+ class File
+ attr_reader :appraisals, :gemfile
+
+ def self.each(&block)
+ new.each(&block)
+ end
+
+ def initialize
+ @appraisals = []
+ @gemfile = Gemfile.new
+ @gemfile.load('Gemfile')
+ run(IO.read(path))
+ end
+
+ def each(&block)
+ appraisals.each(&block)
+ end
+
+ def appraise(name, &block)
+ @appraisals << Appraisal.new(name, gemfile).tap do |appraisal|
+ appraisal.instance_eval(&block)
+ end
+ end
+
+ private
+
+ def run(definitions)
+ instance_eval definitions, __FILE__, __LINE__
+ end
+
+ def path
+ 'Appraisals'
+ end
+ end
+end
+
42 lib/appraisal/gemfile.rb
@@ -0,0 +1,42 @@
+require 'appraisal/dependency'
+
+module Appraisal
+ # Load bundler Gemfiles and merge dependencies
+ class Gemfile
+ attr_reader :dependencies
+
+ def initialize
+ @dependencies = {}
+ end
+
+ def load(path)
+ run(IO.read(path))
+ end
+
+ def run(definitions)
+ instance_eval(definitions, __FILE__, __LINE__)
+ end
+
+ def gem(name, *requirements)
+ @dependencies[name] = Dependency.new(name, requirements)
+ end
+
+ def source(source)
+ @source = source
+ end
+
+ def to_s
+ %{source "#{@source}"\n} <<
+ dependencies.values.map { |dependency| dependency.to_s }.join("\n")
+ end
+
+ def dup
+ Gemfile.new.tap do |gemfile|
+ gemfile.source @source
+ dependencies.values.each do |dependency|
+ gemfile.gem(dependency.name, *dependency.requirements)
+ end
+ end
+ end
+ end
+end
44 lib/appraisal/task.rb
@@ -0,0 +1,44 @@
+require 'appraisal/file'
+require 'rake/tasklib'
+
+module Appraisal
+ # Defines tasks for installing appraisal dependencies and running other tasks
+ # for a given appraisal.
+ class Task < Rake::TaskLib
+ def initialize
+ namespace :appraisal do
+ desc "Generate a Gemfile for each appraisal"
+ task :gemfiles do
+ File.each do |appraisal|
+ appraisal.write_gemfile
+ end
+ end
+
+ desc "Resolve and install dependencies for each appraisal"
+ task :install => :gemfiles do
+ File.each do |appraisal|
+ appraisal.install
+ end
+ end
+
+ File.each do |appraisal|
+ desc "Run the given task for appraisal #{appraisal.name}"
+ task appraisal.name do
+ Command.from_args(appraisal.gemfile_path).exec
+ end
+ end
+
+ task :all do
+ File.each do |appraisal|
+ Command.from_args(appraisal.gemfile_path).run
+ end
+ exit
+ end
+ end
+
+ desc "Run the given task for all appraisals"
+ task :appraisal => "appraisal:all"
+ end
+ end
+end
+
Please sign in to comment.
Something went wrong with that request. Please try again.