diff --git a/.travis.yml b/.travis.yml index b75e324..3870849 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ rvm: - 2.4.0 env: - - "RAILS_VERSION=5.0.2" + - "RAILS_VERSION=5.0.3" diff --git a/Rakefile b/Rakefile index e48a9ea..269cd35 100644 --- a/Rakefile +++ b/Rakefile @@ -4,24 +4,31 @@ require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) +task :default => :ci + task :ci => ['generate_test_gem', 'spec'] do end task :generate_test_gem => ['engine_cart:setup'] do - system("rm -rf .internal_test_gem") - gem 'rails' + destination = EngineCart.destination - rails_path = Gem.bin_path('railties', 'rails') + system("rm -rf #{destination}") + + if ENV['RAILS_VERSION'] + gem 'rails', ENV['RAILS_VERSION'] + else + gem 'rails' + end Bundler.with_clean_env do - system("#{rails_path} plugin new internal_test_gem") + system('bundle exec rails plugin new /tmp/internal_test_gem') end - system("mv internal_test_gem .internal_test_gem") + system("mv /tmp/internal_test_gem #{destination}") - IO.write(".internal_test_gem/internal_test_gem.gemspec", File.open(".internal_test_gem/internal_test_gem.gemspec") {|f| f.read.gsub(/FIXME/, "DONTCARE")}) - IO.write(".internal_test_gem/internal_test_gem.gemspec", File.open(".internal_test_gem/internal_test_gem.gemspec") {|f| f.read.gsub(/TODO/, "DONTCARE")}) - IO.write(".internal_test_gem/internal_test_gem.gemspec", File.open(".internal_test_gem/internal_test_gem.gemspec") {|f| f.read.gsub(/.*homepage.*/, "")}) + IO.write("#{destination}/internal_test_gem.gemspec", File.open("#{destination}/internal_test_gem.gemspec") {|f| f.read.gsub(/FIXME/, "DONTCARE")}) + IO.write("#{destination}/internal_test_gem.gemspec", File.open("#{destination}/internal_test_gem.gemspec") {|f| f.read.gsub(/TODO/, "DONTCARE")}) + IO.write("#{destination}/internal_test_gem.gemspec", File.open("#{destination}/internal_test_gem.gemspec") {|f| f.read.gsub(/.*homepage.*/, "")}) Rake::Task['engine_cart:inject_gemfile_extras'].invoke EngineCart.within_test_app do @@ -48,11 +55,10 @@ task :generate_test_gem => ['engine_cart:setup'] do system %Q{echo '\ngem "sprockets", "~> 2.11.0"\n' >> Gemfile} end Bundler.clean_system "bundle update --quiet" - system "echo 'require \"engine_cart/rake_task\"\n' >> Rakefile" + system "echo 'require \"engine_cart/rake_task\"\n' >> Rakefile" system("bundle exec rake engine_cart:prepare") Bundler.clean_system "bundle install --quiet" end end -task :default => :ci diff --git a/lib/engine_cart.rb b/lib/engine_cart.rb index d119eaa..911fc4c 100644 --- a/lib/engine_cart.rb +++ b/lib/engine_cart.rb @@ -1,13 +1,14 @@ require 'engine_cart/configuration' -require "engine_cart/version" +require 'engine_cart/fingerprint' +require 'engine_cart/version' require 'engine_cart/gemfile_stanza' require 'bundler' module EngineCart - require "engine_cart/engine" if defined? Rails + require 'engine_cart/engine' if defined? Rails - def self.load_application! path = nil - require File.expand_path("config/environment", path || EngineCart.destination) + def self.load_application!(path = nil) + require File.expand_path('config/environment', path || EngineCart.destination) end def self.within_test_app @@ -18,30 +19,9 @@ def self.within_test_app end end - def self.fingerprint - @fingerprint || (@fingerprint_proc || method(:default_fingerprint)).call - end - - def self.fingerprint= fingerprint - @fingerprint = fingerprint - end - - def self.fingerprint_proc= fingerprint_proc - @fingerprint_proc = fingerprint_proc - end - - def self.rails_fingerprint_proc extra_files = [] - lambda do - EngineCart.default_fingerprint + (Dir.glob("./db/migrate/*") + Dir.glob("./lib/generators/**/**") + Dir.glob("./spec/test_app_templates/**/**") + extra_files).map {|f| File.mtime(f) }.max.to_s - end - end - - def self.default_fingerprint - EngineCart.env_fingerprint + (Dir.glob("./*.gemspec") + [Bundler.default_gemfile.to_s, Bundler.default_lockfile.to_s]).map {|f| File.mtime(f) }.max.to_s - end - - def self.env_fingerprint - { 'RUBY_DESCRIPTION' => RUBY_DESCRIPTION, 'BUNDLE_GEMFILE' => Bundler.default_gemfile.to_s }.reject { |k, v| v.nil? || v.empty? }.to_s + def self.update?(fingerprint) + return true if EngineCart.fingerprint_saved.nil? || fingerprint.nil? + EngineCart.fingerprint_saved != fingerprint end def self.configuration(options = {}) diff --git a/lib/engine_cart/configuration.rb b/lib/engine_cart/configuration.rb index 093136e..694b48e 100644 --- a/lib/engine_cart/configuration.rb +++ b/lib/engine_cart/configuration.rb @@ -11,15 +11,15 @@ def initialize(options = {}) end def load_configs(config_files) - config = default_config - - (default_configuration_paths + config_files.compact).each do |p| - path = File.expand_path(p) - next unless File.exist? path - config.merge!(read_config(path)) + @config ||= begin + cfg = default_config + (default_configuration_paths + config_files.compact).each do |p| + path = File.expand_path(p) + next unless File.exist? path + cfg.merge!(read_config(path)) + end + cfg end - - config end ## @@ -79,12 +79,12 @@ def default_config def read_config(config_file) $stdout.puts "Loading configuration from #{config_file}" if verbose? - config = YAML.load(ERB.new(IO.read(config_file)).result(binding)) - unless config + cfg = YAML.load(ERB.new(IO.read(config_file)).result(binding)) + unless cfg $stderr.puts "Unable to parse config #{config_file}" if verbose? return {} end - convert_keys(config) + convert_keys(cfg) end def convert_keys(hash) @@ -95,4 +95,4 @@ def default_configuration_paths ['~/.engine_cart.yml', '.engine_cart.yml'] end end -end \ No newline at end of file +end diff --git a/lib/engine_cart/fingerprint.rb b/lib/engine_cart/fingerprint.rb new file mode 100644 index 0000000..d0d8a8a --- /dev/null +++ b/lib/engine_cart/fingerprint.rb @@ -0,0 +1,96 @@ +require 'bundler' +require 'digest/md5' + +module EngineCart + + def self.fingerprint_current + (@fingerprint_proc || method(:default_fingerprint)).call + end + + def self.fingerprint_saved + File.read(EngineCart.fingerprint_file) + rescue StandardError + nil + end + + def self.fingerprint_save(fp) + fp ||= EngineCart.fingerprint_current + File.open(EngineCart.fingerprint_file, 'w') { |f| f.write(fp) } + end + + def self.fingerprint_update + EngineCart.fingerprint = EngineCart.fingerprint_current + EngineCart.fingerprint_save EngineCart.fingerprint + end + + def self.fingerprint_file + File.expand_path('.generated_engine_cart', EngineCart.destination) + end + + def self.fingerprint + @fingerprint || EngineCart.fingerprint_current + end + + def self.fingerprint=(fp) + @fingerprint = fp + end + + def self.fingerprint_proc=(fingerprint_proc) + @fingerprint_proc = fingerprint_proc + end + + def self.rails_fingerprint_proc(extra_files = []) + lambda do + EngineCart.default_fingerprint + EngineCart.rails_fingerprint(extra_files) + end + end + + def self.rails_fingerprint(extra_files = []) + EngineCart.files_digest(EngineCart.rails_files + extra_files) + end + + def self.rails_files + Dir.glob([ + './db/migrate/*', + './lib/generators/**/**', + './spec/test_app_templates/**/**' + ]) + end + + def self.default_fingerprint + EngineCart.env_fingerprint + EngineCart.gem_fingerprint + end + + def self.gem_fingerprint + EngineCart.files_digest EngineCart.gem_files + end + + def self.gem_files + Dir.glob('./*.gemspec') + [EngineCart.bundle_gemfile, EngineCart.bundle_lockfile] + end + + def self.env_fingerprint + { + 'RUBY_DESCRIPTION' => RUBY_DESCRIPTION, + 'BUNDLE_GEMFILE' => EngineCart.bundle_gemfile + }.reject { |k, v| v.nil? || v.empty? }.to_s + end + + def self.bundle_gemfile + @bundle_gemfile ||= Bundler.default_gemfile.to_s + end + + def self.bundle_lockfile + @bundle_gemfile ||= Bundler.default_lockfile.to_s + end + + def self.files_digest(files) + files_digests = files.collect {|f| file_digest(f) }.join + Digest::MD5.hexdigest(files_digests) + end + + def self.file_digest(f) + File.file?(f) ? Digest::MD5.hexdigest(File.read(f)) : '' + end + +end diff --git a/lib/engine_cart/tasks/engine_cart.rake b/lib/engine_cart/tasks/engine_cart.rake index e5a5061..65f6fdb 100644 --- a/lib/engine_cart/tasks/engine_cart.rake +++ b/lib/engine_cart/tasks/engine_cart.rake @@ -78,11 +78,7 @@ namespace :engine_cart do desc "Create the test rails app" task :generate, [:fingerprint] => [:setup] do |t, args| - original_fingerprint = args[:fingerprint] - args.with_defaults(:fingerprint => EngineCart.fingerprint) unless original_fingerprint - - f = File.expand_path('.generated_engine_cart', EngineCart.destination) - unless File.exist?(f) && File.read(f) == args[:fingerprint] + if EngineCart.update? args[:fingerprint] # Create a new test rails app Rake::Task['engine_cart:create_test_rails_app'].invoke @@ -106,7 +102,7 @@ namespace :engine_cart do Bundler.clean_system "bundle install --quiet" - File.open(File.expand_path('.generated_engine_cart', EngineCart.destination), 'w') { |f| f.write(original_fingerprint || EngineCart.fingerprint) } + EngineCart.fingerprint_update puts "Done generating test app" end diff --git a/lib/generators/engine_cart/install_generator.rb b/lib/generators/engine_cart/install_generator.rb index 4d857d7..8e1b753 100644 --- a/lib/generators/engine_cart/install_generator.rb +++ b/lib/generators/engine_cart/install_generator.rb @@ -32,7 +32,9 @@ def install_engine end end - def ignore_test_app + def ignore_test_app(app_path = nil) + app_path ||= EngineCart.destination + # Ignore the generated test app in the gem's .gitignore file git_root = (`git rev-parse --show-toplevel` rescue '.').strip @@ -40,10 +42,10 @@ def ignore_test_app return unless File.exist? File.expand_path('.gitignore', git_root) # If the directory is already ignored (somehow) don't worry about it - return if (system('git', 'check-ignore', TEST_APP, '-q') rescue false) + return if (system('git', 'check-ignore', app_path, '-q') rescue false) - append_file File.expand_path('.gitignore', git_root) do - "\n#{EngineCart.destination}\n" + append_file File.expand_path('.gitignore', git_root) do + "\n#{app_path}\n" end end diff --git a/spec/integration/engine_cart_spec.rb b/spec/integration/engine_cart_spec.rb index 14e0acb..99473bf 100644 --- a/spec/integration/engine_cart_spec.rb +++ b/spec/integration/engine_cart_spec.rb @@ -1,13 +1,21 @@ require 'spec_helper' describe "EngineCart powered application" do + + # EngineCart.destination can be defined by various config files and options. + # The engine_cart gem contains a .engine_cart.yml file, with destination: '.internal_test_gem' + let(:destination) { EngineCart.destination } + + # The test app does not use a .engine_cart.yml file, so it uses a default destination: '.internal_test_app' + let(:default_destination) { EngineCart.configuration.default_destination } + it "should have the test_app_templates pre-generated" do expect(File).to exist File.expand_path("spec/test_app_templates", EngineCart.destination) end it "should ignore the test app" do git_ignore = File.expand_path(".gitignore", EngineCart.destination) - expect(File.read(git_ignore)).to match /.internal_test_app/ + expect(File.read(git_ignore)).to match /#{default_destination}/ end it "should have a engine_cart:generate rake task available" do @@ -27,27 +35,28 @@ it "should create a rails app when the engine_cart:generate task is invoked" do EngineCart.within_test_app do `rake engine_cart:generate` - expect(File).to exist(File.expand_path('.internal_test_app')) + expect(File).to exist(File.expand_path(default_destination)) end end it "should not recreate an existing rails app when the engine_cart:generate task is reinvoked" do EngineCart.within_test_app do `rake engine_cart:generate` - expect(File).to exist(File.expand_path('.internal_test_app')) - FileUtils.touch File.join('.internal_test_app', ".this_should_still_exist") + expect(File).to exist(File.expand_path(default_destination)) + tmp_file_path = File.expand_path(File.join(default_destination, ".this_should_still_exist")) + FileUtils.touch tmp_file_path `rake engine_cart:generate` - expect(File).to exist(File.expand_path(File.join('.internal_test_app', ".this_should_still_exist"))) + expect(File).to exist(tmp_file_path) end end it "should create a rails app when the fingerprint argument is changed" do EngineCart.within_test_app do `rake engine_cart:generate[this-fingerprint]` - expect(File).to exist(File.expand_path('.internal_test_app')) - FileUtils.touch File.join('.internal_test_app', ".this_should_not_exist") + expect(File).to exist(File.expand_path(default_destination)) + FileUtils.touch File.join(default_destination, ".this_should_not_exist") `rake engine_cart:generate[that-fingerprint]` - expect(File).to_not exist(File.expand_path(File.join('.internal_test_app', ".this_should_not_exist"))) + expect(File).to_not exist(File.expand_path(File.join(default_destination, ".this_should_not_exist"))) end end