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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +14 -0
  3. data/CHANGELOG.md +4 -0
  4. data/README.md +2 -2
  5. data/Rakefile +6 -0
  6. data/hatchet.gemspec +3 -1
  7. data/hatchet.json +3 -2
  8. data/lib/hatchet.rb +2 -0
  9. data/lib/hatchet/anvil_app.rb +28 -18
  10. data/lib/hatchet/app.rb +19 -5
  11. data/lib/hatchet/git_app.rb +5 -2
  12. data/lib/hatchet/tasks.rb +17 -7
  13. data/lib/hatchet/version.rb +1 -1
  14. data/test/fixtures/buildpacks/heroku-buildpack-ruby/.gitignore +4 -0
  15. data/test/fixtures/buildpacks/heroku-buildpack-ruby/CHANGELOG.md +378 -0
  16. data/test/fixtures/buildpacks/heroku-buildpack-ruby/Gemfile +10 -0
  17. data/test/fixtures/buildpacks/heroku-buildpack-ruby/LICENSE +9 -0
  18. data/test/fixtures/buildpacks/heroku-buildpack-ruby/README.md +192 -0
  19. data/test/fixtures/buildpacks/heroku-buildpack-ruby/Rakefile +358 -0
  20. data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/compile +13 -0
  21. data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/detect +12 -0
  22. data/test/fixtures/buildpacks/heroku-buildpack-ruby/bin/release +9 -0
  23. data/test/fixtures/buildpacks/heroku-buildpack-ruby/hatchet.json +25 -0
  24. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack.rb +27 -0
  25. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/base.rb +175 -0
  26. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/bundler_lockfile.rb +19 -0
  27. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/disable_deploys.rb +17 -0
  28. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/no_lockfile.rb +16 -0
  29. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rack.rb +43 -0
  30. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails2.rb +91 -0
  31. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails3.rb +86 -0
  32. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/rails4.rb +66 -0
  33. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/ruby.rb +681 -0
  34. data/test/fixtures/buildpacks/heroku-buildpack-ruby/lib/language_pack/shell_helpers.rb +62 -0
  35. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/bugs_spec.rb +11 -0
  36. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/no_lockfile_spec.rb +10 -0
  37. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails23_spec.rb +11 -0
  38. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails3_spec.rb +22 -0
  39. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rails4_spec.rb +12 -0
  40. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/rubies_spec.rb +38 -0
  41. data/test/fixtures/buildpacks/heroku-buildpack-ruby/spec/spec_helper.rb +35 -0
  42. data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/hmac +79 -0
  43. data/test/fixtures/buildpacks/heroku-buildpack-ruby/support/s3/s3 +223 -0
  44. data/test/fixtures/buildpacks/heroku-buildpack-ruby/vendor/syck_hack.rb +64 -0
  45. data/test/hatchet/allow_failure_anvil_test.rb +21 -0
  46. data/test/hatchet/allow_failure_git_test.rb +17 -0
  47. data/test/hatchet/anvil_test.rb +7 -7
  48. data/test/hatchet/config_test.rb +4 -2
  49. data/test/hatchet/git_test.rb +2 -2
  50. metadata +89 -8
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # sync output
4
+ $stdout.sync = true
5
+
6
+ $:.unshift File.expand_path("../../lib", __FILE__)
7
+ require "language_pack"
8
+
9
+ if pack = LanguagePack.detect(ARGV[0], ARGV[1])
10
+ pack.log("compile") do
11
+ pack.compile
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+ require "language_pack"
5
+
6
+ if pack = LanguagePack.detect(ARGV.first)
7
+ puts pack.name
8
+ exit 0
9
+ else
10
+ puts "no"
11
+ exit 1
12
+ end
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+ require "language_pack"
5
+
6
+ if pack = LanguagePack.detect(ARGV[0], ARGV[1])
7
+ puts pack.release
8
+ end
9
+
@@ -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
+