Minimal `Gemfile/Gemfile.lock` for Heroku environment - ruby

I’m updating the environment on Heroku and one of the buildpack we use is based on Ruby, which is no longer available by default in the new heroku-22 environment/stack (nor required by our PHP app).
From the docs:
[...] end users should add the Ruby buildpack prior to the buildpack in question (they will also need to ensure minimal Gemfile / Gemfile.lock files exist, so that the Ruby buildpack passes detection).
However I have no clue what those files should include as I have zero experience with Ruby. What would be a valid set of minimal Gemfiles to trigger Ruby installation on Heroku?

I suggest you don't use that buildpack at all. It's ancient, and third-party buildpacks are always a bit questionable, even if it's just because they often stop getting updated.
Here's what it claims to do:
This is a Heroku buildpack for vendoring just the mysql binary from the mysql-client-core deb package.
If you just need a mysql binary, you can use the apt buildpack to install it without worrying about Ruby or anything like that.
Add it as your first buildpack:
heroku buildpacks:add --index 1 heroku-community/apt
Create an Aptfile in the root directory of your project that lists the Ubuntu packages you wish to install, e.g.
mysql-client-core-8.0
Note that the buildpack does not do dependency resolution. If any packages you list have their own dependencies you may have to list them explicitly.
Commit, and redeploy.
You should see the Ubuntu packages you listed get installed before your main buildpack runs.
In any case, if you really want to make your application compatible with the Ruby buildpack you should be able to simply include an empty Gemfile in the root of your project:
The Heroku Ruby Support will be applied to applications only when the application has a Gemfile in the root directory. Even if an application has no gem dependencies it should include an empty Gemfile to document that your app has no gem dependencies.
A Gemfile.lock is not required.
Note that you'll need to manually add the buildpacks you require. I believe you'll want Ruby first, then the MySQL buildpack in your question, then whatever language your application is written in, which appears to be PHP:
heroku buildpacks:set heroku/php # Main buildpack; we insert others before it below
heroku buildpacks:add --index 1 heroku/ruby
heroku buildpacks:add --index 2 https://github.com/thoughtbot/heroku-buildpack-mysql.git
heroku buildpacks
# => Should print the buildpacks in the expected order

Edited
It turns out an empty Gemfile is not enough and a Gemfile.lock is actually required as well.
-----> Building on the Heroku-22 stack
-----> Using buildpacks:
1. heroku/python
2. heroku/ruby
3. https://github.com/thoughtbot/heroku-buildpack-mysql
4. heroku/php
5. heroku/nodejs
-----> Python app detected
-----> Using Python version specified in runtime.txt
-----> Stack has changed from heroku-20 to heroku-22, clearing cache
-----> No change in requirements detected, installing from cache
-----> Installing python-3.10.8
-----> Installing pip 22.2.2, setuptools 63.4.3 and wheel 0.37.1
-----> Installing SQLite3
-----> Installing requirements with pip
Collecting supervisor
Downloading supervisor-4.2.4-py2.py3-none-any.whl (749 kB)
Installing collected packages: supervisor
Successfully installed supervisor-4.2.4
-----> Ruby app detected
grep: /tmp/build_bebc9aa2/Gemfile.lock: No such file or directory
-----> Compiling Ruby/NoLockfile
!
! Gemfile.lock required. Please check it in.
!
! Push rejected, failed to compile Ruby app.
! Push failed
An empty Gemfile will trigger the Ruby installation, however the heroku/ruby package itself does require a lock file.
The buildpack will detect your app as Ruby if it has a Gemfile and Gemfile.lock files in the root directory.
After some trial and error I figure out the following files work:
# Gemfile
source 'https://rubygems.org'
# Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
PLATFORMS
ruby
DEPENDENCIES
BUNDLED WITH
1.17.3

Related

Deploying a sinatra app produced on a mac to Heroku

I have built a simple sinatra web app on my macbook. The deployment to heroku fails with the logs below. The problem is that I've already implemented their suggested fix (bundle lock --add-platform x86_64-linux) and I still get the same error message.
Any suggestions as to next steps would be very welcome. Thanks in advance.
-----> Building on the Heroku-20 stack
-----> Determining which buildpack to use for this app
-----> Ruby app detected
-----> Installing bundler 2.2.33
-----> Removing BUNDLED WITH version in the Gemfile.lock
-----> Compiling Ruby/Rack
-----> Using Ruby version: ruby-2.7.5
-----> Installing dependencies using bundler 2.2.33
Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
Your bundle only supports platforms ["arm64-darwin-20"] but your local platform
is x86_64-linux. Add the current platform to the lockfile with `bundle lock
--add-platform x86_64-linux` and try again.
Bundler Output: Your bundle only supports platforms ["arm64-darwin-20"] but your local platform
is x86_64-linux. Add the current platform to the lockfile with `bundle lock
--add-platform x86_64-linux` and try again.
!
! Failed to install gems via Bundler.
!
! Push rejected, failed to compile Ruby app.
! Push failed
*Update
My local repo, with x86_64-linux in Gemfile.lock, is out of sync with the remote repo on github that I have been trying to deploy from. Other files are out of date too. Concerningly, I have both pushed and pulled recently, as well as deleted the remote repo, created a new one and pushed again. Git is telling me that both the local and the remote repos are up to date with each other, when they are obviously not.
I've tried pushing directly to heroku from the command line but hit the same platform error as above.

Dokku: deploy, build & serve middleman statically generated website

Today, I've been trying to configure Dokku to deploy a statically-generated website of mine (built with middleman): push the middleman source to the host, generate the website on the host, and tell a nginx to serve those static files.
Following these resources 1 and 2, I setup my project with:
a .buildpacks file, containing one buildpack to build the site, and the nginx buildpack to serve the generated static HTML files:
https://github.com/heroku/heroku-buildpack-ruby.git#v222
https://github.com/dokku/buildpack-nginx.git#v14
a .static file so that the nginx buildpack knows it must serve a static website
a predeploy action in charge of building the site, using app.json :
{
"scripts": {
"dokku": {
"predeploy": "bundle exec middleman build",
}
}
}
What happened?
Apparently, at the moment I'm trying to build my middleman site with the predeploy hook, the bundle command is not available anymore. Here's an example output I'm getting:
➜ git push dokku master
Enumerating objects: 397, done.
Counting objects: 100% (397/397), done.
Delta compression using up to 8 threads
Compressing objects: 100% (258/258), done.
Writing objects: 100% (397/397), 819.50 KiB | 14.90 MiB/s, done.
Total 397 (delta 195), reused 244 (delta 111), pack-reused 0
remote: Resolving deltas: 100% (195/195), done.
-----> Cleaning up...
-----> Building site from herokuish...
-----> Adding BUILD_ENV to build environment...
-----> Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
Detected buildpacks: multi ruby static
-----> Multipack app detected
=====> Downloading Buildpack: https://github.com/heroku/heroku-buildpack-ruby.git
=====> Detected Framework: Ruby
-----> Installing bundler 2.1.4
-----> Removing BUNDLED WITH version in the Gemfile.lock
-----> Compiling Ruby/Rack
-----> Using Ruby version: ruby-2.6.3
-----> Installing dependencies using bundler 2.1.4
Running: BUNDLE_WITHOUT='development:test' BUNDLE_PATH=vendor/bundle BUNDLE_BIN=vendor/bundle/bin BUNDLE_DEPLOYMENT=1 bundle install -j4
Using concurrent-ruby 1.1.7
Using i18n 0.9.5
Using minitest 5.14.2
Using thread_safe 0.3.6
Using tzinfo 1.2.7
Using activesupport 5.2.4.4
Using public_suffix 4.0.6
Using addressable 2.7.0
Using execjs 2.7.0
Using autoprefixer-rails 9.8.6.5
Using backports 3.18.2
Using bundler 2.1.4
Using coffee-script-source 1.12.2
Using coffee-script 2.4.1
Using contracts 0.13.0
Using dotenv 2.7.6
Using erubis 2.7.0
Using fast_blank 1.0.0
Using fastimage 2.2.0
Using ffi 1.13.1
Using temple 0.8.2
Using tilt 2.0.10
Using haml 5.2.0
Using hamster 3.0.0
Using hashie 3.6.0
Using rexml 3.2.4
Using kramdown 2.3.0
Using rb-fsevent 0.10.4
Using rb-inotify 0.10.1
Using listen 3.0.8
Using memoist 0.16.2
Using thor 1.0.1
Using middleman-cli 4.3.11
Using padrino-support 0.13.3.4
Using padrino-helpers 0.13.3.4
Using parallel 1.19.2
Using rack 2.2.3
Using sassc 2.4.0
Using servolux 0.13.0
Using uglifier 3.2.0
Using middleman-core 4.3.11
Using middleman 4.3.11
Using middleman-autoprefixer 2.10.1
Bundle complete! 3 Gemfile dependencies, 43 gems now installed.
Gems in the groups development and test were not installed.
Bundled gems are installed into `./vendor/bundle`
Bundle completed (0.52s)
Cleaning up the bundler cache.
-----> Writing config/database.yml to read from DATABASE_URL
-----> Installing node-v12.16.2-linux-x64
-----> Detecting rake tasks
###### WARNING:
No Procfile detected, using the default web server.
We recommend explicitly declaring how to boot your server process via a Procfile.
https://devcenter.heroku.com/articles/ruby-default-web-server
=====> Downloading Buildpack: https://github.com/dokku/buildpack-nginx.git
=====> Detected Framework: .static
-----> Copy static files to www
-----> Reusing nginx binary from cache
-----> Using default app-nginx.conf.sigil
-----> Using default mime.types
Using release configuration from last framework (.static).
-----> Discovering process types
Default types for -> web
-----> Releasing site...
-----> Deploying site...
-----> Checking for predeploy task
-----> Executing predeploy task from app.json: bundle exec middleman build
=====> Start of site predeploy task (22fcf68dd) output
remote: ! Execution of predeploy task failed: bundle exec middleman build
/bin/bash: bundle: command not found
remote: 2021/01/02 15:06:19 exit status 1
remote: 2021/01/02 15:06:19 exit status 1
remote: 2021/01/02 15:06:19 exit status 1
=====> End of site predeploy task (22fcf68dd) output
To host:site
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'host:site'
What I tried
I noticed the first buildpack is executed, then the second one, then the predeploy hook kicks in.
I tried removing the nginx "static serve" buildpack and keep only the ruby one, and keep a bundle command in my predeploy hook. It worked and I didn't get the "command not found" error. So switching to the second buildpack seems to be messing things up for me.
I compared the path with and without the nginx "static serve" buildpack, and nothing weird. With the nginx buildpack, a new path is added but the previously set ruby paths are still there:
# with only ruby buildpack
/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/2.6.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# with both ruby & nginx buildpacks
/app/bin:/app/vendor/bundle/bin:/app/vendor/bundle/ruby/2.6.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/app/nginx
Eventually, I'm a bit lost here. Is it expected? Am I not following the dokku way? Am I getting this because of permissions issues, or something in Dokku that I'm not aware of?
For now, as a fallback, I'm serving the site by running a middleman server that receives all requests, but it makes no sense to dynamically serve a statically-generated website.
Thanks to jonrsharpe comment, I reoriented my searches and found this blog post on heroku engineering blog. Eventually, as stated by jonrsharpe:
The Nginx buildpack won't have Ruby in at all - you need to do any building in the Ruby buildpack context, so all the static buildpack needs to do is serve the results.
Therefore, to launch my middleman build command, I needed to hook somewhere in the ruby buildpack thing. And in the "jekyll on heroku" link, everything is explained: one should override the assets:precompile rake task.
Steps I followed
Add gem "rake" to my Gemfile (and bundle, of course)
Create a Rakefile with the assets:precompile task :
task "assets:precompile" do
exec("middleman build")
end
Enjoy!

Heroku is ignoring bundle configuration

I'm trying to install the gem 'taglib-ruby' on Heroku. This gem compiles as a native extension which requires a system dependency called taglib, so after compiling and uploading it through heroku vulcan, I achieved to compile the gem via command line on heroku bash:
bundle exec gem install taglib-ruby -- --with-opt-dir=/app/vendor/taglib
And in order to this parameter would be used by bundler later, I added it as a bundler configuration through the command:
bundle config build.taglib-ruby '--with-opt-dir=/app/vendor/taglib'
I've already verified this config was applied, inspecting the file /.bundle/config and looking for the line BUNDLE_BUILD__TAGLIB-RUBY.
However after pushing out my project to heroku and while it is executing the bundle install command, heroku complains that the above gem (taglib-ruby) cannot be installed due the taglib library isn't present, although it's what I was trying to solve with the option '--with-opt-dir=/app/vendor/taglib' mentioned above.
So it appears that Heroku is ignoring the bundler configuration.
What could be happening? Do you know another way the achieve the same intention (install a gem with custom build options) on Heroku?

Deploying to Heroku without a Gemfile

I'm working with an old Rails app that was initially built before Bundler and Gemfiles. Is it possible to push this app up to Heroku without a Gemfile? The app is in production on the Bamboo Stack and working without one. I'm trying to add a development environment on the Cedar Stack (Bamboo is now closed) and getting an error:
-----> Heroku receiving push
-----> Removing .DS_Store files
! Heroku push rejected, no Cedar-supported app detected
Is it no longer possible to push to Heroku without a Gemfile?
I'll add a Gemfile if that's what it takes.
The official word from Heroku Support:
Hi, yes you need a Gemfile for ruby apps; we don't have any gems
installed on the base system so that's how you specify them. That's
also how we detect it's a ruby app.
Also potentially useful: https://github.com/kch/gemfile-tool

Heroku wrongly detecting my Node app as a Ruby app

I have a Node project that is using Bundler and Guard to handle my pre-compilations steps.
This means that I have a Gemfile in the root of my project along with the package.json file.
My problem is that Heroku believes that my project is a Ruby app, just because the Gemfile exists. And complains that I have not committed the Gemfile.lock, which I don't want to commit.
-----> Heroku receiving push
-----> Ruby app detected
!
! Gemfile.lock is required. Please run "bundle install" locally
! and commit your Gemfile.lock.
!
! Heroku push rejected, failed to compile Ruby app
Is there a way to tell Heroku that the app is a Node app and not a Ruby app?
The solution to this, with a lot of help from Heroku Support is: use a build pack!
Override the Heroku default buildpacks by specifying a custom buildpack in the BUILDPACK_URL config var
$ heroku config:add BUILDPACK_URL=https://github.com/heroku/heroku-buildpack-nodejs
You can also specify a buildpack during app creation
$ heroku create -s cedar --buildpack https://github.com/heroku/heroku-buildpack-nodejs
Simple when you know it. Some more documentation can be found at Heroku Dev Center
It seems there's a new way to do this as BUILDPACK_URL is now deprecated, explained here, but essentially the command is:
$ heroku buildpacks:set heroku/nodejs
You may also specify a buildpack during app creation:
$ heroku create myapp --buildpack heroku/nodejs

Resources