heroku_hatchet 0.0.2 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +14 -0
- data/CHANGELOG.md +4 -0
- data/README.md +2 -2
- data/Rakefile +6 -0
- data/hatchet.gemspec +3 -1
- data/hatchet.json +3 -2
- data/lib/hatchet.rb +2 -0
- data/lib/hatchet/anvil_app.rb +28 -18
- data/lib/hatchet/app.rb +19 -5
- data/lib/hatchet/git_app.rb +5 -2
- data/lib/hatchet/tasks.rb +17 -7
- data/lib/hatchet/version.rb +1 -1
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/.gitignore +4 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/CHANGELOG.md +378 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/Gemfile +10 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/LICENSE +9 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/README.md +192 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/Rakefile +358 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/compile +13 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/detect +12 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/release +9 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/hatchet.json +25 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack.rb +27 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/base.rb +175 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/bundler_lockfile.rb +19 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/disable_deploys.rb +17 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/no_lockfile.rb +16 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rack.rb +43 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails2.rb +91 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails3.rb +86 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails4.rb +66 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/ruby.rb +681 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/shell_helpers.rb +62 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/bugs_spec.rb +11 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/no_lockfile_spec.rb +10 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails23_spec.rb +11 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails3_spec.rb +22 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails4_spec.rb +12 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rubies_spec.rb +38 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/spec_helper.rb +35 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/hmac +79 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/s3 +223 -0
- data/test/fixtures/buildpacks/heroku-buildpack-ruby/vendor/syck_hack.rb +64 -0
- data/test/hatchet/allow_failure_anvil_test.rb +21 -0
- data/test/hatchet/allow_failure_git_test.rb +17 -0
- data/test/hatchet/anvil_test.rb +7 -7
- data/test/hatchet/config_test.rb +4 -2
- data/test/hatchet/git_test.rb +2 -2
- metadata +89 -8
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
2
|
+
"bundler": [
|
3
|
+
"sharpstone/git_gemspec",
|
4
|
+
"sharpstone/no_lockfile"
|
5
|
+
],
|
6
|
+
"ruby": [
|
7
|
+
"sharpstone/mri_187"
|
8
|
+
],
|
9
|
+
"rack": [
|
10
|
+
"sharpstone/mri_187_nokogiri",
|
11
|
+
"sharpstone/mri_192",
|
12
|
+
"sharpstone/mri_193",
|
13
|
+
"sharpstone/mri_200"
|
14
|
+
],
|
15
|
+
"rails2": [
|
16
|
+
"sharpstone/rails23_mri_187"
|
17
|
+
],
|
18
|
+
"rails3": [
|
19
|
+
"sharpstone/rails3_mri_193",
|
20
|
+
"sharpstone/railties3_mri_193"
|
21
|
+
],
|
22
|
+
"rails4": [
|
23
|
+
"sharpstone/rails4-manifest"
|
24
|
+
]
|
25
|
+
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "pathname"
|
2
|
+
|
3
|
+
# General Language Pack module
|
4
|
+
module LanguagePack
|
5
|
+
|
6
|
+
# detects which language pack to use
|
7
|
+
# @param [Array] first argument is a String of the build directory
|
8
|
+
# @return [LanguagePack] the {LanguagePack} detected
|
9
|
+
def self.detect(*args)
|
10
|
+
Dir.chdir(args.first)
|
11
|
+
|
12
|
+
pack = [ NoLockfile, Rails4, Rails3, Rails2, Rack, Ruby ].detect do |klass|
|
13
|
+
klass.use?
|
14
|
+
end
|
15
|
+
|
16
|
+
pack ? pack.new(*args) : nil
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
require "language_pack/ruby"
|
22
|
+
require "language_pack/rack"
|
23
|
+
require "language_pack/rails2"
|
24
|
+
require "language_pack/rails3"
|
25
|
+
require "language_pack/disable_deploys"
|
26
|
+
require "language_pack/rails4"
|
27
|
+
require "language_pack/no_lockfile"
|
@@ -0,0 +1,175 @@
|
|
1
|
+
require "language_pack"
|
2
|
+
require "pathname"
|
3
|
+
require "yaml"
|
4
|
+
require "digest/sha1"
|
5
|
+
require "language_pack/shell_helpers"
|
6
|
+
|
7
|
+
Encoding.default_external = Encoding::UTF_8 if defined?(Encoding)
|
8
|
+
|
9
|
+
# abstract class that all the Ruby based Language Packs inherit from
|
10
|
+
class LanguagePack::Base
|
11
|
+
include LanguagePack::ShellHelpers
|
12
|
+
|
13
|
+
VENDOR_URL = "https://s3.amazonaws.com/heroku-buildpack-ruby"
|
14
|
+
|
15
|
+
attr_reader :build_path, :cache_path
|
16
|
+
|
17
|
+
# changes directory to the build_path
|
18
|
+
# @param [String] the path of the build dir
|
19
|
+
# @param [String] the path of the cache dir
|
20
|
+
def initialize(build_path, cache_path=nil)
|
21
|
+
@build_path = build_path
|
22
|
+
@cache_path = cache_path
|
23
|
+
@id = Digest::SHA1.hexdigest("#{Time.now.to_f}-#{rand(1000000)}")[0..10]
|
24
|
+
|
25
|
+
Dir.chdir build_path
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.===(build_path)
|
29
|
+
raise "must subclass"
|
30
|
+
end
|
31
|
+
|
32
|
+
# name of the Language Pack
|
33
|
+
# @return [String] the result
|
34
|
+
def name
|
35
|
+
raise "must subclass"
|
36
|
+
end
|
37
|
+
|
38
|
+
# list of default addons to install
|
39
|
+
def default_addons
|
40
|
+
raise "must subclass"
|
41
|
+
end
|
42
|
+
|
43
|
+
# config vars to be set on first push.
|
44
|
+
# @return [Hash] the result
|
45
|
+
# @not: this is only set the first time an app is pushed to.
|
46
|
+
def default_config_vars
|
47
|
+
raise "must subclass"
|
48
|
+
end
|
49
|
+
|
50
|
+
# process types to provide for the app
|
51
|
+
# Ex. for rails we provide a web process
|
52
|
+
# @return [Hash] the result
|
53
|
+
def default_process_types
|
54
|
+
raise "must subclass"
|
55
|
+
end
|
56
|
+
|
57
|
+
# this is called to build the slug
|
58
|
+
def compile
|
59
|
+
end
|
60
|
+
|
61
|
+
# collection of values passed for a release
|
62
|
+
# @return [String] in YAML format of the result
|
63
|
+
def release
|
64
|
+
setup_language_pack_environment
|
65
|
+
|
66
|
+
{
|
67
|
+
"addons" => default_addons,
|
68
|
+
"default_process_types" => default_process_types
|
69
|
+
}.to_yaml
|
70
|
+
end
|
71
|
+
|
72
|
+
# log output
|
73
|
+
# Ex. log "some_message", "here", :someattr="value"
|
74
|
+
def log(*args)
|
75
|
+
args.concat [:id => @id]
|
76
|
+
args.concat [:framework => self.class.to_s.split("::").last.downcase]
|
77
|
+
|
78
|
+
start = Time.now.to_f
|
79
|
+
log_internal args, :start => start
|
80
|
+
|
81
|
+
if block_given?
|
82
|
+
begin
|
83
|
+
ret = yield
|
84
|
+
finish = Time.now.to_f
|
85
|
+
log_internal args, :status => "complete", :finish => finish, :elapsed => (finish - start)
|
86
|
+
return ret
|
87
|
+
rescue StandardError => ex
|
88
|
+
finish = Time.now.to_f
|
89
|
+
log_internal args, :status => "error", :finish => finish, :elapsed => (finish - start), :message => ex.message
|
90
|
+
raise ex
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
private ##################################
|
96
|
+
|
97
|
+
# sets up the environment variables for the build process
|
98
|
+
def setup_language_pack_environment
|
99
|
+
end
|
100
|
+
|
101
|
+
def add_to_profiled(string)
|
102
|
+
FileUtils.mkdir_p "#{build_path}/.profile.d"
|
103
|
+
File.open("#{build_path}/.profile.d/ruby.sh", "a") do |file|
|
104
|
+
file.puts string
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def set_env_default(key, val)
|
109
|
+
add_to_profiled "export #{key}=${#{key}:-#{val}}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def set_env_override(key, val)
|
113
|
+
add_to_profiled %{export #{key}="#{val.gsub('"','\"')}"}
|
114
|
+
end
|
115
|
+
|
116
|
+
def log_internal(*args)
|
117
|
+
message = build_log_message(args)
|
118
|
+
%x{ logger -p user.notice -t "slugc[$$]" "buildpack-ruby #{message}" }
|
119
|
+
end
|
120
|
+
|
121
|
+
def build_log_message(args)
|
122
|
+
args.map do |arg|
|
123
|
+
case arg
|
124
|
+
when Float then "%0.2f" % arg
|
125
|
+
when Array then build_log_message(arg)
|
126
|
+
when Hash then arg.map { |k,v| "#{k}=#{build_log_message([v])}" }.join(" ")
|
127
|
+
else arg
|
128
|
+
end
|
129
|
+
end.join(" ")
|
130
|
+
end
|
131
|
+
|
132
|
+
# create a Pathname of the cache dir
|
133
|
+
# @return [Pathname] the cache dir
|
134
|
+
def cache_base
|
135
|
+
Pathname.new(cache_path)
|
136
|
+
end
|
137
|
+
|
138
|
+
# removes the the specified
|
139
|
+
# @param [String] relative path from the cache_base
|
140
|
+
def cache_clear(path)
|
141
|
+
target = (cache_base + path)
|
142
|
+
target.exist? && target.rmtree
|
143
|
+
end
|
144
|
+
|
145
|
+
# write cache contents
|
146
|
+
# @param [String] path of contents to store. it will be stored using this a relative path from the cache_base.
|
147
|
+
# @param [Boolean] defaults to true. if set to true, the cache store directory will be cleared before writing to it.
|
148
|
+
def cache_store(path, clear_first=true)
|
149
|
+
cache_clear(path) if clear_first
|
150
|
+
cache_copy path, (cache_base + path)
|
151
|
+
end
|
152
|
+
|
153
|
+
# load cache contents
|
154
|
+
# @param [String] relative path of the cache contents
|
155
|
+
def cache_load(path)
|
156
|
+
cache_copy (cache_base + path), path
|
157
|
+
end
|
158
|
+
|
159
|
+
# copy cache contents
|
160
|
+
# @param [String] source directory
|
161
|
+
# @param [String] destination directory
|
162
|
+
def cache_copy(from, to)
|
163
|
+
return false unless File.exist?(from)
|
164
|
+
FileUtils.mkdir_p File.dirname(to)
|
165
|
+
system("cp -a #{from}/. #{to}")
|
166
|
+
end
|
167
|
+
|
168
|
+
# check if the cache content exists
|
169
|
+
# @param [String] relative path of the cache contents
|
170
|
+
# @param [Boolean] true if the path exists in the cache and false if otherwise
|
171
|
+
def cache_exists?(path)
|
172
|
+
File.exists?(cache_base + path)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module LanguagePack
|
2
|
+
module BundlerLockfile
|
3
|
+
# checks if the Gemfile and Gemfile.lock exist
|
4
|
+
def gemfile_lock?
|
5
|
+
File.exist?('Gemfile') && File.exist?('Gemfile.lock')
|
6
|
+
end
|
7
|
+
|
8
|
+
# bootstraps bundler so we can use it before bundler is setup properlyLanguagePack::Ruby
|
9
|
+
def bootstrap_bundler(&block)
|
10
|
+
Dir.mktmpdir("bundler-") do |tmpdir|
|
11
|
+
Dir.chdir(tmpdir) do
|
12
|
+
system("curl #{LanguagePack::Base::VENDOR_URL}/#{LanguagePack::Ruby::BUNDLER_GEM_PATH}.tgz -s -o - | tar xzf -")
|
13
|
+
end
|
14
|
+
|
15
|
+
yield tmpdir
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require "language_pack"
|
2
|
+
require "language_pack/base"
|
3
|
+
|
4
|
+
class LanguagePack::DisableDeploys < LanguagePack::Base
|
5
|
+
def self.use?
|
6
|
+
File.exist?("Gemfile")
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
"Ruby/DisableDeploys"
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile
|
14
|
+
error "Ruby deploys have been temporarily disabled due to a Rubygems.org security breach.\nPlease see https://status.heroku.com/incidents/489 for more info and a workaround if you need to deploy."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "language_pack"
|
2
|
+
require "language_pack/base"
|
3
|
+
|
4
|
+
class LanguagePack::NoLockfile < LanguagePack::Base
|
5
|
+
def self.use?
|
6
|
+
File.exist?("Gemfile") && !File.exists?("Gemfile.lock")
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
"Ruby/NoLockfile"
|
11
|
+
end
|
12
|
+
|
13
|
+
def compile
|
14
|
+
error "Gemfile.lock required. Please check it in."
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "language_pack"
|
2
|
+
require "language_pack/ruby"
|
3
|
+
|
4
|
+
# Rack Language Pack. This is for any non-Rails Rack apps like Sinatra.
|
5
|
+
class LanguagePack::Rack < LanguagePack::Ruby
|
6
|
+
|
7
|
+
# detects if this is a valid Rack app by seeing if "config.ru" exists
|
8
|
+
# @return [Boolean] true if it's a Rack app
|
9
|
+
def self.use?
|
10
|
+
gemfile_lock? && LanguagePack::Ruby.gem_version('rack')
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
"Ruby/Rack"
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_config_vars
|
18
|
+
super.merge({
|
19
|
+
"RACK_ENV" => "production"
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
def default_process_types
|
24
|
+
# let's special case thin here if we detect it
|
25
|
+
web_process = gem_is_bundled?("thin") ?
|
26
|
+
"bundle exec thin start -R config.ru -e $RACK_ENV -p $PORT" :
|
27
|
+
"bundle exec rackup config.ru -p $PORT"
|
28
|
+
|
29
|
+
super.merge({
|
30
|
+
"web" => web_process
|
31
|
+
})
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# sets up the profile.d script for this buildpack
|
37
|
+
def setup_profiled
|
38
|
+
super
|
39
|
+
set_env_default "RACK_ENV", "production"
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,91 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
require "language_pack"
|
3
|
+
require "language_pack/rack"
|
4
|
+
|
5
|
+
# Rails 2 Language Pack. This is for any Rails 2.x apps.
|
6
|
+
class LanguagePack::Rails2 < LanguagePack::Ruby
|
7
|
+
|
8
|
+
# detects if this is a valid Rails 2 app
|
9
|
+
# @return [Boolean] true if it's a Rails 2 app
|
10
|
+
def self.use?
|
11
|
+
if gemfile_lock?
|
12
|
+
rails_version = LanguagePack::Ruby.gem_version('rails')
|
13
|
+
rails_version >= Gem::Version.new('2.0.0') && rails_version < Gem::Version.new('3.0.0') if rails_version
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def name
|
18
|
+
"Ruby/Rails"
|
19
|
+
end
|
20
|
+
|
21
|
+
def default_config_vars
|
22
|
+
super.merge({
|
23
|
+
"RAILS_ENV" => "production",
|
24
|
+
"RACK_ENV" => "production"
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_process_types
|
29
|
+
web_process = gem_is_bundled?("thin") ?
|
30
|
+
"bundle exec thin start -e $RAILS_ENV -p $PORT" :
|
31
|
+
"bundle exec ruby script/server -p $PORT"
|
32
|
+
|
33
|
+
super.merge({
|
34
|
+
"web" => web_process,
|
35
|
+
"worker" => "bundle exec rake jobs:work",
|
36
|
+
"console" => "bundle exec script/console"
|
37
|
+
})
|
38
|
+
end
|
39
|
+
|
40
|
+
def compile
|
41
|
+
super
|
42
|
+
install_plugins
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# list of plugins to be installed
|
48
|
+
# @return [Array] resulting list in a String Array
|
49
|
+
def plugins
|
50
|
+
%w( rails_log_stdout )
|
51
|
+
end
|
52
|
+
|
53
|
+
# the root path of where the plugins are to be installed from
|
54
|
+
# @return [String] the resulting path
|
55
|
+
def plugin_root
|
56
|
+
File.expand_path("../../../vendor/plugins", __FILE__)
|
57
|
+
end
|
58
|
+
|
59
|
+
# vendors all the plugins into the slug
|
60
|
+
def install_plugins
|
61
|
+
topic "Rails plugin injection"
|
62
|
+
plugins.each { |plugin| install_plugin(plugin) }
|
63
|
+
end
|
64
|
+
|
65
|
+
# vendors an individual plugin
|
66
|
+
# @param [String] name of the plugin
|
67
|
+
def install_plugin(name)
|
68
|
+
plugin_dir = "vendor/plugins/#{name}"
|
69
|
+
return if File.exist?(plugin_dir)
|
70
|
+
puts "Injecting #{name}"
|
71
|
+
FileUtils.mkdir_p plugin_dir
|
72
|
+
Dir.chdir(plugin_dir) do |dir|
|
73
|
+
run("curl #{VENDOR_URL}/#{name}.tgz -s -o - | tar xzf -")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# most rails apps need a database
|
78
|
+
# @return [Array] shared database addon
|
79
|
+
def add_dev_database_addon
|
80
|
+
['heroku-postgresql:dev']
|
81
|
+
end
|
82
|
+
|
83
|
+
# sets up the profile.d script for this buildpack
|
84
|
+
def setup_profiled
|
85
|
+
super
|
86
|
+
set_env_default "RACK_ENV", "production"
|
87
|
+
set_env_default "RAILS_ENV", "production"
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|