Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge pull request #3 from fny/master

Update to latest build pack
  • Loading branch information...
commit 2fc5560e7ee61afe5c3505a1877f3f92f29652f6 2 parents 46a664b + 3b67683
@ndbroadbent authored
View
1  .gitignore
@@ -1,3 +1,4 @@
repos/*
+.DS_Store
vendor/bundler/*
vendor/bundle/*
View
21 .travis.yml
@@ -0,0 +1,21 @@
+---
+language: ruby
+rvm:
+- 2.0.0
+
+before_script: bundle exec rake hatchet:setup_travis
+
+# Run tests in parallel
+script: bundle exec parallel_rspec -n 7 spec/
+
+after_script:
+ - heroku keys:remove ~/.ssh/id_rsa
+
+env:
+ global:
+ - HATCHET_RETRIES=3
+ # sets the HEROKU_API_KEY to a dummy user for Heroku deploys
+ - secure: |-
+ ccqb7fKumq2+VEkSrkCqmLjALj5R/ZDgAQGZULSFYeD0O0man3hezUEbMB53
+ U+7gLkbqz5saFX9S5Sz26f99vmhWz1bMHkC2UtlyFSlgaqSvXMZNHJAweqRY
+ ptqugqtvT0VVl1g3DInVgjDZhjINICv/CIorNuHijOFanP1Zmxg=
View
43 CHANGELOG.md
@@ -1,3 +1,46 @@
+## v64 (6/19/2013)
+
+Features:
+
+* only download one copy of bundler per process (@dpiddy, #69)
+* roll up all warnings for end of push output
+* write database.yml for Rails 4
+
+Bugfixes:
+
+* fix sqlite3 error messaging detection
+
+## v63 (6/17/2013)
+
+Features:
+
+* Lock default ruby if default ruby is used
+* Change default ruby to 2.0.0
+* Stop using the stack image ruby and always vendor ruby
+
+## v62 (5/21/2013)
+
+Bugfixes:
+
+* Correctly detect asset manifest files in Rails 4
+* Fix jruby 1.8.7 bundler/psych require bug
+
+## v61 (4/18/2013)
+
+Features:
+
+* Start caching the rubygems version used.
+
+Bugfixes:
+
+* Rebuild bundler cache if rubygems 2 is detected. Bugfixes in later rubygems.
+
+## v60 (4/17/2013)
+
+Security:
+
+* Disable Java RMI Remote Classloading for CVE-2013-1537, <https://bugzilla.redhat.com/show_bug.cgi?id=952387>
+
## v59 (4/4/2013)
Bugfixes:
View
8 Gemfile
@@ -1,9 +1,11 @@
-source "http://rubygems.org"
+source "https://rubygems.org"
-group :development do
- gem "hatchet", :github => 'heroku/hatchet', :branch => 'master'
+group :development, :test do
+ gem "heroku_hatchet"
gem "rspec-core"
gem "rspec-expectations"
gem "excon"
gem "rake"
+ gem "parallel_tests"
+ gem 'rspec-retry'
end
View
48 Gemfile.lock
@@ -1,39 +1,45 @@
-GIT
- remote: git://github.com/heroku/hatchet.git
- revision: d0f100bf3ad3e9e3d70a30ea95fb7d8a47238eef
- branch: master
- specs:
- hatchet (0.0.1)
- activesupport
- anvil-cli
- excon
- heroku-api
- thor
-
GEM
- remote: http://rubygems.org/
+ remote: https://rubygems.org/
specs:
activesupport (3.2.13)
i18n (= 0.6.1)
multi_json (~> 1.0)
- anvil-cli (0.15.0)
+ anvil-cli (0.16.0)
progress (~> 2.4.0)
rest-client (~> 1.6.7)
thor (~> 0.15.2)
diff-lcs (1.1.3)
- excon (0.16.10)
- heroku-api (0.3.8)
- excon (~> 0.16.10)
+ excon (0.25.0)
+ heroku-api (0.3.13)
+ excon (~> 0.25.0)
+ heroku_hatchet (0.2.0)
+ activesupport
+ anvil-cli
+ excon
+ heroku-api
+ rrrretry
+ thor
i18n (0.6.1)
- mime-types (1.21)
- multi_json (1.7.2)
+ mime-types (1.23)
+ multi_json (1.7.7)
+ parallel (0.6.5)
+ parallel_tests (0.13.1)
+ parallel
progress (2.4.0)
rake (10.0.4)
rest-client (1.6.7)
mime-types (>= 1.16)
+ rrrretry (0.0.1)
+ rspec (2.2.0)
+ rspec-core (~> 2.2)
+ rspec-expectations (~> 2.2)
+ rspec-mocks (~> 2.2)
rspec-core (2.13.1)
rspec-expectations (2.12.1)
diff-lcs (~> 1.1.3)
+ rspec-mocks (2.13.1)
+ rspec-retry (0.2.1)
+ rspec
thor (0.15.4)
PLATFORMS
@@ -41,7 +47,9 @@ PLATFORMS
DEPENDENCIES
excon
- hatchet!
+ heroku_hatchet
+ parallel_tests
rake
rspec-core
rspec-expectations
+ rspec-retry
View
14 README.md
@@ -35,7 +35,11 @@ The buildpack will detect your app as Ruby if it has a `Gemfile` and `Gemfile.lo
#### Run the Tests
-Clone the repo, then `bundle install` then clone the test fixtures by running:
+The tests on this buildpack are written in Rspec to allow the use of
+`focused: true`. Parallelization of testing is provided by
+https://github.com/grosser/parallel_tests this lib spins up an arbitrary
+number of processes and running a different test file in each process,
+it does not parallelize tests within a test file. To run the tests: clone the repo, then `bundle install` then clone the test fixtures by running:
```sh
$ hatchet install
@@ -44,7 +48,13 @@ $ hatchet install
Now run the tests:
```sh
-$ bundle exec rspec spec
+$ bundle exec parallel_rspec -n 6 spec/
+```
+
+If you don't want to run them in parallel you can still:
+
+```sh
+$ bundle exec rake spec
```
Now go take a nap or something for a really long time.
View
3  Rakefile
@@ -1,5 +1,6 @@
require "fileutils"
require "tmpdir"
+require 'hatchet/tasks'
S3_BUCKET_NAME = "heroku-buildpack-ruby"
VENDOR_URL = "https://s3.amazonaws.com/#{S3_BUCKET_NAME}"
@@ -144,7 +145,7 @@ task "node:install", :version do |t, args|
"rm -rf #{prefix}/bin"
].join(" && ")
- sh "vulcan build -v -o #{name}.tgz --source node-v#{version} --command=\"#{build_command}\""
+ sh "vulcan build -v -o #{name}.tgz --source node-v#{version} --command=\"#{build_command}\" --prefix=\"#{prefix}\""
s3_upload(tmpdir, name)
end
end
View
24 hatchet.json
@@ -1,22 +1,26 @@
{
"bundler": [
- "git@github.com:georgewashington/git_gemspec.git",
- "git@github.com:georgewashington/no_lockfile.git"
+ "sharpstone/git_gemspec",
+ "sharpstone/no_lockfile",
+ "sharpstone/sqlite3_gemfile"
],
"ruby": [
- "git@github.com:georgewashington/mri_187.git"
+ "sharpstone/mri_187"
],
"rack": [
- "git@github.com:georgewashington/mri_187_nokogiri.git",
- "git@github.com:georgewashington/mri_192.git",
- "git@github.com:georgewashington/mri_193.git",
- "git@github.com:georgewashington/mri_200.git"
+ "sharpstone/mri_187_nokogiri",
+ "sharpstone/mri_192",
+ "sharpstone/mri_193",
+ "sharpstone/mri_200"
],
"rails2": [
- "git@github.com:georgewashington/rails23_mri_187.git"
+ "sharpstone/rails23_mri_187"
],
"rails3": [
- "git@github.com:georgewashington/rails3_mri_193.git",
- "git@github.com:georgewashington/railties3_mri_193.git"
+ "sharpstone/rails3_mri_193",
+ "sharpstone/railties3_mri_193"
+ ],
+ "rails4": [
+ "sharpstone/rails4-manifest"
]
}
View
59 lib/language_pack/base.rb
@@ -3,6 +3,8 @@
require "yaml"
require "digest/sha1"
require "language_pack/shell_helpers"
+require "language_pack/cache"
+require "language_pack/metadata"
Encoding.default_external = Encoding::UTF_8 if defined?(Encoding)
@@ -12,15 +14,17 @@ class LanguagePack::Base
VENDOR_URL = "https://s3.amazonaws.com/heroku-buildpack-ruby"
- attr_reader :build_path, :cache_path
+ attr_reader :build_path, :cache
# changes directory to the build_path
# @param [String] the path of the build dir
- # @param [String] the path of the cache dir
+ # @param [String] the path of the cache dir this is nil during detect and release
def initialize(build_path, cache_path=nil)
@build_path = build_path
- @cache_path = cache_path
- @id = Digest::SHA1.hexdigest("#{Time.now.to_f}-#{rand(1000000)}")[0..10]
+ @cache = LanguagePack::Cache.new(cache_path) if cache_path
+ @metadata = LanguagePack::Metadata.new(@cache)
+ @id = Digest::SHA1.hexdigest("#{Time.now.to_f}-#{rand(1000000)}")[0..10]
+ @warnings = []
Dir.chdir build_path
end
@@ -56,6 +60,10 @@ def default_process_types
# this is called to build the slug
def compile
+ if @warnings.any?
+ topic "WARNINGS:"
+ puts @warnings.join("--\n")
+ end
end
# collection of values passed for a release
@@ -128,48 +136,5 @@ def build_log_message(args)
end
end.join(" ")
end
-
- # create a Pathname of the cache dir
- # @return [Pathname] the cache dir
- def cache_base
- Pathname.new(cache_path)
- end
-
- # removes the the specified
- # @param [String] relative path from the cache_base
- def cache_clear(path)
- target = (cache_base + path)
- target.exist? && target.rmtree
- end
-
- # write cache contents
- # @param [String] path of contents to store. it will be stored using this a relative path from the cache_base.
- # @param [Boolean] defaults to true. if set to true, the cache store directory will be cleared before writing to it.
- def cache_store(path, clear_first=true)
- cache_clear(path) if clear_first
- cache_copy path, (cache_base + path)
- end
-
- # load cache contents
- # @param [String] relative path of the cache contents
- def cache_load(path)
- cache_copy (cache_base + path), path
- end
-
- # copy cache contents
- # @param [String] source directory
- # @param [String] destination directory
- def cache_copy(from, to)
- return false unless File.exist?(from)
- FileUtils.mkdir_p File.dirname(to)
- system("cp -a #{from}/. #{to}")
- end
-
- # check if the cache content exists
- # @param [String] relative path of the cache contents
- # @param [Boolean] true if the path exists in the cache and false if otherwise
- def cache_exists?(path)
- File.exists?(cache_base + path)
- end
end
View
41 lib/language_pack/bundler_lockfile.rb
@@ -1,19 +1,40 @@
module LanguagePack
module BundlerLockfile
- # checks if the Gemfile and Gemfile.lock exist
- def gemfile_lock?
- File.exist?('Gemfile') && File.exist?('Gemfile.lock')
- end
+ module ClassMethods
+ # checks if the Gemfile and Gemfile.lock exist
+ def gemfile_lock?
+ File.exist?('Gemfile') && File.exist?('Gemfile.lock')
+ end
+
+ def bundle
+ @bundle ||= parse_bundle
+ end
+
+ def bundler_path
+ @bundler_path ||= fetch_bundler
+ end
- # bootstraps bundler so we can use it before bundler is setup properlyLanguagePack::Ruby
- def bootstrap_bundler(&block)
- Dir.mktmpdir("bundler-") do |tmpdir|
- Dir.chdir(tmpdir) do
- system("curl #{LanguagePack::Base::VENDOR_URL}/#{LanguagePack::Ruby::BUNDLER_GEM_PATH}.tgz -s -o - | tar xzf -")
+ def fetch_bundler
+ Dir.mktmpdir("bundler-").tap do |dir|
+ Dir.chdir(dir) do
+ system("curl #{LanguagePack::Base::VENDOR_URL}/#{LanguagePack::Ruby::BUNDLER_GEM_PATH}.tgz -s -o - | tar xzf -")
+ end
end
+ end
- yield tmpdir
+ def parse_bundle
+ $: << "#{bundler_path}/gems/bundler-#{LanguagePack::Ruby::BUNDLER_VERSION}/lib"
+ require "bundler"
+ Bundler::LockfileParser.new(File.read("Gemfile.lock"))
end
end
+
+ def bundle
+ self.class.bundle
+ end
+
+ def bundler_path
+ self.class.bundler_path
+ end
end
end
View
45 lib/language_pack/cache.rb
@@ -0,0 +1,45 @@
+require "pathname"
+require "language_pack"
+
+class LanguagePack::Cache
+ def initialize(cache_path)
+ @cache_base = Pathname.new(cache_path)
+ end
+
+ # removes the the specified
+ # @param [String] relative path from the cache_base
+ def clear(path)
+ target = (@cache_base + path)
+ target.exist? && target.rmtree
+ end
+
+ # write cache contents
+ # @param [String] path of contents to store. it will be stored using this a relative path from the cache_base.
+ # @param [Boolean] defaults to true. if set to true, the cache store directory will be cleared before writing to it.
+ def store(path, clear_first=true)
+ clear(path) if clear_first
+ copy path, (@cache_base + path)
+ end
+
+ # load cache contents
+ # @param [String] relative path of the cache contents
+ def load(path)
+ copy (@cache_base + path), path
+ end
+
+ # copy cache contents
+ # @param [String] source directory
+ # @param [String] destination directory
+ def copy(from, to)
+ return false unless File.exist?(from)
+ FileUtils.mkdir_p File.dirname(to)
+ system("cp -a #{from}/. #{to}")
+ end
+
+ # check if the cache content exists
+ # @param [String] relative path of the cache contents
+ # @param [Boolean] true if the path exists in the cache and false if otherwise
+ def exists?(path)
+ File.exists?(@cache_base + path)
+ end
+end
View
35 lib/language_pack/metadata.rb
@@ -0,0 +1,35 @@
+require "language_pack"
+require "language_pack/base"
+
+class LanguagePack::Metadata
+ FOLDER = "vendor/heroku"
+
+ def initialize(cache)
+ if cache
+ @cache = cache
+ @cache.load FOLDER
+ end
+ end
+
+ def read(key)
+ full_key = "#{FOLDER}/#{key}"
+ File.read(full_key) if exists?(key)
+ end
+
+ def exists?(key)
+ full_key = "#{FOLDER}/#{key}"
+ File.exists?(full_key) && !Dir.exists?(full_key)
+ end
+
+ def write(key, value, isave = true)
+ FileUtils.mkdir_p(FOLDER)
+
+ full_key = "#{FOLDER}/#{key}"
+ File.open(full_key, 'w') {|f| f.puts value }
+ save if isave
+ end
+
+ def save
+ @cache ? @cache.store(FOLDER) : false
+ end
+end
View
6 lib/language_pack/rails2.rb
@@ -58,8 +58,10 @@ def plugin_root
# vendors all the plugins into the slug
def install_plugins
- topic "Rails plugin injection"
- plugins.each { |plugin| install_plugin(plugin) }
+ if plugins.any?
+ topic "Rails plugin injection"
+ plugins.each { |plugin| install_plugin(plugin) }
+ end
end
# vendors an individual plugin
View
8 lib/language_pack/rails3.rb
@@ -45,7 +45,7 @@ def run_assets_precompile_rake_task
puts "Detected manifest.yml, assuming assets were compiled locally"
else
FileUtils.mkdir_p('public')
- cache_load "public/assets"
+ cache.load "public/assets"
ENV["RAILS_GROUPS"] ||= "assets"
ENV["RAILS_ENV"] ||= "production"
@@ -65,14 +65,14 @@ def run_assets_precompile_rake_task
run("env PATH=$PATH:bin bundle exec rake assets:clean_expired 2>&1")
if $?.success?
log "assets_clean_expired", :status => "success"
- cache_store "public/assets"
+ cache.store "public/assets"
else
log "assets_clean_expired", :status => "failure"
- cache_clear "public/assets"
+ cache.clear "public/assets"
end
end
else
- cache_clear "public/assets"
+ cache.clear "public/assets"
end
else
log "assets_precompile", :status => "failure"
View
43 lib/language_pack/rails4.rb
@@ -17,39 +17,65 @@ def name
end
def default_process_types
- web_process = gem_is_bundled?("thin") ?
- "bin/rails server thin -p $PORT -e $RAILS_ENV" :
- "bin/rails server -p $PORT -e $RAILS_ENV"
super.merge({
- "web" => web_process,
+ "web" => "bin/rails server -p $PORT -e $RAILS_ENV",
"console" => "bin/rails console"
})
end
+ def build_bundler
+ super
+ check_for_rails_gems
+ end
+
private
+ def rails_gems
+ %w(rails_stdout_logging rails_serve_static_assets)
+ end
+
+ def check_for_rails_gems
+ if rails_gems.any? {|gem| !gem_is_bundled?(gem) }
+ warn(<<WARNING)
+Include "rails_12factor" gem to enable all platform features
+See https://devcenter.heroku.com/articles/rails-integration-gems for more information.
+WARNING
+ end
+ end
+
def plugins
[]
end
+ def public_assets_folder
+ "public/assets"
+ end
+
def run_assets_precompile_rake_task
log("assets_precompile") do
setup_database_url_env
if rake_task_defined?("assets:precompile")
topic("Preparing app for Rails asset pipeline")
- if File.exists?("public/assets/manifest.yml")
- puts "Detected manifest.yml, assuming assets were compiled locally"
+ if Dir.glob('public/assets/manifest-*.json').any?
+ puts "Detected manifest file, assuming assets were compiled locally"
else
ENV["RAILS_GROUPS"] ||= "assets"
ENV["RAILS_ENV"] ||= "production"
+ @cache.load public_assets_folder
+
puts "Running: rake assets:precompile"
require 'benchmark'
- time = Benchmark.realtime { pipe("env PATH=$PATH:bin bundle exec rake assets:precompile 2>&1") }
+ time = Benchmark.realtime { pipe("env PATH=$PATH:bin bundle exec rake assets:precompile 2>&1 > /dev/null") }
if $?.success?
log "assets_precompile", :status => "success"
puts "Asset precompilation completed (#{"%.2f" % time}s)"
+
+ puts "Cleaning assets"
+ pipe "env PATH=$PATH:bin bundle exec rake assets:clean 2>& 1"
+
+ @cache.store public_assets_folder
else
log "assets_precompile", :status => "failure"
error "Precompiling assets failed."
@@ -60,7 +86,4 @@ def run_assets_precompile_rake_task
end
end
end
-
- def create_database_yml
- end
end
View
220 lib/language_pack/ruby.rb
@@ -7,17 +7,18 @@
# base Ruby Language Pack. This is for any base ruby app.
class LanguagePack::Ruby < LanguagePack::Base
include LanguagePack::BundlerLockfile
- extend LanguagePack::BundlerLockfile
-
- BUILDPACK_VERSION = "v59"
- LIBYAML_VERSION = "0.1.4"
- LIBYAML_PATH = "libyaml-#{LIBYAML_VERSION}"
- BUNDLER_VERSION = "1.3.2"
- BUNDLER_GEM_PATH = "bundler-#{BUNDLER_VERSION}"
- NODE_VERSION = "0.4.7"
- NODE_JS_BINARY_PATH = "node-#{NODE_VERSION}"
- JVM_BASE_URL = "http://heroku-jdk.s3.amazonaws.com"
- JVM_VERSION = "openjdk7-latest"
+ extend LanguagePack::BundlerLockfile::ClassMethods
+
+ BUILDPACK_VERSION = "v64"
+ LIBYAML_VERSION = "0.1.4"
+ LIBYAML_PATH = "libyaml-#{LIBYAML_VERSION}"
+ BUNDLER_VERSION = "1.3.2"
+ BUNDLER_GEM_PATH = "bundler-#{BUNDLER_VERSION}"
+ NODE_VERSION = "0.4.7"
+ NODE_JS_BINARY_PATH = "node-#{NODE_VERSION}"
+ JVM_BASE_URL = "http://heroku-jdk.s3.amazonaws.com"
+ JVM_VERSION = "openjdk7-latest"
+ DEFAULT_RUBY_VERSION = "ruby-2.0.0"
# detects if this is a valid Ruby app
# @return [Boolean] true if it's a Ruby app
@@ -25,20 +26,10 @@ def self.use?
File.exist?("Gemfile")
end
- def self.lockfile_parser
- require "bundler"
- Bundler::LockfileParser.new(File.read("Gemfile.lock"))
- end
-
def self.gem_version(name)
- gem_version = nil
- bootstrap_bundler do |bundler_path|
- $: << "#{bundler_path}/gems/bundler-#{LanguagePack::Ruby::BUNDLER_VERSION}/lib"
- gem = lockfile_parser.specs.detect {|gem| gem.name == name }
- gem_version = gem.version if gem
+ if gem = bundle.specs.detect {|g| g.name == name }
+ gem.version
end
-
- gem_version
end
def name
@@ -56,7 +47,11 @@ def default_config_vars
"GEM_PATH" => slug_vendor_base,
}
- ruby_version_jruby? ? vars.merge("JAVA_OPTS" => default_java_opts, "JRUBY_OPTS" => default_jruby_opts) : vars
+ ruby_version_jruby? ? vars.merge({
+ "JAVA_OPTS" => default_java_opts,
+ "JRUBY_OPTS" => default_jruby_opts,
+ "JAVA_TOOL_OPTIONS" => default_java_tool_options
+ }) : vars
end
def default_process_types
@@ -80,6 +75,7 @@ def compile
install_binaries
run_assets_precompile_rake_task
end
+ super
end
private
@@ -87,7 +83,7 @@ def compile
# the base PATH environment variable to be used
# @return [String] the resulting PATH
def default_path
- "bin:#{slug_vendor_base}/bin:/usr/local/bin:/usr/bin:/bin"
+ "bin:#{bundler_binstubs_path}:/usr/local/bin:/usr/bin:/bin"
end
# the relative path to the bundler directory of gems
@@ -125,12 +121,12 @@ def build_ruby_path
def ruby_version
return @ruby_version if @ruby_version_run
- @ruby_version_run = true
+ @ruby_version_run = true
+ @ruby_version_env_var = false
+ @ruby_version_set = false
- bootstrap_bundler do |bundler_path|
- old_system_path = "/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
- @ruby_version = run_stdout("env PATH=#{old_system_path}:#{bundler_path}/bin GEM_PATH=#{bundler_path} bundle platform --ruby").chomp
- end
+ old_system_path = "/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin"
+ @ruby_version = run_stdout("env PATH=#{old_system_path}:#{bundler_path}/bin GEM_PATH=#{bundler_path} bundle platform --ruby").chomp
if @ruby_version == "No ruby version specified" && ENV['RUBY_VERSION']
# for backwards compatibility.
@@ -138,10 +134,16 @@ def ruby_version
@ruby_version = ENV['RUBY_VERSION']
@ruby_version_env_var = true
elsif @ruby_version == "No ruby version specified"
- @ruby_version = nil
+ if new_app?
+ @ruby_version = DEFAULT_RUBY_VERSION
+ elsif !@metadata.exists?("buildpack_ruby_version")
+ @ruby_version = "ruby-1.9.2"
+ else
+ @ruby_version = @metadata.read("buildpack_ruby_version").chomp
+ end
else
- @ruby_version = @ruby_version.sub('(', '').sub(')', '').split.join('-')
- @ruby_version_env_var = false
+ @ruby_version = @ruby_version.sub('(', '').sub(')', '').split.join('-')
+ @ruby_version_set = true
end
@ruby_version
@@ -171,6 +173,12 @@ def default_jruby_opts
"-Xcompile.invokedynamic=true"
end
+ # default JAVA_TOOL_OPTIONS
+ # return [String] string of JAVA_TOOL_OPTIONS
+ def default_java_tool_options
+ "-Djava.rmi.server.useCodebaseOnly=true"
+ end
+
# list the available valid ruby versions
# @note the value is memoized
# @return [Array] list of Strings of the ruby versions available
@@ -195,7 +203,7 @@ def setup_language_pack_environment
ENV[key] ||= value
end
ENV["GEM_HOME"] = slug_vendor_base
- ENV["PATH"] = "#{ruby_install_binstub_path}:#{config_vars["PATH"]}"
+ ENV["PATH"] = "#{ruby_install_binstub_path}:#{slug_vendor_base}/bin:#{config_vars["PATH"]}"
end
# sets up the profile.d script for this buildpack
@@ -207,6 +215,7 @@ def setup_profiled
if ruby_version_jruby?
set_env_default "JAVA_OPTS", default_java_opts
set_env_default "JRUBY_OPTS", default_jruby_opts
+ set_env_default "JAVA_TOOL_OPTIONS", default_java_tool_options
end
end
@@ -247,17 +256,33 @@ def install_ruby
run("ln -s ../#{bin} #{bin_dir}")
end
+ @metadata.write("buildpack_ruby_version", ruby_version)
+
if !@ruby_version_env_var
topic "Using Ruby version: #{ruby_version}"
+ if !@ruby_version_set
+ warn(<<WARNING)
+you have not declared a Ruby version in your Gemfile.
+To set your Ruby version add this line to your Gemfile:"
+ruby '#{ruby_version.split("-").last}'"
+# See https://devcenter.heroku.com/articles/ruby-versions for more information."
+WARNING
+ end
else
- topic "Using RUBY_VERSION: #{ruby_version}"
- puts "WARNING: RUBY_VERSION support has been deprecated and will be removed entirely on August 1, 2012."
- puts "See https://devcenter.heroku.com/articles/ruby-versions#selecting_a_version_of_ruby for more information."
+ warn(<<WARNING)
+Using RUBY_VERSION: #{ruby_version}
+RUBY_VERSION support has been deprecated and will be removed entirely on August 1, 2012.
+See https://devcenter.heroku.com/articles/ruby-versions#selecting_a_version_of_ruby for more information.
+WARNING
end
true
end
+ def new_app?
+ !File.exist?("vendor/heroku")
+ end
+
# vendors JVM into the slug for JRuby
def install_jvm
if ruby_version_jruby?
@@ -359,38 +384,47 @@ def install_libyaml(dir)
# https://github.com/heroku/heroku-buildpack-ruby/issues/21
def remove_vendor_bundle
if File.exists?("vendor/bundle")
- topic "WARNING: Removing `vendor/bundle`."
- puts "Checking in `vendor/bundle` is not supported. Please remove this directory"
- puts "and add it to your .gitignore. To vendor your gems with Bundler, use"
- puts "`bundle pack` instead."
+ warn(<<WARNING)
+Removing `vendor/bundle`.
+Checking in `vendor/bundle` is not supported. Please remove this directory
+and add it to your .gitignore. To vendor your gems with Bundler, use
+`bundle pack` instead.
+WARNING
FileUtils.rm_rf("vendor/bundle")
end
end
+ def bundler_binstubs_path
+ "vendor/bundle/bin"
+ end
+
# runs bundler to install the dependencies
def build_bundler
log("bundle") do
bundle_without = ENV["BUNDLE_WITHOUT"] || "development:test"
- bundle_command = "bundle install --without #{bundle_without} --path vendor/bundle --binstubs vendor/bundle/bin"
+ bundle_bin = "bundle"
+ bundle_command = "#{bundle_bin} install --without #{bundle_without} --path vendor/bundle --binstubs #{bundler_binstubs_path}"
unless File.exist?("Gemfile.lock")
error "Gemfile.lock is required. Please run \"bundle install\" locally\nand commit your Gemfile.lock."
end
if has_windows_gemfile_lock?
- topic "WARNING: Removing `Gemfile.lock` because it was generated on Windows."
- puts "Bundler will do a full resolve so native gems are handled properly."
- puts "This may result in unexpected gem versions being used in your app."
+ warn(<<WARNING)
+Removing `Gemfile.lock` because it was generated on Windows.
+Bundler will do a full resolve so native gems are handled properly.
+This may result in unexpected gem versions being used in your app.
+WARNING
log("bundle", "has_windows_gemfile_lock")
File.unlink("Gemfile.lock")
else
# using --deployment is preferred if we can
bundle_command += " --deployment"
- cache_load ".bundle"
+ cache.load ".bundle"
end
- version = run("bundle version").strip
+ version = run_stdout("#{bundle_bin} version").strip
topic("Installing dependencies using #{version}")
load_bundler_cache
@@ -408,7 +442,7 @@ def build_bundler
# we need to set BUNDLE_CONFIG and BUNDLE_GEMFILE for
# codon since it uses bundler.
env_vars = "env BUNDLE_GEMFILE=#{pwd}/Gemfile BUNDLE_CONFIG=#{pwd}/.bundle/config CPATH=#{yaml_include}:$CPATH CPPATH=#{yaml_include}:$CPPATH LIBRARY_PATH=#{yaml_lib}:$LIBRARY_PATH RUBYOPT=\"#{syck_hack}\""
- env_vars += " BUNDLER_LIB_PATH=#{bundler_path}" if ruby_version == "ruby-1.8.7"
+ env_vars += " BUNDLER_LIB_PATH=#{bundler_path}" if ruby_version && ruby_version.match(/^ruby-1\.8\.7/)
puts "Running: #{bundle_command}"
bundler_output << pipe("#{env_vars} #{bundle_command} --no-clean 2>&1")
@@ -417,28 +451,22 @@ def build_bundler
if $?.success?
log "bundle", :status => "success"
puts "Cleaning up the bundler cache."
- pipe "bundle clean"
- cache_store ".bundle"
- cache_store "vendor/bundle"
+ pipe "#{bundle_bin} clean 2> /dev/null"
+ cache.store ".bundle"
+ cache.store "vendor/bundle"
# Keep gem cache out of the slug
FileUtils.rm_rf("#{slug_vendor_base}/cache")
-
- # symlink binstubs
- bin_dir = "bin"
- FileUtils.mkdir_p bin_dir
- Dir["#{slug_vendor_base}/bin/*"].each do |bin|
- run("ln -s ../#{bin} #{bin_dir}") unless File.exist?("#{bin_dir}/#{bin}")
- end
else
log "bundle", :status => "failure"
error_message = "Failed to install gems via Bundler."
- if bundler_output.match(/Installing sqlite3 \([\w.]+\) with native extensions\s+Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension./)
+ puts "Bundler Output: #{bundler_output}"
+ if bundler_output.match(/Installing sqlite3 \([\w.]+\)( with native extensions)?\s+Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension./)
error_message += <<ERROR
Detected sqlite3 gem which is not supported on Heroku.
-http://devcenter.heroku.com/articles/how-do-i-use-sqlite3-for-development
+https://devcenter.heroku.com/articles/sqlite3
ERROR
end
@@ -451,7 +479,7 @@ def build_bundler
# @return [String] require string if needed or else an empty string
def syck_hack
syck_hack_file = File.expand_path(File.join(File.dirname(__FILE__), "../../vendor/syck_hack"))
- ruby_version = run('ruby -e "puts RUBY_VERSION"').chomp
+ ruby_version = run_stdout('ruby -e "puts RUBY_VERSION"').chomp
# < 1.9.3 includes syck, so we need to use the syck hack
if Gem::Version.new(ruby_version) < Gem::Version.new("1.9.3")
"-r#{syck_hack_file}"
@@ -525,18 +553,10 @@ def attribute(name, value, force_string = false)
end
end
- # add bundler to the load path
- # @note it sets a flag, so the path can only be loaded once
- def add_bundler_to_load_path
- return if @bundler_loadpath
- $: << File.expand_path(Dir["#{slug_vendor_base}/gems/bundler*/lib"].first)
- @bundler_loadpath = true
- end
-
# detects whether the Gemfile.lock contains the Windows platform
# @return [Boolean] true if the Gemfile.lock was created on Windows
def has_windows_gemfile_lock?
- lockfile_parser.platforms.detect do |platform|
+ bundle.platforms.detect do |platform|
/mingw|mswin/.match(platform.os) if platform.is_a?(Gem::Platform)
end
end
@@ -545,15 +565,7 @@ def has_windows_gemfile_lock?
# @param [String] name of the gem in question
# @return [String, nil] if it finds the gem, it will return the line from bundle show or nil if nothing is found.
def gem_is_bundled?(gem)
- @bundler_gems ||= lockfile_parser.specs.map(&:name)
- @bundler_gems.include?(gem)
- end
-
- # setup the lockfile parser
- # @return [Bundler::LockfileParser] a Bundler::LockfileParser
- def lockfile_parser
- add_bundler_to_load_path
- @lockfile_parser ||= LanguagePack::Ruby.lockfile_parser
+ bundle.specs.map(&:name).include?(gem)
end
# detects if a rake task is defined in the app
@@ -601,53 +613,61 @@ def bundler_cache
end
def load_bundler_cache
- cache_load "vendor"
+ cache.load "vendor"
- full_ruby_version = run(%q(ruby -v)).chomp
+ full_ruby_version = run_stdout(%q(ruby -v)).chomp
+ rubygems_version = run_stdout(%q(gem -v)).chomp
heroku_metadata = "vendor/heroku"
- ruby_version_cache = "#{heroku_metadata}/ruby_version"
- buildpack_version_cache = "#{heroku_metadata}/buildpack_version"
- bundler_version_cache = "#{heroku_metadata}/bundler_version"
+ old_rubygems_version = nil
+ ruby_version_cache = "ruby_version"
+ buildpack_version_cache = "buildpack_version"
+ bundler_version_cache = "bundler_version"
+ rubygems_version_cache = "rubygems_version"
+
+ old_rubygems_version = @metadata.read(ruby_version_cache).chomp if @metadata.exists?(ruby_version_cache)
# fix bug from v37 deploy
if File.exists?("vendor/ruby_version")
puts "Broken cache detected. Purging build cache."
- cache_clear("vendor")
+ cache.clear("vendor")
FileUtils.rm_rf("vendor/ruby_version")
purge_bundler_cache
# fix bug introduced in v38
- elsif !File.exists?(buildpack_version_cache) && File.exists?(ruby_version_cache)
+ elsif !@metadata.exists?(buildpack_version_cache) && @metadata.exists?(ruby_version_cache)
puts "Broken cache detected. Purging build cache."
purge_bundler_cache
- elsif cache_exists?(bundler_cache) && File.exists?(ruby_version_cache) && full_ruby_version != File.read(ruby_version_cache).chomp
+ elsif cache.exists?(bundler_cache) && @metadata.exists?(ruby_version_cache) && full_ruby_version != @metadata.read(ruby_version_cache).chomp
puts "Ruby version change detected. Clearing bundler cache."
- puts "Old: #{File.read(ruby_version_cache).chomp}"
+ puts "Old: #{@metadata.read(ruby_version_cache).chomp}"
puts "New: #{full_ruby_version}"
purge_bundler_cache
end
# fix git gemspec bug from Bundler 1.3.0+ upgrade
- if File.exists?(bundler_cache) && !File.exists?(bundler_version_cache) && !run("find vendor/bundle/*/*/bundler/gems/*/ -name *.gemspec").include?("No such file or directory")
+ if File.exists?(bundler_cache) && !@metadata.exists?(bundler_version_cache) && !run("find vendor/bundle/*/*/bundler/gems/*/ -name *.gemspec").include?("No such file or directory")
puts "Old bundler cache detected. Clearing bundler cache."
purge_bundler_cache
end
- FileUtils.mkdir_p(heroku_metadata)
- File.open(ruby_version_cache, 'w') do |file|
- file.puts full_ruby_version
- end
- File.open(buildpack_version_cache, 'w') do |file|
- file.puts BUILDPACK_VERSION
- end
- File.open(bundler_version_cache, 'w') do |file|
- file.puts BUNDLER_VERSION
+ # fix for https://github.com/heroku/heroku-buildpack-ruby/issues/86
+ if (!@metadata.exists?(rubygems_version_cache) ||
+ (old_rubygems_version == "2.0.0" && old_rubygems_version != rubygems_version)) &&
+ @metadata.exists?(ruby_version_cache) && @metadata.read(ruby_version_cache).chomp.include?("ruby 2.0.0p0")
+ puts "Updating to rubygems #{rubygems_version}. Clearing bundler cache."
+ purge_bundler_cache
end
- cache_store heroku_metadata
+
+ FileUtils.mkdir_p(heroku_metadata)
+ @metadata.write(ruby_version_cache, full_ruby_version, false)
+ @metadata.write(buildpack_version_cache, BUILDPACK_VERSION, false)
+ @metadata.write(bundler_version_cache, BUNDLER_VERSION, false)
+ @metadata.write(rubygems_version_cache, rubygems_version, false)
+ @metadata.save
end
def purge_bundler_cache
FileUtils.rm_rf(bundler_cache)
- cache_clear bundler_cache
+ cache.clear bundler_cache
# need to reinstall language pack gems
install_language_pack_gems
end
View
5 lib/language_pack/shell_helpers.rb
@@ -58,5 +58,10 @@ def puts(message)
end
$stdout.flush
end
+
+ def warn(message)
+ @warnings ||= []
+ @warnings << message
+ end
end
end
View
5 spec/bugs_spec.rb
@@ -3,8 +3,9 @@
describe "Bugs" do
context "MRI 1.8.7" do
it "should install nokogiri" do
- Hatchet::AnvilApp.new("mri_187_nokogiri", :buildpack => buildpack).deploy do |app, heroku, output|
- expect(app).to be_deployed
+ Hatchet::AnvilApp.new("mri_187_nokogiri").deploy do |app|
+ expect(app.output).to match("Installing nokogiri")
+ expect(app.output).to match("Your bundle is complete!")
end
end
end
View
12 spec/gem_detect_errors_spec.rb
@@ -0,0 +1,12 @@
+require 'spec_helper'
+
+describe "Raise errors on specific gems" do
+ it "should should raise on sqlite3" do
+ Hatchet::AnvilApp.new("sqlite3_gemfile", allow_failure: true).deploy do |app|
+ expect(app).not_to be_deployed
+ expect(app.output).to include("Detected sqlite3 gem which is not supported")
+ expect(app.output).to include("devcenter.heroku.com/articles/sqlite3")
+ end
+ end
+end
+
View
4 spec/no_lockfile_spec.rb
@@ -2,9 +2,9 @@
describe "No Lockfile" do
it "should not deploy" do
- Hatchet::AnvilApp.new("no_lockfile", :buildpack => buildpack).deploy do |app, heroku, output|
+ Hatchet::AnvilApp.new("no_lockfile", allow_failure: true).deploy do |app|
expect(app).not_to be_deployed
- expect(output).to include("ERROR: Gemfile.lock required")
+ expect(app.output).to include("Gemfile.lock required")
end
end
end
View
5 spec/rails23_spec.rb
@@ -2,10 +2,9 @@
describe "Rails 2.3.x" do
it "should deploy on ruby 1.8.7" do
- Hatchet::AnvilApp.new("rails23_mri_187", :buildpack => buildpack).deploy do |app, heroku|
+ Hatchet::AnvilApp.new("rails23_mri_187").deploy do |app, heroku|
add_database(app, heroku)
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body).to eq("hello")
+ expect(successful_body(app)).to eq("hello")
end
end
end
View
12 spec/rails3_spec.rb
@@ -2,20 +2,18 @@
describe "Rails 3.x" do
it "should deploy on ruby 1.9.3" do
- Hatchet::AnvilApp.new("rails3_mri_193", :buildpack => buildpack).deploy do |app, heroku|
+ Hatchet::AnvilApp.new("rails3_mri_193").deploy do |app, heroku|
add_database(app, heroku)
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body).to eq("hello")
+ expect(successful_body(app)).to eq("hello")
end
end
context "when not using the rails gem" do
it "should deploy on ruby 1.9.3" do
- Hatchet::AnvilApp.new("railties3_mri_193", :buildpack => buildpack).deploy do |app, heroku, output|
+ Hatchet::AnvilApp.new("railties3_mri_193").deploy do |app, heroku|
add_database(app, heroku)
- expect(app).to be_deployed
- expect(output).to match("Detecting buildpack... done, .+Ruby/Rails")
- expect(Excon.get("http://#{app.name}.herokuapp.com").body).to eq("hello")
+ expect(app.output).to match("Ruby/Rails")
+ expect(successful_body(app)).to eq("hello")
end
end
end
View
11 spec/rails4_spec.rb
@@ -0,0 +1,11 @@
+require_relative 'spec_helper'
+
+describe "Rails 4.x" do
+ it "should deploy on ruby 1.9.3" do
+ Hatchet::AnvilApp.new("rails4-manifest").deploy do |app, heroku|
+ add_database(app, heroku)
+ expect(app.output).to include("Detected manifest file, assuming assets were compiled locally")
+ end
+ end
+
+end
View
36 spec/rubies_spec.rb
@@ -2,38 +2,42 @@
describe "Ruby Versions" do
it "should deploy ruby 1.8.7 properly" do
- Hatchet::AnvilApp.new("mri_187", :buildpack => buildpack).deploy do |app, heroku, output|
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body.chomp).to eq("ruby 1.8.7 (2012-10-12 patchlevel 371) [x86_64-linux]")
+ Hatchet::AnvilApp.new("mri_187").deploy do |app|
+ version = '1.8.7'
+ expect(app.output).to match(version)
+ expect(app.run('ruby -v')).to match(version)
end
end
it "should deploy ruby 1.9.2 properly" do
- Hatchet::AnvilApp.new("mri_192", :buildpack => buildpack).deploy do |app, heroku, output|
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body.chomp).to eq("ruby 1.9.2p320 (2012-04-20 revision 35421) [x86_64-linux]")
+ Hatchet::AnvilApp.new("mri_192").deploy do |app|
+ version = '1.9.2'
+ expect(app.output).to match(version)
+ expect(app.run('ruby -v')).to match(version)
end
end
it "should deploy ruby 1.9.2 properly (git)" do
- Hatchet::GitApp.new("mri_192", :buildpack => git_repo).deploy do |app, heroku, output|
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body.chomp).to eq("ruby 1.9.2p320 (2012-04-20 revision 35421) [x86_64-linux]")
+ Hatchet::GitApp.new("mri_192", buildpack: git_repo).deploy do |app|
+ version = '1.9.2'
+ expect(app.output).to match(version)
+ expect(app.run('ruby -v')).to match(version)
end
end
it "should deploy ruby 1.9.3 properly" do
- Hatchet::AnvilApp.new("mri_193", :buildpack => buildpack).deploy do |app, heroku, output|
- puts output
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body.chomp).to eq("ruby 1.9.3p392 (2013-02-22 revision 39386) [x86_64-linux]")
+ Hatchet::AnvilApp.new("mri_193").deploy do |app|
+ version = '1.9.3'
+ expect(app.output).to match(version)
+ expect(app.run('ruby -v')).to match(version)
end
end
it "should deploy ruby 2.0.0 properly" do
- Hatchet::AnvilApp.new("mri_200", :buildpack => buildpack).deploy do |app, heroku|
- expect(app).to be_deployed
- expect(Excon.get("http://#{app.name}.herokuapp.com").body.chomp).to eq("ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-linux]")
+ Hatchet::AnvilApp.new("mri_200").deploy do |app|
+ version = '2.0.0'
+ expect(app.output).to match(version)
+ expect(app.run('ruby -v')).to match(version)
end
end
end
View
23 spec/spec_helper.rb
@@ -2,13 +2,19 @@
require 'hatchet'
require 'fileutils'
require 'hatchet'
+require 'rspec/retry'
ENV['RACK_ENV'] = 'test'
+
+
RSpec.configure do |config|
config.filter_run :focused => true
config.run_all_when_everything_filtered = true
config.alias_example_to :fit, :focused => true
+ config.full_backtrace = true
+ config.verbose_retry = true # show retry status in spec process
+ config.default_retry_count = 2 # retry all tests that fail again
config.expect_with :rspec do |c|
c.syntax = :expect
@@ -16,16 +22,19 @@
config.mock_with :none
end
-def buildpack
- File.expand_path(File.dirname(__FILE__) + "/..")
-end
-
def git_repo
"https://github.com/heroku/heroku-buildpack-ruby.git"
end
def add_database(app, heroku)
- heroku.post_addon(app.name, 'heroku-postgresql:dev')
- _, value = heroku.get_config_vars(app.name).body.detect {|key, value| key.match(/HEROKU_POSTGRESQL_[A-Z]+_URL/) }
- heroku.put_config_vars(app.name, 'DATABASE_URL' => value)
+ Hatchet::RETRIES.times.retry do
+ heroku.post_addon(app.name, 'heroku-postgresql:dev')
+ _, value = heroku.get_config_vars(app.name).body.detect {|key, value| key.match(/HEROKU_POSTGRESQL_[A-Z]+_URL/) }
+ heroku.put_config_vars(app.name, 'DATABASE_URL' => value)
+ end
+end
+
+def successful_body(app, options = {})
+ retry_limit = options[:retry_limit] || 50
+ Excon.get("http://#{app.name}.herokuapp.com", :idempotent => true, :expects => 200, :retry_limit => retry_limit).body
end
Please sign in to comment.
Something went wrong with that request. Please try again.